@riverbankcms/sdk 0.64.0 → 0.68.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.
Files changed (126) hide show
  1. package/README.md +21 -11
  2. package/dist/_dts/api/src/aiPlayground.d.ts +75 -20
  3. package/dist/_dts/api/src/apiEndpointTypes.d.ts +12 -0
  4. package/dist/_dts/api/src/billing.d.ts +7 -40
  5. package/dist/_dts/api/src/bookingManagementEndpoints.d.ts +4 -1
  6. package/dist/_dts/api/src/bookingOperations.d.ts +33 -2
  7. package/dist/_dts/api/src/endpoints.d.ts +32 -0
  8. package/dist/_dts/api/src/public/types.d.ts +1 -1
  9. package/dist/_dts/api/src/sdkConfig/contracts.d.ts +0 -40
  10. package/dist/_dts/api/src/sdkContracts.d.ts +1 -1
  11. package/dist/_dts/api/src/siteMembers.d.ts +1 -1
  12. package/dist/_dts/api/src/siteOperations.d.ts +1 -1
  13. package/dist/_dts/billing/src/components/index.d.ts +426 -0
  14. package/dist/_dts/billing/src/plans/types.d.ts +1 -1
  15. package/dist/_dts/blocks/src/PageRenderer.d.ts +4 -0
  16. package/dist/_dts/blocks/src/bindings/index.d.ts +1 -1
  17. package/dist/_dts/blocks/src/client.d.ts +6 -0
  18. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  19. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableDates.d.ts +1 -0
  20. package/dist/_dts/blocks/src/system/runtime/hooks/useAvailableSlots.d.ts +3 -1
  21. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.d.ts +140 -0
  22. package/dist/_dts/blocks/src/system/runtime/hooks/useHeadlessBookingFlow.state.d.ts +2 -0
  23. package/dist/_dts/blocks/src/system/runtime/hooks/useVisibleTabPolling.d.ts +10 -0
  24. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.default-ui.d.ts +8 -0
  25. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.headless.state.d.ts +484 -0
  26. package/dist/_dts/blocks/src/system/runtime/nodes/booking-form.state.d.ts +5 -2
  27. package/dist/_dts/blocks/src/system/transforms/registry/formatting.d.ts +1 -0
  28. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +2 -1
  29. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +81 -0
  30. package/dist/_dts/preview-next/src/client/blocks/pageDesignRuntimePreview.d.ts +7 -3
  31. package/dist/_dts/preview-next/src/client/blocks/previewProjection/runtimeContentDecoration.d.ts +2 -2
  32. package/dist/_dts/sdk/src/bookings/index.d.ts +5 -2
  33. package/dist/_dts/sdk/src/bookings/types.d.ts +2 -0
  34. package/dist/_dts/sdk/src/cli/commands/push/execute/footer.d.ts +33 -0
  35. package/dist/_dts/sdk/src/cli/commands/push/scopes/commandBackedDatedOfferingScope.d.ts +32 -0
  36. package/dist/_dts/sdk/src/cli/commands/push/scopes/types.d.ts +5 -1
  37. package/dist/_dts/sdk/src/cli/commands/push-execute.d.ts +2 -1
  38. package/dist/_dts/sdk/src/cli/env.d.ts +2 -1
  39. package/dist/_dts/sdk/src/cli/merge-remote/entryMergePush.d.ts +2 -1
  40. package/dist/_dts/sdk/src/cli/site-commands/commandKeys.d.ts +13 -0
  41. package/dist/_dts/sdk/src/cli/site-commands/commandRuntime.d.ts +144 -0
  42. package/dist/_dts/sdk/src/cli/site-commands/commandRuntimeCompat.d.ts +21 -0
  43. package/dist/_dts/sdk/src/cli/site-commands/commandSurfaceDispatch.d.ts +27 -0
  44. package/dist/_dts/sdk/src/cli/site-commands/datedOfferingCommands.d.ts +56 -0
  45. package/dist/_dts/sdk/src/cli/site-commands/entryCommands.d.ts +29 -49
  46. package/dist/_dts/sdk/src/cli/site-commands/footerCommands.d.ts +56 -0
  47. package/dist/_dts/sdk/src/cli/site-commands/formCommands.d.ts +53 -0
  48. package/dist/_dts/sdk/src/cli/site-commands/index.d.ts +6 -0
  49. package/dist/_dts/sdk/src/cli/site-commands/navigationCommands.d.ts +53 -0
  50. package/dist/_dts/sdk/src/cli/site-commands/pageCommands.d.ts +79 -0
  51. package/dist/_dts/sdk/src/cli/site-commands/pushExecution.d.ts +19 -20
  52. package/dist/_dts/sdk/src/cli/site-commands/pushExecutionPlan.d.ts +8 -0
  53. package/dist/_dts/sdk/src/cli/site-commands/pushExecutionTypes.d.ts +97 -0
  54. package/dist/_dts/sdk/src/cli/site-commands/residualSettingsTrimming.d.ts +15 -0
  55. package/dist/_dts/sdk/src/cli/sync/executor.d.ts +10 -28
  56. package/dist/_dts/sdk/src/cli/sync/index.d.ts +2 -1
  57. package/dist/_dts/sdk/src/cli/sync/syncResultAggregation.d.ts +4 -0
  58. package/dist/_dts/sdk/src/config/dashboard-validation.d.ts +0 -48
  59. package/dist/_dts/sdk/src/config/types.d.ts +1 -1
  60. package/dist/_dts/sdk/src/rendering/overrides.d.ts +2 -0
  61. package/dist/_dts/sdk/src/theme-bridge/ThemeBridgeProvider.d.ts +4 -4
  62. package/dist/_dts/sdk/src/theme-bridge/generateCssVars.d.ts +4 -12
  63. package/dist/_dts/sdk/src/theme-bridge/index.d.ts +1 -1
  64. package/dist/_dts/sdk/src/theme-bridge/types.d.ts +17 -9
  65. package/dist/_dts/sdk/src/version.d.ts +1 -1
  66. package/dist/_dts/site-commands/src/adapter.d.ts +2 -2
  67. package/dist/_dts/site-commands/src/commands.d.ts +637 -13
  68. package/dist/_dts/site-commands/src/domain.d.ts +3 -3
  69. package/dist/_dts/site-commands/src/exposure.d.ts +41 -0
  70. package/dist/_dts/site-commands/src/index.d.ts +2 -0
  71. package/dist/_dts/site-commands/src/metadata.d.ts +159 -3
  72. package/dist/_dts/site-commands/src/planner.d.ts +13 -6
  73. package/dist/_dts/site-commands/src/refContributions.d.ts +1 -0
  74. package/dist/_dts/site-commands/src/refs.d.ts +19 -1
  75. package/dist/_dts/{sdk/src/cli/merge-remote → site-commands/src}/stableJson.d.ts +2 -0
  76. package/dist/_dts/theme-core/src/generated/containerResponsiveThemeCss.d.ts +1 -1
  77. package/dist/_dts/theme-core/src/index.d.ts +1 -1
  78. package/dist/_dts/theme-core/src/palette/utils/index.d.ts +1 -0
  79. package/dist/_dts/theme-core/src/palette/utils/onColor.d.ts +2 -0
  80. package/dist/_dts/theme-core/src/runtime/buildThemeRuntimeFromBridge.d.ts +30 -23
  81. package/dist/_dts/theme-core/src/site-styles/accessibleSurfaces.d.ts +83 -0
  82. package/dist/_dts/theme-core/src/site-styles/contentTemplateRuntimeCompiler.d.ts +2 -1
  83. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +89 -12
  84. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +8 -2
  85. package/dist/_dts/theme-core/src/site-styles/index.d.ts +1 -0
  86. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +3 -2
  87. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +9 -6
  88. package/dist/_dts/ui/src/callout.d.ts +1 -1
  89. package/dist/cli/index.mjs +4736 -2026
  90. package/dist/client/bookings.mjs +5107 -3348
  91. package/dist/client/client.mjs +4579 -3871
  92. package/dist/client/hooks.mjs +325 -123
  93. package/dist/client/rendering/client.mjs +4474 -3869
  94. package/dist/client/rendering/islands.mjs +4234 -3639
  95. package/dist/client/rendering.mjs +4508 -3798
  96. package/dist/preview-next/before-render.mjs +75 -13
  97. package/dist/preview-next/client/runtime.mjs +3700 -2644
  98. package/dist/preview-next/middleware.mjs +75 -13
  99. package/dist/server/components.mjs +698 -383
  100. package/dist/server/config-validation.mjs +327 -125
  101. package/dist/server/config.mjs +327 -125
  102. package/dist/server/data.mjs +325 -123
  103. package/dist/server/index.mjs +92 -16
  104. package/dist/server/next.mjs +692 -377
  105. package/dist/server/page-converter.mjs +159 -41
  106. package/dist/server/prebuild.mjs +1 -1
  107. package/dist/server/rendering/server.mjs +700 -383
  108. package/dist/server/rendering.mjs +700 -383
  109. package/dist/server/routing.mjs +406 -131
  110. package/dist/server/server.mjs +326 -124
  111. package/dist/server/theme-bridge.mjs +1226 -4697
  112. package/dist/styles/index.css +38 -38
  113. package/package.json +1 -1
  114. package/dist/_dts/blocks/src/system/runtime/components/booking/DateTimeSelectionStep.d.ts +0 -18
  115. package/dist/_dts/blocks/src/system/runtime/components/booking/PaymentOptionSelectionStep.d.ts +0 -9
  116. package/dist/_dts/blocks/src/system/runtime/components/booking/ServiceResourceSelector.d.ts +0 -44
  117. package/dist/_dts/blocks/src/system/runtime/components/booking/ServiceResourceSelector.state.d.ts +0 -23
  118. package/dist/_dts/blocks/src/system/runtime/components/booking/ServiceSelectionStep.d.ts +0 -18
  119. package/dist/_dts/blocks/src/system/runtime/components/booking/slotDisplay.d.ts +0 -2
  120. package/dist/_dts/blocks/src/system/runtime/components/multi-step/MultiStepForm.d.ts +0 -21
  121. package/dist/_dts/blocks/src/system/runtime/components/multi-step/useMultiStep.d.ts +0 -15
  122. package/dist/_dts/blocks/src/system/runtime/components/multi-step/useMultiStep.state.d.ts +0 -51
  123. package/dist/_dts/blocks/src/system/runtime/hooks/useBookingSteps.d.ts +0 -22
  124. package/dist/_dts/path-utils/src/index.d.ts +0 -8
  125. package/dist/_dts/path-utils/src/redirectPaths.d.ts +0 -26
  126. package/dist/_dts/path-utils/src/safeAppPath.d.ts +0 -26
