@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) : [];
29812
30066
  }
29813
- return Object.values(services).map(normalizeService);
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;
30117
+ }
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;
@@ -49016,6 +49255,17 @@ function normalizeLoaderParams(endpoint, params, context) {
49016
49255
  // ../blocks/src/primitives/content/primitives.tsx
49017
49256
  var RichText2 = RichText;
49018
49257
 
49258
+ // ../api/src/apiEndpointTypes.ts
49259
+ function blockedDemoMutationPolicy(classification, publicMessage) {
49260
+ if (publicMessage.trim() === "") {
49261
+ throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
49262
+ }
49263
+ return {
49264
+ classification,
49265
+ publicMessage
49266
+ };
49267
+ }
49268
+
49019
49269
  // ../api/src/cache-tags.ts
49020
49270
  var TAG_TEMPLATES = {
49021
49271
  siteCollection: "riverbank:site",
@@ -49046,6 +49296,18 @@ var TAG_TEMPLATES = {
49046
49296
  };
49047
49297
 
49048
49298
  // ../api/src/endpoints.ts
49299
+ var DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy(
49300
+ "blocked-hidden",
49301
+ "This action is not available in demo sites."
49302
+ );
49303
+ var DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy(
49304
+ "blocked-disabled",
49305
+ "This setting is disabled in demo sites."
49306
+ );
49307
+ var DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy(
49308
+ "internal-only",
49309
+ "This internal operation is not available in demo sites."
49310
+ );
49049
49311
  var ENDPOINT_DEFINITIONS = {
49050
49312
  // AI endpoints - no cache due to dynamic nature
49051
49313
  aiContentUpdateChat: {
@@ -49162,7 +49424,8 @@ var ENDPOINT_DEFINITIONS = {
49162
49424
  path: "/sites/{siteId}/ai/generate",
49163
49425
  method: "POST",
49164
49426
  auth: "user",
49165
- responseKind: "json"
49427
+ responseKind: "json",
49428
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49166
49429
  },
49167
49430
  getOnboardingPreviewStatus: {
49168
49431
  path: "/public/sites/{siteId}/onboarding/preview-status",
@@ -49183,7 +49446,8 @@ var ENDPOINT_DEFINITIONS = {
49183
49446
  method: "POST",
49184
49447
  auth: "user",
49185
49448
  errors: [],
49186
- responseKind: "json"
49449
+ responseKind: "json",
49450
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED
49187
49451
  },
49188
49452
  goLiveSite: {
49189
49453
  path: "/sites/{siteId}/launch/go-live",
@@ -49252,20 +49516,23 @@ var ENDPOINT_DEFINITIONS = {
49252
49516
  path: "/sites/{siteId}/ai/site-wizard/goals",
49253
49517
  method: "POST",
49254
49518
  auth: "user",
49255
- responseKind: "json"
49519
+ responseKind: "json",
49520
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49256
49521
  },
49257
49522
  aiSiteWizardIntakeTriage: {
49258
49523
  path: "/sites/{siteId}/ai/site-wizard/intake-triage",
49259
49524
  method: "POST",
49260
49525
  auth: "user",
49261
- responseKind: "json"
49526
+ responseKind: "json",
49527
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49262
49528
  },
49263
49529
  aiSiteWizardTelemetry: {
49264
49530
  path: "/sites/{siteId}/ai/site-wizard/telemetry",
49265
49531
  method: "POST",
49266
49532
  auth: "user",
49267
49533
  errors: [],
49268
- responseKind: "json"
49534
+ responseKind: "json",
49535
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49269
49536
  },
49270
49537
  // Admin SEO
49271
49538
  listGscPropertiesAdmin: {
@@ -49472,7 +49739,7 @@ var ENDPOINT_DEFINITIONS = {
49472
49739
  responseKind: "json",
49473
49740
  errors: ["resource:not_found", "server:internal_error"]
49474
49741
  },
49475
- // Ops (event hosts/admins)
49742
+ // Ops (staff event operators/admins)
49476
49743
  opsListUpcomingEventOccurrences: {
49477
49744
  path: "/ops/sites/{siteId}/events",
49478
49745
  method: "GET",
@@ -49490,6 +49757,7 @@ var ENDPOINT_DEFINITIONS = {
49490
49757
  method: "POST",
49491
49758
  auth: "user",
49492
49759
  responseKind: "json",
49760
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49493
49761
  errors: [
49494
49762
  "validation:invalid_input",
49495
49763
  "auth:forbidden",
@@ -49502,6 +49770,7 @@ var ENDPOINT_DEFINITIONS = {
49502
49770
  method: "POST",
49503
49771
  auth: "user",
49504
49772
  responseKind: "json",
49773
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49505
49774
  errors: [
49506
49775
  "validation:invalid_input",
49507
49776
  "auth:forbidden",
@@ -49520,6 +49789,7 @@ var ENDPOINT_DEFINITIONS = {
49520
49789
  method: "POST",
49521
49790
  auth: "user",
49522
49791
  responseKind: "json",
49792
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49523
49793
  errors: [
49524
49794
  "validation:invalid_input",
49525
49795
  "auth:forbidden",
@@ -49553,6 +49823,7 @@ var ENDPOINT_DEFINITIONS = {
49553
49823
  method: "POST",
49554
49824
  auth: "user",
49555
49825
  responseKind: "json",
49826
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49556
49827
  errors: [
49557
49828
  "validation:invalid_input",
49558
49829
  "auth:forbidden",
@@ -49581,7 +49852,8 @@ var ENDPOINT_DEFINITIONS = {
49581
49852
  method: "POST",
49582
49853
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings],
49583
49854
  auth: "user",
49584
- responseKind: "json"
49855
+ responseKind: "json",
49856
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49585
49857
  },
49586
49858
  previewEmailTemplate: {
49587
49859
  path: "/sites/{siteId}/settings/emails/preview",
@@ -49632,14 +49904,16 @@ var ENDPOINT_DEFINITIONS = {
49632
49904
  method: "POST",
49633
49905
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49634
49906
  auth: "user",
49635
- responseKind: "json"
49907
+ responseKind: "json",
49908
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49636
49909
  },
49637
49910
  createNewsletterSubscribersImportUploadUrl: {
49638
49911
  path: "/sites/{siteId}/newsletter/subscribers/import-url",
49639
49912
  method: "POST",
49640
49913
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49641
49914
  auth: "user",
49642
- responseKind: "json"
49915
+ responseKind: "json",
49916
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49643
49917
  },
49644
49918
  exportNewsletterSubscribersCsv: {
49645
49919
  path: "/sites/{siteId}/newsletter/subscribers/export.csv",
@@ -49836,14 +50110,16 @@ var ENDPOINT_DEFINITIONS = {
49836
50110
  method: "POST",
49837
50111
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49838
50112
  auth: "user",
49839
- responseKind: "json"
50113
+ responseKind: "json",
50114
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49840
50115
  },
49841
50116
  testSendNewsletterCampaign: {
49842
50117
  path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/test-send",
49843
50118
  method: "POST",
49844
50119
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49845
50120
  auth: "user",
49846
- responseKind: "json"
50121
+ responseKind: "json",
50122
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49847
50123
  },
49848
50124
  listNewsletterSendJobs: {
49849
50125
  path: "/sites/{siteId}/newsletter/jobs",
@@ -49891,6 +50167,20 @@ var ENDPOINT_DEFINITIONS = {
49891
50167
  responseKind: "json",
49892
50168
  errors: ["validation:invalid_input", "billing:plan_limit_exceeded", "server:internal_error"]
49893
50169
  },
50170
+ createAppointmentResourceWithAccountAccess: {
50171
+ path: "/sites/{siteId}/bookings/resources/account-access",
50172
+ method: "POST",
50173
+ auth: "user",
50174
+ responseKind: "json",
50175
+ errors: [
50176
+ "validation:invalid_input",
50177
+ "auth:forbidden",
50178
+ "billing:plan_limit_exceeded",
50179
+ "resource:conflict",
50180
+ "resource:not_found",
50181
+ "server:internal_error"
50182
+ ]
50183
+ },
49894
50184
  getAppointmentResource: {
49895
50185
  path: "/sites/{siteId}/bookings/resources/{resourceId}",
49896
50186
  method: "GET",
@@ -50531,7 +50821,8 @@ var ENDPOINT_DEFINITIONS = {
50531
50821
  method: "DELETE",
50532
50822
  tags: ["site", "site-{siteId}"],
50533
50823
  auth: "user",
50534
- responseKind: "json"
50824
+ responseKind: "json",
50825
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
50535
50826
  },
50536
50827
  listSiteMembers: {
50537
50828
  path: "/sites/{siteId}/members",
@@ -50987,7 +51278,8 @@ var ENDPOINT_DEFINITIONS = {
50987
51278
  method: "POST",
50988
51279
  tags: ["site-{siteId}", "content-{siteId}-{type}"],
50989
51280
  auth: "user",
50990
- responseKind: "json"
51281
+ responseKind: "json",
51282
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
50991
51283
  },
50992
51284
  updateSiteGeneralSettings: {
50993
51285
  path: "/sites/{siteId}/settings/general",
@@ -53226,6 +53518,7 @@ var ENDPOINT_DEFINITIONS = {
53226
53518
  method: "POST",
53227
53519
  tags: ["site-{siteId}"],
53228
53520
  auth: "user",
53521
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
53229
53522
  errors: [
53230
53523
  "validation:invalid_input",
53231
53524
  "auth:forbidden",
@@ -53240,6 +53533,7 @@ var ENDPOINT_DEFINITIONS = {
53240
53533
  method: "POST",
53241
53534
  tags: ["site-{siteId}"],
53242
53535
  auth: "user",
53536
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
53243
53537
  errors: [
53244
53538
  "validation:invalid_input",
53245
53539
  "auth:forbidden",
@@ -53549,6 +53843,7 @@ var ENDPOINT_DEFINITIONS = {
53549
53843
  tags: ["site-{siteId}", "passes-{siteId}"],
53550
53844
  auth: "user",
53551
53845
  responseKind: "json",
53846
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53552
53847
  errors: ["validation:invalid_input", "server:internal_error"]
53553
53848
  },
53554
53849
  getBookingPass: {
@@ -53564,6 +53859,7 @@ var ENDPOINT_DEFINITIONS = {
53564
53859
  tags: ["site-{siteId}", "passes-{siteId}"],
53565
53860
  auth: "user",
53566
53861
  responseKind: "json",
53862
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53567
53863
  errors: [
53568
53864
  "validation:invalid_input",
53569
53865
  "resource:not_found",
@@ -53576,6 +53872,7 @@ var ENDPOINT_DEFINITIONS = {
53576
53872
  tags: ["site-{siteId}", "passes-{siteId}"],
53577
53873
  auth: "user",
53578
53874
  responseKind: "json",
53875
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53579
53876
  errors: [
53580
53877
  "validation:invalid_input",
53581
53878
  "resource:not_found",
@@ -53631,6 +53928,7 @@ var ENDPOINT_DEFINITIONS = {
53631
53928
  tags: ["site-{siteId}", "memberships-{siteId}"],
53632
53929
  auth: "user",
53633
53930
  responseKind: "json",
53931
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53634
53932
  errors: ["validation:invalid_input", "server:internal_error"]
53635
53933
  },
53636
53934
  getBookingMembership: {
@@ -53646,6 +53944,7 @@ var ENDPOINT_DEFINITIONS = {
53646
53944
  tags: ["site-{siteId}", "memberships-{siteId}"],
53647
53945
  auth: "user",
53648
53946
  responseKind: "json",
53947
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53649
53948
  errors: [
53650
53949
  "validation:invalid_input",
53651
53950
  "resource:not_found",
@@ -53658,6 +53957,7 @@ var ENDPOINT_DEFINITIONS = {
53658
53957
  tags: ["site-{siteId}", "memberships-{siteId}"],
53659
53958
  auth: "user",
53660
53959
  responseKind: "json",
53960
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53661
53961
  errors: [
53662
53962
  "validation:invalid_input",
53663
53963
  "resource:not_found",
@@ -53874,6 +54174,7 @@ var ENDPOINT_DEFINITIONS = {
53874
54174
  tags: ["site-{siteId}", "customers-{siteId}"],
53875
54175
  auth: "user",
53876
54176
  responseKind: "json",
54177
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53877
54178
  errors: [
53878
54179
  "validation:invalid_input",
53879
54180
  "auth:forbidden",
@@ -55251,8 +55552,7 @@ var dashboardNavVisibilityBaseSchema = z66.object({
55251
55552
  var dashboardNavVisibilityRolesSchema = z66.object({
55252
55553
  administrator: dashboardNavVisibilityBaseSchema.optional(),
55253
55554
  editor: dashboardNavVisibilityBaseSchema.optional(),
55254
- team_member: dashboardNavVisibilityBaseSchema.optional(),
55255
- event_host: dashboardNavVisibilityBaseSchema.optional()
55555
+ team_member: dashboardNavVisibilityBaseSchema.optional()
55256
55556
  }).strip().optional();
55257
55557
  var dashboardNavVisibilitySchema = dashboardNavVisibilityBaseSchema.extend({
55258
55558
  roles: dashboardNavVisibilityRolesSchema
@@ -55724,7 +56024,7 @@ function preset(id, verticalId, canonicalBehaviour, label, pluralLabel, descript
55724
56024
  }
55725
56025
 
55726
56026
  // ../api/src/utils/isRecord.ts
55727
- function isRecord4(value) {
56027
+ function isRecord5(value) {
55728
56028
  return typeof value === "object" && value !== null && !Array.isArray(value);
55729
56029
  }
55730
56030
 
@@ -55773,6 +56073,21 @@ var appointmentSetupServiceDraftSchema = z68.object({
55773
56073
  timezone: z68.string().trim().min(1).nullable(),
55774
56074
  payment: appointmentSetupPaymentDraftSchema,
55775
56075
  assignment: appointmentSetupServiceAssignmentDraftSchema
56076
+ }).superRefine((service, ctx) => {
56077
+ if (service.payment.priceType === "paid" && (service.priceAmount === null || service.priceAmount <= 0)) {
56078
+ ctx.addIssue({
56079
+ code: "custom",
56080
+ path: ["priceAmount"],
56081
+ message: "Paid appointment services need a positive price."
56082
+ });
56083
+ }
56084
+ if (service.payment.priceType === "free" && service.priceAmount !== null && service.priceAmount > 0) {
56085
+ ctx.addIssue({
56086
+ code: "custom",
56087
+ path: ["priceAmount"],
56088
+ message: "Free appointment services cannot carry a positive price."
56089
+ });
56090
+ }
55776
56091
  });
55777
56092
  var appointmentSetupPractitionerDraftSchema = z68.object({
55778
56093
  ref: appointmentSetupRefSchema,
@@ -55998,7 +56313,7 @@ function sanitizeMarks(marks) {
55998
56313
  if (mark.type === "bold" || mark.type === "strong" || mark.type === "italic" || mark.type === "em") {
55999
56314
  return [{ type: mark.type }];
56000
56315
  }
56001
- if (mark.type === "link" && isRecord4(mark.attrs) && typeof mark.attrs.href === "string") {
56316
+ if (mark.type === "link" && isRecord5(mark.attrs) && typeof mark.attrs.href === "string") {
56002
56317
  const attrs = { href: mark.attrs.href };
56003
56318
  if (typeof mark.attrs.target === "string" && mark.attrs.target.trim().length > 0) {
56004
56319
  attrs.target = mark.attrs.target;
@@ -56013,10 +56328,10 @@ function sanitizeMarks(marks) {
56013
56328
  return sanitized.length > 0 ? sanitized : void 0;
56014
56329
  }
56015
56330
  function unwrapRichTextValue(value) {
56016
- if (isRecord4(value) && isRecord4(value.doc)) {
56331
+ if (isRecord5(value) && isRecord5(value.doc)) {
56017
56332
  return unwrapRichTextValue(value.doc);
56018
56333
  }
56019
- if (isRecord4(value) && value.type === "doc") {
56334
+ if (isRecord5(value) && value.type === "doc") {
56020
56335
  return {
56021
56336
  type: "doc",
56022
56337
  content: Array.isArray(value.content) ? value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) : []
@@ -56025,7 +56340,7 @@ function unwrapRichTextValue(value) {
56025
56340
  return EMPTY_SITE_BANNER_BODY;
56026
56341
  }
56027
56342
  function isTipTapNodeLike(value) {
56028
- return isRecord4(value) && typeof value.type === "string";
56343
+ return isRecord5(value) && typeof value.type === "string";
56029
56344
  }
56030
56345
  function coerceTipTapNode(value) {
56031
56346
  return {
@@ -56033,9 +56348,9 @@ function coerceTipTapNode(value) {
56033
56348
  ...Array.isArray(value.content) ? { content: value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) } : {},
56034
56349
  ...typeof value.text === "string" ? { text: value.text } : {},
56035
56350
  ...Array.isArray(value.marks) ? {
56036
- marks: value.marks.filter((mark) => isRecord4(mark) && typeof mark.type === "string").map((mark) => ({
56351
+ marks: value.marks.filter((mark) => isRecord5(mark) && typeof mark.type === "string").map((mark) => ({
56037
56352
  type: mark.type,
56038
- ...isRecord4(mark.attrs) ? { attrs: mark.attrs } : {}
56353
+ ...isRecord5(mark.attrs) ? { attrs: mark.attrs } : {}
56039
56354
  }))
56040
56355
  } : {}
56041
56356
  };
@@ -56509,6 +56824,8 @@ function renderBlockOverride({
56509
56824
  themeConfig: props2.theme,
56510
56825
  data: resolvedData,
56511
56826
  siteId: props2.siteId,
56827
+ apiBaseUrl: props2.apiBaseUrl,
56828
+ portalToken: props2.portalToken ?? null,
56512
56829
  supabaseUrl: props2.supabaseUrl,
56513
56830
  imageResolveContext: runtime.imageResolveContext,
56514
56831
  blockId: props2.blockId ?? null,