riverbankcms 0.22.2 → 0.23.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,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { $t as assertNever, An as unsafeAsPositiveSeconds, B as parseWeeklyOpeningHours, Bn as unsafeAsUploadSessionId, C as stableJsonStringify, Dn as unsafeAsOriginalFilename, Fn as unsafeAsSiteId, H as isPresent, Hn as err, Ht as mapNonEmptyArray, In as unsafeAsSiteScopedStoragePath, L as isCanonicalRichTextDoc, M as parseFooterCompositionV1, Mn as unsafeAsProductId, N as footerNavigationLayouts, Nn as unsafeAsSafeDownloadFilename, Pn as unsafeAsSiteFontId, Rn as unsafeAsStorageBucketName, Tn as unsafeAsMediaAssetId, Un as ok, Ut as mapReadonlyNonEmptyArray, Vn as unsafeAsUserId, Vt as fromArray, _n as unsafeAsDeclaredMimeType, _t as validateBookingPaymentOptionKinds, bn as unsafeAsEntitlementId, c as resolveSiteVerticalBookingConfig, d as ORDINARY_EVENT_PRESET_VALUES, gt as parseBookingTimeZone, hn as unsafeAsBookingSessionId, kn as unsafeAsPositiveByteCount, mn as unsafeAsBookingRequirementId, on as parseMediaAssetId, r as NAVIGATION_LOCATIONS, st as localScheduleTimePattern, u as EVENT_PRESET_VALUES, un as parseSiteId, ut as parseUtcIsoDateTimeString, wn as unsafeAsFileChecksumSha256, yn as unsafeAsDetectedMimeType, z as parsePublicContactDetails, zn as unsafeAsStoragePath } from "./src-ZACBG29u.mjs";
2
+ import { An as unsafeAsPositiveByteCount, B as parsePublicContactDetails, Bn as unsafeAsStoragePath, En as unsafeAsMediaAssetId, Fn as unsafeAsSiteFontId, G as isPresent, Hn as unsafeAsUserId, Ht as fromArray, In as unsafeAsSiteId, Ln as unsafeAsSiteScopedStoragePath, N as parseFooterCompositionV1, Nn as unsafeAsProductId, On as unsafeAsOriginalFilename, P as footerNavigationLayouts, Pn as unsafeAsSafeDownloadFilename, R as isCanonicalRichTextDoc, Tn as unsafeAsFileChecksumSha256, Un as err, Ut as mapNonEmptyArray, V as parseWeeklyOpeningHours, Vn as unsafeAsUploadSessionId, Wn as ok, Wt as mapReadonlyNonEmptyArray, _t as parseBookingTimeZone, bn as unsafeAsDetectedMimeType, ct as localScheduleTimePattern, d as EVENT_PRESET_VALUES, dn as parseSiteId, dt as parseUtcIsoDateTimeString, en as assertNever, f as ORDINARY_EVENT_PRESET_VALUES, gn as unsafeAsBookingSessionId, hn as unsafeAsBookingRequirementId, i as NAVIGATION_LOCATIONS, jn as unsafeAsPositiveSeconds, l as resolveSiteVerticalBookingConfig, sn as parseMediaAssetId, t as authoredValuesEqual, vn as unsafeAsDeclaredMimeType, vt as validateBookingPaymentOptionKinds, w as stableJsonStringify, xn as unsafeAsEntitlementId, zn as unsafeAsStorageBucketName } from "./src-BPh_OivC.mjs";
3
3
  import "node:module";
4
4
  import { z } from "zod";
5
5
 
@@ -30,6 +30,21 @@ var __toESM = (mod$1, isNodeMode, target) => (target = mod$1 != null ? __create(
30
30
  enumerable: true
31
31
  }) : target, mod$1));
32
32
 
33
+ //#endregion
34
+ //#region ../theme-core/src/site-styles/ownedThemeSnapshot.ts
35
+ /** Copy before freezing: the editor still owns its source data. */
36
+ function ownedThemeSnapshot(input) {
37
+ return freezeOwnedThemeValue(structuredClone(input));
38
+ }
39
+ /** Only freshly owned data belongs here; no caller-owned object is frozen. */
40
+ function freezeOwnedThemeValue(value) {
41
+ if (typeof value === "object" && value !== null) {
42
+ Object.values(value).forEach(freezeOwnedThemeValue);
43
+ Object.freeze(value);
44
+ }
45
+ return value;
46
+ }
47
+
33
48
  //#endregion
34
49
  //#region ../theme-core/src/palette/utils/colorConversion.ts
35
50
  const clamp01$2 = (x) => Math.max(0, Math.min(1, x));
@@ -593,11 +608,33 @@ function relativeLuminance(r, g, b) {
593
608
  const R = srgbToLinear(r), G = srgbToLinear(g), B = srgbToLinear(b);
594
609
  return .2126 * R + .7152 * G + .0722 * B;
595
610
  }
