@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
@@ -1992,6 +1992,144 @@ function resolveVariantKey(manifest, content) {
1992
1992
  return null;
1993
1993
  }
1994
1994
 
1995
+ // ../theme-core/src/palette/utils/colorConversion.ts
1996
+ var clamp01 = (x) => Math.max(0, Math.min(1, x));
1997
+ var mod = (a, n) => (a % n + n) % n;
1998
+ var deg = (x) => mod(x, 360);
1999
+ function hexToRgb(hex) {
2000
+ const h = hex.replace(/^#/, "");
2001
+ const m = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
2002
+ if (m.length !== 6) throw new Error("Bad hex");
2003
+ const int = parseInt(m, 16);
2004
+ return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
2005
+ }
2006
+ function rgbToHex(r2, g, b) {
2007
+ const to = (n) => Math.round(n).toString(16).padStart(2, "0");
2008
+ return `#${to(r2)}${to(g)}${to(b)}`;
2009
+ }
2010
+ function srgbToLinear(u) {
2011
+ const x = u / 255;
2012
+ return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
2013
+ }
2014
+ function linearToSrgb(x) {
2015
+ const y = x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
2016
+ return clamp01(y) * 255;
2017
+ }
2018
+ function rgbToHsl(r2, g, b) {
2019
+ const R = r2 / 255, G = g / 255, B = b / 255;
2020
+ const max = Math.max(R, G, B), min = Math.min(R, G, B);
2021
+ const d = max - min;
2022
+ let h = 0;
2023
+ if (d !== 0) {
2024
+ switch (max) {
2025
+ case R:
2026
+ h = (G - B) / d + (G < B ? 6 : 0);
2027
+ break;
2028
+ case G:
2029
+ h = (B - R) / d + 2;
2030
+ break;
2031
+ case B:
2032
+ h = (R - G) / d + 4;
2033
+ break;
2034
+ }
2035
+ h *= 60;
2036
+ }
2037
+ const l = (max + min) / 2;
2038
+ const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
2039
+ return { h, s, l };
2040
+ }
2041
+ function srgbToOklab(r2, g, b) {
2042
+ const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
2043
+ const l = 0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B;
2044
+ const m = 0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B;
2045
+ const s = 0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B;
2046
+ const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
2047
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
2048
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
2049
+ const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
2050
+ return { L, a, b: b2 };
2051
+ }
2052
+ function oklabToSrgb(L, a, b) {
2053
+ const l_ = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
2054
+ const m_ = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
2055
+ const s_ = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
2056
+ const R = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
2057
+ const G = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
2058
+ const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
2059
+ return { r: linearToSrgb(R), g: linearToSrgb(G), b: linearToSrgb(B) };
2060
+ }
2061
+ function oklabToOklch(L, a, b) {
2062
+ const C = Math.sqrt(a * a + b * b);
2063
+ const h = C < 1e-7 ? 0 : deg(Math.atan2(b, a) * 180 / Math.PI);
2064
+ return { L, C, h };
2065
+ }
2066
+ function oklchToOklab(L, C, h) {
2067
+ const hr = h * Math.PI / 180;
2068
+ const a = C * Math.cos(hr);
2069
+ const b = C * Math.sin(hr);
2070
+ return { L, a, b };
2071
+ }
2072
+ function inSRGB(r2, g, b) {
2073
+ return r2 >= 0 && r2 <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
2074
+ }
2075
+ function oklchToHexGamut(L, C, h) {
2076
+ let lo = 0, hi = C, best = 0;
2077
+ for (let i = 0; i < 18; i++) {
2078
+ const mid = (lo + hi) / 2;
2079
+ const { a: a2, b: b2 } = oklchToOklab(L, mid, h);
2080
+ const { r: r3, g: g2, b: bb2 } = oklabToSrgb(L, a2, b2);
2081
+ if (inSRGB(r3, g2, bb2)) {
2082
+ best = mid;
2083
+ lo = mid;
2084
+ } else {
2085
+ hi = mid;
2086
+ }
2087
+ }
2088
+ const { a, b } = oklchToOklab(L, best, h);
2089
+ const { r: r2, g, b: bb } = oklabToSrgb(L, a, b);
2090
+ return rgbToHex(r2, g, bb);
2091
+ }
2092
+ function featuresFromHex(hex) {
2093
+ const { r: r2, g, b } = hexToRgb(hex);
2094
+ const { h, s, l } = rgbToHsl(r2, g, b);
2095
+ const { L, a, b: b2 } = srgbToOklab(r2, g, b);
2096
+ const { L: okL, C: okC, h: okH } = oklabToOklch(L, a, b2);
2097
+ const max = Math.max(r2, g, b);
2098
+ const v = max / 255;
2099
+ const Y = 0.2126 * srgbToLinear(r2) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
2100
+ const chroma = s;
2101
+ return { r: r2, g, b, h, s, l, v, Y, chroma, okL, okC, okH, hex };
2102
+ }
2103
+
2104
+ // ../theme-core/src/palette/utils/contrast.ts
2105
+ function relativeLuminance(r2, g, b) {
2106
+ const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
2107
+ return 0.2126 * R + 0.7152 * G + 0.0722 * B;
2108
+ }
2109
+
2110
+ // ../theme-core/src/palette/utils/onColor.ts
2111
+ var BACKGROUND_ROLE_NAMES = /* @__PURE__ */ new Set([
2112
+ "primary",
2113
+ "secondary",
2114
+ "accent",
2115
+ "success",
2116
+ "warning",
2117
+ "destructive",
2118
+ "info",
2119
+ "background",
2120
+ "surface",
2121
+ "surfaceAlt",
2122
+ "muted",
2123
+ "neutral"
2124
+ ]);
2125
+ function onColorTokenName(backgroundToken) {
2126
+ return `on${backgroundToken.split("-").filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}`;
2127
+ }
2128
+ function isOnColorBackgroundCandidateToken(token) {
2129
+ const role = token.match(/^(.*?)(?:-\d{2,3})?$/)?.[1] ?? token;
2130
+ return BACKGROUND_ROLE_NAMES.has(role);
2131
+ }
2132
+
1995
2133
  // ../theme-core/src/site-styles/appearancePresetResolution.ts
1996
2134
  function assertValidOptionGroups(preset2) {
1997
2135
  preset2.optionGroups?.forEach((group) => {
@@ -7613,6 +7751,9 @@ var curatedSiteStyleIdValues = [
7613
7751
  "site-style:bright-community",
7614
7752
  "site-style:quiet-luxury",
7615
7753
  "site-style:practical-services",
7754
+ "site-style:quiet-practice",
7755
+ "site-style:personal-retreat-journal",
7756
+ "site-style:tactile-workshop",
7616
7757
  "site-style:modern-wellness",
7617
7758
  "site-style:bold-launch",
7618
7759
  "site-style:south-west-twerk-school"
@@ -7695,7 +7836,8 @@ function defineCuratedSiteStyle(input) {
7695
7836
  name: input.name,
7696
7837
  description: input.description,
7697
7838
  generationBrief: input.generationBrief,
7698
- selectionKeywords: input.selectionKeywords ?? [],
7839
+ selectionKeywordRules: input.selectionKeywordRules ?? [],
7840
+ siteCreatorSelection: input.siteCreatorSelection ?? { kind: "explicit_only" },
7699
7841
  template: {
7700
7842
  id: asDesignSystemTemplateId(`template:${input.id.replace("site-style:", "")}`),
7701
7843
  name: input.name,
@@ -7839,12 +7981,13 @@ var curatedSiteStyles = [
7839
7981
  name: "Quiet Luxury",
7840
7982
  description: "Minimal, confident, and refined for premium experiences and private services.",
7841
7983
  generationBrief: "Use fewer claims, more specificity, and restrained sensory detail. Favor elegant media and low repetition over dense panels.",
7842
- selectionKeywords: [
7843
- "luxury",
7844
- "premium",
7845
- "boutique",
7846
- "bespoke",
7847
- "exclusive"
7984
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 20 },
7985
+ selectionKeywordRules: [
7986
+ { kind: "word", value: "luxury" },
7987
+ { kind: "word", value: "premium" },
7988
+ { kind: "word", value: "boutique" },
7989
+ { kind: "word", value: "bespoke" },
7990
+ { kind: "word", value: "exclusive" }
7848
7991
  ],
7849
7992
  tokenRecipes: {
7850
7993
  palette: "high-contrast",
@@ -7873,13 +8016,14 @@ var curatedSiteStyles = [
7873
8016
  name: "Practical Services",
7874
8017
  description: "Efficient, plainspoken, and conversion-focused for trades and everyday services.",
7875
8018
  generationBrief: "Make services, location, trust signals, and contact paths obvious. Keep copy brief and avoid ornate visual treatments.",
7876
- selectionKeywords: [
7877
- "repair",
7878
- "plumb",
7879
- "electric",
7880
- "cleaning",
7881
- "landscap",
7882
- "contractor"
8019
+ siteCreatorSelection: { kind: "primary_goal_support" },
8020
+ selectionKeywordRules: [
8021
+ { kind: "word", value: "repair" },
8022
+ { kind: "substring", value: "plumb" },
8023
+ { kind: "substring", value: "electric" },
8024
+ { kind: "word", value: "cleaning" },
8025
+ { kind: "substring", value: "landscap" },
8026
+ { kind: "substring", value: "contractor" }
7883
8027
  ],
7884
8028
  tokenRecipes: {
7885
8029
  palette: "brand-led",
@@ -7930,18 +8074,134 @@ var curatedSiteStyles = [
7930
8074
  paletteChoice("warm-neutral-forest")
7931
8075
  ]
7932
8076
  }),
8077
+ defineCuratedSiteStyle({
8078
+ id: "site-style:quiet-practice",
8079
+ name: "Quiet Practice",
8080
+ description: "Grounded, calm, and practical for small appointment-first practices.",
8081
+ 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.",
8082
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 30 },
8083
+ selectionKeywordRules: [
8084
+ { kind: "substring", value: "massage" },
8085
+ { kind: "word", value: "bodywork" },
8086
+ { kind: "phrase", value: "appointment practice" },
8087
+ { kind: "phrase", value: "appointment-first" },
8088
+ { kind: "substring", value: "practitioner" },
8089
+ { kind: "substring", value: "therap" },
8090
+ { kind: "substring", value: "clinic" },
8091
+ { kind: "phrase", value: "wellness practice" }
8092
+ ],
8093
+ tokenRecipes: {
8094
+ palette: "soft-natural",
8095
+ contrast: "standard",
8096
+ radius: "soft",
8097
+ shadow: "subtle",
8098
+ typography: "clean-sans",
8099
+ spacing: "regular",
8100
+ motion: "subtle"
8101
+ },
8102
+ compositionBudget: quietBudget,
8103
+ recommendedHeaderLookIds: ["practical-utility", "clean-base", "centered-calm"],
8104
+ buttonPersonalityChoices: [
8105
+ buttonChoice("pebble"),
8106
+ buttonChoice("soft-pill"),
8107
+ buttonChoice("editorial-link")
8108
+ ],
8109
+ paletteVariantChoices: [
8110
+ paletteChoice("soft-natural-stone"),
8111
+ paletteChoice("soft-natural-sage"),
8112
+ paletteChoice("warm-neutral-clay")
8113
+ ]
8114
+ }),
8115
+ defineCuratedSiteStyle({
8116
+ id: "site-style:personal-retreat-journal",
8117
+ name: "Personal Retreat Journal",
8118
+ description: "Warm, story-led, and readable for solo practitioners with mixed offers.",
8119
+ 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.",
8120
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 40 },
8121
+ selectionKeywordRules: [
8122
+ { kind: "substring", value: "retreat" },
8123
+ { kind: "phrase", value: "solo practitioner" },
8124
+ { kind: "phrase", value: "personal brand" },
8125
+ { kind: "substring", value: "teacher" },
8126
+ { kind: "substring", value: "coach" },
8127
+ { kind: "phrase", value: "retreat resources" },
8128
+ { kind: "substring", value: "journal" }
8129
+ ],
8130
+ tokenRecipes: {
8131
+ palette: "warm-neutral",
8132
+ contrast: "standard",
8133
+ radius: "soft",
8134
+ shadow: "subtle",
8135
+ typography: "serif-editorial",
8136
+ spacing: "airy",
8137
+ motion: "subtle"
8138
+ },
8139
+ compositionBudget: balancedBudget,
8140
+ recommendedHeaderLookIds: ["editorial-line", "centered-calm", "minimal-transparent"],
8141
+ buttonPersonalityChoices: [
8142
+ buttonChoice("editorial-link"),
8143
+ buttonChoice("soft-pill"),
8144
+ buttonChoice("brushed-wash")
8145
+ ],
8146
+ paletteVariantChoices: [
8147
+ paletteChoice("warm-neutral-forest"),
8148
+ paletteChoice("warm-neutral-clay"),
8149
+ paletteChoice("soft-natural-stone")
8150
+ ]
8151
+ }),
8152
+ defineCuratedSiteStyle({
8153
+ id: "site-style:tactile-workshop",
8154
+ name: "Tactile Workshop",
8155
+ description: "Bright, hands-on, and image-led for maker studios, workshops, and creative classes.",
8156
+ 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.",
8157
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 50 },
8158
+ selectionKeywordRules: [
8159
+ { kind: "substring", value: "ceramic" },
8160
+ { kind: "word", value: "pottery" },
8161
+ { kind: "phrase", value: "maker studio" },
8162
+ { kind: "phrase", value: "craft class" },
8163
+ { kind: "phrase", value: "craft workshop" },
8164
+ { kind: "word", value: "clay" },
8165
+ { kind: "word", value: "kiln" }
8166
+ ],
8167
+ tokenRecipes: {
8168
+ palette: "brand-led",
8169
+ contrast: "standard",
8170
+ radius: "soft",
8171
+ shadow: "subtle",
8172
+ typography: "friendly-sans",
8173
+ spacing: "regular",
8174
+ motion: "subtle"
8175
+ },
8176
+ compositionBudget: balancedBudget,
8177
+ recommendedHeaderLookIds: ["brand-solid", "practical-utility", "clean-base"],
8178
+ recommendedFooterLookIds: ["site-footer-brand-two-band", "footer-muted-grounding"],
8179
+ buttonPersonalityChoices: [
8180
+ buttonChoice("pebble"),
8181
+ buttonChoice("confident-chip"),
8182
+ buttonChoice("ink-stamp"),
8183
+ buttonChoice("editorial-link")
8184
+ ],
8185
+ paletteVariantChoices: [
8186
+ paletteChoice("brand-led-warm"),
8187
+ paletteChoice("brand-led-cool"),
8188
+ paletteChoice("soft-natural-watercolor"),
8189
+ paletteChoice("warm-neutral-clay")
8190
+ ]
8191
+ }),
7933
8192
  defineCuratedSiteStyle({
7934
8193
  id: "site-style:bold-launch",
7935
8194
  name: "Bold Launch",
7936
8195
  description: "High-energy and punchy for launches, campaigns, and creative offers.",
7937
8196
  generationBrief: "Use crisp positioning, bold hero structure, strong calls to action, and confident visual rhythm. Keep it precise, not shouty.",
7938
- selectionKeywords: [
7939
- "launch",
7940
- "campaign",
7941
- "preorder",
7942
- "pre-order",
7943
- "waitlist",
7944
- "drop"
8197
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 10 },
8198
+ selectionKeywordRules: [
8199
+ { kind: "substring", value: "launch" },
8200
+ { kind: "substring", value: "campaign" },
8201
+ { kind: "word", value: "preorder" },
8202
+ { kind: "phrase", value: "pre-order" },
8203
+ { kind: "substring", value: "waitlist" },
8204
+ { kind: "word", value: "drop" }
7945
8205
  ],
7946
8206
  tokenRecipes: {
7947
8207
  palette: "high-contrast",
@@ -7972,15 +8232,6 @@ var curatedSiteStyles = [
7972
8232
  name: "South West Twerk School",
7973
8233
  description: "Energetic, editorial, and high-contrast for a branded dance school presence.",
7974
8234
  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.",
7975
- selectionKeywords: [
7976
- "dance",
7977
- "classes",
7978
- "workshop",
7979
- "school",
7980
- "movement",
7981
- "performance",
7982
- "community"
7983
- ],
7984
8235
  tokenRecipes: {
7985
8236
  palette: "brand-led",
7986
8237
  contrast: "maximum",
@@ -8223,6 +8474,148 @@ var modernMinimalTheme = {
8223
8474
  }
8224
8475
  };
8225
8476
 
8477
+ // ../theme-core/src/palette/generateShades.ts
8478
+ function generateShades(hexColor, name) {
8479
+ const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
8480
+ const base = featuresFromHex(hexColor);
8481
+ const hue = base.okH;
8482
+ const baseChroma = base.okC;
8483
+ const toneMap = {
8484
+ 50: 0.975,
8485
+ 100: 0.945,
8486
+ 200: 0.89,
8487
+ 300: 0.82,
8488
+ 400: 0.74,
8489
+ 500: 0.66,
8490
+ 600: 0.58,
8491
+ 700: 0.49,
8492
+ 800: 0.4,
8493
+ 900: 0.28,
8494
+ 950: 0.16
8495
+ };
8496
+ const shadeDefs = shadeSteps.map((step, idx) => {
8497
+ const t = idx / (shadeSteps.length - 1);
8498
+ const L = toneMap[step];
8499
+ const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t);
8500
+ const C = baseChroma * chromaFactor;
8501
+ return {
8502
+ name: `${name}-${step}`,
8503
+ hex: oklchToHexGamut(L, C, hue)
8504
+ };
8505
+ });
8506
+ shadeDefs.push({ name, hex: hexColor });
8507
+ return shadeDefs;
8508
+ }
8509
+
8510
+ // ../theme-core/src/palette/neutralScale.ts
8511
+ function generateNeutralScale({
8512
+ background,
8513
+ steps = 11,
8514
+ warm = false
8515
+ }) {
8516
+ const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
8517
+ const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
8518
+ const count = Math.min(steps, shadeNames.length);
8519
+ const scale = [];
8520
+ for (let i = 0; i < count; i++) {
8521
+ const t = i / (count - 1);
8522
+ const tone = isDark ? mix(0.06, 0.92, t) : mix(0.98, 0.1, t);
8523
+ const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
8524
+ const name = `neutral-${shadeNames[i]}`;
8525
+ scale.push({ name, hex });
8526
+ }
8527
+ return scale;
8528
+ }
8529
+ function mix(a, b, t) {
8530
+ return a + (b - a) * Math.max(0, Math.min(1, t));
8531
+ }
8532
+
8533
+ // ../theme-core/src/palette/utils/textColor.ts
8534
+ function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
8535
+ const { r: r2, g, b } = parseColorToRgb(background);
8536
+ const luminance = relativeLuminance(r2, g, b);
8537
+ const blackContrast = (luminance + 0.05) / 0.05;
8538
+ const whiteContrast = 1.05 / (luminance + 0.05);
8539
+ if (blackContrast >= minContrast && whiteContrast < minContrast) {
8540
+ return "#000000";
8541
+ }
8542
+ if (whiteContrast >= minContrast && blackContrast < minContrast) {
8543
+ return "#FFFFFF";
8544
+ }
8545
+ return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
8546
+ }
8547
+ function getTextColorForBackground(background) {
8548
+ return pickBlackOrWhiteTextColor(background);
8549
+ }
8550
+ function parseColorToRgb(input) {
8551
+ const trimmed = input.trim();
8552
+ if (trimmed.startsWith("#")) {
8553
+ return hexToRgb(trimmed);
8554
+ }
8555
+ const rgbMatch = trimmed.match(
8556
+ /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
8557
+ );
8558
+ if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
8559
+ return {
8560
+ r: clamp255(Number(rgbMatch[1])),
8561
+ g: clamp255(Number(rgbMatch[2])),
8562
+ b: clamp255(Number(rgbMatch[3]))
8563
+ };
8564
+ }
8565
+ throw new Error("Unsupported color format");
8566
+ }
8567
+ function clamp255(value) {
8568
+ if (Number.isNaN(value)) return 0;
8569
+ return Math.max(0, Math.min(255, value));
8570
+ }
8571
+
8572
+ // ../theme-core/src/palette/expandPalette.ts
8573
+ function colorsToMap(palette) {
8574
+ const map = {};
8575
+ for (const c of palette.colors) {
8576
+ map[c.name] = c.hex;
8577
+ }
8578
+ return map;
8579
+ }
8580
+ function isBackgroundDark(hex) {
8581
+ try {
8582
+ return featuresFromHex(hex).Y < 0.5;
8583
+ } catch {
8584
+ return false;
8585
+ }
8586
+ }
8587
+ function expandPalette(palette) {
8588
+ const base = colorsToMap(palette);
8589
+ const expanded = { ...base };
8590
+ const background = base.background || base.surface || "#ffffff";
8591
+ const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
8592
+ neutral2.forEach((n) => {
8593
+ expanded[n.name] = n.hex;
8594
+ });
8595
+ for (const [name, hex] of Object.entries(base)) {
8596
+ if (hex) {
8597
+ const shades = generateShades(hex, name);
8598
+ shades.forEach((shade) => {
8599
+ expanded[shade.name] = shade.hex;
8600
+ });
8601
+ }
8602
+ }
8603
+ if (base.text) expanded.body = base.text;
8604
+ if (base.danger && !base.destructive) {
8605
+ expanded.destructive = base.danger;
8606
+ }
8607
+ const isDark = base.background ? isBackgroundDark(base.background) : false;
8608
+ const isDarkMode = palette.meta?.mode === "dark" || isDark;
8609
+ expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
8610
+ for (const [token, hex] of Object.entries({ ...expanded })) {
8611
+ if (!hex || !isOnColorBackgroundCandidateToken(token)) continue;
8612
+ const onToken = onColorTokenName(token);
8613
+ if (expanded[onToken]) continue;
8614
+ expanded[onToken] = getTextColorForBackground(hex);
8615
+ }
8616
+ return expanded;
8617
+ }
8618
+
8226
8619
  // ../theme-core/src/site-styles/designState.ts
8227
8620
  import { z as z24 } from "zod";
8228
8621
 
@@ -8391,25 +8784,19 @@ var defaultDesignRuntimeRules = defineDesignRuntimeRules({
8391
8784
  "muted-band": {
8392
8785
  background: {
8393
8786
  type: "color",
8394
- color: "muted",
8395
- textColor: "text",
8396
- headingColor: "text"
8787
+ color: "muted"
8397
8788
  }
8398
8789
  },
8399
8790
  "accent-band": {
8400
8791
  background: {
8401
8792
  type: "color",
8402
- color: "primary",
8403
- textColor: "primaryForeground",
8404
- headingColor: "primaryForeground"
8793
+ color: "primary"
8405
8794
  }
8406
8795
  },
8407
8796
  "brand-depth-band": {
8408
8797
  background: {
8409
8798
  type: "color",
8410
- color: "primary-800",
8411
- textColor: "primaryForeground",
8412
- headingColor: "primaryForeground"
8799
+ color: "primary-800"
8413
8800
  }
8414
8801
  },
8415
8802
  "hero-image": {
@@ -14631,6 +15018,16 @@ var jsonArrayTransform = {
14631
15018
  return "";
14632
15019
  }
14633
15020
  };
15021
+ var csvTransform = {
15022
+ id: "value.csv",
15023
+ kind: "formatter",
15024
+ summary: "Normalize a string or array of strings into a comma-separated list",
15025
+ run: (value) => {
15026
+ const rawValues = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
15027
+ const normalized = rawValues.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
15028
+ return normalized.length > 0 ? Array.from(new Set(normalized)).join(",") : "";
15029
+ }
15030
+ };
14634
15031
  var marqueeLoopOptionsSchema = z33.object({
14635
15032
  minItems: z33.number().int().min(1).default(10)
14636
15033
  });
@@ -14656,6 +15053,7 @@ var formattingTransforms = [
14656
15053
  dateFormatShort,
14657
15054
  arrayLengthTransform,
14658
15055
  jsonArrayTransform,
15056
+ csvTransform,
14659
15057
  marqueeLoopTransform
14660
15058
  ];
14661
15059
 
@@ -15139,117 +15537,6 @@ var uiTransforms = [
15139
15537
 
15140
15538
  // ../blocks/src/system/transforms/registry/layout.ts
15141
15539
  import { z as z35 } from "zod";
15142
-
15143
- // ../theme-core/src/palette/utils/colorConversion.ts
15144
- var clamp01 = (x) => Math.max(0, Math.min(1, x));
15145
- var mod = (a, n) => (a % n + n) % n;
15146
- var deg = (x) => mod(x, 360);
15147
- function hexToRgb(hex) {
15148
- const h = hex.replace(/^#/, "");
15149
- const m = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
15150
- if (m.length !== 6) throw new Error("Bad hex");
15151
- const int = parseInt(m, 16);
15152
- return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
15153
- }
15154
- function rgbToHex(r2, g, b) {
15155
- const to = (n) => Math.round(n).toString(16).padStart(2, "0");
15156
- return `#${to(r2)}${to(g)}${to(b)}`;
15157
- }
15158
- function srgbToLinear(u) {
15159
- const x = u / 255;
15160
- return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
15161
- }
15162
- function linearToSrgb(x) {
15163
- const y = x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
15164
- return clamp01(y) * 255;
15165
- }
15166
- function rgbToHsl(r2, g, b) {
15167
- const R = r2 / 255, G = g / 255, B = b / 255;
15168
- const max = Math.max(R, G, B), min = Math.min(R, G, B);
15169
- const d = max - min;
15170
- let h = 0;
15171
- if (d !== 0) {
15172
- switch (max) {
15173
- case R:
15174
- h = (G - B) / d + (G < B ? 6 : 0);
15175
- break;
15176
- case G:
15177
- h = (B - R) / d + 2;
15178
- break;
15179
- case B:
15180
- h = (R - G) / d + 4;
15181
- break;
15182
- }
15183
- h *= 60;
15184
- }
15185
- const l = (max + min) / 2;
15186
- const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
15187
- return { h, s, l };
15188
- }
15189
- function srgbToOklab(r2, g, b) {
15190
- const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
15191
- const l = 0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B;
15192
- const m = 0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B;
15193
- const s = 0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B;
15194
- const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
15195
- const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
15196
- const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
15197
- const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
15198
- return { L, a, b: b2 };
15199
- }
15200
- function oklabToSrgb(L, a, b) {
15201
- const l_ = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
15202
- const m_ = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
15203
- const s_ = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
15204
- const R = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
15205
- const G = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
15206
- const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
15207
- return { r: linearToSrgb(R), g: linearToSrgb(G), b: linearToSrgb(B) };
15208
- }
15209
- function oklabToOklch(L, a, b) {
15210
- const C = Math.sqrt(a * a + b * b);
15211
- const h = C < 1e-7 ? 0 : deg(Math.atan2(b, a) * 180 / Math.PI);
15212
- return { L, C, h };
15213
- }
15214
- function oklchToOklab(L, C, h) {
15215
- const hr = h * Math.PI / 180;
15216
- const a = C * Math.cos(hr);
15217
- const b = C * Math.sin(hr);
15218
- return { L, a, b };
15219
- }
15220
- function inSRGB(r2, g, b) {
15221
- return r2 >= 0 && r2 <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
15222
- }
15223
- function oklchToHexGamut(L, C, h) {
15224
- let lo = 0, hi = C, best = 0;
15225
- for (let i = 0; i < 18; i++) {
15226
- const mid = (lo + hi) / 2;
15227
- const { a: a2, b: b2 } = oklchToOklab(L, mid, h);
15228
- const { r: r3, g: g2, b: bb2 } = oklabToSrgb(L, a2, b2);
15229
- if (inSRGB(r3, g2, bb2)) {
15230
- best = mid;
15231
- lo = mid;
15232
- } else {
15233
- hi = mid;
15234
- }
15235
- }
15236
- const { a, b } = oklchToOklab(L, best, h);
15237
- const { r: r2, g, b: bb } = oklabToSrgb(L, a, b);
15238
- return rgbToHex(r2, g, bb);
15239
- }
15240
- function featuresFromHex(hex) {
15241
- const { r: r2, g, b } = hexToRgb(hex);
15242
- const { h, s, l } = rgbToHsl(r2, g, b);
15243
- const { L, a, b: b2 } = srgbToOklab(r2, g, b);
15244
- const { L: okL, C: okC, h: okH } = oklabToOklch(L, a, b2);
15245
- const max = Math.max(r2, g, b);
15246
- const v = max / 255;
15247
- const Y = 0.2126 * srgbToLinear(r2) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
15248
- const chroma = s;
15249
- return { r: r2, g, b, h, s, l, v, Y, chroma, okL, okC, okH, hex };
15250
- }
15251
-
15252
- // ../blocks/src/system/transforms/registry/layout.ts
15253
15540
  var joinClasses4 = (parts) => parts.filter(
15254
15541
  (part) => typeof part === "string" && part.trim().length > 0
15255
15542
  ).join(" ").replace(/\s+/g, " ").trim();
@@ -20198,51 +20485,6 @@ function resolveEventCta(event, buttonText) {
20198
20485
  return { label, href: event.path, hidden: false };
20199
20486
  }
20200
20487
 
20201
- // ../theme-core/src/palette/utils/contrast.ts
20202
- function relativeLuminance(r2, g, b) {
20203
- const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
20204
- return 0.2126 * R + 0.7152 * G + 0.0722 * B;
20205
- }
20206
-
20207
- // ../theme-core/src/palette/utils/textColor.ts
20208
- function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
20209
- const { r: r2, g, b } = parseColorToRgb(background);
20210
- const luminance = relativeLuminance(r2, g, b);
20211
- const blackContrast = (luminance + 0.05) / 0.05;
20212
- const whiteContrast = 1.05 / (luminance + 0.05);
20213
- if (blackContrast >= minContrast && whiteContrast < minContrast) {
20214
- return "#000000";
20215
- }
20216
- if (whiteContrast >= minContrast && blackContrast < minContrast) {
20217
- return "#FFFFFF";
20218
- }
20219
- return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
20220
- }
20221
- function getTextColorForBackground(background) {
20222
- return pickBlackOrWhiteTextColor(background);
20223
- }
20224
- function parseColorToRgb(input) {
20225
- const trimmed = input.trim();
20226
- if (trimmed.startsWith("#")) {
20227
- return hexToRgb(trimmed);
20228
- }
20229
- const rgbMatch = trimmed.match(
20230
- /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
20231
- );
20232
- if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
20233
- return {
20234
- r: clamp255(Number(rgbMatch[1])),
20235
- g: clamp255(Number(rgbMatch[2])),
20236
- b: clamp255(Number(rgbMatch[3]))
20237
- };
20238
- }
20239
- throw new Error("Unsupported color format");
20240
- }
20241
- function clamp255(value) {
20242
- if (Number.isNaN(value)) return 0;
20243
- return Math.max(0, Math.min(255, value));
20244
- }
20245
-
20246
20488
  // ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
20247
20489
  function r(e) {
20248
20490
  var t, f, n = "";
@@ -22169,7 +22411,12 @@ var eventListingBlockDefinition = {
22169
22411
  detailLevel: "listing",
22170
22412
  kind: { $bind: { from: "content.kind" } },
22171
22413
  eventSurface: { $bind: { from: "content.eventSurface" } },
22172
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
22414
+ eventPresets: {
22415
+ $bind: {
22416
+ from: "content.filterEventPresets",
22417
+ transforms: [{ id: "value.csv" }]
22418
+ }
22419
+ },
22173
22420
  scheduleScope: { $bind: { from: "content.scheduleScope" } }
22174
22421
  },
22175
22422
  mode: "server"
@@ -22954,7 +23201,12 @@ var eventCalendarBlockDefinition = {
22954
23201
  // Pass filter params if configured
22955
23202
  kind: { $bind: { from: "content.kind" } },
22956
23203
  eventSurface: { $bind: { from: "content.eventSurface" } },
22957
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
23204
+ eventPresets: {
23205
+ $bind: {
23206
+ from: "content.filterEventPresets",
23207
+ transforms: [{ id: "value.csv" }]
23208
+ }
23209
+ },
22958
23210
  scheduleScope: { $bind: { from: "content.scheduleScope" } },
22959
23211
  categoryIds: { $bind: { from: "content.filterCategoryIds" } },
22960
23212
  staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
@@ -29774,16 +30026,18 @@ function toTrimmedString(value) {
29774
30026
  return trimmed ? trimmed : void 0;
29775
30027
  }
29776
30028
  function normalizeBookingFormConfig(form2) {
29777
- if (!form2) return null;
30029
+ if (!isRecord4(form2)) return null;
30030
+ const id = readNonEmptyString(form2.id);
30031
+ const name = readNonEmptyString(form2.name);
30032
+ if (!id || !name) return null;
30033
+ const schemaSource = isRecord4(form2.schema) ? form2.schema : isRecord4(form2.schemaJson) ? form2.schemaJson : null;
30034
+ const settingsSource = isRecord4(form2.settings) ? form2.settings : isRecord4(form2.settingsJson) ? form2.settingsJson : null;
29778
30035
  return {
29779
- id: form2.id,
29780
- name: form2.name,
29781
- slug: "",
29782
- settings: form2.settingsJson,
29783
- schema: form2.schemaJson ? {
29784
- version: form2.schemaJson.version,
29785
- fields: form2.schemaJson.fields ?? []
29786
- } : void 0
30036
+ id,
30037
+ name,
30038
+ slug: typeof form2.slug === "string" ? form2.slug : "",
30039
+ settings: normalizeBookingSettings(settingsSource),
30040
+ schema: normalizeBookingSchema(schemaSource)
29787
30041
  };
29788
30042
  }
29789
30043
  function normalizeBookingServices(services) {
@@ -29799,12 +30053,106 @@ function normalizeBookingServices(services) {
29799
30053
  return [];
29800
30054
  }
29801
30055
  if (Array.isArray(services)) {
29802
- return services.map(normalizeService);
30056
+ return services.filter(isBookingFormService).map(normalizeService);
29803
30057
  }
29804
- if ("services" in services) {
29805
- return Array.isArray(services.services) ? services.services.map(normalizeService) : [];
30058
+ if (isRecord4(services) && "services" in services) {
30059
+ return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
29806
30060
  }
29807
- return Object.values(services).map(normalizeService);
30061
+ return isRecord4(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
30062
+ }
30063
+ function normalizeBookingSchema(value) {
30064
+ if (!value) return void 0;
30065
+ const rawFields = Array.isArray(value.fields) ? value.fields : [];
30066
+ const fields3 = rawFields.map(readBookingFormField).filter((field) => field !== null);
30067
+ return {
30068
+ version: typeof value.version === "string" ? value.version : void 0,
30069
+ fields: fields3
30070
+ };
30071
+ }
30072
+ function readBookingFormField(value) {
30073
+ if (!isRecord4(value)) return null;
30074
+ const id = readNonEmptyString(value.id);
30075
+ const label = readNonEmptyString(value.label);
30076
+ const type = readBookingFieldType(value.type);
30077
+ if (!id || !label || !type) return null;
30078
+ return {
30079
+ id,
30080
+ label,
30081
+ type,
30082
+ required: typeof value.required === "boolean" ? value.required : void 0,
30083
+ placeholder: readOptionalString(value.placeholder),
30084
+ helpText: readOptionalString(value.helpText),
30085
+ options: readBookingFieldOptions(value.options),
30086
+ multiple: typeof value.multiple === "boolean" ? value.multiple : void 0,
30087
+ minLength: readOptionalNumber(value.minLength),
30088
+ maxLength: readOptionalNumber(value.maxLength),
30089
+ pattern: readOptionalString(value.pattern),
30090
+ min: readOptionalNumber(value.min),
30091
+ max: readOptionalNumber(value.max)
30092
+ };
30093
+ }
30094
+ function readBookingFieldType(value) {
30095
+ switch (value) {
30096
+ case "text":
30097
+ case "email":
30098
+ case "textarea":
30099
+ case "select":
30100
+ case "radio":
30101
+ case "checkbox":
30102
+ case "booking_requirement_consent":
30103
+ case "tel":
30104
+ case "url":
30105
+ case "number":
30106
+ case "date":
30107
+ case "time":
30108
+ return value;
30109
+ default:
30110
+ return null;
30111
+ }
30112
+ }
30113
+ function readBookingFieldOptions(value) {
30114
+ if (!Array.isArray(value)) return void 0;
30115
+ const options = value.map(readBookingFieldOption).filter((option) => option !== null);
30116
+ return options.length > 0 ? options : void 0;
30117
+ }
30118
+ function readBookingFieldOption(value) {
30119
+ if (!isRecord4(value)) return null;
30120
+ const optionValue = readNonEmptyString(value.value);
30121
+ const label = readNonEmptyString(value.label);
30122
+ return optionValue && label ? { value: optionValue, label } : null;
30123
+ }
30124
+ function normalizeBookingSettings(value) {
30125
+ if (!value || value.type !== "booking") return void 0;
30126
+ return {
30127
+ type: "booking",
30128
+ serviceId: readOptionalString(value.serviceId),
30129
+ serviceIds: readStringArray(value.serviceIds),
30130
+ resourceId: readOptionalString(value.resourceId),
30131
+ requiresApproval: typeof value.requiresApproval === "boolean" ? value.requiresApproval : void 0,
30132
+ successMessage: readOptionalString(value.successMessage)
30133
+ };
30134
+ }
30135
+ function isBookingFormService(value) {
30136
+ return isRecord4(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
30137
+ }
30138
+ function readNonEmptyString(value) {
30139
+ if (typeof value !== "string") return null;
30140
+ const trimmed = value.trim();
30141
+ return trimmed.length > 0 ? trimmed : null;
30142
+ }
30143
+ function readOptionalString(value) {
30144
+ return typeof value === "string" ? value : void 0;
30145
+ }
30146
+ function readOptionalNumber(value) {
30147
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
30148
+ }
30149
+ function readStringArray(value) {
30150
+ if (!Array.isArray(value)) return void 0;
30151
+ const strings = value.filter((item) => typeof item === "string");
30152
+ return strings.length > 0 ? strings : void 0;
30153
+ }
30154
+ function isRecord4(value) {
30155
+ return typeof value === "object" && value !== null;
29808
30156
  }
29809
30157
 
29810
30158
  // ../blocks/src/system/runtime/nodes/booking-form.interactive.ts
@@ -33416,119 +33764,6 @@ function renderBlock(manifest, content, options = {}) {
33416
33764
  );
33417
33765
  }
33418
33766
 
33419
- // ../theme-core/src/palette/generateShades.ts
33420
- function generateShades(hexColor, name) {
33421
- const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
33422
- const base = featuresFromHex(hexColor);
33423
- const hue = base.okH;
33424
- const baseChroma = base.okC;
33425
- const toneMap = {
33426
- 50: 0.975,
33427
- 100: 0.945,
33428
- 200: 0.89,
33429
- 300: 0.82,
33430
- 400: 0.74,
33431
- 500: 0.66,
33432
- 600: 0.58,
33433
- 700: 0.49,
33434
- 800: 0.4,
33435
- 900: 0.28,
33436
- 950: 0.16
33437
- };
33438
- const shadeDefs = shadeSteps.map((step, idx) => {
33439
- const t = idx / (shadeSteps.length - 1);
33440
- const L = toneMap[step];
33441
- const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t);
33442
- const C = baseChroma * chromaFactor;
33443
- return {
33444
- name: `${name}-${step}`,
33445
- hex: oklchToHexGamut(L, C, hue)
33446
- };
33447
- });
33448
- shadeDefs.push({ name, hex: hexColor });
33449
- return shadeDefs;
33450
- }
33451
-
33452
- // ../theme-core/src/palette/neutralScale.ts
33453
- function generateNeutralScale({
33454
- background,
33455
- steps = 11,
33456
- warm = false
33457
- }) {
33458
- const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
33459
- const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
33460
- const count = Math.min(steps, shadeNames.length);
33461
- const scale = [];
33462
- for (let i = 0; i < count; i++) {
33463
- const t = i / (count - 1);
33464
- const tone = isDark ? mix(0.06, 0.92, t) : mix(0.98, 0.1, t);
33465
- const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
33466
- const name = `neutral-${shadeNames[i]}`;
33467
- scale.push({ name, hex });
33468
- }
33469
- return scale;
33470
- }
33471
- function mix(a, b, t) {
33472
- return a + (b - a) * Math.max(0, Math.min(1, t));
33473
- }
33474
-
33475
- // ../theme-core/src/palette/expandPalette.ts
33476
- function colorsToMap(palette) {
33477
- const map = {};
33478
- for (const c of palette.colors) {
33479
- map[c.name] = c.hex;
33480
- }
33481
- return map;
33482
- }
33483
- function isBackgroundDark(hex) {
33484
- try {
33485
- return featuresFromHex(hex).Y < 0.5;
33486
- } catch {
33487
- return false;
33488
- }
33489
- }
33490
- function expandPalette(palette) {
33491
- const base = colorsToMap(palette);
33492
- const expanded = { ...base };
33493
- const background = base.background || base.surface || "#ffffff";
33494
- const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
33495
- neutral2.forEach((n) => {
33496
- expanded[n.name] = n.hex;
33497
- });
33498
- for (const [name, hex] of Object.entries(base)) {
33499
- if (hex) {
33500
- const shades = generateShades(hex, name);
33501
- shades.forEach((shade) => {
33502
- expanded[shade.name] = shade.hex;
33503
- });
33504
- }
33505
- }
33506
- if (base.text) expanded.body = base.text;
33507
- if (base.danger && !base.destructive) {
33508
- expanded.destructive = base.danger;
33509
- }
33510
- const isDark = base.background ? isBackgroundDark(base.background) : false;
33511
- const isDarkMode = palette.meta?.mode === "dark" || isDark;
33512
- expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
33513
- const onRoles = [
33514
- { role: "primary", on: "onPrimary" },
33515
- { role: "secondary", on: "onSecondary" },
33516
- { role: "accent", on: "onAccent" },
33517
- { role: "success", on: "onSuccess" },
33518
- { role: "warning", on: "onWarning" },
33519
- { role: "destructive", on: "onDestructive" },
33520
- { role: "info", on: "onInfo" },
33521
- { role: "surface", on: "onSurface" }
33522
- ];
33523
- for (const { role, on } of onRoles) {
33524
- const bg = base[role];
33525
- if (!bg) continue;
33526
- if (expanded[on]) continue;
33527
- expanded[on] = getTextColorForBackground(bg);
33528
- }
33529
- return expanded;
33530
- }
33531
-
33532
33767
  // ../theme-core/src/runtime/fontFamily.ts
33533
33768
  var GENERIC_CSS_FAMILIES = [
33534
33769
  "serif",
@@ -37225,6 +37460,8 @@ var MemoBlockSection = React6.memo(
37225
37460
  themeConfig,
37226
37461
  data: void 0,
37227
37462
  siteId: dataContext?.siteId,
37463
+ apiBaseUrl: dataContext?.apiBaseUrl,
37464
+ portalToken: dataContext?.portalToken ?? null,
37228
37465
  supabaseUrl: dataContext?.supabaseUrl,
37229
37466
  imageResolveContext,
37230
37467
  blockId: block.id ?? null,
@@ -37339,6 +37576,8 @@ var MemoBlockSection = React6.memo(
37339
37576
  themeConfig,
37340
37577
  data: resolved,
37341
37578
  siteId: dataContext?.siteId,
37579
+ apiBaseUrl: dataContext?.apiBaseUrl,
37580
+ portalToken: dataContext?.portalToken ?? null,
37342
37581
  supabaseUrl: dataContext?.supabaseUrl,
37343
37582
  imageResolveContext,
37344
37583
  blockId: block.id ?? null,
@@ -43101,32 +43340,32 @@ var containerResponsiveThemeCss = `/*
43101
43340
  }
43102
43341
 
43103
43342
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-text--muted {
43104
- opacity: var(--ab-text-muted-opacity);
43343
+ opacity: var(--ab-text-muted-opacity, 0.6);
43105
43344
  }
43106
43345
 
43107
43346
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-text--faint {
43108
- opacity: var(--ab-text-faint-opacity);
43347
+ opacity: var(--ab-text-faint-opacity, 0.4);
43109
43348
  }
43110
43349
 
43111
43350
  /* Selection cards (service, resource, time slot) */
43112
43351
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card {
43113
43352
  position: relative;
43114
43353
  padding: 1rem;
43115
- border: 2px solid var(--ab-card-border);
43116
- border-radius: var(--rb-block-radius);
43354
+ border: 2px solid var(--ab-card-border, rgb(var(--tb-border, 226 232 240)));
43355
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43117
43356
  text-align: left;
43118
43357
  background: transparent;
43119
43358
  cursor: pointer;
43120
- transition: border-color var(--rb-block-transition) ease, background-color var(--rb-block-transition) ease;
43359
+ transition: border-color var(--rb-block-transition, 150ms) ease, background-color var(--rb-block-transition, 150ms) ease;
43121
43360
  }
43122
43361
 
43123
43362
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card:hover {
43124
- border-color: var(--ab-card-border-hover);
43363
+ border-color: var(--ab-card-border-hover, rgba(var(--tb-primary, 17 24 39), 0.5));
43125
43364
  }
43126
43365
 
43127
43366
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card--selected {
43128
- border-color: var(--ab-card-border-selected);
43129
- background-color: var(--ab-card-bg-selected);
43367
+ border-color: var(--ab-card-border-selected, rgb(var(--tb-primary, 17 24 39)));
43368
+ background-color: var(--ab-card-bg-selected, rgba(var(--tb-primary, 17 24 39), 0.05));
43130
43369
  }
43131
43370
 
43132
43371
  /* Checkmark indicator */
@@ -43135,7 +43374,7 @@ var containerResponsiveThemeCss = `/*
43135
43374
  width: 1.25rem;
43136
43375
  height: 1.25rem;
43137
43376
  border-radius: 50%;
43138
- background-color: var(--ab-check-bg);
43377
+ background-color: var(--ab-check-bg, rgb(var(--tb-primary, 17 24 39)));
43139
43378
  display: flex;
43140
43379
  align-items: center;
43141
43380
  justify-content: center;
@@ -43144,42 +43383,42 @@ var containerResponsiveThemeCss = `/*
43144
43383
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-check svg {
43145
43384
  width: 0.75rem;
43146
43385
  height: 0.75rem;
43147
- color: var(--ab-check-text);
43386
+ color: var(--ab-check-text, rgb(var(--tb-background, 255 255 255)));
43148
43387
  }
43149
43388
 
43150
43389
  /* Info box (service summary) */
43151
43390
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-info-box {
43152
43391
  padding: 1rem;
43153
- border: 1px solid var(--ab-card-border);
43154
- border-radius: var(--rb-block-radius);
43155
- background-color: var(--ab-muted-bg);
43392
+ border: 1px solid var(--ab-card-border, rgb(var(--tb-border, 226 232 240)));
43393
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43394
+ background-color: var(--ab-muted-bg, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
43156
43395
  }
43157
43396
 
43158
43397
  /* Alert states */
43159
43398
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert {
43160
43399
  padding: 0.75rem 1rem;
43161
- border-radius: var(--rb-block-radius);
43400
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43162
43401
  font-size: 0.875rem;
43163
43402
  }
43164
43403
 
43165
43404
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--success {
43166
- background-color: var(--ab-success-bg);
43167
- color: var(--ab-success-text);
43405
+ background-color: var(--ab-success-bg, rgba(var(--tb-success, 22 163 74), 0.1));
43406
+ color: var(--ab-success-text, rgb(var(--tb-success, 22 163 74)));
43168
43407
  }
43169
43408
 
43170
43409
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--error {
43171
- background-color: var(--ab-error-bg);
43172
- color: var(--ab-error-text);
43410
+ background-color: var(--ab-error-bg, rgba(var(--tb-destructive, 220 38 38), 0.1));
43411
+ color: var(--ab-error-text, rgb(var(--tb-destructive, 220 38 38)));
43173
43412
  }
43174
43413
 
43175
43414
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--warning {
43176
- background-color: var(--ab-warning-bg);
43177
- color: var(--ab-warning-text);
43415
+ background-color: var(--ab-warning-bg, rgba(var(--tb-warning, 245 158 11), 0.1));
43416
+ color: var(--ab-warning-text, rgb(var(--tb-warning, 245 158 11)));
43178
43417
  }
43179
43418
 
43180
43419
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--info {
43181
- background-color: var(--ab-info-bg);
43182
- color: var(--ab-info-text);
43420
+ background-color: var(--ab-info-bg, rgba(var(--tb-info, 14 165 233), 0.1));
43421
+ color: var(--ab-info-text, rgb(var(--tb-info, 14 165 233)));
43183
43422
  }
43184
43423
 
43185
43424
  /* Form elements */
@@ -43191,7 +43430,7 @@ var containerResponsiveThemeCss = `/*
43191
43430
  }
43192
43431
 
43193
43432
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-required {
43194
- color: var(--ab-error-text);
43433
+ color: var(--ab-error-text, rgb(var(--tb-destructive, 220 38 38)));
43195
43434
  margin-left: 0.125rem;
43196
43435
  }
43197
43436
 
@@ -43200,19 +43439,19 @@ var containerResponsiveThemeCss = `/*
43200
43439
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-textarea {
43201
43440
  width: 100%;
43202
43441
  padding: 0.5rem 0.75rem;
43203
- border: 1px solid var(--ab-input-border);
43204
- border-radius: var(--rb-block-radius);
43442
+ border: 1px solid var(--ab-input-border, rgb(var(--tb-border, 226 232 240)));
43443
+ border-radius: var(--ab-input-radius, var(--radius-control, var(--rb-block-radius, 1rem)));
43205
43444
  background: transparent;
43206
43445
  font-size: 0.875rem;
43207
- transition: border-color var(--rb-block-transition) ease, box-shadow var(--rb-block-transition) ease;
43446
+ transition: border-color var(--rb-block-transition, 150ms) ease, box-shadow var(--rb-block-transition, 150ms) ease;
43208
43447
  }
43209
43448
 
43210
43449
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-input:focus,
43211
43450
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-select:focus,
43212
43451
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-textarea:focus {
43213
43452
  outline: none;
43214
- border-color: var(--ab-card-border-selected);
43215
- box-shadow: 0 0 0 3px var(--ab-input-focus-ring);
43453
+ border-color: var(--ab-card-border-selected, rgb(var(--tb-primary, 17 24 39)));
43454
+ box-shadow: 0 0 0 3px var(--ab-input-focus-ring, rgba(var(--tb-primary, 17 24 39), 0.3));
43216
43455
  }
43217
43456
 
43218
43457
  /* Buttons */
@@ -43221,31 +43460,31 @@ var containerResponsiveThemeCss = `/*
43221
43460
  align-items: center;
43222
43461
  justify-content: center;
43223
43462
  padding: 0.5rem 1.5rem;
43224
- border-radius: var(--rb-block-radius);
43463
+ border-radius: var(--ab-button-radius, var(--rb-button-radius, var(--rb-block-radius, 1rem)));
43225
43464
  font-size: 0.875rem;
43226
43465
  font-weight: 500;
43227
43466
  cursor: pointer;
43228
- transition: background-color var(--rb-block-transition) ease, border-color var(--rb-block-transition) ease;
43467
+ transition: background-color var(--rb-block-transition, 150ms) ease, border-color var(--rb-block-transition, 150ms) ease;
43229
43468
  }
43230
43469
 
43231
43470
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--primary {
43232
43471
  flex: 1;
43233
- background-color: var(--ab-btn-primary-bg);
43234
- color: var(--ab-btn-primary-text);
43472
+ background-color: var(--ab-btn-primary-bg, rgb(var(--tb-primary, 17 24 39)));
43473
+ color: var(--ab-btn-primary-text, rgb(var(--tb-primaryForeground, 255 255 255)));
43235
43474
  border: none;
43236
43475
  }
43237
43476
 
43238
43477
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--primary:hover:not(:disabled) {
43239
- background-color: var(--ab-btn-primary-hover);
43478
+ background-color: var(--ab-btn-primary-hover, rgba(var(--tb-primary, 17 24 39), 0.9));
43240
43479
  }
43241
43480
 
43242
43481
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--secondary {
43243
43482
  background: transparent;
43244
- border: 1px solid var(--ab-btn-secondary-border);
43483
+ border: 1px solid var(--ab-btn-secondary-border, rgb(var(--tb-border, 226 232 240)));
43245
43484
  }
43246
43485
 
43247
43486
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--secondary:hover:not(:disabled) {
43248
- background-color: var(--ab-btn-secondary-hover);
43487
+ background-color: var(--ab-btn-secondary-hover, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
43249
43488
  }
43250
43489
 
43251
43490
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--link {
@@ -43275,8 +43514,8 @@ var containerResponsiveThemeCss = `/*
43275
43514
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-skeleton {
43276
43515
  height: 2.5rem;
43277
43516
  width: 100%;
43278
- background-color: var(--ab-muted-bg);
43279
- border-radius: var(--rb-block-radius);
43517
+ background-color: var(--ab-muted-bg, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
43518
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
43280
43519
  animation: ab-pulse 1.5s ease-in-out infinite;
43281
43520
  }
43282
43521
 
@@ -43305,7 +43544,7 @@ var containerResponsiveThemeCss = `/*
43305
43544
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-link {
43306
43545
  display: inline;
43307
43546
  margin-left: 0.5rem;
43308
- color: rgb(var(--tb-primary));
43547
+ color: rgb(var(--tb-primary, 17 24 39));
43309
43548
  background: none;
43310
43549
  border: none;
43311
43550
  padding: 0;
@@ -48993,6 +49232,17 @@ function normalizeLoaderParams(endpoint, params, context) {
48993
49232
  return out;
48994
49233
  }
48995
49234
 
49235
+ // ../api/src/apiEndpointTypes.ts
49236
+ function blockedDemoMutationPolicy(classification, publicMessage) {
49237
+ if (publicMessage.trim() === "") {
49238
+ throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
49239
+ }
49240
+ return {
49241
+ classification,
49242
+ publicMessage
49243
+ };
49244
+ }
49245
+
48996
49246
  // ../api/src/cache-tags.ts
48997
49247
  var TAG_TEMPLATES = {
48998
49248
  siteCollection: "riverbank:site",
@@ -49023,6 +49273,18 @@ var TAG_TEMPLATES = {
49023
49273
  };
49024
49274
 
49025
49275
  // ../api/src/endpoints.ts
49276
+ var DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy(
49277
+ "blocked-hidden",
49278
+ "This action is not available in demo sites."
49279
+ );
49280
+ var DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy(
49281
+ "blocked-disabled",
49282
+ "This setting is disabled in demo sites."
49283
+ );
49284
+ var DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy(
49285
+ "internal-only",
49286
+ "This internal operation is not available in demo sites."
49287
+ );
49026
49288
  var ENDPOINT_DEFINITIONS = {
49027
49289
  // AI endpoints - no cache due to dynamic nature
49028
49290
  aiContentUpdateChat: {
@@ -49139,7 +49401,8 @@ var ENDPOINT_DEFINITIONS = {
49139
49401
  path: "/sites/{siteId}/ai/generate",
49140
49402
  method: "POST",
49141
49403
  auth: "user",
49142
- responseKind: "json"
49404
+ responseKind: "json",
49405
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49143
49406
  },
49144
49407
  getOnboardingPreviewStatus: {
49145
49408
  path: "/public/sites/{siteId}/onboarding/preview-status",
@@ -49160,7 +49423,8 @@ var ENDPOINT_DEFINITIONS = {
49160
49423
  method: "POST",
49161
49424
  auth: "user",
49162
49425
  errors: [],
49163
- responseKind: "json"
49426
+ responseKind: "json",
49427
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED
49164
49428
  },
49165
49429
  goLiveSite: {
49166
49430
  path: "/sites/{siteId}/launch/go-live",
@@ -49229,20 +49493,23 @@ var ENDPOINT_DEFINITIONS = {
49229
49493
  path: "/sites/{siteId}/ai/site-wizard/goals",
49230
49494
  method: "POST",
49231
49495
  auth: "user",
49232
- responseKind: "json"
49496
+ responseKind: "json",
49497
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49233
49498
  },
49234
49499
  aiSiteWizardIntakeTriage: {
49235
49500
  path: "/sites/{siteId}/ai/site-wizard/intake-triage",
49236
49501
  method: "POST",
49237
49502
  auth: "user",
49238
- responseKind: "json"
49503
+ responseKind: "json",
49504
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49239
49505
  },
49240
49506
  aiSiteWizardTelemetry: {
49241
49507
  path: "/sites/{siteId}/ai/site-wizard/telemetry",
49242
49508
  method: "POST",
49243
49509
  auth: "user",
49244
49510
  errors: [],
49245
- responseKind: "json"
49511
+ responseKind: "json",
49512
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49246
49513
  },
49247
49514
  // Admin SEO
49248
49515
  listGscPropertiesAdmin: {
@@ -49449,7 +49716,7 @@ var ENDPOINT_DEFINITIONS = {
49449
49716
  responseKind: "json",
49450
49717
  errors: ["resource:not_found", "server:internal_error"]
49451
49718
  },
49452
- // Ops (event hosts/admins)
49719
+ // Ops (staff event operators/admins)
49453
49720
  opsListUpcomingEventOccurrences: {
49454
49721
  path: "/ops/sites/{siteId}/events",
49455
49722
  method: "GET",
@@ -49467,6 +49734,7 @@ var ENDPOINT_DEFINITIONS = {
49467
49734
  method: "POST",
49468
49735
  auth: "user",
49469
49736
  responseKind: "json",
49737
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49470
49738
  errors: [
49471
49739
  "validation:invalid_input",
49472
49740
  "auth:forbidden",
@@ -49479,6 +49747,7 @@ var ENDPOINT_DEFINITIONS = {
49479
49747
  method: "POST",
49480
49748
  auth: "user",
49481
49749
  responseKind: "json",
49750
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49482
49751
  errors: [
49483
49752
  "validation:invalid_input",
49484
49753
  "auth:forbidden",
@@ -49497,6 +49766,7 @@ var ENDPOINT_DEFINITIONS = {
49497
49766
  method: "POST",
49498
49767
  auth: "user",
49499
49768
  responseKind: "json",
49769
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49500
49770
  errors: [
49501
49771
  "validation:invalid_input",
49502
49772
  "auth:forbidden",
@@ -49530,6 +49800,7 @@ var ENDPOINT_DEFINITIONS = {
49530
49800
  method: "POST",
49531
49801
  auth: "user",
49532
49802
  responseKind: "json",
49803
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
49533
49804
  errors: [
49534
49805
  "validation:invalid_input",
49535
49806
  "auth:forbidden",
@@ -49558,7 +49829,8 @@ var ENDPOINT_DEFINITIONS = {
49558
49829
  method: "POST",
49559
49830
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings],
49560
49831
  auth: "user",
49561
- responseKind: "json"
49832
+ responseKind: "json",
49833
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49562
49834
  },
49563
49835
  previewEmailTemplate: {
49564
49836
  path: "/sites/{siteId}/settings/emails/preview",
@@ -49609,14 +49881,16 @@ var ENDPOINT_DEFINITIONS = {
49609
49881
  method: "POST",
49610
49882
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49611
49883
  auth: "user",
49612
- responseKind: "json"
49884
+ responseKind: "json",
49885
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49613
49886
  },
49614
49887
  createNewsletterSubscribersImportUploadUrl: {
49615
49888
  path: "/sites/{siteId}/newsletter/subscribers/import-url",
49616
49889
  method: "POST",
49617
49890
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49618
49891
  auth: "user",
49619
- responseKind: "json"
49892
+ responseKind: "json",
49893
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49620
49894
  },
49621
49895
  exportNewsletterSubscribersCsv: {
49622
49896
  path: "/sites/{siteId}/newsletter/subscribers/export.csv",
@@ -49813,14 +50087,16 @@ var ENDPOINT_DEFINITIONS = {
49813
50087
  method: "POST",
49814
50088
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49815
50089
  auth: "user",
49816
- responseKind: "json"
50090
+ responseKind: "json",
50091
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49817
50092
  },
49818
50093
  testSendNewsletterCampaign: {
49819
50094
  path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/test-send",
49820
50095
  method: "POST",
49821
50096
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
49822
50097
  auth: "user",
49823
- responseKind: "json"
50098
+ responseKind: "json",
50099
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
49824
50100
  },
49825
50101
  listNewsletterSendJobs: {
49826
50102
  path: "/sites/{siteId}/newsletter/jobs",
@@ -49868,6 +50144,20 @@ var ENDPOINT_DEFINITIONS = {
49868
50144
  responseKind: "json",
49869
50145
  errors: ["validation:invalid_input", "billing:plan_limit_exceeded", "server:internal_error"]
49870
50146
  },
50147
+ createAppointmentResourceWithAccountAccess: {
50148
+ path: "/sites/{siteId}/bookings/resources/account-access",
50149
+ method: "POST",
50150
+ auth: "user",
50151
+ responseKind: "json",
50152
+ errors: [
50153
+ "validation:invalid_input",
50154
+ "auth:forbidden",
50155
+ "billing:plan_limit_exceeded",
50156
+ "resource:conflict",
50157
+ "resource:not_found",
50158
+ "server:internal_error"
50159
+ ]
50160
+ },
49871
50161
  getAppointmentResource: {
49872
50162
  path: "/sites/{siteId}/bookings/resources/{resourceId}",
49873
50163
  method: "GET",
@@ -50508,7 +50798,8 @@ var ENDPOINT_DEFINITIONS = {
50508
50798
  method: "DELETE",
50509
50799
  tags: ["site", "site-{siteId}"],
50510
50800
  auth: "user",
50511
- responseKind: "json"
50801
+ responseKind: "json",
50802
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
50512
50803
  },
50513
50804
  listSiteMembers: {
50514
50805
  path: "/sites/{siteId}/members",
@@ -50964,7 +51255,8 @@ var ENDPOINT_DEFINITIONS = {
50964
51255
  method: "POST",
50965
51256
  tags: ["site-{siteId}", "content-{siteId}-{type}"],
50966
51257
  auth: "user",
50967
- responseKind: "json"
51258
+ responseKind: "json",
51259
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
50968
51260
  },
50969
51261
  updateSiteGeneralSettings: {
50970
51262
  path: "/sites/{siteId}/settings/general",
@@ -53203,6 +53495,7 @@ var ENDPOINT_DEFINITIONS = {
53203
53495
  method: "POST",
53204
53496
  tags: ["site-{siteId}"],
53205
53497
  auth: "user",
53498
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
53206
53499
  errors: [
53207
53500
  "validation:invalid_input",
53208
53501
  "auth:forbidden",
@@ -53217,6 +53510,7 @@ var ENDPOINT_DEFINITIONS = {
53217
53510
  method: "POST",
53218
53511
  tags: ["site-{siteId}"],
53219
53512
  auth: "user",
53513
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
53220
53514
  errors: [
53221
53515
  "validation:invalid_input",
53222
53516
  "auth:forbidden",
@@ -53526,6 +53820,7 @@ var ENDPOINT_DEFINITIONS = {
53526
53820
  tags: ["site-{siteId}", "passes-{siteId}"],
53527
53821
  auth: "user",
53528
53822
  responseKind: "json",
53823
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53529
53824
  errors: ["validation:invalid_input", "server:internal_error"]
53530
53825
  },
53531
53826
  getBookingPass: {
@@ -53541,6 +53836,7 @@ var ENDPOINT_DEFINITIONS = {
53541
53836
  tags: ["site-{siteId}", "passes-{siteId}"],
53542
53837
  auth: "user",
53543
53838
  responseKind: "json",
53839
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53544
53840
  errors: [
53545
53841
  "validation:invalid_input",
53546
53842
  "resource:not_found",
@@ -53553,6 +53849,7 @@ var ENDPOINT_DEFINITIONS = {
53553
53849
  tags: ["site-{siteId}", "passes-{siteId}"],
53554
53850
  auth: "user",
53555
53851
  responseKind: "json",
53852
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53556
53853
  errors: [
53557
53854
  "validation:invalid_input",
53558
53855
  "resource:not_found",
@@ -53608,6 +53905,7 @@ var ENDPOINT_DEFINITIONS = {
53608
53905
  tags: ["site-{siteId}", "memberships-{siteId}"],
53609
53906
  auth: "user",
53610
53907
  responseKind: "json",
53908
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53611
53909
  errors: ["validation:invalid_input", "server:internal_error"]
53612
53910
  },
53613
53911
  getBookingMembership: {
@@ -53623,6 +53921,7 @@ var ENDPOINT_DEFINITIONS = {
53623
53921
  tags: ["site-{siteId}", "memberships-{siteId}"],
53624
53922
  auth: "user",
53625
53923
  responseKind: "json",
53924
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53626
53925
  errors: [
53627
53926
  "validation:invalid_input",
53628
53927
  "resource:not_found",
@@ -53635,6 +53934,7 @@ var ENDPOINT_DEFINITIONS = {
53635
53934
  tags: ["site-{siteId}", "memberships-{siteId}"],
53636
53935
  auth: "user",
53637
53936
  responseKind: "json",
53937
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53638
53938
  errors: [
53639
53939
  "validation:invalid_input",
53640
53940
  "resource:not_found",
@@ -53851,6 +54151,7 @@ var ENDPOINT_DEFINITIONS = {
53851
54151
  tags: ["site-{siteId}", "customers-{siteId}"],
53852
54152
  auth: "user",
53853
54153
  responseKind: "json",
54154
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
53854
54155
  errors: [
53855
54156
  "validation:invalid_input",
53856
54157
  "auth:forbidden",
@@ -55228,8 +55529,7 @@ var dashboardNavVisibilityBaseSchema = z66.object({
55228
55529
  var dashboardNavVisibilityRolesSchema = z66.object({
55229
55530
  administrator: dashboardNavVisibilityBaseSchema.optional(),
55230
55531
  editor: dashboardNavVisibilityBaseSchema.optional(),
55231
- team_member: dashboardNavVisibilityBaseSchema.optional(),
55232
- event_host: dashboardNavVisibilityBaseSchema.optional()
55532
+ team_member: dashboardNavVisibilityBaseSchema.optional()
55233
55533
  }).strip().optional();
55234
55534
  var dashboardNavVisibilitySchema = dashboardNavVisibilityBaseSchema.extend({
55235
55535
  roles: dashboardNavVisibilityRolesSchema
@@ -55701,7 +56001,7 @@ function preset(id, verticalId, canonicalBehaviour, label, pluralLabel, descript
55701
56001
  }
55702
56002
 
55703
56003
  // ../api/src/utils/isRecord.ts
55704
- function isRecord4(value) {
56004
+ function isRecord5(value) {
55705
56005
  return typeof value === "object" && value !== null && !Array.isArray(value);
55706
56006
  }
55707
56007
 
@@ -55750,6 +56050,21 @@ var appointmentSetupServiceDraftSchema = z68.object({
55750
56050
  timezone: z68.string().trim().min(1).nullable(),
55751
56051
  payment: appointmentSetupPaymentDraftSchema,
55752
56052
  assignment: appointmentSetupServiceAssignmentDraftSchema
56053
+ }).superRefine((service, ctx) => {
56054
+ if (service.payment.priceType === "paid" && (service.priceAmount === null || service.priceAmount <= 0)) {
56055
+ ctx.addIssue({
56056
+ code: "custom",
56057
+ path: ["priceAmount"],
56058
+ message: "Paid appointment services need a positive price."
56059
+ });
56060
+ }
56061
+ if (service.payment.priceType === "free" && service.priceAmount !== null && service.priceAmount > 0) {
56062
+ ctx.addIssue({
56063
+ code: "custom",
56064
+ path: ["priceAmount"],
56065
+ message: "Free appointment services cannot carry a positive price."
56066
+ });
56067
+ }
55753
56068
  });
55754
56069
  var appointmentSetupPractitionerDraftSchema = z68.object({
55755
56070
  ref: appointmentSetupRefSchema,
@@ -55975,7 +56290,7 @@ function sanitizeMarks(marks) {
55975
56290
  if (mark.type === "bold" || mark.type === "strong" || mark.type === "italic" || mark.type === "em") {
55976
56291
  return [{ type: mark.type }];
55977
56292
  }
55978
- if (mark.type === "link" && isRecord4(mark.attrs) && typeof mark.attrs.href === "string") {
56293
+ if (mark.type === "link" && isRecord5(mark.attrs) && typeof mark.attrs.href === "string") {
55979
56294
  const attrs = { href: mark.attrs.href };
55980
56295
  if (typeof mark.attrs.target === "string" && mark.attrs.target.trim().length > 0) {
55981
56296
  attrs.target = mark.attrs.target;
@@ -55990,10 +56305,10 @@ function sanitizeMarks(marks) {
55990
56305
  return sanitized.length > 0 ? sanitized : void 0;
55991
56306
  }
55992
56307
  function unwrapRichTextValue(value) {
55993
- if (isRecord4(value) && isRecord4(value.doc)) {
56308
+ if (isRecord5(value) && isRecord5(value.doc)) {
55994
56309
  return unwrapRichTextValue(value.doc);
55995
56310
  }
55996
- if (isRecord4(value) && value.type === "doc") {
56311
+ if (isRecord5(value) && value.type === "doc") {
55997
56312
  return {
55998
56313
  type: "doc",
55999
56314
  content: Array.isArray(value.content) ? value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) : []
@@ -56002,7 +56317,7 @@ function unwrapRichTextValue(value) {
56002
56317
  return EMPTY_SITE_BANNER_BODY;
56003
56318
  }
56004
56319
  function isTipTapNodeLike(value) {
56005
- return isRecord4(value) && typeof value.type === "string";
56320
+ return isRecord5(value) && typeof value.type === "string";
56006
56321
  }
56007
56322
  function coerceTipTapNode(value) {
56008
56323
  return {
@@ -56010,9 +56325,9 @@ function coerceTipTapNode(value) {
56010
56325
  ...Array.isArray(value.content) ? { content: value.content.filter(isTipTapNodeLike).map(coerceTipTapNode) } : {},
56011
56326
  ...typeof value.text === "string" ? { text: value.text } : {},
56012
56327
  ...Array.isArray(value.marks) ? {
56013
- marks: value.marks.filter((mark) => isRecord4(mark) && typeof mark.type === "string").map((mark) => ({
56328
+ marks: value.marks.filter((mark) => isRecord5(mark) && typeof mark.type === "string").map((mark) => ({
56014
56329
  type: mark.type,
56015
- ...isRecord4(mark.attrs) ? { attrs: mark.attrs } : {}
56330
+ ...isRecord5(mark.attrs) ? { attrs: mark.attrs } : {}
56016
56331
  }))
56017
56332
  } : {}
56018
56333
  };
@@ -56479,6 +56794,8 @@ function renderBlockOverride({
56479
56794
  themeConfig: props2.theme,
56480
56795
  data: resolvedData,
56481
56796
  siteId: props2.siteId,
56797
+ apiBaseUrl: props2.apiBaseUrl,
56798
+ portalToken: props2.portalToken ?? null,
56482
56799
  supabaseUrl: props2.supabaseUrl,
56483
56800
  imageResolveContext: runtime.imageResolveContext,
56484
56801
  blockId: props2.blockId ?? null,