@@ -1995,6 +1995,144 @@ function resolveVariantKey(manifest, content) {
1995
1995
  return null;
1996
1996
  }
1997
1997
 
1998
+ // ../theme-core/src/palette/utils/colorConversion.ts
1999
+ var clamp01 = (x) => Math.max(0, Math.min(1, x));
2000
+ var mod = (a, n) => (a % n + n) % n;
2001
+ var deg = (x) => mod(x, 360);
2002
+ function hexToRgb(hex) {
2003
+ const h = hex.replace(/^#/, "");
2004
+ const m = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
2005
+ if (m.length !== 6) throw new Error("Bad hex");
2006
+ const int = parseInt(m, 16);
2007
+ return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
2008
+ }
2009
+ function rgbToHex(r2, g, b) {
2010
+ const to = (n) => Math.round(n).toString(16).padStart(2, "0");
2011
+ return `#${to(r2)}${to(g)}${to(b)}`;
2012
+ }
2013
+ function srgbToLinear(u) {
2014
+ const x = u / 255;
2015
+ return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
2016
+ }
2017
+ function linearToSrgb(x) {
2018
+ const y = x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
2019
+ return clamp01(y) * 255;
2020
+ }
2021
+ function rgbToHsl(r2, g, b) {
2022
+ const R = r2 / 255, G = g / 255, B = b / 255;
2023
+ const max = Math.max(R, G, B), min = Math.min(R, G, B);
2024
+ const d = max - min;
2025
+ let h = 0;
2026
+ if (d !== 0) {
2027
+ switch (max) {
2028
+ case R:
2029
+ h = (G - B) / d + (G < B ? 6 : 0);
2030
+ break;
2031
+ case G:
2032
+ h = (B - R) / d + 2;
2033
+ break;
2034
+ case B:
2035
+ h = (R - G) / d + 4;
2036
+ break;
2037
+ }
2038
+ h *= 60;
2039
+ }
2040
+ const l = (max + min) / 2;
2041
+ const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
2042
+ return { h, s, l };
2043
+ }
2044
+ function srgbToOklab(r2, g, b) {
2045
+ const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
2046
+ const l = 0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B;
2047
+ const m = 0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B;
2048
+ const s = 0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B;
2049
+ const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
2050
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
2051
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
2052
+ const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
2053
+ return { L, a, b: b2 };
2054
+ }
2055
+ function oklabToSrgb(L, a, b) {
2056
+ const l_ = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
2057
+ const m_ = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
2058
+ const s_ = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
2059
+ const R = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
2060
+ const G = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
2061
+ const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
2062
+ return { r: linearToSrgb(R), g: linearToSrgb(G), b: linearToSrgb(B) };
2063
+ }
2064
+ function oklabToOklch(L, a, b) {
2065
+ const C = Math.sqrt(a * a + b * b);
2066
+ const h = C < 1e-7 ? 0 : deg(Math.atan2(b, a) * 180 / Math.PI);
2067
+ return { L, C, h };
2068
+ }
2069
+ function oklchToOklab(L, C, h) {
2070
+ const hr = h * Math.PI / 180;
2071
+ const a = C * Math.cos(hr);
2072
+ const b = C * Math.sin(hr);
2073
+ return { L, a, b };
2074
+ }
2075
+ function inSRGB(r2, g, b) {
2076
+ return r2 >= 0 && r2 <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
2077
+ }
2078
+ function oklchToHexGamut(L, C, h) {
2079
+ let lo = 0, hi = C, best = 0;
2080
+ for (let i = 0; i < 18; i++) {
2081
+ const mid = (lo + hi) / 2;
2082
+ const { a: a2, b: b2 } = oklchToOklab(L, mid, h);
2083
+ const { r: r3, g: g2, b: bb2 } = oklabToSrgb(L, a2, b2);
2084
+ if (inSRGB(r3, g2, bb2)) {
2085
+ best = mid;
2086
+ lo = mid;
2087
+ } else {
2088
+ hi = mid;
2089
+ }
2090
+ }
2091
+ const { a, b } = oklchToOklab(L, best, h);
2092
+ const { r: r2, g, b: bb } = oklabToSrgb(L, a, b);
2093
+ return rgbToHex(r2, g, bb);
2094
+ }
2095
+ function featuresFromHex(hex) {
2096
+ const { r: r2, g, b } = hexToRgb(hex);
2097
+ const { h, s, l } = rgbToHsl(r2, g, b);
2098
+ const { L, a, b: b2 } = srgbToOklab(r2, g, b);
2099
+ const { L: okL, C: okC, h: okH } = oklabToOklch(L, a, b2);
2100
+ const max = Math.max(r2, g, b);
2101
+ const v = max / 255;
2102
+ const Y = 0.2126 * srgbToLinear(r2) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
2103
+ const chroma = s;
2104
+ return { r: r2, g, b, h, s, l, v, Y, chroma, okL, okC, okH, hex };
2105
+ }
2106
+
2107
+ // ../theme-core/src/palette/utils/contrast.ts
2108
+ function relativeLuminance(r2, g, b) {
2109
+ const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
2110
+ return 0.2126 * R + 0.7152 * G + 0.0722 * B;
2111
+ }
2112
+
2113
+ // ../theme-core/src/palette/utils/onColor.ts
2114
+ var BACKGROUND_ROLE_NAMES = /* @__PURE__ */ new Set([
2115
+ "primary",
2116
+ "secondary",
2117
+ "accent",
2118
+ "success",
2119
+ "warning",
2120
+ "destructive",
2121
+ "info",
2122
+ "background",
2123
+ "surface",
2124
+ "surfaceAlt",
2125
+ "muted",
2126
+ "neutral"
2127
+ ]);
2128
+ function onColorTokenName(backgroundToken) {
2129
+ return `on${backgroundToken.split("-").filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}`;
2130
+ }
2131
+ function isOnColorBackgroundCandidateToken(token) {
2132
+ const role = token.match(/^(.*?)(?:-\d{2,3})?$/)?.[1] ?? token;
2133
+ return BACKGROUND_ROLE_NAMES.has(role);
2134
+ }
2135
+
1998
2136
  // ../theme-core/src/site-styles/appearancePresetResolution.ts
1999
2137
  function assertValidOptionGroups(preset2) {
2000
2138
  preset2.optionGroups?.forEach((group) => {
@@ -7616,6 +7754,9 @@ var curatedSiteStyleIdValues = [
7616
7754
  "site-style:bright-community",
7617
7755
  "site-style:quiet-luxury",
7618
7756
  "site-style:practical-services",
7757
+ "site-style:quiet-practice",
7758
+ "site-style:personal-retreat-journal",
7759
+ "site-style:tactile-workshop",
7619
7760
  "site-style:modern-wellness",
7620
7761
  "site-style:bold-launch",
7621
7762
  "site-style:south-west-twerk-school"
@@ -7698,7 +7839,8 @@ function defineCuratedSiteStyle(input) {
7698
7839
  name: input.name,
7699
7840
  description: input.description,
7700
7841
  generationBrief: input.generationBrief,
7701
- selectionKeywords: input.selectionKeywords ?? [],
7842
+ selectionKeywordRules: input.selectionKeywordRules ?? [],
7843
+ siteCreatorSelection: input.siteCreatorSelection ?? { kind: "explicit_only" },
7702
7844
  template: {
7703
7845
  id: asDesignSystemTemplateId(`template:${input.id.replace("site-style:", "")}`),
7704
7846
  name: input.name,
@@ -7842,12 +7984,13 @@ var curatedSiteStyles = [
7842
7984
  name: "Quiet Luxury",
7843
7985
  description: "Minimal, confident, and refined for premium experiences and private services.",
7844
7986
  generationBrief: "Use fewer claims, more specificity, and restrained sensory detail. Favor elegant media and low repetition over dense panels.",
7845
- selectionKeywords: [
7846
- "luxury",
7847
- "premium",
7848
- "boutique",
7849
- "bespoke",
7850
- "exclusive"
7987
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 20 },
7988
+ selectionKeywordRules: [
7989
+ { kind: "word", value: "luxury" },
7990
+ { kind: "word", value: "premium" },
7991
+ { kind: "word", value: "boutique" },
7992
+ { kind: "word", value: "bespoke" },
7993
+ { kind: "word", value: "exclusive" }
7851
7994
  ],
7852
7995
  tokenRecipes: {
7853
7996
  palette: "high-contrast",
@@ -7876,13 +8019,14 @@ var curatedSiteStyles = [
7876
8019
  name: "Practical Services",
7877
8020
  description: "Efficient, plainspoken, and conversion-focused for trades and everyday services.",
7878
8021
  generationBrief: "Make services, location, trust signals, and contact paths obvious. Keep copy brief and avoid ornate visual treatments.",
7879
- selectionKeywords: [
7880
- "repair",
7881
- "plumb",
7882
- "electric",
7883
- "cleaning",
7884
- "landscap",
7885
- "contractor"
8022
+ siteCreatorSelection: { kind: "primary_goal_support" },
8023
+ selectionKeywordRules: [
8024
+ { kind: "word", value: "repair" },
8025
+ { kind: "substring", value: "plumb" },
8026
+ { kind: "substring", value: "electric" },
8027
+ { kind: "word", value: "cleaning" },
8028
+ { kind: "substring", value: "landscap" },
8029
+ { kind: "substring", value: "contractor" }
7886
8030
  ],
7887
8031
  tokenRecipes: {
7888
8032
  palette: "brand-led",
@@ -7933,18 +8077,134 @@ var curatedSiteStyles = [
7933
8077
  paletteChoice("warm-neutral-forest")
7934
8078
  ]
7935
8079
  }),
8080
+ defineCuratedSiteStyle({
8081
+ id: "site-style:quiet-practice",
8082
+ name: "Quiet Practice",
8083
+ description: "Grounded, calm, and practical for small appointment-first practices.",
8084
+ generationBrief: "Make services, practitioner trust, preparation notes, and booking routes easy to scan. Keep the tone warm and specific, with quiet confidence rather than spa cliches or medical claims.",
8085
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 30 },
8086
+ selectionKeywordRules: [
8087
+ { kind: "substring", value: "massage" },
8088
+ { kind: "word", value: "bodywork" },
8089
+ { kind: "phrase", value: "appointment practice" },
8090
+ { kind: "phrase", value: "appointment-first" },
8091
+ { kind: "substring", value: "practitioner" },
8092
+ { kind: "substring", value: "therap" },
8093
+ { kind: "substring", value: "clinic" },
8094
+ { kind: "phrase", value: "wellness practice" }
8095
+ ],
8096
+ tokenRecipes: {
8097
+ palette: "soft-natural",
8098
+ contrast: "standard",
8099
+ radius: "soft",
8100
+ shadow: "subtle",
8101
+ typography: "clean-sans",
8102
+ spacing: "regular",
8103
+ motion: "subtle"
8104
+ },
8105
+ compositionBudget: quietBudget,
8106
+ recommendedHeaderLookIds: ["practical-utility", "clean-base", "centered-calm"],
8107
+ buttonPersonalityChoices: [
8108
+ buttonChoice("pebble"),
8109
+ buttonChoice("soft-pill"),
8110
+ buttonChoice("editorial-link")
8111
+ ],
8112
+ paletteVariantChoices: [
8113
+ paletteChoice("soft-natural-stone"),
8114
+ paletteChoice("soft-natural-sage"),
8115
+ paletteChoice("warm-neutral-clay")
8116
+ ]
8117
+ }),
8118
+ defineCuratedSiteStyle({
8119
+ id: "site-style:personal-retreat-journal",
8120
+ name: "Personal Retreat Journal",
8121
+ description: "Warm, story-led, and readable for solo practitioners with mixed offers.",
8122
+ generationBrief: "Center the practitioner as the guide, then make private sessions, classes, retreats, and resources feel like clear pathways. Keep retreat copy grounded and practical, with enough editorial warmth for longer reading.",
8123
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 40 },
8124
+ selectionKeywordRules: [
8125
+ { kind: "substring", value: "retreat" },
8126
+ { kind: "phrase", value: "solo practitioner" },
8127
+ { kind: "phrase", value: "personal brand" },
8128
+ { kind: "substring", value: "teacher" },
8129
+ { kind: "substring", value: "coach" },
8130
+ { kind: "phrase", value: "retreat resources" },
8131
+ { kind: "substring", value: "journal" }
8132
+ ],
8133
+ tokenRecipes: {
8134
+ palette: "warm-neutral",
8135
+ contrast: "standard",
8136
+ radius: "soft",
8137
+ shadow: "subtle",
8138
+ typography: "serif-editorial",
8139
+ spacing: "airy",
8140
+ motion: "subtle"
8141
+ },
8142
+ compositionBudget: balancedBudget,
8143
+ recommendedHeaderLookIds: ["editorial-line", "centered-calm", "minimal-transparent"],
8144
+ buttonPersonalityChoices: [
8145
+ buttonChoice("editorial-link"),
8146
+ buttonChoice("soft-pill"),
8147
+ buttonChoice("brushed-wash")
8148
+ ],
8149
+ paletteVariantChoices: [
8150
+ paletteChoice("warm-neutral-forest"),
8151
+ paletteChoice("warm-neutral-clay"),
8152
+ paletteChoice("soft-natural-stone")
8153
+ ]
8154
+ }),
8155
+ defineCuratedSiteStyle({
8156
+ id: "site-style:tactile-workshop",
8157
+ name: "Tactile Workshop",
8158
+ description: "Bright, hands-on, and image-led for maker studios, workshops, and creative classes.",
8159
+ generationBrief: "Lead with objects, materials, studio process, and practical booking detail. Keep the tone warm and direct, with useful mess, clear dates, and enough gallery rhythm to feel like a real creative studio.",
8160
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 50 },
8161
+ selectionKeywordRules: [
8162
+ { kind: "substring", value: "ceramic" },
8163
+ { kind: "word", value: "pottery" },
8164
+ { kind: "phrase", value: "maker studio" },
8165
+ { kind: "phrase", value: "craft class" },
8166
+ { kind: "phrase", value: "craft workshop" },
8167
+ { kind: "word", value: "clay" },
8168
+ { kind: "word", value: "kiln" }
8169
+ ],
8170
+ tokenRecipes: {
8171
+ palette: "brand-led",
8172
+ contrast: "standard",
8173
+ radius: "soft",
8174
+ shadow: "subtle",
8175
+ typography: "friendly-sans",
8176
+ spacing: "regular",
8177
+ motion: "subtle"
8178
+ },
8179
+ compositionBudget: balancedBudget,
8180
+ recommendedHeaderLookIds: ["brand-solid", "practical-utility", "clean-base"],
8181
+ recommendedFooterLookIds: ["site-footer-brand-two-band", "footer-muted-grounding"],
8182
+ buttonPersonalityChoices: [
8183
+ buttonChoice("pebble"),
8184
+ buttonChoice("confident-chip"),
8185
+ buttonChoice("ink-stamp"),
8186
+ buttonChoice("editorial-link")
8187
+ ],
8188
+ paletteVariantChoices: [
8189
+ paletteChoice("brand-led-warm"),
8190
+ paletteChoice("brand-led-cool"),
8191
+ paletteChoice("soft-natural-watercolor"),
8192
+ paletteChoice("warm-neutral-clay")
8193
+ ]
8194
+ }),
7936
8195
  defineCuratedSiteStyle({
7937
8196
  id: "site-style:bold-launch",
7938
8197
  name: "Bold Launch",
7939
8198
  description: "High-energy and punchy for launches, campaigns, and creative offers.",
7940
8199
  generationBrief: "Use crisp positioning, bold hero structure, strong calls to action, and confident visual rhythm. Keep it precise, not shouty.",
7941
- selectionKeywords: [
7942
- "launch",
7943
- "campaign",
7944
- "preorder",
7945
- "pre-order",
7946
- "waitlist",
7947
- "drop"
8200
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 10 },
8201
+ selectionKeywordRules: [
8202
+ { kind: "substring", value: "launch" },
8203
+ { kind: "substring", value: "campaign" },
8204
+ { kind: "word", value: "preorder" },
8205
+ { kind: "phrase", value: "pre-order" },
8206
+ { kind: "substring", value: "waitlist" },
8207
+ { kind: "word", value: "drop" }
7948
8208
  ],
7949
8209
  tokenRecipes: {
7950
8210
  palette: "high-contrast",
@@ -7975,15 +8235,6 @@ var curatedSiteStyles = [
7975
8235
  name: "South West Twerk School",
7976
8236
  description: "Energetic, editorial, and high-contrast for a branded dance school presence.",
7977
8237
  generationBrief: "Use confident rhythm, bold burgundy-and-gold accents, large editorial intro copy, strong booking routes, and dark feature sections where proof or forms need emphasis.",
7978
- selectionKeywords: [
7979
- "dance",
7980
- "classes",
7981
- "workshop",
7982
- "school",
7983
- "movement",
7984
- "performance",
7985
- "community"
7986
- ],
7987
8238
  tokenRecipes: {
7988
8239
  palette: "brand-led",
7989
8240
  contrast: "maximum",
@@ -8226,6 +8477,148 @@ var modernMinimalTheme = {
8226
8477
  }
8227
8478
  };
8228
8479
 
8480
+ // ../theme-core/src/palette/generateShades.ts
8481
+ function generateShades(hexColor, name) {
8482
+ const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
8483
+ const base = featuresFromHex(hexColor);
8484
+ const hue = base.okH;
8485
+ const baseChroma = base.okC;
8486
+ const toneMap = {
8487
+ 50: 0.975,
8488
+ 100: 0.945,
8489
+ 200: 0.89,
8490
+ 300: 0.82,
8491
+ 400: 0.74,
8492
+ 500: 0.66,
8493
+ 600: 0.58,
8494
+ 700: 0.49,
8495
+ 800: 0.4,
8496
+ 900: 0.28,
8497
+ 950: 0.16
8498
+ };
8499
+ const shadeDefs = shadeSteps.map((step, idx) => {
8500
+ const t = idx / (shadeSteps.length - 1);
8501
+ const L = toneMap[step];
8502
+ const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t);
8503
+ const C = baseChroma * chromaFactor;
8504
+ return {
8505
+ name: `${name}-${step}`,
8506
+ hex: oklchToHexGamut(L, C, hue)
8507
+ };
8508
+ });
8509
+ shadeDefs.push({ name, hex: hexColor });
8510
+ return shadeDefs;
8511
+ }
8512
+
8513
+ // ../theme-core/src/palette/neutralScale.ts
8514
+ function generateNeutralScale({
8515
+ background,
8516
+ steps = 11,
8517
+ warm = false
8518
+ }) {
8519
+ const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
8520
+ const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
8521
+ const count = Math.min(steps, shadeNames.length);
8522
+ const scale = [];
8523
+ for (let i = 0; i < count; i++) {
8524
+ const t = i / (count - 1);
8525
+ const tone = isDark ? mix(0.06, 0.92, t) : mix(0.98, 0.1, t);
8526
+ const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
8527
+ const name = `neutral-${shadeNames[i]}`;
8528
+ scale.push({ name, hex });
8529
+ }
8530
+ return scale;
8531
+ }
8532
+ function mix(a, b, t) {
8533
+ return a + (b - a) * Math.max(0, Math.min(1, t));
8534
+ }
8535
+
8536
+ // ../theme-core/src/palette/utils/textColor.ts
8537
+ function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
8538
+ const { r: r2, g, b } = parseColorToRgb(background);
8539
+ const luminance = relativeLuminance(r2, g, b);
8540
+ const blackContrast = (luminance + 0.05) / 0.05;
8541
+ const whiteContrast = 1.05 / (luminance + 0.05);
8542
+ if (blackContrast >= minContrast && whiteContrast < minContrast) {
8543
+ return "#000000";
8544
+ }
8545
+ if (whiteContrast >= minContrast && blackContrast < minContrast) {
8546
+ return "#FFFFFF";
8547
+ }
8548
+ return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
8549
+ }
8550
+ function getTextColorForBackground(background) {
8551
+ return pickBlackOrWhiteTextColor(background);
8552
+ }
8553
+ function parseColorToRgb(input) {
8554
+ const trimmed = input.trim();
8555
+ if (trimmed.startsWith("#")) {
8556
+ return hexToRgb(trimmed);
8557
+ }
8558
+ const rgbMatch = trimmed.match(
8559
+ /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
8560
+ );
8561
+ if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
8562
+ return {
8563
+ r: clamp255(Number(rgbMatch[1])),
8564
+ g: clamp255(Number(rgbMatch[2])),
8565
+ b: clamp255(Number(rgbMatch[3]))
8566
+ };
8567
+ }
8568
+ throw new Error("Unsupported color format");
8569
+ }
8570
+ function clamp255(value) {
8571
+ if (Number.isNaN(value)) return 0;
8572
+ return Math.max(0, Math.min(255, value));
8573
+ }
8574
+
8575
+ // ../theme-core/src/palette/expandPalette.ts
8576
+ function colorsToMap(palette) {
8577
+ const map = {};
8578
+ for (const c of palette.colors) {
8579
+ map[c.name] = c.hex;
8580
+ }
8581
+ return map;
8582
+ }
8583
+ function isBackgroundDark(hex) {
8584
+ try {
8585
+ return featuresFromHex(hex).Y < 0.5;
8586
+ } catch {
8587
+ return false;
8588
+ }
8589
+ }
8590
+ function expandPalette(palette) {
8591
+ const base = colorsToMap(palette);
8592
+ const expanded = { ...base };
8593
+ const background = base.background || base.surface || "#ffffff";
8594
+ const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
8595
+ neutral2.forEach((n) => {
8596
+ expanded[n.name] = n.hex;
8597
+ });
8598
+ for (const [name, hex] of Object.entries(base)) {
8599
+ if (hex) {
8600
+ const shades = generateShades(hex, name);
8601
+ shades.forEach((shade) => {
8602
+ expanded[shade.name] = shade.hex;
8603
+ });
8604
+ }
8605
+ }
8606
+ if (base.text) expanded.body = base.text;
8607
+ if (base.danger && !base.destructive) {
8608
+ expanded.destructive = base.danger;
8609
+ }
8610
+ const isDark = base.background ? isBackgroundDark(base.background) : false;
8611
+ const isDarkMode = palette.meta?.mode === "dark" || isDark;
8612
+ expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
8613
+ for (const [token, hex] of Object.entries({ ...expanded })) {
8614
+ if (!hex || !isOnColorBackgroundCandidateToken(token)) continue;
8615
+ const onToken = onColorTokenName(token);
8616
+ if (expanded[onToken]) continue;
8617
+ expanded[onToken] = getTextColorForBackground(hex);
8618
+ }
8619
+ return expanded;
8620
+ }
8621
+
8229
8622
  // ../theme-core/src/site-styles/designState.ts
8230
8623
  import { z as z24 } from "zod";
8231
8624
 
@@ -8394,25 +8787,19 @@ var defaultDesignRuntimeRules = defineDesignRuntimeRules({
8394
8787
  "muted-band": {
8395
8788
  background: {
8396
8789
  type: "color",
8397
- color: "muted",
8398
- textColor: "text",
8399
- headingColor: "text"
8790
+ color: "muted"
8400
8791
  }
8401
8792
  },
8402
8793
  "accent-band": {
8403
8794
  background: {
8404
8795
  type: "color",
8405
- color: "primary",
8406
- textColor: "primaryForeground",
8407
- headingColor: "primaryForeground"
8796
+ color: "primary"
8408
8797
  }
8409
8798
  },
8410
8799
  "brand-depth-band": {
8411
8800
  background: {
8412
8801
  type: "color",
8413
- color: "primary-800",
8414
- textColor: "primaryForeground",
8415
- headingColor: "primaryForeground"
8802
+ color: "primary-800"
8416
8803
  }
8417
8804
  },
8418
8805
  "hero-image": {
@@ -14634,6 +15021,16 @@ var jsonArrayTransform = {
14634
15021
  return "";
14635
15022
  }
14636
15023
  };
15024
+ var csvTransform = {
15025
+ id: "value.csv",
15026
+ kind: "formatter",
15027
+ summary: "Normalize a string or array of strings into a comma-separated list",
15028
+ run: (value) => {
15029
+ const rawValues = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
15030
+ const normalized = rawValues.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
15031
+ return normalized.length > 0 ? Array.from(new Set(normalized)).join(",") : "";
15032
+ }
15033
+ };
14637
15034
  var marqueeLoopOptionsSchema = z33.object({
14638
15035
  minItems: z33.number().int().min(1).default(10)
14639
15036
  });
@@ -14659,6 +15056,7 @@ var formattingTransforms = [
14659
15056
  dateFormatShort,
14660
15057
  arrayLengthTransform,
14661
15058
  jsonArrayTransform,
15059
+ csvTransform,
14662
15060
  marqueeLoopTransform
14663
15061
  ];
14664
15062
 
@@ -15142,117 +15540,6 @@ var uiTransforms = [
15142
15540
 
15143
15541
  // ../blocks/src/system/transforms/registry/layout.ts
15144
15542
  import { z as z35 } from "zod";
15145
-
15146
- // ../theme-core/src/palette/utils/colorConversion.ts
15147
- var clamp01 = (x) => Math.max(0, Math.min(1, x));
15148
- var mod = (a, n) => (a % n + n) % n;
15149
- var deg = (x) => mod(x, 360);
15150
- function hexToRgb(hex) {
15151
- const h = hex.replace(/^#/, "");
15152
- const m = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
15153
- if (m.length !== 6) throw new Error("Bad hex");
15154
- const int = parseInt(m, 16);
15155
- return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
15156
- }
15157
- function rgbToHex(r2, g, b) {
15158
- const to = (n) => Math.round(n).toString(16).padStart(2, "0");
15159
- return `#${to(r2)}${to(g)}${to(b)}`;
15160
- }
15161
- function srgbToLinear(u) {
15162
- const x = u / 255;
15163
- return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
15164
- }
15165
- function linearToSrgb(x) {
15166
- const y = x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
15167
- return clamp01(y) * 255;
15168
- }
15169
- function rgbToHsl(r2, g, b) {
15170
- const R = r2 / 255, G = g / 255, B = b / 255;
15171
- const max = Math.max(R, G, B), min = Math.min(R, G, B);
15172
- const d = max - min;
15173
- let h = 0;
15174
- if (d !== 0) {
15175
- switch (max) {
15176
- case R:
15177
- h = (G - B) / d + (G < B ? 6 : 0);
15178
- break;
15179
- case G:
15180
- h = (B - R) / d + 2;
15181
- break;
15182
- case B:
15183
- h = (R - G) / d + 4;
15184
- break;
15185
- }
15186
- h *= 60;
15187
- }
15188
- const l = (max + min) / 2;
15189
- const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
15190
- return { h, s, l };
15191
- }
15192
- function srgbToOklab(r2, g, b) {
15193
- const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
15194
- const l = 0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B;
15195
- const m = 0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B;
15196
- const s = 0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B;
15197
- const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
15198
- const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
15199
- const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
15200
- const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
15201
- return { L, a, b: b2 };
15202
- }
15203
- function oklabToSrgb(L, a, b) {
15204
- const l_ = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
15205
- const m_ = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
15206
- const s_ = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
15207
- const R = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
15208
- const G = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
15209
- const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
15210
- return { r: linearToSrgb(R), g: linearToSrgb(G), b: linearToSrgb(B) };
15211
- }
15212
- function oklabToOklch(L, a, b) {
15213
- const C = Math.sqrt(a * a + b * b);
15214
- const h = C < 1e-7 ? 0 : deg(Math.atan2(b, a) * 180 / Math.PI);
15215
- return { L, C, h };
15216
- }
15217
- function oklchToOklab(L, C, h) {
15218
- const hr = h * Math.PI / 180;
15219
- const a = C * Math.cos(hr);
15220
- const b = C * Math.sin(hr);
15221
- return { L, a, b };
15222
- }
15223
- function inSRGB(r2, g, b) {
15224
- return r2 >= 0 && r2 <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
15225
- }
15226
- function oklchToHexGamut(L, C, h) {
15227
- let lo = 0, hi = C, best = 0;
15228
- for (let i = 0; i < 18; i++) {
15229
- const mid = (lo + hi) / 2;
15230
- const { a: a2, b: b2 } = oklchToOklab(L, mid, h);
15231
- const { r: r3, g: g2, b: bb2 } = oklabToSrgb(L, a2, b2);
15232
- if (inSRGB(r3, g2, bb2)) {
15233
- best = mid;
15234
- lo = mid;
15235
- } else {
15236
- hi = mid;
15237
- }
15238
- }
15239
- const { a, b } = oklchToOklab(L, best, h);
15240
- const { r: r2, g, b: bb } = oklabToSrgb(L, a, b);
15241
- return rgbToHex(r2, g, bb);
15242
- }
15243
- function featuresFromHex(hex) {
15244
- const { r: r2, g, b } = hexToRgb(hex);
15245
- const { h, s, l } = rgbToHsl(r2, g, b);
15246
- const { L, a, b: b2 } = srgbToOklab(r2, g, b);
15247
- const { L: okL, C: okC, h: okH } = oklabToOklch(L, a, b2);
15248
- const max = Math.max(r2, g, b);
15249
- const v = max / 255;
15250
- const Y = 0.2126 * srgbToLinear(r2) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
15251
- const chroma = s;
15252
- return { r: r2, g, b, h, s, l, v, Y, chroma, okL, okC, okH, hex };
15253
- }
15254
-
15255
- // ../blocks/src/system/transforms/registry/layout.ts
15256
15543
  var joinClasses4 = (parts) => parts.filter(
15257
15544
  (part) => typeof part === "string" && part.trim().length > 0
15258
15545
  ).join(" ").replace(/\s+/g, " ").trim();
@@ -20201,51 +20488,6 @@ function resolveEventCta(event, buttonText) {
20201
20488
  return { label, href: event.path, hidden: false };
20202
20489
  }
20203
20490
 
20204
- // ../theme-core/src/palette/utils/contrast.ts
20205
- function relativeLuminance(r2, g, b) {
20206
- const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
20207
- return 0.2126 * R + 0.7152 * G + 0.0722 * B;
20208
- }
20209
-
20210
- // ../theme-core/src/palette/utils/textColor.ts
20211
- function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
20212
- const { r: r2, g, b } = parseColorToRgb(background);
20213
- const luminance = relativeLuminance(r2, g, b);
20214
- const blackContrast = (luminance + 0.05) / 0.05;
20215
- const whiteContrast = 1.05 / (luminance + 0.05);
20216
- if (blackContrast >= minContrast && whiteContrast < minContrast) {
20217
- return "#000000";
20218
- }
20219
- if (whiteContrast >= minContrast && blackContrast < minContrast) {
20220
- return "#FFFFFF";
20221
- }
20222
- return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
20223
- }
20224
- function getTextColorForBackground(background) {
20225
- return pickBlackOrWhiteTextColor(background);
20226
- }
20227
- function parseColorToRgb(input) {
20228
- const trimmed = input.trim();
20229
- if (trimmed.startsWith("#")) {
20230
- return hexToRgb(trimmed);
20231
- }
20232
- const rgbMatch = trimmed.match(
20233
- /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
20234
- );
20235
- if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
20236
- return {
20237
- r: clamp255(Number(rgbMatch[1])),
20238
- g: clamp255(Number(rgbMatch[2])),
20239
- b: clamp255(Number(rgbMatch[3]))
20240
- };
20241
- }
20242
- throw new Error("Unsupported color format");
20243
- }
20244
- function clamp255(value) {
20245
- if (Number.isNaN(value)) return 0;
20246
- return Math.max(0, Math.min(255, value));
20247
- }
20248
-
20249
20491
  // ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
20250
20492
  function r(e) {
20251
20493
  var t, f, n = "";
@@ -22175,7 +22417,12 @@ var eventListingBlockDefinition = {
22175
22417
  detailLevel: "listing",
22176
22418
  kind: { $bind: { from: "content.kind" } },
22177
22419
  eventSurface: { $bind: { from: "content.eventSurface" } },
22178
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
22420
+ eventPresets: {
22421
+ $bind: {
22422
+ from: "content.filterEventPresets",
22423
+ transforms: [{ id: "value.csv" }]
22424
+ }
22425
+ },
22179
22426
  scheduleScope: { $bind: { from: "content.scheduleScope" } }
22180
22427
  },
22181
22428
  mode: "server"
@@ -22960,7 +23207,12 @@ var eventCalendarBlockDefinition = {
22960
23207
  // Pass filter params if configured
22961
23208
  kind: { $bind: { from: "content.kind" } },
22962
23209
  eventSurface: { $bind: { from: "content.eventSurface" } },
22963
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
23210
+ eventPresets: {
23211
+ $bind: {
23212
+ from: "content.filterEventPresets",
23213
+ transforms: [{ id: "value.csv" }]
23214
+ }
23215
+ },
22964
23216
  scheduleScope: { $bind: { from: "content.scheduleScope" } },
22965
23217
  categoryIds: { $bind: { from: "content.filterCategoryIds" } },
22966
23218
  staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
@@ -29780,16 +30032,18 @@ function toTrimmedString(value) {
29780
30032
  return trimmed ? trimmed : void 0;
29781
30033
  }
29782
30034
  function normalizeBookingFormConfig(form2) {
29783
- if (!form2) return null;
30035
+ if (!isRecord4(form2)) return null;
30036
+ const id = readNonEmptyString(form2.id);
30037
+ const name = readNonEmptyString(form2.name);
30038
+ if (!id || !name) return null;
30039
+ const schemaSource = isRecord4(form2.schema) ? form2.schema : isRecord4(form2.schemaJson) ? form2.schemaJson : null;
30040
+ const settingsSource = isRecord4(form2.settings) ? form2.settings : isRecord4(form2.settingsJson) ? form2.settingsJson : null;
29784
30041
  return {
29785
- id: form2.id,
29786
- name: form2.name,
29787
- slug: "",
29788
- settings: form2.settingsJson,
29789
- schema: form2.schemaJson ? {
29790
- version: form2.schemaJson.version,
29791
- fields: form2.schemaJson.fields ?? []
29792
- } : void 0
30042
+ id,
30043
+ name,
30044
+ slug: typeof form2.slug === "string" ? form2.slug : "",
30045
+ settings: normalizeBookingSettings(settingsSource),
30046
+ schema: normalizeBookingSchema(schemaSource)
29793
30047
  };
29794
30048
  }
29795
30049
  function normalizeBookingServices(services) {
@@ -29805,12 +30059,106 @@ function normalizeBookingServices(services) {
29805
30059
  return [];
29806
30060
  }
29807
30061
  if (Array.isArray(services)) {
29808
- return services.map(normalizeService);
30062
+ return services.filter(isBookingFormService).map(normalizeService);
29809
30063
  }
29810
- if ("services" in services) {
29811
- return Array.isArray(services.services) ? services.services.map(normalizeService) : [];
30064
+ if (isRecord4(services) && "services" in services) {
30065
+ return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
30066
+ }
30067
+ return isRecord4(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
30068
+ }
30069
+ function normalizeBookingSchema(value) {
30070
+ if (!value) return void 0;
30071
+ const rawFields = Array.isArray(value.fields) ? value.fields : [];
30072
+ const fields3 = rawFields.map(readBookingFormField).filter((field) => field !== null);
30073
+ return {
30074
+ version: typeof value.version === "string" ? value.version : void 0,
30075
+ fields: fields3
30076
+ };
30077
+ }
30078
+ function readBookingFormField(value) {
30079
+ if (!isRecord4(value)) return null;
30080
+ const id = readNonEmptyString(value.id);
30081
+ const label = readNonEmptyString(value.label);
30082
+ const type = readBookingFieldType(value.type);
30083
+ if (!id || !label || !type) return null;
30084
+ return {
30085
+ id,
30086
+ label,
30087
+ type,
30088
+ required: typeof value.required === "boolean" ? value.required : void 0,
30089
+ placeholder: readOptionalString(value.placeholder),
30090
+ helpText: readOptionalString(value.helpText),
30091
+ options: readBookingFieldOptions(value.options),
30092
+ multiple: typeof value.multiple === "boolean" ? value.multiple : void 0,
30093
+ minLength: readOptionalNumber(value.minLength),
30094
+ maxLength: readOptionalNumber(value.maxLength),
30095
+ pattern: readOptionalString(value.pattern),
30096
+ min: readOptionalNumber(value.min),
30097
+ max: readOptionalNumber(value.max)
30098
+ };
30099
+ }
30100
+ function readBookingFieldType(value) {
30101
+ switch (value) {
30102
+ case "text":
30103
+ case "email":
30104
+ case "textarea":
30105
+ case "select":
30106
+ case "radio":
30107
+ case "checkbox":
30108
+ case "booking_requirement_consent":
30109
+ case "tel":
30110
+ case "url":
30111
+ case "number":
30112
+ case "date":
30113
+ case "time":
30114
+ return value;
30115
+ default:
30116
+ return null;
29812
30117
  }
29813
- return Object.values(services).map(normalizeService);
30118
+ }
30119
+ function readBookingFieldOptions(value) {
30120
+ if (!Array.isArray(value)) return void 0;
30121
+ const options = value.map(readBookingFieldOption).filter((option) => option !== null);
30122
+ return options.length > 0 ? options : void 0;
30123
+ }
30124
+ function readBookingFieldOption(value) {
30125
+ if (!isRecord4(value)) return null;
30126
+ const optionValue = readNonEmptyString(value.value);
30127
+ const label = readNonEmptyString(value.label);
30128
+ return optionValue && label ? { value: optionValue, label } : null;
30129
+ }
30130
+ function normalizeBookingSettings(value) {
30131
+ if (!value || value.type !== "booking") return void 0;
30132
+ return {
30133
+ type: "booking",
30134
+ serviceId: readOptionalString(value.serviceId),
30135
+ serviceIds: readStringArray(value.serviceIds),
30136
+ resourceId: readOptionalString(value.resourceId),
30137
+ requiresApproval: typeof value.requiresApproval === "boolean" ? value.requiresApproval : void 0,
30138
+ successMessage: readOptionalString(value.successMessage)
30139
+ };
30140
+ }
30141
+ function isBookingFormService(value) {
30142
+ return isRecord4(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
30143
+ }
30144
+ function readNonEmptyString(value) {
30145
+ if (typeof value !== "string") return null;
30146
+ const trimmed = value.trim();
30147
+ return trimmed.length > 0 ? trimmed : null;
30148
+ }
30149
+ function readOptionalString(value) {
30150
+ return typeof value === "string" ? value : void 0;
30151
+ }
30152
+ function readOptionalNumber(value) {
30153
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
30154
+ }
30155
+ function readStringArray(value) {
30156
+ if (!Array.isArray(value)) return void 0;
30157
+ const strings = value.filter((item) => typeof item === "string");
30158
+ return strings.length > 0 ? strings : void 0;
30159
+ }
30160
+ function isRecord4(value) {
30161
+ return typeof value === "object" && value !== null;
29814
30162
  }
29815
30163
 
29816
30164
  // ../blocks/src/system/runtime/nodes/booking-form.interactive.ts
@@ -33422,119 +33770,6 @@ function renderBlock(manifest, content, options = {}) {
33422
33770
  );
33423
33771
  }
33424
33772
 
33425
- // ../theme-core/src/palette/generateShades.ts
33426
- function generateShades(hexColor, name) {
33427
- const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
33428
- const base = featuresFromHex(hexColor);
33429
- const hue = base.okH;
33430
- const baseChroma = base.okC;
33431
- const toneMap = {
33432
- 50: 0.975,
33433
- 100: 0.945,
33434
- 200: 0.89,
33435
- 300: 0.82,
33436
- 400: 0.74,
33437
- 500: 0.66,
33438
- 600: 0.58,
33439
- 700: 0.49,
33440
- 800: 0.4,
33441
- 900: 0.28,
33442
- 950: 0.16
33443
- };
33444
- const shadeDefs = shadeSteps.map((step, idx) => {
33445
- const t = idx / (shadeSteps.length - 1);
33446
- const L = toneMap[step];
33447
- const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t);
33448
- const C = baseChroma * chromaFactor;
33449
- return {
33450
- name: `${name}-${step}`,
33451
- hex: oklchToHexGamut(L, C, hue)
33452
- };
33453
- });
33454
- shadeDefs.push({ name, hex: hexColor });
33455
- return shadeDefs;
33456
- }
33457
-
33458
- // ../theme-core/src/palette/neutralScale.ts
33459
- function generateNeutralScale({
33460
- background,
33461
- steps = 11,
33462
- warm = false
33463
- }) {
33464
- const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
33465
- const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
33466
- const count = Math.min(steps, shadeNames.length);
33467
- const scale = [];
33468
- for (let i = 0; i < count; i++) {
33469
- const t = i / (count - 1);
33470
- const tone = isDark ? mix(0.06, 0.92, t) : mix(0.98, 0.1, t);
33471
- const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
33472
- const name = `neutral-${shadeNames[i]}`;
33473
- scale.push({ name, hex });
33474
- }
33475
- return scale;
33476
- }
33477
- function mix(a, b, t) {
33478
- return a + (b - a) * Math.max(0, Math.min(1, t));
33479
- }
33480
-
33481
- // ../theme-core/src/palette/expandPalette.ts
33482
- function colorsToMap(palette) {
33483
- const map = {};
33484
- for (const c of palette.colors) {
33485
- map[c.name] = c.hex;
33486
- }
33487
- return map;
33488
- }
33489
- function isBackgroundDark(hex) {
33490
- try {
33491
- return featuresFromHex(hex).Y < 0.5;
33492
- } catch {
33493
- return false;
33494
- }
33495
- }
33496
- function expandPalette(palette) {
33497
- const base = colorsToMap(palette);
33498
- const expanded = { ...base };
33499
- const background = base.background || base.surface || "#ffffff";
33500
- const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
33501
- neutral2.forEach((n) => {
33502
- expanded[n.name] = n.hex;
33503
- });
33504
- for (const [name, hex] of Object.entries(base)) {
33505
- if (hex) {
33506
- const shades = generateShades(hex, name);
33507
- shades.forEach((shade) => {
33508
- expanded[shade.name] = shade.hex;
33509
- });
33510
- }
33511
- }
33512
- if (base.text) expanded.body = base.text;
33513
- if (base.danger && !base.destructive) {
33514
- expanded.destructive = base.danger;
33515
- }
33516
- const isDark = base.background ? isBackgroundDark(base.background) : false;
33517
- const isDarkMode = palette.meta?.mode === "dark" || isDark;
33518
- expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
33519
- const onRoles = [
33520
- { role: "primary", on: "onPrimary" },
33521
- { role: "secondary", on: "onSecondary" },
33522
- { role: "accent", on: "onAccent" },
33523
- { role: "success", on: "onSuccess" },
33524
- { role: "warning", on: "onWarning" },
33525
- { role: "destructive", on: "onDestructive" },
33526
- { role: "info", on: "onInfo" },
33527
- { role: "surface", on: "onSurface" }
33528
- ];
33529
- for (const { role, on } of onRoles) {
33530
- const bg = base[role];
33531
- if (!bg) continue;
33532
- if (expanded[on]) continue;
33533
- expanded[on] = getTextColorForBackground(bg);
33534
- }
33535
- return expanded;
33536
- }
33537
-
33538
33773
  // ../theme-core/src/runtime/fontFamily.ts
33539
33774
  var GENERIC_CSS_FAMILIES = [
33540
33775
  "serif",
@@ -37231,6 +37466,8 @@ var MemoBlockSection = React6.memo(
37231
37466
  themeConfig,
37232
37467
  data: void 0,
37233
37468
  siteId: dataContext?.siteId,
37469
+ apiBaseUrl: dataContext?.apiBaseUrl,
37470
+ portalToken: dataContext?.portalToken ?? null,
37234
37471
  supabaseUrl: dataContext?.supabaseUrl,
37235
37472
  imageResolveContext,
37236
37473
  blockId: block.id ?? null,
@@ -37345,6 +37582,8 @@ var MemoBlockSection = React6.memo(
37345
37582
  themeConfig,
37346
37583
  data: resolved,
37347
37584
  siteId: dataContext?.siteId,
37585
+ apiBaseUrl: dataContext?.apiBaseUrl,
37586
+ portalToken: dataContext?.portalToken ?? null,
37348
37587
  supabaseUrl: dataContext?.supabaseUrl,
37349
37588
  imageResolveContext,
37350
37589
  blockId: block.id ?? null,
@@ -43107,32 +43346,32 @@ var containerResponsiveThemeCss = `/*
43107
43346
  }
43108
43347
 
43109
43348
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-text--muted {
43110
- opacity: var(--ab-text-muted-opacity);
43349
+ opacity: var(--ab-text-muted-opacity, 0.6);
43111
43350
  }
43112
43351
 
43113
43352
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-text--faint {
43114
- opacity: var(--ab-text-faint-opacity);
43353
+ opacity: var(--ab-text-faint-opacity, 0.4);
43115
43354
  }
43116
43355
 
43117
43356
  /* Selection cards (service, resource, time slot) */
43118
43357
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card {
43119
43358
  position: relative;
43120
43359
  padding: 1rem;
43121
- border: 2px solid var(--ab-card-border);
43122
- border-radius: var(--rb-block-radius);
43360
+ border: 2px solid var(--ab-card-border, rgb(var(--tb-border, 226 232 240)));
43361
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43123
43362
  text-align: left;
43124
43363
  background: transparent;
43125
43364
  cursor: pointer;
43126
- transition: border-color var(--rb-block-transition) ease, background-color var(--rb-block-transition) ease;
43365
+ transition: border-color var(--rb-block-transition, 150ms) ease, background-color var(--rb-block-transition, 150ms) ease;
43127
43366
  }
43128
43367
 
43129
43368
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card:hover {
43130
- border-color: var(--ab-card-border-hover);
43369
+ border-color: var(--ab-card-border-hover, rgba(var(--tb-primary, 17 24 39), 0.5));
43131
43370
  }
43132
43371
 
43133
43372
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card--selected {
43134
- border-color: var(--ab-card-border-selected);
43135
- background-color: var(--ab-card-bg-selected);
43373
+ border-color: var(--ab-card-border-selected, rgb(var(--tb-primary, 17 24 39)));
43374
+ background-color: var(--ab-card-bg-selected, rgba(var(--tb-primary, 17 24 39), 0.05));
43136
43375
  }
43137
43376
 
43138
43377
  /* Checkmark indicator */
@@ -43141,7 +43380,7 @@ var containerResponsiveThemeCss = `/*
43141
43380
  width: 1.25rem;
43142
43381
  height: 1.25rem;
43143
43382
  border-radius: 50%;
43144
- background-color: var(--ab-check-bg);
43383
+ background-color: var(--ab-check-bg, rgb(var(--tb-primary, 17 24 39)));
43145
43384
  display: flex;
43146
43385
  align-items: center;
43147
43386
  justify-content: center;
@@ -43150,42 +43389,42 @@ var containerResponsiveThemeCss = `/*
43150
43389
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-check svg {
43151
43390
  width: 0.75rem;
43152
43391
  height: 0.75rem;
43153
- color: var(--ab-check-text);
43392
+ color: var(--ab-check-text, rgb(var(--tb-background, 255 255 255)));
43154
43393
  }
43155
43394
 
43156
43395
  /* Info box (service summary) */
43157
43396
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-info-box {
43158
43397
  padding: 1rem;
43159
- border: 1px solid var(--ab-card-border);
43160
- border-radius: var(--rb-block-radius);
43161
- background-color: var(--ab-muted-bg);
43398
+ border: 1px solid var(--ab-card-border, rgb(var(--tb-border, 226 232 240)));
43399
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43400
+ background-color: var(--ab-muted-bg, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
43162
43401
  }
43163
43402
 
43164
43403
  /* Alert states */
43165
43404
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert {
43166
43405
  padding: 0.75rem 1rem;
43167
- border-radius: var(--rb-block-radius);
43406
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43168
43407
  font-size: 0.875rem;
43169
43408
  }
43170
43409
 
43171
43410
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--success {
43172
- background-color: var(--ab-success-bg);
43173
- color: var(--ab-success-text);
43411
+ background-color: var(--ab-success-bg, rgba(var(--tb-success, 22 163 74), 0.1));
43412
+ color: var(--ab-success-text, rgb(var(--tb-success, 22 163 74)));
43174
43413
  }
43175
43414
 
43176
43415
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--error {
43177
- background-color: var(--ab-error-bg);
43178
- color: var(--ab-error-text);
43416
+ background-color: var(--ab-error-bg, rgba(var(--tb-destructive, 220 38 38), 0.1));
43417
+ color: var(--ab-error-text, rgb(var(--tb-destructive, 220 38 38)));
43179
43418
  }
43180
43419
 
43181
43420
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--warning {
43182
- background-color: var(--ab-warning-bg);
43183
- color: var(--ab-warning-text);
43421
+ background-color: var(--ab-warning-bg, rgba(var(--tb-warning, 245 158 11), 0.1));
43422
+ color: var(--ab-warning-text, rgb(var(--tb-warning, 245 158 11)));
43184
43423
  }
43185
43424
 
43186
43425
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--info {
43187
- background-color: var(--ab-info-bg);
43188
- color: var(--ab-info-text);
43426
+ background-color: var(--ab-info-bg, rgba(var(--tb-info, 14 165 233), 0.1));
43427
+ color: var(--ab-info-text, rgb(var(--tb-info, 14 165 233)));
43189
43428
  }
43190
43429
 
43191
43430
  /* Form elements */
@@ -43197,7 +43436,7 @@ var containerResponsiveThemeCss = `/*
43197
43436
  }
43198
43437
 
43199
43438
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-required {
43200
- color: var(--ab-error-text);
43439
+ color: var(--ab-error-text, rgb(var(--tb-destructive, 220 38 38)));
43201
43440
  margin-left: 0.125rem;
43202
43441
  }
43203
43442
 
@@ -43206,19 +43445,19 @@ var containerResponsiveThemeCss = `/*
43206
43445
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-textarea {
43207
43446
  width: 100%;
43208
43447
  padding: 0.5rem 0.75rem;
43209
- border: 1px solid var(--ab-input-border);
43210
- border-radius: var(--rb-block-radius);
43448
+ border: 1px solid var(--ab-input-border, rgb(var(--tb-border, 226 232 240)));
43449
+ border-radius: var(--ab-input-radius, var(--radius-control, var(--rb-block-radius, 1rem)));
43211
43450
  background: transparent;
43212
43451
  font-size: 0.875rem;
43213
- transition: border-color var(--rb-block-transition) ease, box-shadow var(--rb-block-transition) ease;
43452
+ transition: border-color var(--rb-block-transition, 150ms) ease, box-shadow var(--rb-block-transition, 150ms) ease;
43214
43453
  }
43215
43454
 
43216
43455
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-input:focus,
43217
43456
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-select:focus,
43218
43457
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-textarea:focus {
43219
43458
  outline: none;
43220
- border-color: var(--ab-card-border-selected);
43221
- box-shadow: 0 0 0 3px var(--ab-input-focus-ring);
43459
+ border-color: var(--ab-card-border-selected, rgb(var(--tb-primary, 17 24 39)));
43460
+ box-shadow: 0 0 0 3px var(--ab-input-focus-ring, rgba(var(--tb-primary, 17 24 39), 0.3));
43222
43461
  }
43223
43462
 
43224
43463
  /* Buttons */
@@ -43227,31 +43466,31 @@ var containerResponsiveThemeCss = `/*
43227
43466
  align-items: center;
43228
43467
  justify-content: center;
43229
43468
  padding: 0.5rem 1.5rem;
43230
- border-radius: var(--rb-block-radius);
43469
+ border-radius: var(--ab-button-radius, var(--rb-button-radius, var(--rb-block-radius, 1rem)));
43231
43470
  font-size: 0.875rem;
43232
43471
  font-weight: 500;
43233
43472
  cursor: pointer;
43234
- transition: background-color var(--rb-block-transition) ease, border-color var(--rb-block-transition) ease;
43473
+ transition: background-color var(--rb-block-transition, 150ms) ease, border-color var(--rb-block-transition, 150ms) ease;
43235
43474
  }
43236
43475
 
43237
43476
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--primary {
43238
43477
  flex: 1;
43239
- background-color: var(--ab-btn-primary-bg);
43240
- color: var(--ab-btn-primary-text);
43478
+ background-color: var(--ab-btn-primary-bg, rgb(var(--tb-primary, 17 24 39)));
43479
+ color: var(--ab-btn-primary-text, rgb(var(--tb-primaryForeground, 255 255 255)));
43241
43480
  border: none;
43242
43481
  }
43243
43482
 
43244
43483
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--primary:hover:not(:disabled) {
43245
- background-color: var(--ab-btn-primary-hover);
43484
+ background-color: var(--ab-btn-primary-hover, rgba(var(--tb-primary, 17 24 39), 0.9));
43246
43485
  }
43247
43486
 
43248
43487
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--secondary {
43249
43488
  background: transparent;
43250
- border: 1px solid var(--ab-btn-secondary-border);
43489
+ border: 1px solid var(--ab-btn-secondary-border, rgb(var(--tb-border, 226 232 240)));
43251
43490
  }
43252
43491
 
43253
43492
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--secondary:hover:not(:disabled) {
43254
- background-color: var(--ab-btn-secondary-hover);
43493
+ background-color: var(--ab-btn-secondary-hover, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
43255
43494
  }
43256
43495
 
43257
43496
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--link {
@@ -43281,8 +43520,8 @@ var containerResponsiveThemeCss = `/*
43281
43520
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-skeleton {
43282
43521
  height: 2.5rem;
43283
43522
  width: 100%;
43284
- background-color: var(--ab-muted-bg);
43285
- border-radius: var(--rb-block-radius);
43523
+ background-color: var(--ab-muted-bg, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
43524
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43286
43525
  animation: ab-pulse 1.5s ease-in-out infinite;
43287
43526
  }
43288
43527
 
@@ -43311,7 +43550,7 @@ var containerResponsiveThemeCss = `/*
43311
43550
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-link {
43312
43551
  display: inline;
43313
43552
  margin-left: 0.5rem;
43314
- color: rgb(var(--tb-primary));
43553
+ color: rgb(var(--tb-primary, 17 24 39));
43315
43554
  background: none;
43316
43555
  border: none;
43317
43556
  padding: 0;
@@ -48682,6 +48921,17 @@ var SUPPORTED_LOADER_ENDPOINTS = [
48682
48921
  // ../blocks/src/primitives/content/primitives.tsx
48683
48922
  var RichText2 = RichText;
48684
48923
 
48924
+ // ../api/src/apiEndpointTypes.ts
48925
+ function blockedDemoMutationPolicy(classification, publicMessage) {
48926
+ if (publicMessage.trim() === "") {
48927
+ throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
48928
+ }
48929
+ return {
48930
+ classification,
48931
+ publicMessage
48932
+ };
48933
+ }
48934
+
48685
48935
  // ../api/src/cache-tags.ts
48686
48936
  var TAG_TEMPLATES = {
48687
48937
  siteCollection: "riverbank:site",
@@ -48712,6 +48962,18 @@ var TAG_TEMPLATES = {
48712
48962
  };
48713
48963
 
48714
48964
  // ../api/src/endpoints.ts
48965
+ var DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy(
48966
+ "blocked-hidden",
48967
+ "This action is not available in demo sites."
48968
+ );
48969
+ var DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy(
48970
+ "blocked-disabled",
48971
+ "This setting is disabled in demo sites."
48972
+ );
48973
+ var DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy(
48974
+ "internal-only",
48975
+ "This internal operation is not available in demo sites."
48976
+ );
48715
48977
  var ENDPOINT_DEFINITIONS = {
48716
48978
  // AI endpoints - no cache due to dynamic nature
48717
48979
  aiContentUpdateChat: {
@@ -48828,7 +49090,8 @@ var ENDPOINT_DEFINITIONS = {
48828
49090
  path: "/sites/{siteId}/ai/generate",
48829
49091
  method: "POST",
48830
49092
  auth: "user",
48831
- responseKind: "json"
49093
+ responseKind: "json",
49094
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
48832
49095
  },
48833
49096
  getOnboardingPreviewStatus: {
48834
49097
  path: "/public/sites/{siteId}/onboarding/preview-status",
@@ -48849,7 +49112,8 @@ var ENDPOINT_DEFINITIONS = {
48849
49112
  method: "POST",
48850
49113
  auth: "user",
48851
49114
  errors: [],
48852
- responseKind: "json"
49115
+ responseKind: "json",
49116
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED
48853
49117
  },
48854
49118
  goLiveSite: {
48855
49119
  path: "/sites/{siteId}/launch/go-live",
@@ -48918,20 +49182,23 @@ var ENDPOINT_DEFINITIONS = {
48918
49182
  path: "/sites/{siteId}/ai/site-wizard/goals",
48919
49183
  method: "POST",
48920
49184
  auth: "user",
48921
- responseKind: "json"
49185
+ responseKind: "json",
49186
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
48922
49187
  },
48923
49188
  aiSiteWizardIntakeTriage: {
48924
49189
  path: "/sites/{siteId}/ai/site-wizard/intake-triage",
48925
49190
  method: "POST",
48926
49191
  auth: "user",
48927
- responseKind: "json"
49192
+ responseKind: "json",
49193
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
48928
49194
  },
48929
49195
  aiSiteWizardTelemetry: {
48930
49196
  path: "/sites/{siteId}/ai/site-wizard/telemetry",
48931
49197
  method: "POST",
48932
49198
  auth: "user",
48933
49199
  errors: [],
48934
- responseKind: "json"
49200
+ responseKind: "json",
49201
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
48935
49202
  },
48936
49203
  // Admin SEO
48937
49204
  listGscPropertiesAdmin: {
@@ -49138,7 +49405,7 @@ var ENDPOINT_DEFINITIONS = {
49138
49405
  responseKind: "json",
49139
49406
  errors: ["resource:not_found", "server:internal_error"]
49140
49407
  },
49141
- // Ops (event hosts/admins)
49408
+ // Ops (staff event operators/admins)
49142
49409
  opsListUpcomingEventOccurrences: {
49143
49410
  path: "/ops/sites/{siteId}/events",
49144
49411
  method: "GET",
@@ -49156,6 +49423,7 @@ var ENDPOINT_DEFINITIONS = {
49156
49423
  method: "POST",
49157
49424
  auth: "user",
49158
49425
  responseKind: "json",
49426
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49159
49427
  errors: [
49160
49428
  "validation:invalid_input",
49161
49429
  "auth:forbidden",
@@ -49168,6 +49436,7 @@ var ENDPOINT_DEFINITIONS = {
49168
49436
  method: "POST",
49169
49437
  auth: "user",
49170
49438
  responseKind: "json",
49439
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49171
49440
  errors: [
49172
49441
  "validation:invalid_input",
49173
49442
  "auth:forbidden",
@@ -49186,6 +49455,7 @@ var ENDPOINT_DEFINITIONS = {
49186
49455
  method: "POST",
49187
49456
  auth: "user",
49188
49457
  responseKind: "json",
49458
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49189
49459
  errors: [
49190
49460
  "validation:invalid_input",
49191
49461
  "auth:forbidden",
@@ -49219,6 +49489,7 @@ var ENDPOINT_DEFINITIONS = {
49219
49489
  method: "POST",
49220
49490
  auth: "user",
49221
49491
  responseKind: "json",
49492
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49222
49493
  errors: [
49223
49494
  "validation:invalid_input",
49224
49495
  "auth:forbidden",
@@ -49247,7 +49518,8 @@ var ENDPOINT_DEFINITIONS = {
49247
49518
  method: "POST",
49248
49519
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings],
49249
49520
  auth: "user",
49250
- responseKind: "json"
49521
+ responseKind: "json",
49522
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49251
49523
  },
49252
49524
  previewEmailTemplate: {
49253
49525
  path: "/sites/{siteId}/settings/emails/preview",
@@ -49298,14 +49570,16 @@ var ENDPOINT_DEFINITIONS = {
49298
49570
  method: "POST",
49299
49571
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49300
49572
  auth: "user",
49301
- responseKind: "json"
49573
+ responseKind: "json",
49574
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49302
49575
  },
49303
49576
  createNewsletterSubscribersImportUploadUrl: {
49304
49577
  path: "/sites/{siteId}/newsletter/subscribers/import-url",
49305
49578
  method: "POST",
49306
49579
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49307
49580
  auth: "user",
49308
- responseKind: "json"
49581
+ responseKind: "json",
49582
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49309
49583
  },
49310
49584
  exportNewsletterSubscribersCsv: {
49311
49585
  path: "/sites/{siteId}/newsletter/subscribers/export.csv",
@@ -49502,14 +49776,16 @@ var ENDPOINT_DEFINITIONS = {
49502
49776
  method: "POST",
49503
49777
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49504
49778
  auth: "user",
49505
- responseKind: "json"
49779
+ responseKind: "json",
49780
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49506
49781
  },
49507
49782
  testSendNewsletterCampaign: {
49508
49783
  path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/test-send",
49509
49784
  method: "POST",
49510
49785
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49511
49786
  auth: "user",
49512
- responseKind: "json"
49787
+ responseKind: "json",
49788
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49513
49789
  },
49514
49790
  listNewsletterSendJobs: {
49515
49791
  path: "/sites/{siteId}/newsletter/jobs",
@@ -49557,6 +49833,20 @@ var ENDPOINT_DEFINITIONS = {
49557
49833
  responseKind: "json",
49558
49834
  errors: ["validation:invalid_input", "billing:plan_limit_exceeded", "server:internal_error"]
49559
49835
  },
49836
+ createAppointmentResourceWithAccountAccess: {
49837
+ path: "/sites/{siteId}/bookings/resources/account-access",
49838
+ method: "POST",
49839
+ auth: "user",
49840
+ responseKind: "json",
49841
+ errors: [
49842
+ "validation:invalid_input",
49843
+ "auth:forbidden",
49844
+ "billing:plan_limit_exceeded",
49845
+ "resource:conflict",
49846
+ "resource:not_found",
49847
+ "server:internal_error"
49848
+ ]
49849
+ },
49560
49850
  getAppointmentResource: {
49561
49851
  path: "/sites/{siteId}/bookings/resources/{resourceId}",
49562
49852
  method: "GET",
@@ -50197,7 +50487,8 @@ var ENDPOINT_DEFINITIONS = {
50197
50487
  method: "DELETE",
50198
50488
  tags: ["site", "site-{siteId}"],
50199
50489
  auth: "user",
50200
- responseKind: "json"
50490
+ responseKind: "json",
50491
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
50201
50492
  },
50202
50493
  listSiteMembers: {
50203
50494
  path: "/sites/{siteId}/members",
@@ -50653,7 +50944,8 @@ var ENDPOINT_DEFINITIONS = {
50653
50944
  method: "POST",
50654
50945
  tags: ["site-{siteId}", "content-{siteId}-{type}"],
50655
50946
  auth: "user",
50656
- responseKind: "json"
50947
+ responseKind: "json",
50948
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
50657
50949
  },
50658
50950
  updateSiteGeneralSettings: {
50659
50951
  path: "/sites/{siteId}/settings/general",
@@ -52892,6 +53184,7 @@ var ENDPOINT_DEFINITIONS = {
52892
53184
  method: "POST",
52893
53185
  tags: ["site-{siteId}"],
52894
53186
  auth: "user",
53187
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
52895
53188
  errors: [
52896
53189
  "validation:invalid_input",
52897
53190
  "auth:forbidden",
@@ -52906,6 +53199,7 @@ var ENDPOINT_DEFINITIONS = {
52906
53199
  method: "POST",
52907
53200
  tags: ["site-{siteId}"],
52908
53201
  auth: "user",
53202
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
52909
53203
  errors: [
52910
53204
  "validation:invalid_input",
52911
53205
  "auth:forbidden",
@@ -53215,6 +53509,7 @@ var ENDPOINT_DEFINITIONS = {
53215
53509
  tags: ["site-{siteId}", "passes-{siteId}"],
53216
53510
  auth: "user",
53217
53511
  responseKind: "json",
53512
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53218
53513
  errors: ["validation:invalid_input", "server:internal_error"]
53219
53514
  },
53220
53515
  getBookingPass: {
@@ -53230,6 +53525,7 @@ var ENDPOINT_DEFINITIONS = {
53230
53525
  tags: ["site-{siteId}", "passes-{siteId}"],
53231
53526
  auth: "user",
53232
53527
  responseKind: "json",
53528
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53233
53529
  errors: [
53234
53530
  "validation:invalid_input",
53235
53531
  "resource:not_found",
@@ -53242,6 +53538,7 @@ var ENDPOINT_DEFINITIONS = {
53242
53538
  tags: ["site-{siteId}", "passes-{siteId}"],
53243
53539
  auth: "user",
53244
53540
  responseKind: "json",
53541
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53245
53542
  errors: [
53246
53543
  "validation:invalid_input",
53247
53544
  "resource:not_found",
@@ -53297,6 +53594,7 @@ var ENDPOINT_DEFINITIONS = {
53297
53594
  tags: ["site-{siteId}", "memberships-{siteId}"],
53298
53595
  auth: "user",
53299
53596
  responseKind: "json",
53597
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53300
53598
  errors: ["validation:invalid_input", "server:internal_error"]
53301
53599
  },
53302
53600
  getBookingMembership: {
@@ -53312,6 +53610,7 @@ var ENDPOINT_DEFINITIONS = {
53312
53610
  tags: ["site-{siteId}", "memberships-{siteId}"],
53313
53611
  auth: "user",
53314
53612
  responseKind: "json",
53613
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53315
53614
  errors: [
53316
53615
  "validation:invalid_input",
53317
53616
  "resource:not_found",
@@ -53324,6 +53623,7 @@ var ENDPOINT_DEFINITIONS = {
53324
53623
  tags: ["site-{siteId}", "memberships-{siteId}"],
53325
53624
  auth: "user",
53326
53625
  responseKind: "json",
53626
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53327
53627
  errors: [
53328
53628
  "validation:invalid_input",
53329
53629
  "resource:not_found",
@@ -53540,6 +53840,7 @@ var ENDPOINT_DEFINITIONS = {
53540
53840
  tags: ["site-{siteId}", "customers-{siteId}"],
53541
53841
  auth: "user",
53542
53842
  responseKind: "json",
53843
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53543
53844
  errors: [
53544
53845
  "validation:invalid_input",
53545
53846
  "auth:forbidden",
@@ -54917,8 +55218,7 @@ var dashboardNavVisibilityBaseSchema = z66.object({
54917
55218
  var dashboardNavVisibilityRolesSchema = z66.object({
54918
55219
  administrator: dashboardNavVisibilityBaseSchema.optional(),
54919
55220
  editor: dashboardNavVisibilityBaseSchema.optional(),
54920
- team_member: dashboardNavVisibilityBaseSchema.optional(),
54921
- event_host: dashboardNavVisibilityBaseSchema.optional()
55221
+ team_member: dashboardNavVisibilityBaseSchema.optional()
54922
55222
  }).strip().optional();
54923
55223
  var dashboardNavVisibilitySchema = dashboardNavVisibilityBaseSchema.extend({
54924
55224
  roles: dashboardNavVisibilityRolesSchema
@@ -55390,7 +55690,7 @@ function preset(id, verticalId, canonicalBehaviour, label, pluralLabel, descript
55390
55690
  }
55391
55691
 
55392
55692
  // ../api/src/utils/isRecord.ts
55393
- function isRecord4(value) {
55693
+ function isRecord5(value) {
55394
55694
  return typeof value === "object" && value !== null && !Array.isArray(value);
55395
55695
  }
55396
55696
 
@@ -55439,6 +55739,21 @@ var appointmentSetupServiceDraftSchema = z68.object({
55439
55739
  timezone: z68.string().trim().min(1).nullable(),
55440
55740
  payment: appointmentSetupPaymentDraftSchema,
55441
55741
  assignment: appointmentSetupServiceAssignmentDraftSchema
55742
+ }).superRefine((service, ctx) => {
55743
+ if (service.payment.priceType === "paid" && (service.priceAmount === null || service.priceAmount <= 0)) {
55744
+ ctx.addIssue({
55745
+ code: "custom",
55746
+ path: ["priceAmount"],
55747
+ message: "Paid appointment services need a positive price."
55748
+ });
55749
+ }
55750
+ if (service.payment.priceType === "free" && service.priceAmount !== null && service.priceAmount > 0) {
55751
+ ctx.addIssue({
55752
+ code: "custom",
55753
+ path: ["priceAmount"],
55754
+ message: "Free appointment services cannot carry a positive price."
55755
+ });
55756
+ }
55442
55757
  });
55443
55758
  var appointmentSetupPractitionerDraftSchema = z68.object({
55444
55759
  ref: appointmentSetupRefSchema,
@@ -55664,7 +55979,7 @@ function sanitizeMarks(marks) {
55664
55979
  if (mark.type === "bold" || mark.type === "strong" || mark.type === "italic" || mark.type === "em") {
55665
55980
  return [{ type: mark.type }];
55666
55981
  }
55667
- if (mark.type === "link" && isRecord4(mark.attrs) && typeof mark.attrs.href === "string") {
55982
+ if (mark.type === "link" && isRecord5(mark.attrs) && typeof mark.attrs.href === "string") {
55668
55983
  const attrs = { href: mark.attrs.href };
55669
55984
  if (typeof mark.attrs.target === "string" && mark.attrs.target.trim().length > 0) {
55670
55985
  attrs.target = mark.attrs.target;
@@ -55679,10 +55994,10 @@ function sanitizeMarks(marks) {
55679
55994
  return sanitized.length > 0 ? sanitized : void 0;
55680
55995
  }
55681
55996
  function unwrapRichTextValue(value) {
55682
- if (isRecord4(value) && isRecord4(value.doc)) {
55997
+ if (isRecord5(value) && isRecord5(value.doc)) {
55683
55998
  return unwrapRichTextValue(value.doc);
55684
55999
  }
55685
- if (isRecord4(value) && value.type === "doc") {
56000
+ if (isRecord5(value) && value.type === "doc") {
55686
56001
  return {
55687
56002
  type: "doc",
55688
56003
  content: Array.isArray(value.content) ? value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) : []
@@ -55691,7 +56006,7 @@ function unwrapRichTextValue(value) {
55691
56006
  return EMPTY_SITE_BANNER_BODY;
55692
56007
  }
55693
56008
  function isTipTapNodeLike(value) {
55694
- return isRecord4(value) && typeof value.type === "string";
56009
+ return isRecord5(value) && typeof value.type === "string";
55695
56010
  }
55696
56011
  function coerceTipTapNode(value) {
55697
56012
  return {
@@ -55699,9 +56014,9 @@ function coerceTipTapNode(value) {
55699
56014
  ...Array.isArray(value.content) ? { content: value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) } : {},
55700
56015
  ...typeof value.text === "string" ? { text: value.text } : {},
55701
56016
  ...Array.isArray(value.marks) ? {
55702
- marks: value.marks.filter((mark) => isRecord4(mark) && typeof mark.type === "string").map((mark) => ({
56017
+ marks: value.marks.filter((mark) => isRecord5(mark) && typeof mark.type === "string").map((mark) => ({
55703
56018
  type: mark.type,
55704
- ...isRecord4(mark.attrs) ? { attrs: mark.attrs } : {}
56019
+ ...isRecord5(mark.attrs) ? { attrs: mark.attrs } : {}
55705
56020
  }))
55706
56021
  } : {}
55707
56022
  };