596
- function contrastRatio(hex1, hex2) {
597
- const { r: r1, g: g1, b: b1 } = hexToRgb(hex1);
598
- const { r: r2, g: g2, b: b2 } = hexToRgb(hex2);
599
- const L1 = relativeLuminance(r1, g1, b1);
600
- const L2 = relativeLuminance(r2, g2, b2);
611
+ function preparePaletteColourIndex(palette) {
612
+ const colours = [...new Set([
613
+ ...Object.values(palette),
614
+ "#000000",
615
+ "#ffffff",
616
+ "#FFFFFF"
617
+ ])];
618
+ return Object.freeze(Object.fromEntries(colours.flatMap(colourIndexEntry)));
619
+ }
620
+ /** An unused unsupported colour must not turn preparation into an eager validation failure. */
621
+ function colourIndexEntry(hex) {
622
+ try {
623
+ return [[hex, colourLuminance(hex)]];
624
+ } catch {
625
+ return [];
626
+ }
627
+ }
628
+ function colourLuminance(hex) {
629
+ const { r, g, b } = hexToRgb(hex);
630
+ return relativeLuminance(r, g, b);
631
+ }
632
+ function indexedLuminance(hex, index) {
633
+ return (index && Object.prototype.hasOwnProperty.call(index, hex) ? index[hex] : undefined) ?? colourLuminance(hex);
634
+ }
635
+ function contrastRatio(hex1, hex2, index) {
636
+ const L1 = indexedLuminance(hex1, index);
637
+ const L2 = indexedLuminance(hex2, index);
601
638
  const [hi, lo] = L1 >= L2 ? [L1, L2] : [L2, L1];
602
639
  return (hi + .05) / (lo + .05);
603
640
  }
@@ -1719,6 +1756,7 @@ function defineButtonStyleRecipe(recipe) {
1719
1756
  }
1720
1757
  function mapButtonVisualAppearances(states$1, transform) {
1721
1758
  return {
1759
+ ...states$1,
1722
1760
  base: transform(states$1.base, "base"),
1723
1761
  hover: transform(states$1.hover, "hover"),
1724
1762
  focus: transform(states$1.focus, "focus"),
@@ -2593,7 +2631,7 @@ function formatButtonColourContractError(error) {
2593
2631
  }
2594
2632
  }
2595
2633
  function validateButtonSurfaceContrast(input) {
2596
- const ratio$1 = contrastRatio(input.buttonPaint, input.surfaceHex);
2634
+ const ratio$1 = contrastRatio(input.buttonPaint, input.surfaceHex, input.colourIndex);
2597
2635
  return ratio$1 >= BUTTON_CONTRAST_POLICY.nonTextMinimumRatio ? { ok: true } : {
2598
2636
  ok: false,
2599
2637
  error: {
@@ -2608,7 +2646,7 @@ function validateButtonSurfaceContrast(input) {
2608
2646
  };
2609
2647
  }
2610
2648
  function validateButtonTextContrast(input) {
2611
- const ratio$1 = contrastRatio(input.backgroundHex, input.foregroundHex);
2649
+ const ratio$1 = contrastRatio(input.backgroundHex, input.foregroundHex, input.colourIndex);
2612
2650
  return ratio$1 >= BUTTON_CONTRAST_POLICY.textMinimumRatio ? { ok: true } : {
2613
2651
  ok: false,
2614
2652
  error: {
@@ -2631,7 +2669,7 @@ function solidForegroundToken(backgroundToken$1) {
2631
2669
  //#region ../theme-core/src/buttons/contextualHover.ts
2632
2670
  function resolveContextualHoverPreference(input) {
2633
2671
  const preferred = input.instruction.preferredToken;
2634
- if (preferred && isSafeCandidate(preferred, input.palette, input.surface)) {
2672
+ if (preferred && isSafeCandidate(preferred, input.palette, input.surface, input.colourIndex)) {
2635
2673
  return {
2636
2674
  kind: "resolved",
2637
2675
  token: preferred,
@@ -2663,7 +2701,7 @@ function resolveContextualHover(input) {
2663
2701
  reason: "no-distinct-shade"
2664
2702
  };
2665
2703
  }
2666
- const textSafe = candidates.filter((candidate$1) => hasSafeTextContrast(candidate$1.token, input.palette));
2704
+ const textSafe = candidates.filter((candidate$1) => hasSafeTextContrast(candidate$1.token, input.palette, input.colourIndex));
2667
2705
  if (textSafe.length === 0) {
2668
2706
  return {
2669
2707
  kind: "unavailable",
@@ -2682,18 +2720,12 @@ function resolveContextualHover(input) {
2682
2720
  reason: "no-text-safe-candidate"
2683
2721
  };
2684
2722
  }
2685
- const surfaceSafe = textSafe.map((candidate$1) => ({
2686
- ...candidate$1,
2687
- surfaceContrast: contrastRatio(input.palette[candidate$1.token] ?? "", input.surface?.backgroundHex ?? "")
2688
- })).filter((candidate$1) => candidate$1.surfaceContrast !== null && candidate$1.surfaceContrast >= BUTTON_CONTRAST_POLICY.nonTextMinimumRatio).sort((left, right) => {
2689
- const distanceDifference = left.distance - right.distance;
2690
- if (distanceDifference !== 0) return distanceDifference;
2691
- const contrastDifference = (right.surfaceContrast ?? 0) - (left.surfaceContrast ?? 0);
2692
- if (contrastDifference !== 0) return contrastDifference;
2693
- if (left.direction === right.direction) return left.token.localeCompare(right.token);
2694
- return left.direction === input.instruction.fallbackDirection ? -1 : 1;
2723
+ const selected = selectSurfaceSafeHover(textSafe, {
2724
+ palette: input.palette,
2725
+ surface: input.surface,
2726
+ colourIndex: input.colourIndex,
2727
+ fallbackDirection: input.instruction.fallbackDirection
2695
2728
  });
2696
- const selected = surfaceSafe[0];
2697
2729
  return selected ? {
2698
2730
  kind: "resolved",
2699
2731
  token: selected.token,
@@ -2704,6 +2736,21 @@ function resolveContextualHover(input) {
2704
2736
  reason: "no-surface-safe-candidate"
2705
2737
  };
2706
2738
  }
2739
+ /** Rank the proven-surface candidates without mixing selection with fallback policy. */
2740
+ function selectSurfaceSafeHover(candidates, input) {
2741
+ const surfaceSafe = candidates.map((candidate$1) => ({
2742
+ ...candidate$1,
2743
+ surfaceContrast: contrastRatio(input.palette[candidate$1.token] ?? "", input.surface.backgroundHex, input.colourIndex)
2744
+ })).filter((candidate$1) => candidate$1.surfaceContrast !== null && candidate$1.surfaceContrast >= BUTTON_CONTRAST_POLICY.nonTextMinimumRatio).sort((left, right) => {
2745
+ const distanceDifference = left.distance - right.distance;
2746
+ if (distanceDifference !== 0) return distanceDifference;
2747
+ const contrastDifference = (right.surfaceContrast ?? 0) - (left.surfaceContrast ?? 0);
2748
+ if (contrastDifference !== 0) return contrastDifference;
2749
+ if (left.direction === right.direction) return left.token.localeCompare(right.token);
2750
+ return left.direction === input.fallbackDirection ? -1 : 1;
2751
+ });
2752
+ return surfaceSafe[0];
2753
+ }
2707
2754
  function shadeCandidates(seedToken, palette) {
2708
2755
  const match = String(seedToken).match(/^(.*?)(?:-(\d{2,3}))?$/);
2709
2756
  const family = match?.[1] ?? String(seedToken);
@@ -2729,14 +2776,14 @@ function candidate(family, shade, currentShade, direction, seedHex, palette) {
2729
2776
  surfaceContrast: null
2730
2777
  };
2731
2778
  }
2732
- function hasSafeTextContrast(token, palette) {
2779
+ function hasSafeTextContrast(token, palette, colourIndex) {
2733
2780
  const background = palette[token];
2734
2781
  const foreground = palette[solidForegroundToken(token)];
2735
- return typeof background === "string" && typeof foreground === "string" && contrastRatio(background, foreground) >= BUTTON_CONTRAST_POLICY.textMinimumRatio;
2782
+ return typeof background === "string" && typeof foreground === "string" && contrastRatio(background, foreground, colourIndex) >= BUTTON_CONTRAST_POLICY.textMinimumRatio;
2736
2783
  }
2737
- function isSafeCandidate(token, palette, surface$1) {
2738
- if (!hasSafeTextContrast(token, palette)) return false;
2739
- return surface$1 ? contrastRatio(palette[token] ?? "", surface$1.backgroundHex) >= BUTTON_CONTRAST_POLICY.nonTextMinimumRatio : true;
2784
+ function isSafeCandidate(token, palette, surface$1, colourIndex) {
2785
+ if (!hasSafeTextContrast(token, palette, colourIndex)) return false;
2786
+ return surface$1 ? contrastRatio(palette[token] ?? "", surface$1.backgroundHex, colourIndex) >= BUTTON_CONTRAST_POLICY.nonTextMinimumRatio : true;
2740
2787
  }
2741
2788
  function escapeRegExp(value) {
2742
2789
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
@@ -2749,6 +2796,7 @@ function resolveButtonHoverTreatment(input) {
2749
2796
  const contextual = resolveContextualHoverPreference({
2750
2797
  instruction: input.variant.contextualHover,
2751
2798
  palette: input.palette,
2799
+ colourIndex: input.colourIndex,
2752
2800
  surface: input.surface
2753
2801
  });
2754
2802
  if (contextual.kind === "resolved") {
@@ -2803,7 +2851,8 @@ function compileButtonColourStates(input) {
2803
2851
  global: input.global,
2804
2852
  fallback: base.treatment,
2805
2853
  palette: input.palette,
2806
- surface: input.surface
2854
+ surface: input.surface,
2855
+ colourIndex: input.colourIndex
2807
2856
  });
2808
2857
  const edge = buttonEdge(input.variant);
2809
2858
  const results = mapVisualStates((state) => compileVisualState(input, state, state === "hover" ? hover.treatment : base.treatment, edge, base.nonColourEffects));
@@ -2863,6 +2912,7 @@ function compileDeclaredVisualState(input, states$1, state, treatment) {
2863
2912
  treatment: transition.treatment,
2864
2913
  palette: input.palette,
2865
2914
  surface: input.surface,
2915
+ colourIndex: input.colourIndex,
2866
2916
  edge
2867
2917
  });
2868
2918
  return resolved.ok ? {
@@ -2890,6 +2940,7 @@ function compileVisualState(input, state, treatment, edge, baseEffects) {
2890
2940
  treatment: transition.treatment,
2891
2941
  palette: input.palette,
2892
2942
  surface: input.surface,
2943
+ colourIndex: input.colourIndex,
2893
2944
  edge
2894
2945
  });
2895
2946
  return resolved.ok ? {
@@ -3113,11 +3164,11 @@ function interpolateHex(startHex, endHex, position) {
3113
3164
  * Derive only what the rendered section can honestly prove about its backing.
3114
3165
  * Images, gradients, alpha/composite layers and arbitrary CSS remain unknown.
3115
3166
  */
3116
- function deriveButtonSurfaceContext(input, palette, fallbackToken) {
3167
+ function deriveButtonSurfaceContext(input, palette, fallbackToken, colourIndex) {
3117
3168
  const background = deriveKnownBackground(input, palette, fallbackToken);
3118
3169
  if (background.kind === "unknown") return background;
3119
3170
  const explicitForeground = resolveKnownColour(input.kind === "solid" || input.kind === "inherit" ? input.foreground ?? "" : "", palette);
3120
- const foreground = explicitForeground && contrastRatio(background.colour.hex, explicitForeground.hex) >= ORDINARY_TEXT_MIN_CONTRAST_RATIO ? explicitForeground : safestBlackOrWhite(background.colour.hex);
3171
+ const foreground = explicitForeground && contrastRatio(background.colour.hex, explicitForeground.hex, colourIndex) >= ORDINARY_TEXT_MIN_CONTRAST_RATIO ? explicitForeground : safestBlackOrWhite(background.colour.hex, colourIndex);
3121
3172
  return {
3122
3173
  kind: "known-solid",
3123
3174
  source: background.source,
@@ -3202,7 +3253,7 @@ function resolveSurfaceButtonContext(input) {
3202
3253
  kind: "inherit",
3203
3254
  styles: {}
3204
3255
  };
3205
- const context = deriveButtonSurfaceContext(input.surface, input.palette, input.fallbackToken);
3256
+ const context = deriveButtonSurfaceContext(input.surface, input.palette, input.fallbackToken, input.colourIndex);
3206
3257
  if (context.kind !== "known-solid") {
3207
3258
  return context.reason === "missing-background" ? {
3208
3259
  kind: "inherit",
@@ -3217,6 +3268,7 @@ function resolveSurfaceButtonContext(input) {
3217
3268
  styles: knownSurfaceButtonContextStyles({
3218
3269
  surface: context.surface,
3219
3270
  palette: input.palette,
3271
+ colourIndex: input.colourIndex,
3220
3272
  buttonSystem: surfaceButtonSystem(input.buttonSystem, input.primaryToken)
3221
3273
  })
3222
3274
  };
@@ -3227,6 +3279,7 @@ function knownSurfaceButtonContextStyles(input) {
3227
3279
  role,
3228
3280
  buttonSystem: input.buttonSystem,
3229
3281
  palette: input.palette,
3282
+ colourIndex: input.colourIndex,
3230
3283
  surface: input.surface
3231
3284
  })))));
3232
3285
  }
@@ -3237,59 +3290,54 @@ function resolveContextualButtonRole(input) {
3237
3290
  requestedRole: input.role,
3238
3291
  rejectedCandidates: []
3239
3292
  };
3240
- const rejected$1 = [];
3241
- const preferred = compileCandidate(requested, input.buttonSystem, input.palette, input.surface);
3242
- if (preferred.ok) {
3243
- if (preferred.contextualHoverRepair) {
3244
- return {
3245
- kind: "repaired",
3246
- requestedRole: input.role,
3247
- candidate: "contextual-hover",
3248
- states: preferred.states,
3249
- focusIndicator: preferred.focusIndicator,
3250
- boundary: boundaryForVariant(requested),
3251
- rejectedCandidates: []
3252
- };
3253
- }
3254
- return {
3255
- kind: "preferred",
3256
- requestedRole: input.role,
3257
- states: preferred.states,
3258
- focusIndicator: preferred.focusIndicator,
3259
- boundary: boundaryForVariant(requested)
3260
- };
3261
- }
3262
- rejected$1.push({
3293
+ const preferred = compileCandidate(requested, input);
3294
+ if (preferred.ok) return preferredButtonResolution(requested, preferred, input.role);
3295
+ const policy = input.buttonSystem.surfacePolicy ?? STANDARD_BUTTON_SURFACE_POLICY;
3296
+ return resolveFallbackButtonRole(input, requested, policy[input.role], [{
3263
3297
  candidate: "preferred",
3264
3298
  error: preferred.error
3265
- });
3266
- const policy = input.buttonSystem.surfacePolicy ?? STANDARD_BUTTON_SURFACE_POLICY;
3267
- for (const fallback of policy[input.role]) {
3268
- const candidate$1 = candidateVariant(fallback, requested, input.buttonSystem);
3269
- if (!candidate$1) continue;
3270
- const compiled = compileCandidate(candidate$1.variant, input.buttonSystem, input.palette, input.surface);
3271
- if (!compiled.ok) {
3272
- rejected$1.push({
3273
- candidate: candidate$1.name,
3274
- error: compiled.error
3275
- });
3276
- continue;
3277
- }
3278
- return {
3279
- kind: "repaired",
3280
- requestedRole: input.role,
3281
- candidate: candidate$1.name,
3282
- states: candidate$1.name === "surface-outline" ? withSurfaceInversion(compiled.states, input.surface) : compiled.states,
3283
- focusIndicator: compiled.focusIndicator,
3284
- boundary: candidate$1.boundary,
3285
- rejectedCandidates: rejected$1
3286
- };
3287
- }
3288
- return {
3299
+ }]);
3300
+ }
3301
+ function preferredButtonResolution(requested, compiled, role) {
3302
+ const appearance = {
3303
+ requestedRole: role,
3304
+ states: compiled.states,
3305
+ focusIndicator: compiled.focusIndicator,
3306
+ boundary: boundaryForVariant(requested)
3307
+ };
3308
+ return compiled.contextualHoverRepair ? {
3309
+ ...appearance,
3310
+ kind: "repaired",
3311
+ candidate: "contextual-hover",
3312
+ rejectedCandidates: []
3313
+ } : {
3314
+ ...appearance,
3315
+ kind: "preferred"
3316
+ };
3317
+ }
3318
+ /** Ordered, lazy fallback selection; the rejected evidence belongs to this decision. */
3319
+ function resolveFallbackButtonRole(input, requested, fallbacks, rejected$1) {
3320
+ const [fallback, ...remaining] = fallbacks;
3321
+ if (!fallback) return {
3289
3322
  kind: "unresolved",
3290
3323
  requestedRole: input.role,
3291
3324
  rejectedCandidates: rejected$1
3292
3325
  };
3326
+ const candidate$1 = candidateVariant(fallback, requested, input.buttonSystem);
3327
+ if (!candidate$1) return resolveFallbackButtonRole(input, requested, remaining, rejected$1);
3328
+ const compiled = compileCandidate(candidate$1.variant, input);
3329
+ return compiled.ok ? {
3330
+ kind: "repaired",
3331
+ requestedRole: input.role,
3332
+ candidate: candidate$1.name,
3333
+ states: candidate$1.name === "surface-outline" ? withSurfaceInversion(compiled.states, input.surface) : compiled.states,
3334
+ focusIndicator: compiled.focusIndicator,
3335
+ boundary: candidate$1.boundary,
3336
+ rejectedCandidates: rejected$1
3337
+ } : resolveFallbackButtonRole(input, requested, remaining, [...rejected$1, {
3338
+ candidate: candidate$1.name,
3339
+ error: compiled.error
3340
+ }]);
3293
3341
  }
3294
3342
  function contextualButtonSurfaceStyles(resolution) {
3295
3343
  if (resolution.kind === "unresolved") {
@@ -3362,12 +3410,13 @@ function actionVariableFallback(role, state, property, fallback) {
3362
3410
  function actionVariablePrefix(role, state) {
3363
3411
  return `--rb-action-${role}-${state}`;
3364
3412
  }
3365
- function compileCandidate(variant, system, palette, surface$1) {
3413
+ function compileCandidate(variant, context) {
3366
3414
  return compileButtonColourStates({
3367
3415
  variant,
3368
- global: system.global,
3369
- palette,
3370
- surface: surface$1
3416
+ global: context.buttonSystem.global,
3417
+ palette: context.palette,
3418
+ surface: context.surface,
3419
+ colourIndex: context.colourIndex
3371
3420
  });
3372
3421
  }
3373
3422
  function candidateVariant(fallback, requested, system) {
@@ -3491,8 +3540,8 @@ function normalizeOpaqueHex(value) {
3491
3540
  const digits = match[1].length === 3 ? match[1].split("").map((digit) => `${digit}${digit}`).join("") : match[1];
3492
3541
  return `#${digits.toLowerCase()}`;
3493
3542
  }
3494
- function safestBlackOrWhite(backgroundHex) {
3495
- return contrastRatio(backgroundHex, "#000000") >= contrastRatio(backgroundHex, "#ffffff") ? {
3543
+ function safestBlackOrWhite(backgroundHex, colourIndex) {
3544
+ return contrastRatio(backgroundHex, "#000000", colourIndex) >= contrastRatio(backgroundHex, "#ffffff", colourIndex) ? {
3496
3545
  hex: "#000000",
3497
3546
  css: "#000000",
3498
3547
  source: "literal-css"
@@ -3519,8 +3568,10 @@ function contextualBoundaryStyles(boundary) {
3519
3568
  //#endregion
3520
3569
  //#region ../theme-core/src/surfaces/opaqueSurface.ts
3521
3570
  function opaqueSurfaceContextFromTheme(theme) {
3571
+ const palette = expandPalette(theme.palette);
3522
3572
  return {
3523
- palette: expandPalette(theme.palette),
3573
+ palette,
3574
+ colourIndex: preparePaletteColourIndex(palette),
3524
3575
  buttonSystem: theme.buttons,
3525
3576
  linkHoverToken: theme.typography.proseLinkStyle?.hoverColorToken
3526
3577
  };
@@ -4451,8 +4502,82 @@ function assertNeverSurface(value) {
4451
4502
  throw new Error(`Unhandled Theme V2 surface intent: ${String(value)}`);
4452
4503
  }
4453
4504
  function resolveSurface(spec, context) {
4505
+ return spec.kind === "section" ? resolveSectionSurface(spec.background, context) : preparedSurfaceValue(spec, context) ?? resolveSurfaceSpec(spec, context);
4506
+ }
4507
+ /** Own one theme revision; derive its surface decisions without copying its inputs again. */
4508
+ function prepareThemeSurfaceRevision(inputTheme, selectSurfaces = () => []) {
4509
+ const theme = structuredClone(inputTheme);
4510
+ const snapshot = freezeOwnedThemeValue(theme);
4511
+ const declarations = ownedThemeSnapshot(selectSurfaces(snapshot));
4512
+ const palette = freezeOwnedThemeValue(expandPalette(snapshot.palette, {
4513
+ arrangement: snapshot.skin !== undefined,
4514
+ marksFrom: snapshot.skinMarks
4515
+ }));
4516
+ const context = Object.freeze({
4517
+ kind: "concrete-palette",
4518
+ palette,
4519
+ colourIndex: preparePaletteColourIndex(palette),
4520
+ buttonSystem: snapshot.buttons
4521
+ });
4522
+ const preparedSurfaces = declarations.length === 0 ? undefined : surfaceIndexFromOwnedInputs(declarations, context);
4523
+ return Object.freeze({
4524
+ theme,
4525
+ context: Object.freeze({
4526
+ ...context,
4527
+ preparedSurfaces
4528
+ })
4529
+ });
4530
+ }
4531
+ function prepareSurfaceIndex(specs, context) {
4532
+ const snapshot = ownedThemeSnapshot({
4533
+ palette: context.palette,
4534
+ buttonSystem: context.buttonSystem,
4535
+ colourIndex: context.colourIndex,
4536
+ linkHoverToken: context.linkHoverToken,
4537
+ foreground: context.foreground,
4538
+ compositeBase: context.compositeBase,
4539
+ buttonContext: context.buttonContext
4540
+ });
4541
+ return surfaceIndexFromOwnedInputs(ownedThemeSnapshot(specs), snapshot);
4542
+ }
4543
+ /** Private construction path: both entry points above own and freeze these inputs. */
4544
+ function surfaceIndexFromOwnedInputs(specs, context) {
4545
+ const unique = new Map(specs.map((spec) => [surfaceResolutionKey(spec, context), spec]));
4546
+ const entries = [...unique].flatMap(([key, spec]) => preparedSurfaceEntry(key, spec, context));
4547
+ return Object.freeze({
4548
+ palette: context.palette,
4549
+ buttonSystem: context.buttonSystem,
4550
+ colourIndex: context.colourIndex,
4551
+ values: freezeOwnedThemeValue(Object.fromEntries(entries))
4552
+ });
4553
+ }
4554
+ function preparedSurfaceEntry(key, spec, context) {
4555
+ try {
4556
+ return [[key, resolveSurfaceSpec(spec, context)]];
4557
+ } catch {
4558
+ return [];
4559
+ }
4560
+ }
4561
+ function preparedSurfaceValue(spec, context) {
4562
+ const index = context.preparedSurfaces;
4563
+ if (!index || index.palette !== context.palette || index.buttonSystem !== context.buttonSystem || index.colourIndex !== context.colourIndex) return undefined;
4564
+ return index.values[surfaceResolutionKey(spec, context)];
4565
+ }
4566
+ function surfaceResolutionKey(spec, context) {
4567
+ const declaration = spec.kind === "tint" ? {
4568
+ ...spec,
4569
+ opacity: String(spec.opacity)
4570
+ } : spec;
4571
+ return JSON.stringify([
4572
+ declaration,
4573
+ context.linkHoverToken,
4574
+ context.foreground,
4575
+ context.compositeBase,
4576
+ context.buttonContext
4577
+ ]);
4578
+ }
4579
+ function resolveSurfaceSpec(spec, context) {
4454
4580
  switch (spec.kind) {
4455
- case "section": return resolveSectionSurface(spec.background, context);
4456
4581
  case "recipe": return resolveRecipeSurface(spec.intent, context);
4457
4582
  case "paint": return spec.paint.kind === "transparent" ? { kind: "inherit" } : resolveOwnedSurface(spec.paint, context);
4458
4583
  case "token": return resolveOwnedSurface({
@@ -4533,7 +4658,7 @@ function resolveOwnedSurface(paint, context) {
4533
4658
  decorations: surfaceDecorationColors(resolved, context.palette),
4534
4659
  hoverDecoration: resolved.kind === "known" ? resolved.hoverDecoration : "underline",
4535
4660
  buttonContext: resolveSurfaceButtons(paint, resolved, context),
4536
- contrast: surfaceContrast(resolved, context.palette)
4661
+ contrast: surfaceContrast(resolved, context.palette, context.colourIndex)
4537
4662
  };
4538
4663
  }
4539
4664
  /** Unprovable legacy paint retains its declared foreground instead of inventing one. */
@@ -4558,15 +4683,16 @@ function resolveSurfaceButtons(paint, foreground, context) {
4558
4683
  foreground: foreground.kind === "known" ? foreground.roles.link : undefined
4559
4684
  } : { kind: "gradient" },
4560
4685
  palette: context.palette,
4686
+ colourIndex: context.colourIndex,
4561
4687
  buttonSystem: context.buttonSystem,
4562
4688
  primaryToken: context.buttonContext?.primary ?? (paint.kind === "solid" ? context.buttonSystem?.surfaceContexts?.[paint.token]?.primary : undefined),
4563
4689
  withoutButtonSystem: "reset"
4564
4690
  });
4565
4691
  }
4566
- function surfaceContrast(foreground, palette) {
4692
+ function surfaceContrast(foreground, palette, colourIndex) {
4567
4693
  if (foreground.kind !== "known" || foreground.provenance.kind !== "measured") return { kind: "unmeasured" };
4568
4694
  const backdrop = foreground.provenance.backdropHex;
4569
- const ratio$1 = (token) => contrastRatio(resolveConcreteColorHex(token, palette) ?? backdrop, backdrop);
4695
+ const ratio$1 = (token) => contrastRatio(resolveConcreteColorHex(token, palette) ?? backdrop, backdrop, colourIndex);
4570
4696
  const ratios = {
4571
4697
  text: ratio$1(foreground.roles.text),
4572
4698
  heading: ratio$1(foreground.roles.heading),
@@ -4598,6 +4724,7 @@ function resolveSectionSurface(background, context) {
4598
4724
  buttonStyles: resolveSurfaceButtonContext({
4599
4725
  surface: surface$1,
4600
4726
  palette: context.palette,
4727
+ colourIndex: context.colourIndex,
4601
4728
  buttonSystem: context.buttonSystem,
4602
4729
  primaryToken: sectionPrimaryButtonToken(background, context),
4603
4730
  fallbackToken: context.compositeBase,
@@ -4617,10 +4744,11 @@ function surfaceDecorationColors(foreground, palette) {
4617
4744
  }
4618
4745
  /** Composite the declared palette tint before checking every foreground role. */
4619
4746
  function resolveTintSurface(spec, context) {
4620
- const base = resolveOwnedSurface({
4621
- kind: "solid",
4747
+ const base = resolveSurface({
4748
+ kind: "token",
4622
4749
  token: spec.base
4623
4750
  }, context);
4751
+ if (base.kind !== "owned") throw new Error(`Cannot derive tint on ${spec.base}`);
4624
4752
  const source = spec.source === "text" ? base.foreground.text : base.decorations?.mark;
4625
4753
  const token = source ? resolveOpaqueSurfaceHex(`${source}/${spec.opacity}`, context.palette, spec.base) : null;
4626
4754
  const hex = source ? resolveConcreteColorHex(source, context.palette) : null;
@@ -4971,7 +5099,7 @@ const lookKnobBlocks = {
4971
5099
  smallCaption: "block.hero",
4972
5100
  candleGlow: "block.hero",
4973
5101
  columnGuides: "block.hero",
4974
- showPhotos: cardListFamilyBlocks,
5102
+ showPhotos: cardListKnobBlocks,
4975
5103
  cardMarker: cardListFamilyBlocks,
4976
5104
  dates: "block.offerings-preview",
4977
5105
  showCapacity: "block.event-calendar",
@@ -6086,7 +6214,7 @@ const blockAppearancePresets = [
6086
6214
  }),
6087
6215
  defineArrangementLook("event-calendar-ruled-rows", "event-calendar", "Ruled rows", "ledger", ["showCapacity"]),
6088
6216
  defineArrangementLook("event-calendar-grouped-by-day", "event-calendar", "Grouped by day", "day-groups", ["showCapacity"], { styleFallback: [id$1("event-calendar-ruled-rows")] }),
6089
- defineArrangementLook("event-calendar-session-cards", "event-calendar", "Session cards", "grid", ["showCapacity"], {
6217
+ defineArrangementLook("event-calendar-session-cards", "event-calendar", "Session cards", "grid", ["showCapacity", "showPhotos"], {
6090
6218
  itemRoles: { items: "card" },
6091
6219
  slotRoles: { date: "highlight" },
6092
6220
  styleFallback: [id$1("event-calendar-ruled-rows")]
@@ -6095,6 +6223,22 @@ const blockAppearancePresets = [
6095
6223
  itemRoles: { container: "card" },
6096
6224
  styleFallback: [id$1("event-calendar-ruled-rows")]
6097
6225
  }),
6226
+ defineArrangementLook("events-spotlight", "event-calendar", "Event spotlight", "grid", ["showCapacity", "showPhotos"], {
6227
+ itemRoles: { items: "card" },
6228
+ slotRoles: { date: "highlight" },
6229
+ styleFallback: [id$1("event-calendar-session-cards")]
6230
+ }),
6231
+ {
6232
+ ...defineArrangementLook("events-recurring-week", "event-calendar", "Weekly schedule", "ledger", []),
6233
+ structure: {
6234
+ kind: "arrangement",
6235
+ byMode: { week: "ledger" },
6236
+ knobs: [],
6237
+ itemRoles: {},
6238
+ whenMissing: [],
6239
+ styleFallback: []
6240
+ }
6241
+ },
6098
6242
  defineArrangementLook("hero-framed-title", "hero", "Title framed between two photos", "copy-over-gallery", ["titleSize", "smallCaption"], { styleFallback: [id$1("hero-copy-over-gallery")] }),
6099
6243
  defineArrangementLook("testimonials-lead-quote", "testimonials", "Big quote with others beside", "lead-rest", ["quoteCount"], { knobDescriptions: { quoteCount: "Shows your chosen quotes: the first one large, the rest beside it." } }),
6100
6244
  defineArrangementLook("testimonials-quote-cards", "testimonials", "Quote cards", "columns", ["quoteCount"], {
@@ -15242,13 +15386,13 @@ const pageDesignBlockLookPinSchema = z.object({
15242
15386
  choice: pageDesignUserPinnedAppearanceChoiceSchema
15243
15387
  }).strict();
15244
15388
  const pageDesignBoundaryPinSchema = z.object({
15245
- boundaryId: z.string().min(1).transform(asDesignBoundaryId),
15389
+ boundaryId: z.string().min(1).startsWith("boundary:", { error: "DesignBoundaryId must start with \"boundary:\"." }).transform(asDesignBoundaryId),
15246
15390
  previousBlockId: z.string().min(1).transform(asDesignBlockId),
15247
15391
  nextBlockId: z.string().min(1).transform(asDesignBlockId),
15248
15392
  choice: pageDesignUserPinnedBoundaryTreatmentChoiceSchema
15249
15393
  }).strict().superRefine(validateBoundaryPinIdMatchesBlocks);
15250
15394
  const legacyPageDesignBoundaryPinSchema = z.object({
15251
- boundaryId: z.string().min(1).transform(asDesignBoundaryId),
15395
+ boundaryId: z.string().min(1).startsWith("boundary:", { error: "DesignBoundaryId must start with \"boundary:\"." }).transform(asDesignBoundaryId),
15252
15396
  previousBlockId: z.string().min(1).transform(asDesignBlockId),
15253
15397
  nextBlockId: z.string().min(1).transform(asDesignBlockId),
15254
15398
  choice: pageDesignUserPinnedBoundaryChoiceSchema
@@ -15260,18 +15404,18 @@ const legacyPageDesignBoundaryPinSchema = z.object({
15260
15404
  */
15261
15405
  const pageDesignIntentV1Schema = z.object({
15262
15406
  schemaVersion: z.literal(legacyPageDesignIntentSchemaVersion),
15263
- siteStyleId: z.string().min(1).transform(asSiteStyleId),
15407
+ siteStyleId: z.string().min(1).startsWith("site-style:", { error: "SiteStyleId must start with \"site-style:\"." }).transform(asSiteStyleId),
15264
15408
  pageFlowPresetId: z.string().min(1).transform(asPageFlowPresetId),
15265
15409
  blockLookPins: z.array(pageDesignBlockLookPinSchema),
15266
15410
  boundaryPins: z.array(legacyPageDesignBoundaryPinSchema)
15267
15411
  }).strict().superRefine(validateUniquePageDesignPins);
15268
- const pageDesignIntentV2Schema = z.object({
15412
+ const pageDesignDecisionsV2Schema = z.object({
15269
15413
  schemaVersion: z.literal(pageDesignIntentSchemaVersion),
15270
- siteStyleId: z.string().min(1).transform(asSiteStyleId),
15271
15414
  pageFlowPresetId: z.string().min(1).transform(asPageFlowPresetId),
15272
15415
  blockLookPins: z.array(pageDesignBlockLookPinSchema),
15273
15416
  boundaryPins: z.array(pageDesignBoundaryPinSchema)
15274
15417
  }).strict().superRefine(validateUniquePageDesignPins);
15418
+ const pageDesignIntentV2Schema = pageDesignDecisionsV2Schema.safeExtend({ siteStyleId: z.string().min(1).startsWith("site-style:", { error: "SiteStyleId must start with \"site-style:\"." }).transform(asSiteStyleId) });
15275
15419
  function parsePageDesignIntent(value, options = {}) {
15276
15420
  if (isLegacyPageDesignIntentCandidate(value)) {
15277
15421
  const legacyParsed = parseSchemaVersionedJson({
@@ -15806,6 +15950,15 @@ function followStyleFallback(look, options, catalogue, mode, chain, visited) {
15806
15950
  }
15807
15951
  /** Design-stage serialisable payload; content-dependent choices stay downstream. */
15808
15952
  function compileArrangementLookRuntime(input) {
15953
+ const surfaceContext = {
15954
+ palette: input.context.palette,
15955
+ buttonSystem: input.context.buttonSystem,
15956
+ colourIndex: input.context.colourIndex
15957
+ };
15958
+ const resolutionContext = {
15959
+ ...surfaceContext,
15960
+ preparedSurfaces: input.context.preparedSurfaces
15961
+ };
15809
15962
  const available = input.looks.flatMap((look) => {
15810
15963
  const offer = input.style.offers.find((candidate$1) => candidate$1.id === look.id);
15811
15964
  if (!offer) return [];
@@ -15813,10 +15966,7 @@ function compileArrangementLookRuntime(input) {
15813
15966
  const surfaceStyle = {
15814
15967
  roleMap: offer.roleMap,
15815
15968
  surfaces: input.style.surfaces,
15816
- context: {
15817
- palette: input.context.palette,
15818
- buttonSystem: input.context.buttonSystem
15819
- }
15969
+ context: resolutionContext
15820
15970
  };
15821
15971
  const itemSurfaces = resolveLookSlotSurfaces(look, roles, {
15822
15972
  card: resolveItemSurface("card", "light", surfaceStyle),
@@ -15839,10 +15989,7 @@ function compileArrangementLookRuntime(input) {
15839
15989
  return {
15840
15990
  available,
15841
15991
  surfaces: input.style.surfaces,
15842
- surfaceContext: {
15843
- palette: input.context.palette,
15844
- buttonSystem: input.context.buttonSystem
15845
- },
15992
+ surfaceContext,
15846
15993
  byMode: Object.fromEntries(Object.entries(input.selected).flatMap(([mode, look]) => {
15847
15994
  const compiled = available.find((candidate$1) => candidate$1.look.id === look.id);
15848
15995
  return compiled ? [[mode, compiled]] : [];
@@ -15850,10 +15997,7 @@ function compileArrangementLookRuntime(input) {
15850
15997
  rhythm: (input.style.rhythm?.[input.flowPreset] ?? []).flatMap((surfaceName) => {
15851
15998
  const spec = input.style.surfaces[surfaceName];
15852
15999
  if (!spec) throw new Error(`Undeclared rhythm surface ${surfaceName}`);
15853
- const surface$1 = resolveSurface(spec, {
15854
- palette: input.context.palette,
15855
- buttonSystem: input.context.buttonSystem
15856
- });
16000
+ const surface$1 = resolveSurface(spec, resolutionContext);
15857
16001
  return surface$1.kind === "owned" && surface$1.paint.kind === "solid" ? [{
15858
16002
  type: "color",
15859
16003
  color: surface$1.paint.token,
@@ -17493,7 +17637,7 @@ const gradientTextEffect = {
17493
17637
  customizableOption: {
17494
17638
  name: "solidOnHover",
17495
17639
  type: "select",
17496
- label: "Hover Behavior",
17640
+ label: "Hover behaviour",
17497
17641
  default: "false",
17498
17642
  options: ["false", "true"]
17499
17643
  },
@@ -32779,19 +32923,21 @@ function stripCompiledRuntimeStyleFields(content) {
32779
32923
  return Object.fromEntries(Object.entries(stripStaleTransitionStyleGroup(content)).filter(([fieldName]) => !compiledRuntimeStyleFieldNames.includes(fieldName)));
32780
32924
  }
32781
32925
  function surfaceResolutionContextFromPalette(palette) {
32782
- return {
32926
+ const snapshot = ownedThemeSnapshot(palette);
32927
+ return Object.freeze({
32783
32928
  kind: "concrete-palette",
32784
- palette
32785
- };
32929
+ palette: snapshot,
32930
+ colourIndex: preparePaletteColourIndex(snapshot),
32931
+ buttonSystem: undefined
32932
+ });
32786
32933
  }
32787
- function surfaceResolutionContextFromTheme(theme) {
32788
- return {
32789
- ...surfaceResolutionContextFromPalette(expandPalette(theme.palette, {
32790
- arrangement: theme.skin !== undefined,
32791
- marksFrom: theme.skinMarks
32792
- })),
32793
- buttonSystem: theme.buttons
32794
- };
32934
+ function surfaceResolutionContextFromTheme(theme, declaredSurfaces = []) {
32935
+ return prepareThemeSurfaceRevision({
32936
+ palette: theme.palette,
32937
+ buttons: theme.buttons,
32938
+ skin: theme.skin,
32939
+ skinMarks: theme.skinMarks
32940
+ }, () => declaredSurfaces).context;
32795
32941
  }
32796
32942
  function defineDesignRuntimeRules(rules) {
32797
32943
  return rules;
@@ -34083,6 +34229,16 @@ const folioLooks = {
34083
34229
  treatment: "calendar-compact",
34084
34230
  roleMap: folioRoles
34085
34231
  },
34232
+ {
34233
+ id: id("events-spotlight"),
34234
+ treatment: "calendar-spotlight",
34235
+ roleMap: folioRoles
34236
+ },
34237
+ {
34238
+ id: id("events-recurring-week"),
34239
+ treatment: "calendar-recurring-week",
34240
+ roleMap: folioRoles
34241
+ },
34086
34242
  {
34087
34243
  id: id("event-calendar-month-grid"),
34088
34244
  treatment: "calendar-month",
@@ -34317,6 +34473,16 @@ const fulcrumOffers = [
34317
34473
  treatment: "compact",
34318
34474
  roleMap: fulcrumRoles
34319
34475
  },
34476
+ {
34477
+ id: id("events-spotlight"),
34478
+ treatment: "calendar-spotlight",
34479
+ roleMap: fulcrumRoles
34480
+ },
34481
+ {
34482
+ id: id("events-recurring-week"),
34483
+ treatment: "calendar-recurring-week",
34484
+ roleMap: fulcrumRoles
34485
+ },
34320
34486
  {
34321
34487
  id: id("event-calendar-month-grid"),
34322
34488
  treatment: "sheet",
@@ -34647,6 +34813,16 @@ const posterOffers = [
34647
34813
  treatment: "compact",
34648
34814
  roleMap: posterRoles
34649
34815
  },
34816
+ {
34817
+ id: id("events-spotlight"),
34818
+ treatment: "calendar-spotlight",
34819
+ roleMap: posterRoles
34820
+ },
34821
+ {
34822
+ id: id("events-recurring-week"),
34823
+ treatment: "calendar-recurring-week",
34824
+ roleMap: posterRoles
34825
+ },
34650
34826
  {
34651
34827
  id: id("event-calendar-month-grid"),
34652
34828
  treatment: "heavy",
@@ -35040,6 +35216,16 @@ const lanternOffers = [
35040
35216
  treatment: "compact",
35041
35217
  roleMap: lanternRoles
35042
35218
  },
35219
+ {
35220
+ id: id("events-spotlight"),
35221
+ treatment: "calendar-spotlight",
35222
+ roleMap: lanternRoles
35223
+ },
35224
+ {
35225
+ id: id("events-recurring-week"),
35226
+ treatment: "calendar-recurring-week",
35227
+ roleMap: lanternRoles
35228
+ },
35043
35229
  {
35044
35230
  id: id("event-calendar-month-grid"),
35045
35231
  treatment: "lit",
@@ -35332,6 +35518,16 @@ const measureOffers = [
35332
35518
  treatment: "compact",
35333
35519
  roleMap: measureRuledPanelRoles
35334
35520
  },
35521
+ {
35522
+ id: id("events-spotlight"),
35523
+ treatment: "calendar-spotlight",
35524
+ roleMap: measureRoles
35525
+ },
35526
+ {
35527
+ id: id("events-recurring-week"),
35528
+ treatment: "calendar-recurring-week",
35529
+ roleMap: measureRoles
35530
+ },
35335
35531
  {
35336
35532
  id: id("event-calendar-month-grid"),
35337
35533
  treatment: "fill",
@@ -36933,7 +37129,13 @@ function lookOptionsForBlock(input) {
36933
37129
  function lookOptionsByLayoutForBlock(input) {
36934
37130
  return input.availableLayouts.map((layout) => {
36935
37131
  const availableLooks = lookOptionsForBlock({
36936
- block: input.block,
37132
+ block: input.block.variantMeaning?.kind === "mode" ? {
37133
+ ...input.block,
37134
+ storedVariant: {
37135
+ kind: "explicit",
37136
+ key: layout.id
37137
+ }
37138
+ } : input.block,
36937
37139
  effectiveLayoutProfile: layout.profile,
36938
37140
  siteStyle: input.siteStyle,
36939
37141
  policy: input.policy
@@ -40770,6 +40972,168 @@ function isCanonicalObject(value) {
40770
40972
  return typeof value === "object" && value !== null && !Array.isArray(value);
40771
40973
  }
40772
40974
 
40975
+ //#endregion
40976
+ //#region ../theme-core/src/page-document/pageAuthoredComparison.ts
40977
+ function projectPageAuthoredMetadata(value) {
40978
+ return {
40979
+ title: value.title,
40980
+ path: value.path,
40981
+ metaTitle: value.metaTitle,
40982
+ metaDescription: value.metaDescription
40983
+ };
40984
+ }
40985
+ /** Automatic is a valid authored document, even without a site style or stored version. */
40986
+ function projectPageAuthoredDesign(intent) {
40987
+ return {
40988
+ pageFlowPresetId: intent?.pageFlowPresetId ?? defaultPolicyPageFlowPresetId,
40989
+ blockLookPins: (intent?.blockLookPins ?? []).map((pin) => ({
40990
+ blockId: pin.blockId,
40991
+ blockKind: pin.blockKind,
40992
+ value: pin.choice.value
40993
+ })).sort((a, b) => a.blockId.localeCompare(b.blockId)),
40994
+ boundaryPins: (intent?.boundaryPins ?? []).map((pin) => ({
40995
+ previousBlockId: pin.previousBlockId,
40996
+ nextBlockId: pin.nextBlockId,
40997
+ value: boundaryOptionIdForTreatment(pin.choice.value)
40998
+ })).sort((a, b) => a.previousBlockId.localeCompare(b.previousBlockId) || a.nextBlockId.localeCompare(b.nextBlockId))
40999
+ };
41000
+ }
41001
+ /** Editor choices project to the same meaning as persisted intent; effective auto choices are live. */
41002
+ function projectPageEditorAuthoredDesign(model) {
41003
+ return {
41004
+ pageFlowPresetId: model.pageFlow.value,
41005
+ blockLookPins: model.blocks.flatMap((block) => block.look.kind === "user-pinned" ? [{
41006
+ blockId: block.blockId,
41007
+ blockKind: block.blockKind,
41008
+ value: block.look.value
41009
+ }] : []).sort((a, b) => a.blockId.localeCompare(b.blockId)),
41010
+ boundaryPins: model.boundaries.flatMap((boundary) => boundary.breakChoice.kind === "user-pinned" ? [{
41011
+ previousBlockId: boundary.previousBlockId,
41012
+ nextBlockId: boundary.nextBlockId,
41013
+ value: boundary.breakChoice.value
41014
+ }] : []).sort((a, b) => a.previousBlockId.localeCompare(b.previousBlockId) || a.nextBlockId.localeCompare(b.nextBlockId))
41015
+ };
41016
+ }
41017
+ function pageAuthoredBlockContentEqual(before, after) {
41018
+ return before.blockKind === after.blockKind && authoredValuesEqual(before.content, after.content);
41019
+ }
41020
+ /** Inputs are authored projections, never storage records. */
41021
+ function comparePageAuthoredDocuments(draft, published) {
41022
+ const scopes = {
41023
+ metadata: !authoredValuesEqual(draft.metadata, published.metadata),
41024
+ blocks: !authoredValuesEqual(draft.blocks, published.blocks),
41025
+ design: !authoredValuesEqual(draft.design, published.design)
41026
+ };
41027
+ return {
41028
+ scopes,
41029
+ hasUnpublishedChanges: Object.values(scopes).some(Boolean)
41030
+ };
41031
+ }
41032
+ function pageDesignHasUnpublishedChanges(model, published) {
41033
+ return !authoredValuesEqual(projectPageEditorAuthoredDesign(model), projectPageAuthoredDesign(published));
41034
+ }
41035
+
41036
+ //#endregion
41037
+ //#region ../theme-core/src/page-document/pageDocument.ts
41038
+ const revisionSchema = z.number().int().nonnegative().brand();
41039
+ const pageDocumentRevision = (value) => revisionSchema.parse(value);
41040
+ const nextPageDocumentRevision = (value) => pageDocumentRevision(value + 1);
41041
+ const automaticPageDocumentIntent = {
41042
+ schemaVersion: 2,
41043
+ pageFlowPresetId: defaultPolicyPageFlowPresetId,
41044
+ blockLookPins: [],
41045
+ boundaryPins: []
41046
+ };
41047
+ function pageDocumentPublishedBaseline(publication) {
41048
+ switch (publication.kind) {
41049
+ case "never-published": return null;
41050
+ case "published": return publication.document;
41051
+ case "unpublished": return publication.baseline;
41052
+ }
41053
+ }
41054
+ /** Comparison only: never-published has an empty automatic baseline, with no stored row or metadata. */
41055
+ function pageDocumentComparisonBaseline(aggregate) {
41056
+ return pageDocumentPublishedBaseline(aggregate.publication) ?? {
41057
+ pageId: aggregate.pageId,
41058
+ stage: "published",
41059
+ blocks: [],
41060
+ metadata: {
41061
+ title: null,
41062
+ path: null,
41063
+ metaTitle: null,
41064
+ metaDescription: null
41065
+ },
41066
+ intent: automaticPageDocumentIntent
41067
+ };
41068
+ }
41069
+
41070
+ //#endregion
41071
+ //#region ../theme-core/src/site-styles/pageDocumentCheckpoint.ts
41072
+ /** Owned by edit admission. Installing schema never activates document authority. */
41073
+ const pageDocumentCheckpointSchema = z.discriminatedUnion("kind", [
41074
+ z.object({
41075
+ kind: z.literal("legacy"),
41076
+ pauseAnnouncedAt: z.string().datetime({ offset: true }).optional()
41077
+ }).strict(),
41078
+ z.object({
41079
+ kind: z.literal("paused"),
41080
+ authority: z.enum(["legacy", "document"]),
41081
+ checkpointId: z.string().uuid(),
41082
+ pausedAt: z.string().datetime({ offset: true })
41083
+ }).strict(),
41084
+ z.object({
41085
+ kind: z.literal("document"),
41086
+ checkpointId: z.string().uuid(),
41087
+ activatedAt: z.string().datetime({ offset: true })
41088
+ }).strict()
41089
+ ]);
41090
+ /** Admission identity is kind plus checkpoint ID; notice/activation timestamps are descriptive.
41091
+ * SQL uses private.page_document_checkpoint_identity; integration tests enforce parity. */
41092
+ function pageDocumentCheckpointsEqual(left, right) {
41093
+ const first = pageDocumentCheckpointSchema.parse(left);
41094
+ const second = pageDocumentCheckpointSchema.parse(right);
41095
+ switch (first.kind) {
41096
+ case "legacy": return second.kind === "legacy";
41097
+ case "paused": return second.kind === "paused" && first.checkpointId === second.checkpointId;
41098
+ case "document": return second.kind === "document" && first.checkpointId === second.checkpointId;
41099
+ default: return assertNever$1(first);
41100
+ }
41101
+ }
41102
+ function pageDocumentAdmissionState(checkpoint) {
41103
+ return checkpoint.kind;
41104
+ }
41105
+ function pageDocumentReadAuthority(checkpoint) {
41106
+ switch (checkpoint.kind) {
41107
+ case "legacy": return "legacy";
41108
+ case "paused": return checkpoint.authority;
41109
+ case "document": return "document";
41110
+ default: return assertNever$1(checkpoint);
41111
+ }
41112
+ }
41113
+
41114
+ //#endregion
41115
+ //#region ../theme-core/src/site-styles/pageDesignVersionIntent.ts
41116
+ function taggedStyledIntent(intent) {
41117
+ const { siteStyleId, ...decisions } = intent;
41118
+ return {
41119
+ kind: "legacy-styled",
41120
+ siteStyleId,
41121
+ decisions
41122
+ };
41123
+ }
41124
+ const decodedPageDesignIntentSchema = z.union([
41125
+ z.nullish(z.never()).transform(() => ({ kind: "automatic" })),
41126
+ pageDesignDecisionsV2Schema.transform((decisions) => ({
41127
+ kind: "decisions",
41128
+ decisions
41129
+ })),
41130
+ pageDesignIntentV2Schema.transform(taggedStyledIntent),
41131
+ pageDesignIntentV1Schema.transform((intent) => taggedStyledIntent(normalizeLegacyPageDesignIntent(intent)))
41132
+ ], { error: (issue$1) => {
41133
+ const value = issue$1.input;
41134
+ return typeof value === "object" && value !== null && "schemaVersion" in value && value.schemaVersion !== 1 && value.schemaVersion !== 2 ? "Unsupported Theme V2 page design intent schemaVersion." : "Invalid Theme V2 page design intent shape.";
41135
+ } });
41136
+
40773
41137
  //#endregion
40774
41138
  //#region ../site-commands/src/application.ts
40775
41139
  const commandEffectKinds = [