@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
@@ -31,6 +31,17 @@ function getPortalToken(cookieStore) {
31
31
  // src/next/catch-all.tsx
32
32
  import { BlocksIslandsHydrator } from "#sdk-rendering-client";
33
33
 
34
+ // ../api/src/apiEndpointTypes.ts
35
+ function blockedDemoMutationPolicy(classification, publicMessage) {
36
+ if (publicMessage.trim() === "") {
37
+ throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
38
+ }
39
+ return {
40
+ classification,
41
+ publicMessage
42
+ };
43
+ }
44
+
34
45
  // ../api/src/cache-tags.ts
35
46
  var TAG_TEMPLATES = {
36
47
  siteCollection: "riverbank:site",
@@ -61,6 +72,18 @@ var TAG_TEMPLATES = {
61
72
  };
62
73
 
63
74
  // ../api/src/endpoints.ts
75
+ var DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy(
76
+ "blocked-hidden",
77
+ "This action is not available in demo sites."
78
+ );
79
+ var DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy(
80
+ "blocked-disabled",
81
+ "This setting is disabled in demo sites."
82
+ );
83
+ var DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy(
84
+ "internal-only",
85
+ "This internal operation is not available in demo sites."
86
+ );
64
87
  var ENDPOINT_DEFINITIONS = {
65
88
  // AI endpoints - no cache due to dynamic nature
66
89
  aiContentUpdateChat: {
@@ -177,7 +200,8 @@ var ENDPOINT_DEFINITIONS = {
177
200
  path: "/sites/{siteId}/ai/generate",
178
201
  method: "POST",
179
202
  auth: "user",
180
- responseKind: "json"
203
+ responseKind: "json",
204
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
181
205
  },
182
206
  getOnboardingPreviewStatus: {
183
207
  path: "/public/sites/{siteId}/onboarding/preview-status",
@@ -198,7 +222,8 @@ var ENDPOINT_DEFINITIONS = {
198
222
  method: "POST",
199
223
  auth: "user",
200
224
  errors: [],
201
- responseKind: "json"
225
+ responseKind: "json",
226
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED
202
227
  },
203
228
  goLiveSite: {
204
229
  path: "/sites/{siteId}/launch/go-live",
@@ -267,20 +292,23 @@ var ENDPOINT_DEFINITIONS = {
267
292
  path: "/sites/{siteId}/ai/site-wizard/goals",
268
293
  method: "POST",
269
294
  auth: "user",
270
- responseKind: "json"
295
+ responseKind: "json",
296
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
271
297
  },
272
298
  aiSiteWizardIntakeTriage: {
273
299
  path: "/sites/{siteId}/ai/site-wizard/intake-triage",
274
300
  method: "POST",
275
301
  auth: "user",
276
- responseKind: "json"
302
+ responseKind: "json",
303
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
277
304
  },
278
305
  aiSiteWizardTelemetry: {
279
306
  path: "/sites/{siteId}/ai/site-wizard/telemetry",
280
307
  method: "POST",
281
308
  auth: "user",
282
309
  errors: [],
283
- responseKind: "json"
310
+ responseKind: "json",
311
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
284
312
  },
285
313
  // Admin SEO
286
314
  listGscPropertiesAdmin: {
@@ -487,7 +515,7 @@ var ENDPOINT_DEFINITIONS = {
487
515
  responseKind: "json",
488
516
  errors: ["resource:not_found", "server:internal_error"]
489
517
  },
490
- // Ops (event hosts/admins)
518
+ // Ops (staff event operators/admins)
491
519
  opsListUpcomingEventOccurrences: {
492
520
  path: "/ops/sites/{siteId}/events",
493
521
  method: "GET",
@@ -505,6 +533,7 @@ var ENDPOINT_DEFINITIONS = {
505
533
  method: "POST",
506
534
  auth: "user",
507
535
  responseKind: "json",
536
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
508
537
  errors: [
509
538
  "validation:invalid_input",
510
539
  "auth:forbidden",
@@ -517,6 +546,7 @@ var ENDPOINT_DEFINITIONS = {
517
546
  method: "POST",
518
547
  auth: "user",
519
548
  responseKind: "json",
549
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
520
550
  errors: [
521
551
  "validation:invalid_input",
522
552
  "auth:forbidden",
@@ -535,6 +565,7 @@ var ENDPOINT_DEFINITIONS = {
535
565
  method: "POST",
536
566
  auth: "user",
537
567
  responseKind: "json",
568
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
538
569
  errors: [
539
570
  "validation:invalid_input",
540
571
  "auth:forbidden",
@@ -568,6 +599,7 @@ var ENDPOINT_DEFINITIONS = {
568
599
  method: "POST",
569
600
  auth: "user",
570
601
  responseKind: "json",
602
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
571
603
  errors: [
572
604
  "validation:invalid_input",
573
605
  "auth:forbidden",
@@ -596,7 +628,8 @@ var ENDPOINT_DEFINITIONS = {
596
628
  method: "POST",
597
629
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings],
598
630
  auth: "user",
599
- responseKind: "json"
631
+ responseKind: "json",
632
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
600
633
  },
601
634
  previewEmailTemplate: {
602
635
  path: "/sites/{siteId}/settings/emails/preview",
@@ -647,14 +680,16 @@ var ENDPOINT_DEFINITIONS = {
647
680
  method: "POST",
648
681
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
649
682
  auth: "user",
650
- responseKind: "json"
683
+ responseKind: "json",
684
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
651
685
  },
652
686
  createNewsletterSubscribersImportUploadUrl: {
653
687
  path: "/sites/{siteId}/newsletter/subscribers/import-url",
654
688
  method: "POST",
655
689
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
656
690
  auth: "user",
657
- responseKind: "json"
691
+ responseKind: "json",
692
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
658
693
  },
659
694
  exportNewsletterSubscribersCsv: {
660
695
  path: "/sites/{siteId}/newsletter/subscribers/export.csv",
@@ -851,14 +886,16 @@ var ENDPOINT_DEFINITIONS = {
851
886
  method: "POST",
852
887
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
853
888
  auth: "user",
854
- responseKind: "json"
889
+ responseKind: "json",
890
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
855
891
  },
856
892
  testSendNewsletterCampaign: {
857
893
  path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/test-send",
858
894
  method: "POST",
859
895
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
860
896
  auth: "user",
861
- responseKind: "json"
897
+ responseKind: "json",
898
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
862
899
  },
863
900
  listNewsletterSendJobs: {
864
901
  path: "/sites/{siteId}/newsletter/jobs",
@@ -906,6 +943,20 @@ var ENDPOINT_DEFINITIONS = {
906
943
  responseKind: "json",
907
944
  errors: ["validation:invalid_input", "billing:plan_limit_exceeded", "server:internal_error"]
908
945
  },
946
+ createAppointmentResourceWithAccountAccess: {
947
+ path: "/sites/{siteId}/bookings/resources/account-access",
948
+ method: "POST",
949
+ auth: "user",
950
+ responseKind: "json",
951
+ errors: [
952
+ "validation:invalid_input",
953
+ "auth:forbidden",
954
+ "billing:plan_limit_exceeded",
955
+ "resource:conflict",
956
+ "resource:not_found",
957
+ "server:internal_error"
958
+ ]
959
+ },
909
960
  getAppointmentResource: {
910
961
  path: "/sites/{siteId}/bookings/resources/{resourceId}",
911
962
  method: "GET",
@@ -1546,7 +1597,8 @@ var ENDPOINT_DEFINITIONS = {
1546
1597
  method: "DELETE",
1547
1598
  tags: ["site", "site-{siteId}"],
1548
1599
  auth: "user",
1549
- responseKind: "json"
1600
+ responseKind: "json",
1601
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
1550
1602
  },
1551
1603
  listSiteMembers: {
1552
1604
  path: "/sites/{siteId}/members",
@@ -2002,7 +2054,8 @@ var ENDPOINT_DEFINITIONS = {
2002
2054
  method: "POST",
2003
2055
  tags: ["site-{siteId}", "content-{siteId}-{type}"],
2004
2056
  auth: "user",
2005
- responseKind: "json"
2057
+ responseKind: "json",
2058
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
2006
2059
  },
2007
2060
  updateSiteGeneralSettings: {
2008
2061
  path: "/sites/{siteId}/settings/general",
@@ -4241,6 +4294,7 @@ var ENDPOINT_DEFINITIONS = {
4241
4294
  method: "POST",
4242
4295
  tags: ["site-{siteId}"],
4243
4296
  auth: "user",
4297
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
4244
4298
  errors: [
4245
4299
  "validation:invalid_input",
4246
4300
  "auth:forbidden",
@@ -4255,6 +4309,7 @@ var ENDPOINT_DEFINITIONS = {
4255
4309
  method: "POST",
4256
4310
  tags: ["site-{siteId}"],
4257
4311
  auth: "user",
4312
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
4258
4313
  errors: [
4259
4314
  "validation:invalid_input",
4260
4315
  "auth:forbidden",
@@ -4564,6 +4619,7 @@ var ENDPOINT_DEFINITIONS = {
4564
4619
  tags: ["site-{siteId}", "passes-{siteId}"],
4565
4620
  auth: "user",
4566
4621
  responseKind: "json",
4622
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4567
4623
  errors: ["validation:invalid_input", "server:internal_error"]
4568
4624
  },
4569
4625
  getBookingPass: {
@@ -4579,6 +4635,7 @@ var ENDPOINT_DEFINITIONS = {
4579
4635
  tags: ["site-{siteId}", "passes-{siteId}"],
4580
4636
  auth: "user",
4581
4637
  responseKind: "json",
4638
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4582
4639
  errors: [
4583
4640
  "validation:invalid_input",
4584
4641
  "resource:not_found",
@@ -4591,6 +4648,7 @@ var ENDPOINT_DEFINITIONS = {
4591
4648
  tags: ["site-{siteId}", "passes-{siteId}"],
4592
4649
  auth: "user",
4593
4650
  responseKind: "json",
4651
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4594
4652
  errors: [
4595
4653
  "validation:invalid_input",
4596
4654
  "resource:not_found",
@@ -4646,6 +4704,7 @@ var ENDPOINT_DEFINITIONS = {
4646
4704
  tags: ["site-{siteId}", "memberships-{siteId}"],
4647
4705
  auth: "user",
4648
4706
  responseKind: "json",
4707
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4649
4708
  errors: ["validation:invalid_input", "server:internal_error"]
4650
4709
  },
4651
4710
  getBookingMembership: {
@@ -4661,6 +4720,7 @@ var ENDPOINT_DEFINITIONS = {
4661
4720
  tags: ["site-{siteId}", "memberships-{siteId}"],
4662
4721
  auth: "user",
4663
4722
  responseKind: "json",
4723
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4664
4724
  errors: [
4665
4725
  "validation:invalid_input",
4666
4726
  "resource:not_found",
@@ -4673,6 +4733,7 @@ var ENDPOINT_DEFINITIONS = {
4673
4733
  tags: ["site-{siteId}", "memberships-{siteId}"],
4674
4734
  auth: "user",
4675
4735
  responseKind: "json",
4736
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4676
4737
  errors: [
4677
4738
  "validation:invalid_input",
4678
4739
  "resource:not_found",
@@ -4889,6 +4950,7 @@ var ENDPOINT_DEFINITIONS = {
4889
4950
  tags: ["site-{siteId}", "customers-{siteId}"],
4890
4951
  auth: "user",
4891
4952
  responseKind: "json",
4953
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4892
4954
  errors: [
4893
4955
  "validation:invalid_input",
4894
4956
  "auth:forbidden",
@@ -7537,8 +7599,7 @@ var dashboardNavVisibilityBaseSchema = z5.object({
7537
7599
  var dashboardNavVisibilityRolesSchema = z5.object({
7538
7600
  administrator: dashboardNavVisibilityBaseSchema.optional(),
7539
7601
  editor: dashboardNavVisibilityBaseSchema.optional(),
7540
- team_member: dashboardNavVisibilityBaseSchema.optional(),
7541
- event_host: dashboardNavVisibilityBaseSchema.optional()
7602
+ team_member: dashboardNavVisibilityBaseSchema.optional()
7542
7603
  }).strip().optional();
7543
7604
  var dashboardNavVisibilitySchema = dashboardNavVisibilityBaseSchema.extend({
7544
7605
  roles: dashboardNavVisibilityRolesSchema
@@ -8483,6 +8544,21 @@ var appointmentSetupServiceDraftSchema = z7.object({
8483
8544
  timezone: z7.string().trim().min(1).nullable(),
8484
8545
  payment: appointmentSetupPaymentDraftSchema,
8485
8546
  assignment: appointmentSetupServiceAssignmentDraftSchema
8547
+ }).superRefine((service, ctx) => {
8548
+ if (service.payment.priceType === "paid" && (service.priceAmount === null || service.priceAmount <= 0)) {
8549
+ ctx.addIssue({
8550
+ code: "custom",
8551
+ path: ["priceAmount"],
8552
+ message: "Paid appointment services need a positive price."
8553
+ });
8554
+ }
8555
+ if (service.payment.priceType === "free" && service.priceAmount !== null && service.priceAmount > 0) {
8556
+ ctx.addIssue({
8557
+ code: "custom",
8558
+ path: ["priceAmount"],
8559
+ message: "Free appointment services cannot carry a positive price."
8560
+ });
8561
+ }
8486
8562
  });
8487
8563
  var appointmentSetupPractitionerDraftSchema = z7.object({
8488
8564
  ref: appointmentSetupRefSchema,
@@ -9556,6 +9632,144 @@ function resolveVariantKey(manifest, content) {
9556
9632
  return null;
9557
9633
  }
9558
9634
 
9635
+ // ../theme-core/src/palette/utils/colorConversion.ts
9636
+ var clamp01 = (x) => Math.max(0, Math.min(1, x));
9637
+ var mod = (a, n) => (a % n + n) % n;
9638
+ var deg = (x) => mod(x, 360);
9639
+ function hexToRgb(hex) {
9640
+ const h = hex.replace(/^#/, "");
9641
+ const m = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
9642
+ if (m.length !== 6) throw new Error("Bad hex");
9643
+ const int = parseInt(m, 16);
9644
+ return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
9645
+ }
9646
+ function rgbToHex(r2, g, b) {
9647
+ const to = (n) => Math.round(n).toString(16).padStart(2, "0");
9648
+ return `#${to(r2)}${to(g)}${to(b)}`;
9649
+ }
9650
+ function srgbToLinear(u) {
9651
+ const x = u / 255;
9652
+ return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
9653
+ }
9654
+ function linearToSrgb(x) {
9655
+ const y = x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
9656
+ return clamp01(y) * 255;
9657
+ }
9658
+ function rgbToHsl(r2, g, b) {
9659
+ const R = r2 / 255, G = g / 255, B = b / 255;
9660
+ const max = Math.max(R, G, B), min = Math.min(R, G, B);
9661
+ const d = max - min;
9662
+ let h = 0;
9663
+ if (d !== 0) {
9664
+ switch (max) {
9665
+ case R:
9666
+ h = (G - B) / d + (G < B ? 6 : 0);
9667
+ break;
9668
+ case G:
9669
+ h = (B - R) / d + 2;
9670
+ break;
9671
+ case B:
9672
+ h = (R - G) / d + 4;
9673
+ break;
9674
+ }
9675
+ h *= 60;
9676
+ }
9677
+ const l = (max + min) / 2;
9678
+ const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
9679
+ return { h, s, l };
9680
+ }
9681
+ function srgbToOklab(r2, g, b) {
9682
+ const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
9683
+ const l = 0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B;
9684
+ const m = 0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B;
9685
+ const s = 0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B;
9686
+ const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
9687
+ const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
9688
+ const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
9689
+ const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
9690
+ return { L, a, b: b2 };
9691
+ }
9692
+ function oklabToSrgb(L, a, b) {
9693
+ const l_ = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
9694
+ const m_ = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
9695
+ const s_ = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
9696
+ const R = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
9697
+ const G = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
9698
+ const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
9699
+ return { r: linearToSrgb(R), g: linearToSrgb(G), b: linearToSrgb(B) };
9700
+ }
9701
+ function oklabToOklch(L, a, b) {
9702
+ const C = Math.sqrt(a * a + b * b);
9703
+ const h = C < 1e-7 ? 0 : deg(Math.atan2(b, a) * 180 / Math.PI);
9704
+ return { L, C, h };
9705
+ }
9706
+ function oklchToOklab(L, C, h) {
9707
+ const hr = h * Math.PI / 180;
9708
+ const a = C * Math.cos(hr);
9709
+ const b = C * Math.sin(hr);
9710
+ return { L, a, b };
9711
+ }
9712
+ function inSRGB(r2, g, b) {
9713
+ return r2 >= 0 && r2 <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
9714
+ }
9715
+ function oklchToHexGamut(L, C, h) {
9716
+ let lo = 0, hi = C, best = 0;
9717
+ for (let i = 0; i < 18; i++) {
9718
+ const mid = (lo + hi) / 2;
9719
+ const { a: a2, b: b2 } = oklchToOklab(L, mid, h);
9720
+ const { r: r3, g: g2, b: bb2 } = oklabToSrgb(L, a2, b2);
9721
+ if (inSRGB(r3, g2, bb2)) {
9722
+ best = mid;
9723
+ lo = mid;
9724
+ } else {
9725
+ hi = mid;
9726
+ }
9727
+ }
9728
+ const { a, b } = oklchToOklab(L, best, h);
9729
+ const { r: r2, g, b: bb } = oklabToSrgb(L, a, b);
9730
+ return rgbToHex(r2, g, bb);
9731
+ }
9732
+ function featuresFromHex(hex) {
9733
+ const { r: r2, g, b } = hexToRgb(hex);
9734
+ const { h, s, l } = rgbToHsl(r2, g, b);
9735
+ const { L, a, b: b2 } = srgbToOklab(r2, g, b);
9736
+ const { L: okL, C: okC, h: okH } = oklabToOklch(L, a, b2);
9737
+ const max = Math.max(r2, g, b);
9738
+ const v = max / 255;
9739
+ const Y = 0.2126 * srgbToLinear(r2) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
9740
+ const chroma = s;
9741
+ return { r: r2, g, b, h, s, l, v, Y, chroma, okL, okC, okH, hex };
9742
+ }
9743
+
9744
+ // ../theme-core/src/palette/utils/contrast.ts
9745
+ function relativeLuminance(r2, g, b) {
9746
+ const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
9747
+ return 0.2126 * R + 0.7152 * G + 0.0722 * B;
9748
+ }
9749
+
9750
+ // ../theme-core/src/palette/utils/onColor.ts
9751
+ var BACKGROUND_ROLE_NAMES = /* @__PURE__ */ new Set([
9752
+ "primary",
9753
+ "secondary",
9754
+ "accent",
9755
+ "success",
9756
+ "warning",
9757
+ "destructive",
9758
+ "info",
9759
+ "background",
9760
+ "surface",
9761
+ "surfaceAlt",
9762
+ "muted",
9763
+ "neutral"
9764
+ ]);
9765
+ function onColorTokenName(backgroundToken) {
9766
+ return `on${backgroundToken.split("-").filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}`;
9767
+ }
9768
+ function isOnColorBackgroundCandidateToken(token) {
9769
+ const role = token.match(/^(.*?)(?:-\d{2,3})?$/)?.[1] ?? token;
9770
+ return BACKGROUND_ROLE_NAMES.has(role);
9771
+ }
9772
+
9559
9773
  // ../theme-core/src/site-styles/appearancePresetResolution.ts
9560
9774
  function assertValidOptionGroups(preset2) {
9561
9775
  preset2.optionGroups?.forEach((group) => {
@@ -15177,6 +15391,9 @@ var curatedSiteStyleIdValues = [
15177
15391
  "site-style:bright-community",
15178
15392
  "site-style:quiet-luxury",
15179
15393
  "site-style:practical-services",
15394
+ "site-style:quiet-practice",
15395
+ "site-style:personal-retreat-journal",
15396
+ "site-style:tactile-workshop",
15180
15397
  "site-style:modern-wellness",
15181
15398
  "site-style:bold-launch",
15182
15399
  "site-style:south-west-twerk-school"
@@ -15259,7 +15476,8 @@ function defineCuratedSiteStyle(input) {
15259
15476
  name: input.name,
15260
15477
  description: input.description,
15261
15478
  generationBrief: input.generationBrief,
15262
- selectionKeywords: input.selectionKeywords ?? [],
15479
+ selectionKeywordRules: input.selectionKeywordRules ?? [],
15480
+ siteCreatorSelection: input.siteCreatorSelection ?? { kind: "explicit_only" },
15263
15481
  template: {
15264
15482
  id: asDesignSystemTemplateId(`template:${input.id.replace("site-style:", "")}`),
15265
15483
  name: input.name,
@@ -15403,12 +15621,13 @@ var curatedSiteStyles = [
15403
15621
  name: "Quiet Luxury",
15404
15622
  description: "Minimal, confident, and refined for premium experiences and private services.",
15405
15623
  generationBrief: "Use fewer claims, more specificity, and restrained sensory detail. Favor elegant media and low repetition over dense panels.",
15406
- selectionKeywords: [
15407
- "luxury",
15408
- "premium",
15409
- "boutique",
15410
- "bespoke",
15411
- "exclusive"
15624
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 20 },
15625
+ selectionKeywordRules: [
15626
+ { kind: "word", value: "luxury" },
15627
+ { kind: "word", value: "premium" },
15628
+ { kind: "word", value: "boutique" },
15629
+ { kind: "word", value: "bespoke" },
15630
+ { kind: "word", value: "exclusive" }
15412
15631
  ],
15413
15632
  tokenRecipes: {
15414
15633
  palette: "high-contrast",
@@ -15437,13 +15656,14 @@ var curatedSiteStyles = [
15437
15656
  name: "Practical Services",
15438
15657
  description: "Efficient, plainspoken, and conversion-focused for trades and everyday services.",
15439
15658
  generationBrief: "Make services, location, trust signals, and contact paths obvious. Keep copy brief and avoid ornate visual treatments.",
15440
- selectionKeywords: [
15441
- "repair",
15442
- "plumb",
15443
- "electric",
15444
- "cleaning",
15445
- "landscap",
15446
- "contractor"
15659
+ siteCreatorSelection: { kind: "primary_goal_support" },
15660
+ selectionKeywordRules: [
15661
+ { kind: "word", value: "repair" },
15662
+ { kind: "substring", value: "plumb" },
15663
+ { kind: "substring", value: "electric" },
15664
+ { kind: "word", value: "cleaning" },
15665
+ { kind: "substring", value: "landscap" },
15666
+ { kind: "substring", value: "contractor" }
15447
15667
  ],
15448
15668
  tokenRecipes: {
15449
15669
  palette: "brand-led",
@@ -15494,18 +15714,134 @@ var curatedSiteStyles = [
15494
15714
  paletteChoice("warm-neutral-forest")
15495
15715
  ]
15496
15716
  }),
15717
+ defineCuratedSiteStyle({
15718
+ id: "site-style:quiet-practice",
15719
+ name: "Quiet Practice",
15720
+ description: "Grounded, calm, and practical for small appointment-first practices.",
15721
+ 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.",
15722
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 30 },
15723
+ selectionKeywordRules: [
15724
+ { kind: "substring", value: "massage" },
15725
+ { kind: "word", value: "bodywork" },
15726
+ { kind: "phrase", value: "appointment practice" },
15727
+ { kind: "phrase", value: "appointment-first" },
15728
+ { kind: "substring", value: "practitioner" },
15729
+ { kind: "substring", value: "therap" },
15730
+ { kind: "substring", value: "clinic" },
15731
+ { kind: "phrase", value: "wellness practice" }
15732
+ ],
15733
+ tokenRecipes: {
15734
+ palette: "soft-natural",
15735
+ contrast: "standard",
15736
+ radius: "soft",
15737
+ shadow: "subtle",
15738
+ typography: "clean-sans",
15739
+ spacing: "regular",
15740
+ motion: "subtle"
15741
+ },
15742
+ compositionBudget: quietBudget,
15743
+ recommendedHeaderLookIds: ["practical-utility", "clean-base", "centered-calm"],
15744
+ buttonPersonalityChoices: [
15745
+ buttonChoice("pebble"),
15746
+ buttonChoice("soft-pill"),
15747
+ buttonChoice("editorial-link")
15748
+ ],
15749
+ paletteVariantChoices: [
15750
+ paletteChoice("soft-natural-stone"),
15751
+ paletteChoice("soft-natural-sage"),
15752
+ paletteChoice("warm-neutral-clay")
15753
+ ]
15754
+ }),
15755
+ defineCuratedSiteStyle({
15756
+ id: "site-style:personal-retreat-journal",
15757
+ name: "Personal Retreat Journal",
15758
+ description: "Warm, story-led, and readable for solo practitioners with mixed offers.",
15759
+ 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.",
15760
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 40 },
15761
+ selectionKeywordRules: [
15762
+ { kind: "substring", value: "retreat" },
15763
+ { kind: "phrase", value: "solo practitioner" },
15764
+ { kind: "phrase", value: "personal brand" },
15765
+ { kind: "substring", value: "teacher" },
15766
+ { kind: "substring", value: "coach" },
15767
+ { kind: "phrase", value: "retreat resources" },
15768
+ { kind: "substring", value: "journal" }
15769
+ ],
15770
+ tokenRecipes: {
15771
+ palette: "warm-neutral",
15772
+ contrast: "standard",
15773
+ radius: "soft",
15774
+ shadow: "subtle",
15775
+ typography: "serif-editorial",
15776
+ spacing: "airy",
15777
+ motion: "subtle"
15778
+ },
15779
+ compositionBudget: balancedBudget,
15780
+ recommendedHeaderLookIds: ["editorial-line", "centered-calm", "minimal-transparent"],
15781
+ buttonPersonalityChoices: [
15782
+ buttonChoice("editorial-link"),
15783
+ buttonChoice("soft-pill"),
15784
+ buttonChoice("brushed-wash")
15785
+ ],
15786
+ paletteVariantChoices: [
15787
+ paletteChoice("warm-neutral-forest"),
15788
+ paletteChoice("warm-neutral-clay"),
15789
+ paletteChoice("soft-natural-stone")
15790
+ ]
15791
+ }),
15792
+ defineCuratedSiteStyle({
15793
+ id: "site-style:tactile-workshop",
15794
+ name: "Tactile Workshop",
15795
+ description: "Bright, hands-on, and image-led for maker studios, workshops, and creative classes.",
15796
+ 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.",
15797
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 50 },
15798
+ selectionKeywordRules: [
15799
+ { kind: "substring", value: "ceramic" },
15800
+ { kind: "word", value: "pottery" },
15801
+ { kind: "phrase", value: "maker studio" },
15802
+ { kind: "phrase", value: "craft class" },
15803
+ { kind: "phrase", value: "craft workshop" },
15804
+ { kind: "word", value: "clay" },
15805
+ { kind: "word", value: "kiln" }
15806
+ ],
15807
+ tokenRecipes: {
15808
+ palette: "brand-led",
15809
+ contrast: "standard",
15810
+ radius: "soft",
15811
+ shadow: "subtle",
15812
+ typography: "friendly-sans",
15813
+ spacing: "regular",
15814
+ motion: "subtle"
15815
+ },
15816
+ compositionBudget: balancedBudget,
15817
+ recommendedHeaderLookIds: ["brand-solid", "practical-utility", "clean-base"],
15818
+ recommendedFooterLookIds: ["site-footer-brand-two-band", "footer-muted-grounding"],
15819
+ buttonPersonalityChoices: [
15820
+ buttonChoice("pebble"),
15821
+ buttonChoice("confident-chip"),
15822
+ buttonChoice("ink-stamp"),
15823
+ buttonChoice("editorial-link")
15824
+ ],
15825
+ paletteVariantChoices: [
15826
+ paletteChoice("brand-led-warm"),
15827
+ paletteChoice("brand-led-cool"),
15828
+ paletteChoice("soft-natural-watercolor"),
15829
+ paletteChoice("warm-neutral-clay")
15830
+ ]
15831
+ }),
15497
15832
  defineCuratedSiteStyle({
15498
15833
  id: "site-style:bold-launch",
15499
15834
  name: "Bold Launch",
15500
15835
  description: "High-energy and punchy for launches, campaigns, and creative offers.",
15501
15836
  generationBrief: "Use crisp positioning, bold hero structure, strong calls to action, and confident visual rhythm. Keep it precise, not shouty.",
15502
- selectionKeywords: [
15503
- "launch",
15504
- "campaign",
15505
- "preorder",
15506
- "pre-order",
15507
- "waitlist",
15508
- "drop"
15837
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 10 },
15838
+ selectionKeywordRules: [
15839
+ { kind: "substring", value: "launch" },
15840
+ { kind: "substring", value: "campaign" },
15841
+ { kind: "word", value: "preorder" },
15842
+ { kind: "phrase", value: "pre-order" },
15843
+ { kind: "substring", value: "waitlist" },
15844
+ { kind: "word", value: "drop" }
15509
15845
  ],
15510
15846
  tokenRecipes: {
15511
15847
  palette: "high-contrast",
@@ -15536,15 +15872,6 @@ var curatedSiteStyles = [
15536
15872
  name: "South West Twerk School",
15537
15873
  description: "Energetic, editorial, and high-contrast for a branded dance school presence.",
15538
15874
  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.",
15539
- selectionKeywords: [
15540
- "dance",
15541
- "classes",
15542
- "workshop",
15543
- "school",
15544
- "movement",
15545
- "performance",
15546
- "community"
15547
- ],
15548
15875
  tokenRecipes: {
15549
15876
  palette: "brand-led",
15550
15877
  contrast: "maximum",
@@ -15787,6 +16114,148 @@ var modernMinimalTheme = {
15787
16114
  }
15788
16115
  };
15789
16116
 
16117
+ // ../theme-core/src/palette/generateShades.ts
16118
+ function generateShades(hexColor, name) {
16119
+ const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
16120
+ const base = featuresFromHex(hexColor);
16121
+ const hue = base.okH;
16122
+ const baseChroma = base.okC;
16123
+ const toneMap = {
16124
+ 50: 0.975,
16125
+ 100: 0.945,
16126
+ 200: 0.89,
16127
+ 300: 0.82,
16128
+ 400: 0.74,
16129
+ 500: 0.66,
16130
+ 600: 0.58,
16131
+ 700: 0.49,
16132
+ 800: 0.4,
16133
+ 900: 0.28,
16134
+ 950: 0.16
16135
+ };
16136
+ const shadeDefs = shadeSteps.map((step, idx) => {
16137
+ const t = idx / (shadeSteps.length - 1);
16138
+ const L = toneMap[step];
16139
+ const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t);
16140
+ const C = baseChroma * chromaFactor;
16141
+ return {
16142
+ name: `${name}-${step}`,
16143
+ hex: oklchToHexGamut(L, C, hue)
16144
+ };
16145
+ });
16146
+ shadeDefs.push({ name, hex: hexColor });
16147
+ return shadeDefs;
16148
+ }
16149
+
16150
+ // ../theme-core/src/palette/neutralScale.ts
16151
+ function generateNeutralScale({
16152
+ background,
16153
+ steps = 11,
16154
+ warm = false
16155
+ }) {
16156
+ const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
16157
+ const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
16158
+ const count = Math.min(steps, shadeNames.length);
16159
+ const scale = [];
16160
+ for (let i = 0; i < count; i++) {
16161
+ const t = i / (count - 1);
16162
+ const tone = isDark ? mix(0.06, 0.92, t) : mix(0.98, 0.1, t);
16163
+ const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
16164
+ const name = `neutral-${shadeNames[i]}`;
16165
+ scale.push({ name, hex });
16166
+ }
16167
+ return scale;
16168
+ }
16169
+ function mix(a, b, t) {
16170
+ return a + (b - a) * Math.max(0, Math.min(1, t));
16171
+ }
16172
+
16173
+ // ../theme-core/src/palette/utils/textColor.ts
16174
+ function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
16175
+ const { r: r2, g, b } = parseColorToRgb(background);
16176
+ const luminance = relativeLuminance(r2, g, b);
16177
+ const blackContrast = (luminance + 0.05) / 0.05;
16178
+ const whiteContrast = 1.05 / (luminance + 0.05);
16179
+ if (blackContrast >= minContrast && whiteContrast < minContrast) {
16180
+ return "#000000";
16181
+ }
16182
+ if (whiteContrast >= minContrast && blackContrast < minContrast) {
16183
+ return "#FFFFFF";
16184
+ }
16185
+ return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
16186
+ }
16187
+ function getTextColorForBackground(background) {
16188
+ return pickBlackOrWhiteTextColor(background);
16189
+ }
16190
+ function parseColorToRgb(input) {
16191
+ const trimmed = input.trim();
16192
+ if (trimmed.startsWith("#")) {
16193
+ return hexToRgb(trimmed);
16194
+ }
16195
+ const rgbMatch = trimmed.match(
16196
+ /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
16197
+ );
16198
+ if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
16199
+ return {
16200
+ r: clamp255(Number(rgbMatch[1])),
16201
+ g: clamp255(Number(rgbMatch[2])),
16202
+ b: clamp255(Number(rgbMatch[3]))
16203
+ };
16204
+ }
16205
+ throw new Error("Unsupported color format");
16206
+ }
16207
+ function clamp255(value) {
16208
+ if (Number.isNaN(value)) return 0;
16209
+ return Math.max(0, Math.min(255, value));
16210
+ }
16211
+
16212
+ // ../theme-core/src/palette/expandPalette.ts
16213
+ function colorsToMap(palette) {
16214
+ const map = {};
16215
+ for (const c of palette.colors) {
16216
+ map[c.name] = c.hex;
16217
+ }
16218
+ return map;
16219
+ }
16220
+ function isBackgroundDark(hex) {
16221
+ try {
16222
+ return featuresFromHex(hex).Y < 0.5;
16223
+ } catch {
16224
+ return false;
16225
+ }
16226
+ }
16227
+ function expandPalette(palette) {
16228
+ const base = colorsToMap(palette);
16229
+ const expanded = { ...base };
16230
+ const background = base.background || base.surface || "#ffffff";
16231
+ const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
16232
+ neutral2.forEach((n) => {
16233
+ expanded[n.name] = n.hex;
16234
+ });
16235
+ for (const [name, hex] of Object.entries(base)) {
16236
+ if (hex) {
16237
+ const shades = generateShades(hex, name);
16238
+ shades.forEach((shade) => {
16239
+ expanded[shade.name] = shade.hex;
16240
+ });
16241
+ }
16242
+ }
16243
+ if (base.text) expanded.body = base.text;
16244
+ if (base.danger && !base.destructive) {
16245
+ expanded.destructive = base.danger;
16246
+ }
16247
+ const isDark = base.background ? isBackgroundDark(base.background) : false;
16248
+ const isDarkMode = palette.meta?.mode === "dark" || isDark;
16249
+ expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
16250
+ for (const [token, hex] of Object.entries({ ...expanded })) {
16251
+ if (!hex || !isOnColorBackgroundCandidateToken(token)) continue;
16252
+ const onToken = onColorTokenName(token);
16253
+ if (expanded[onToken]) continue;
16254
+ expanded[onToken] = getTextColorForBackground(hex);
16255
+ }
16256
+ return expanded;
16257
+ }
16258
+
15790
16259
  // ../theme-core/src/site-styles/designState.ts
15791
16260
  import { z as z30 } from "zod";
15792
16261
 
@@ -15955,25 +16424,19 @@ var defaultDesignRuntimeRules = defineDesignRuntimeRules({
15955
16424
  "muted-band": {
15956
16425
  background: {
15957
16426
  type: "color",
15958
- color: "muted",
15959
- textColor: "text",
15960
- headingColor: "text"
16427
+ color: "muted"
15961
16428
  }
15962
16429
  },
15963
16430
  "accent-band": {
15964
16431
  background: {
15965
16432
  type: "color",
15966
- color: "primary",
15967
- textColor: "primaryForeground",
15968
- headingColor: "primaryForeground"
16433
+ color: "primary"
15969
16434
  }
15970
16435
  },
15971
16436
  "brand-depth-band": {
15972
16437
  background: {
15973
16438
  type: "color",
15974
- color: "primary-800",
15975
- textColor: "primaryForeground",
15976
- headingColor: "primaryForeground"
16439
+ color: "primary-800"
15977
16440
  }
15978
16441
  },
15979
16442
  "hero-image": {
@@ -22195,6 +22658,16 @@ var jsonArrayTransform = {
22195
22658
  return "";
22196
22659
  }
22197
22660
  };
22661
+ var csvTransform = {
22662
+ id: "value.csv",
22663
+ kind: "formatter",
22664
+ summary: "Normalize a string or array of strings into a comma-separated list",
22665
+ run: (value) => {
22666
+ const rawValues = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
22667
+ const normalized = rawValues.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
22668
+ return normalized.length > 0 ? Array.from(new Set(normalized)).join(",") : "";
22669
+ }
22670
+ };
22198
22671
  var marqueeLoopOptionsSchema = z39.object({
22199
22672
  minItems: z39.number().int().min(1).default(10)
22200
22673
  });
@@ -22220,6 +22693,7 @@ var formattingTransforms = [
22220
22693
  dateFormatShort,
22221
22694
  arrayLengthTransform,
22222
22695
  jsonArrayTransform,
22696
+ csvTransform,
22223
22697
  marqueeLoopTransform
22224
22698
  ];
22225
22699
 
@@ -22703,117 +23177,6 @@ var uiTransforms = [
22703
23177
 
22704
23178
  // ../blocks/src/system/transforms/registry/layout.ts
22705
23179
  import { z as z41 } from "zod";
22706
-
22707
- // ../theme-core/src/palette/utils/colorConversion.ts
22708
- var clamp01 = (x) => Math.max(0, Math.min(1, x));
22709
- var mod = (a, n) => (a % n + n) % n;
22710
- var deg = (x) => mod(x, 360);
22711
- function hexToRgb(hex) {
22712
- const h = hex.replace(/^#/, "");
22713
- const m = h.length === 3 ? h.split("").map((c) => c + c).join("") : h;
22714
- if (m.length !== 6) throw new Error("Bad hex");
22715
- const int = parseInt(m, 16);
22716
- return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
22717
- }
22718
- function rgbToHex(r2, g, b) {
22719
- const to = (n) => Math.round(n).toString(16).padStart(2, "0");
22720
- return `#${to(r2)}${to(g)}${to(b)}`;
22721
- }
22722
- function srgbToLinear(u) {
22723
- const x = u / 255;
22724
- return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
22725
- }
22726
- function linearToSrgb(x) {
22727
- const y = x <= 31308e-7 ? 12.92 * x : 1.055 * Math.pow(x, 1 / 2.4) - 0.055;
22728
- return clamp01(y) * 255;
22729
- }
22730
- function rgbToHsl(r2, g, b) {
22731
- const R = r2 / 255, G = g / 255, B = b / 255;
22732
- const max = Math.max(R, G, B), min = Math.min(R, G, B);
22733
- const d = max - min;
22734
- let h = 0;
22735
- if (d !== 0) {
22736
- switch (max) {
22737
- case R:
22738
- h = (G - B) / d + (G < B ? 6 : 0);
22739
- break;
22740
- case G:
22741
- h = (B - R) / d + 2;
22742
- break;
22743
- case B:
22744
- h = (R - G) / d + 4;
22745
- break;
22746
- }
22747
- h *= 60;
22748
- }
22749
- const l = (max + min) / 2;
22750
- const s = d === 0 ? 0 : d / (1 - Math.abs(2 * l - 1));
22751
- return { h, s, l };
22752
- }
22753
- function srgbToOklab(r2, g, b) {
22754
- const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
22755
- const l = 0.4122214708 * R + 0.5363325363 * G + 0.0514459929 * B;
22756
- const m = 0.2119034982 * R + 0.6806995451 * G + 0.1073969566 * B;
22757
- const s = 0.0883024619 * R + 0.2817188376 * G + 0.6299787005 * B;
22758
- const l_ = Math.cbrt(l), m_ = Math.cbrt(m), s_ = Math.cbrt(s);
22759
- const L = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
22760
- const a = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
22761
- const b2 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
22762
- return { L, a, b: b2 };
22763
- }
22764
- function oklabToSrgb(L, a, b) {
22765
- const l_ = Math.pow(L + 0.3963377774 * a + 0.2158037573 * b, 3);
22766
- const m_ = Math.pow(L - 0.1055613458 * a - 0.0638541728 * b, 3);
22767
- const s_ = Math.pow(L - 0.0894841775 * a - 1.291485548 * b, 3);
22768
- const R = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
22769
- const G = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
22770
- const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
22771
- return { r: linearToSrgb(R), g: linearToSrgb(G), b: linearToSrgb(B) };
22772
- }
22773
- function oklabToOklch(L, a, b) {
22774
- const C = Math.sqrt(a * a + b * b);
22775
- const h = C < 1e-7 ? 0 : deg(Math.atan2(b, a) * 180 / Math.PI);
22776
- return { L, C, h };
22777
- }
22778
- function oklchToOklab(L, C, h) {
22779
- const hr = h * Math.PI / 180;
22780
- const a = C * Math.cos(hr);
22781
- const b = C * Math.sin(hr);
22782
- return { L, a, b };
22783
- }
22784
- function inSRGB(r2, g, b) {
22785
- return r2 >= 0 && r2 <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255;
22786
- }
22787
- function oklchToHexGamut(L, C, h) {
22788
- let lo = 0, hi = C, best = 0;
22789
- for (let i = 0; i < 18; i++) {
22790
- const mid = (lo + hi) / 2;
22791
- const { a: a2, b: b2 } = oklchToOklab(L, mid, h);
22792
- const { r: r3, g: g2, b: bb2 } = oklabToSrgb(L, a2, b2);
22793
- if (inSRGB(r3, g2, bb2)) {
22794
- best = mid;
22795
- lo = mid;
22796
- } else {
22797
- hi = mid;
22798
- }
22799
- }
22800
- const { a, b } = oklchToOklab(L, best, h);
22801
- const { r: r2, g, b: bb } = oklabToSrgb(L, a, b);
22802
- return rgbToHex(r2, g, bb);
22803
- }
22804
- function featuresFromHex(hex) {
22805
- const { r: r2, g, b } = hexToRgb(hex);
22806
- const { h, s, l } = rgbToHsl(r2, g, b);
22807
- const { L, a, b: b2 } = srgbToOklab(r2, g, b);
22808
- const { L: okL, C: okC, h: okH } = oklabToOklch(L, a, b2);
22809
- const max = Math.max(r2, g, b);
22810
- const v = max / 255;
22811
- const Y = 0.2126 * srgbToLinear(r2) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);
22812
- const chroma = s;
22813
- return { r: r2, g, b, h, s, l, v, Y, chroma, okL, okC, okH, hex };
22814
- }
22815
-
22816
- // ../blocks/src/system/transforms/registry/layout.ts
22817
23180
  var joinClasses4 = (parts) => parts.filter(
22818
23181
  (part) => typeof part === "string" && part.trim().length > 0
22819
23182
  ).join(" ").replace(/\s+/g, " ").trim();
@@ -27762,51 +28125,6 @@ function resolveEventCta(event, buttonText) {
27762
28125
  return { label, href: event.path, hidden: false };
27763
28126
  }
27764
28127
 
27765
- // ../theme-core/src/palette/utils/contrast.ts
27766
- function relativeLuminance(r2, g, b) {
27767
- const R = srgbToLinear(r2), G = srgbToLinear(g), B = srgbToLinear(b);
27768
- return 0.2126 * R + 0.7152 * G + 0.0722 * B;
27769
- }
27770
-
27771
- // ../theme-core/src/palette/utils/textColor.ts
27772
- function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
27773
- const { r: r2, g, b } = parseColorToRgb(background);
27774
- const luminance = relativeLuminance(r2, g, b);
27775
- const blackContrast = (luminance + 0.05) / 0.05;
27776
- const whiteContrast = 1.05 / (luminance + 0.05);
27777
- if (blackContrast >= minContrast && whiteContrast < minContrast) {
27778
- return "#000000";
27779
- }
27780
- if (whiteContrast >= minContrast && blackContrast < minContrast) {
27781
- return "#FFFFFF";
27782
- }
27783
- return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
27784
- }
27785
- function getTextColorForBackground(background) {
27786
- return pickBlackOrWhiteTextColor(background);
27787
- }
27788
- function parseColorToRgb(input) {
27789
- const trimmed = input.trim();
27790
- if (trimmed.startsWith("#")) {
27791
- return hexToRgb(trimmed);
27792
- }
27793
- const rgbMatch = trimmed.match(
27794
- /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
27795
- );
27796
- if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
27797
- return {
27798
- r: clamp255(Number(rgbMatch[1])),
27799
- g: clamp255(Number(rgbMatch[2])),
27800
- b: clamp255(Number(rgbMatch[3]))
27801
- };
27802
- }
27803
- throw new Error("Unsupported color format");
27804
- }
27805
- function clamp255(value) {
27806
- if (Number.isNaN(value)) return 0;
27807
- return Math.max(0, Math.min(255, value));
27808
- }
27809
-
27810
28128
  // ../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs
27811
28129
  function r(e) {
27812
28130
  var t, f, n = "";
@@ -29733,7 +30051,12 @@ var eventListingBlockDefinition = {
29733
30051
  detailLevel: "listing",
29734
30052
  kind: { $bind: { from: "content.kind" } },
29735
30053
  eventSurface: { $bind: { from: "content.eventSurface" } },
29736
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
30054
+ eventPresets: {
30055
+ $bind: {
30056
+ from: "content.filterEventPresets",
30057
+ transforms: [{ id: "value.csv" }]
30058
+ }
30059
+ },
29737
30060
  scheduleScope: { $bind: { from: "content.scheduleScope" } }
29738
30061
  },
29739
30062
  mode: "server"
@@ -30518,7 +30841,12 @@ var eventCalendarBlockDefinition = {
30518
30841
  // Pass filter params if configured
30519
30842
  kind: { $bind: { from: "content.kind" } },
30520
30843
  eventSurface: { $bind: { from: "content.eventSurface" } },
30521
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
30844
+ eventPresets: {
30845
+ $bind: {
30846
+ from: "content.filterEventPresets",
30847
+ transforms: [{ id: "value.csv" }]
30848
+ }
30849
+ },
30522
30850
  scheduleScope: { $bind: { from: "content.scheduleScope" } },
30523
30851
  categoryIds: { $bind: { from: "content.filterCategoryIds" } },
30524
30852
  staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
@@ -37335,16 +37663,18 @@ function toTrimmedString(value) {
37335
37663
  return trimmed ? trimmed : void 0;
37336
37664
  }
37337
37665
  function normalizeBookingFormConfig(form2) {
37338
- if (!form2) return null;
37666
+ if (!isRecord5(form2)) return null;
37667
+ const id = readNonEmptyString(form2.id);
37668
+ const name = readNonEmptyString(form2.name);
37669
+ if (!id || !name) return null;
37670
+ const schemaSource = isRecord5(form2.schema) ? form2.schema : isRecord5(form2.schemaJson) ? form2.schemaJson : null;
37671
+ const settingsSource = isRecord5(form2.settings) ? form2.settings : isRecord5(form2.settingsJson) ? form2.settingsJson : null;
37339
37672
  return {
37340
- id: form2.id,
37341
- name: form2.name,
37342
- slug: "",
37343
- settings: form2.settingsJson,
37344
- schema: form2.schemaJson ? {
37345
- version: form2.schemaJson.version,
37346
- fields: form2.schemaJson.fields ?? []
37347
- } : void 0
37673
+ id,
37674
+ name,
37675
+ slug: typeof form2.slug === "string" ? form2.slug : "",
37676
+ settings: normalizeBookingSettings(settingsSource),
37677
+ schema: normalizeBookingSchema(schemaSource)
37348
37678
  };
37349
37679
  }
37350
37680
  function normalizeBookingServices(services) {
@@ -37360,12 +37690,106 @@ function normalizeBookingServices(services) {
37360
37690
  return [];
37361
37691
  }
37362
37692
  if (Array.isArray(services)) {
37363
- return services.map(normalizeService);
37693
+ return services.filter(isBookingFormService).map(normalizeService);
37364
37694
  }
37365
- if ("services" in services) {
37366
- return Array.isArray(services.services) ? services.services.map(normalizeService) : [];
37695
+ if (isRecord5(services) && "services" in services) {
37696
+ return Array.isArray(services.services) ? services.services.filter(isBookingFormService).map(normalizeService) : [];
37367
37697
  }
37368
- return Object.values(services).map(normalizeService);
37698
+ return isRecord5(services) ? Object.values(services).filter(isBookingFormService).map(normalizeService) : [];
37699
+ }
37700
+ function normalizeBookingSchema(value) {
37701
+ if (!value) return void 0;
37702
+ const rawFields = Array.isArray(value.fields) ? value.fields : [];
37703
+ const fields3 = rawFields.map(readBookingFormField).filter((field) => field !== null);
37704
+ return {
37705
+ version: typeof value.version === "string" ? value.version : void 0,
37706
+ fields: fields3
37707
+ };
37708
+ }
37709
+ function readBookingFormField(value) {
37710
+ if (!isRecord5(value)) return null;
37711
+ const id = readNonEmptyString(value.id);
37712
+ const label = readNonEmptyString(value.label);
37713
+ const type = readBookingFieldType(value.type);
37714
+ if (!id || !label || !type) return null;
37715
+ return {
37716
+ id,
37717
+ label,
37718
+ type,
37719
+ required: typeof value.required === "boolean" ? value.required : void 0,
37720
+ placeholder: readOptionalString(value.placeholder),
37721
+ helpText: readOptionalString(value.helpText),
37722
+ options: readBookingFieldOptions(value.options),
37723
+ multiple: typeof value.multiple === "boolean" ? value.multiple : void 0,
37724
+ minLength: readOptionalNumber(value.minLength),
37725
+ maxLength: readOptionalNumber(value.maxLength),
37726
+ pattern: readOptionalString(value.pattern),
37727
+ min: readOptionalNumber(value.min),
37728
+ max: readOptionalNumber(value.max)
37729
+ };
37730
+ }
37731
+ function readBookingFieldType(value) {
37732
+ switch (value) {
37733
+ case "text":
37734
+ case "email":
37735
+ case "textarea":
37736
+ case "select":
37737
+ case "radio":
37738
+ case "checkbox":
37739
+ case "booking_requirement_consent":
37740
+ case "tel":
37741
+ case "url":
37742
+ case "number":
37743
+ case "date":
37744
+ case "time":
37745
+ return value;
37746
+ default:
37747
+ return null;
37748
+ }
37749
+ }
37750
+ function readBookingFieldOptions(value) {
37751
+ if (!Array.isArray(value)) return void 0;
37752
+ const options = value.map(readBookingFieldOption).filter((option) => option !== null);
37753
+ return options.length > 0 ? options : void 0;
37754
+ }
37755
+ function readBookingFieldOption(value) {
37756
+ if (!isRecord5(value)) return null;
37757
+ const optionValue = readNonEmptyString(value.value);
37758
+ const label = readNonEmptyString(value.label);
37759
+ return optionValue && label ? { value: optionValue, label } : null;
37760
+ }
37761
+ function normalizeBookingSettings(value) {
37762
+ if (!value || value.type !== "booking") return void 0;
37763
+ return {
37764
+ type: "booking",
37765
+ serviceId: readOptionalString(value.serviceId),
37766
+ serviceIds: readStringArray(value.serviceIds),
37767
+ resourceId: readOptionalString(value.resourceId),
37768
+ requiresApproval: typeof value.requiresApproval === "boolean" ? value.requiresApproval : void 0,
37769
+ successMessage: readOptionalString(value.successMessage)
37770
+ };
37771
+ }
37772
+ function isBookingFormService(value) {
37773
+ return isRecord5(value) && typeof value.id === "string" && typeof value.siteId === "string" && typeof value.title === "string";
37774
+ }
37775
+ function readNonEmptyString(value) {
37776
+ if (typeof value !== "string") return null;
37777
+ const trimmed = value.trim();
37778
+ return trimmed.length > 0 ? trimmed : null;
37779
+ }
37780
+ function readOptionalString(value) {
37781
+ return typeof value === "string" ? value : void 0;
37782
+ }
37783
+ function readOptionalNumber(value) {
37784
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
37785
+ }
37786
+ function readStringArray(value) {
37787
+ if (!Array.isArray(value)) return void 0;
37788
+ const strings = value.filter((item) => typeof item === "string");
37789
+ return strings.length > 0 ? strings : void 0;
37790
+ }
37791
+ function isRecord5(value) {
37792
+ return typeof value === "object" && value !== null;
37369
37793
  }
37370
37794
 
37371
37795
  // ../blocks/src/system/runtime/nodes/booking-form.interactive.ts
@@ -40936,119 +41360,6 @@ function makeDefaultBlockComponent(args) {
40936
41360
  };
40937
41361
  }
40938
41362
 
40939
- // ../theme-core/src/palette/generateShades.ts
40940
- function generateShades(hexColor, name) {
40941
- const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
40942
- const base = featuresFromHex(hexColor);
40943
- const hue = base.okH;
40944
- const baseChroma = base.okC;
40945
- const toneMap = {
40946
- 50: 0.975,
40947
- 100: 0.945,
40948
- 200: 0.89,
40949
- 300: 0.82,
40950
- 400: 0.74,
40951
- 500: 0.66,
40952
- 600: 0.58,
40953
- 700: 0.49,
40954
- 800: 0.4,
40955
- 900: 0.28,
40956
- 950: 0.16
40957
- };
40958
- const shadeDefs = shadeSteps.map((step, idx) => {
40959
- const t = idx / (shadeSteps.length - 1);
40960
- const L = toneMap[step];
40961
- const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t);
40962
- const C = baseChroma * chromaFactor;
40963
- return {
40964
- name: `${name}-${step}`,
40965
- hex: oklchToHexGamut(L, C, hue)
40966
- };
40967
- });
40968
- shadeDefs.push({ name, hex: hexColor });
40969
- return shadeDefs;
40970
- }
40971
-
40972
- // ../theme-core/src/palette/neutralScale.ts
40973
- function generateNeutralScale({
40974
- background,
40975
- steps = 11,
40976
- warm = false
40977
- }) {
40978
- const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
40979
- const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
40980
- const count = Math.min(steps, shadeNames.length);
40981
- const scale = [];
40982
- for (let i = 0; i < count; i++) {
40983
- const t = i / (count - 1);
40984
- const tone = isDark ? mix(0.06, 0.92, t) : mix(0.98, 0.1, t);
40985
- const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
40986
- const name = `neutral-${shadeNames[i]}`;
40987
- scale.push({ name, hex });
40988
- }
40989
- return scale;
40990
- }
40991
- function mix(a, b, t) {
40992
- return a + (b - a) * Math.max(0, Math.min(1, t));
40993
- }
40994
-
40995
- // ../theme-core/src/palette/expandPalette.ts
40996
- function colorsToMap(palette) {
40997
- const map = {};
40998
- for (const c of palette.colors) {
40999
- map[c.name] = c.hex;
41000
- }
41001
- return map;
41002
- }
41003
- function isBackgroundDark(hex) {
41004
- try {
41005
- return featuresFromHex(hex).Y < 0.5;
41006
- } catch {
41007
- return false;
41008
- }
41009
- }
41010
- function expandPalette(palette) {
41011
- const base = colorsToMap(palette);
41012
- const expanded = { ...base };
41013
- const background = base.background || base.surface || "#ffffff";
41014
- const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
41015
- neutral2.forEach((n) => {
41016
- expanded[n.name] = n.hex;
41017
- });
41018
- for (const [name, hex] of Object.entries(base)) {
41019
- if (hex) {
41020
- const shades = generateShades(hex, name);
41021
- shades.forEach((shade) => {
41022
- expanded[shade.name] = shade.hex;
41023
- });
41024
- }
41025
- }
41026
- if (base.text) expanded.body = base.text;
41027
- if (base.danger && !base.destructive) {
41028
- expanded.destructive = base.danger;
41029
- }
41030
- const isDark = base.background ? isBackgroundDark(base.background) : false;
41031
- const isDarkMode = palette.meta?.mode === "dark" || isDark;
41032
- expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
41033
- const onRoles = [
41034
- { role: "primary", on: "onPrimary" },
41035
- { role: "secondary", on: "onSecondary" },
41036
- { role: "accent", on: "onAccent" },
41037
- { role: "success", on: "onSuccess" },
41038
- { role: "warning", on: "onWarning" },
41039
- { role: "destructive", on: "onDestructive" },
41040
- { role: "info", on: "onInfo" },
41041
- { role: "surface", on: "onSurface" }
41042
- ];
41043
- for (const { role, on } of onRoles) {
41044
- const bg = base[role];
41045
- if (!bg) continue;
41046
- if (expanded[on]) continue;
41047
- expanded[on] = getTextColorForBackground(bg);
41048
- }
41049
- return expanded;
41050
- }
41051
-
41052
41363
  // ../theme-core/src/runtime/fontFamily.ts
41053
41364
  var GENERIC_CSS_FAMILIES = [
41054
41365
  "serif",
@@ -44745,6 +45056,8 @@ var MemoBlockSection = React6.memo(
44745
45056
  themeConfig,
44746
45057
  data: void 0,
44747
45058
  siteId: dataContext?.siteId,
45059
+ apiBaseUrl: dataContext?.apiBaseUrl,
45060
+ portalToken: dataContext?.portalToken ?? null,
44748
45061
  supabaseUrl: dataContext?.supabaseUrl,
44749
45062
  imageResolveContext,
44750
45063
  blockId: block.id ?? null,
@@ -44859,6 +45172,8 @@ var MemoBlockSection = React6.memo(
44859
45172
  themeConfig,
44860
45173
  data: resolved,
44861
45174
  siteId: dataContext?.siteId,
45175
+ apiBaseUrl: dataContext?.apiBaseUrl,
45176
+ portalToken: dataContext?.portalToken ?? null,
44862
45177
  supabaseUrl: dataContext?.supabaseUrl,
44863
45178
  imageResolveContext,
44864
45179
  blockId: block.id ?? null,
@@ -50627,32 +50942,32 @@ var containerResponsiveThemeCss = `/*
50627
50942
  }
50628
50943
 
50629
50944
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-text--muted {
50630
- opacity: var(--ab-text-muted-opacity);
50945
+ opacity: var(--ab-text-muted-opacity, 0.6);
50631
50946
  }
50632
50947
 
50633
50948
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-text--faint {
50634
- opacity: var(--ab-text-faint-opacity);
50949
+ opacity: var(--ab-text-faint-opacity, 0.4);
50635
50950
  }
50636
50951
 
50637
50952
  /* Selection cards (service, resource, time slot) */
50638
50953
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card {
50639
50954
  position: relative;
50640
50955
  padding: 1rem;
50641
- border: 2px solid var(--ab-card-border);
50642
- border-radius: var(--rb-block-radius);
50956
+ border: 2px solid var(--ab-card-border, rgb(var(--tb-border, 226 232 240)));
50957
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
50643
50958
  text-align: left;
50644
50959
  background: transparent;
50645
50960
  cursor: pointer;
50646
- transition: border-color var(--rb-block-transition) ease, background-color var(--rb-block-transition) ease;
50961
+ transition: border-color var(--rb-block-transition, 150ms) ease, background-color var(--rb-block-transition, 150ms) ease;
50647
50962
  }
50648
50963
 
50649
50964
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card:hover {
50650
- border-color: var(--ab-card-border-hover);
50965
+ border-color: var(--ab-card-border-hover, rgba(var(--tb-primary, 17 24 39), 0.5));
50651
50966
  }
50652
50967
 
50653
50968
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-card--selected {
50654
- border-color: var(--ab-card-border-selected);
50655
- background-color: var(--ab-card-bg-selected);
50969
+ border-color: var(--ab-card-border-selected, rgb(var(--tb-primary, 17 24 39)));
50970
+ background-color: var(--ab-card-bg-selected, rgba(var(--tb-primary, 17 24 39), 0.05));
50656
50971
  }
50657
50972
 
50658
50973
  /* Checkmark indicator */
@@ -50661,7 +50976,7 @@ var containerResponsiveThemeCss = `/*
50661
50976
  width: 1.25rem;
50662
50977
  height: 1.25rem;
50663
50978
  border-radius: 50%;
50664
- background-color: var(--ab-check-bg);
50979
+ background-color: var(--ab-check-bg, rgb(var(--tb-primary, 17 24 39)));
50665
50980
  display: flex;
50666
50981
  align-items: center;
50667
50982
  justify-content: center;
@@ -50670,42 +50985,42 @@ var containerResponsiveThemeCss = `/*
50670
50985
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-check svg {
50671
50986
  width: 0.75rem;
50672
50987
  height: 0.75rem;
50673
- color: var(--ab-check-text);
50988
+ color: var(--ab-check-text, rgb(var(--tb-background, 255 255 255)));
50674
50989
  }
50675
50990
 
50676
50991
  /* Info box (service summary) */
50677
50992
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-info-box {
50678
50993
  padding: 1rem;
50679
- border: 1px solid var(--ab-card-border);
50680
- border-radius: var(--rb-block-radius);
50681
- background-color: var(--ab-muted-bg);
50994
+ border: 1px solid var(--ab-card-border, rgb(var(--tb-border, 226 232 240)));
50995
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
50996
+ background-color: var(--ab-muted-bg, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
50682
50997
  }
50683
50998
 
50684
50999
  /* Alert states */
50685
51000
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert {
50686
51001
  padding: 0.75rem 1rem;
50687
- border-radius: var(--rb-block-radius);
51002
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
50688
51003
  font-size: 0.875rem;
50689
51004
  }
50690
51005
 
50691
51006
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--success {
50692
- background-color: var(--ab-success-bg);
50693
- color: var(--ab-success-text);
51007
+ background-color: var(--ab-success-bg, rgba(var(--tb-success, 22 163 74), 0.1));
51008
+ color: var(--ab-success-text, rgb(var(--tb-success, 22 163 74)));
50694
51009
  }
50695
51010
 
50696
51011
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--error {
50697
- background-color: var(--ab-error-bg);
50698
- color: var(--ab-error-text);
51012
+ background-color: var(--ab-error-bg, rgba(var(--tb-destructive, 220 38 38), 0.1));
51013
+ color: var(--ab-error-text, rgb(var(--tb-destructive, 220 38 38)));
50699
51014
  }
50700
51015
 
50701
51016
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--warning {
50702
- background-color: var(--ab-warning-bg);
50703
- color: var(--ab-warning-text);
51017
+ background-color: var(--ab-warning-bg, rgba(var(--tb-warning, 245 158 11), 0.1));
51018
+ color: var(--ab-warning-text, rgb(var(--tb-warning, 245 158 11)));
50704
51019
  }
50705
51020
 
50706
51021
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-alert--info {
50707
- background-color: var(--ab-info-bg);
50708
- color: var(--ab-info-text);
51022
+ background-color: var(--ab-info-bg, rgba(var(--tb-info, 14 165 233), 0.1));
51023
+ color: var(--ab-info-text, rgb(var(--tb-info, 14 165 233)));
50709
51024
  }
50710
51025
 
50711
51026
  /* Form elements */
@@ -50717,7 +51032,7 @@ var containerResponsiveThemeCss = `/*
50717
51032
  }
50718
51033
 
50719
51034
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-required {
50720
- color: var(--ab-error-text);
51035
+ color: var(--ab-error-text, rgb(var(--tb-destructive, 220 38 38)));
50721
51036
  margin-left: 0.125rem;
50722
51037
  }
50723
51038
 
@@ -50726,19 +51041,19 @@ var containerResponsiveThemeCss = `/*
50726
51041
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-textarea {
50727
51042
  width: 100%;
50728
51043
  padding: 0.5rem 0.75rem;
50729
- border: 1px solid var(--ab-input-border);
50730
- border-radius: var(--rb-block-radius);
51044
+ border: 1px solid var(--ab-input-border, rgb(var(--tb-border, 226 232 240)));
51045
+ border-radius: var(--ab-input-radius, var(--radius-control, var(--rb-block-radius, 1rem)));
50731
51046
  background: transparent;
50732
51047
  font-size: 0.875rem;
50733
- transition: border-color var(--rb-block-transition) ease, box-shadow var(--rb-block-transition) ease;
51048
+ transition: border-color var(--rb-block-transition, 150ms) ease, box-shadow var(--rb-block-transition, 150ms) ease;
50734
51049
  }
50735
51050
 
50736
51051
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-input:focus,
50737
51052
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-select:focus,
50738
51053
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-textarea:focus {
50739
51054
  outline: none;
50740
- border-color: var(--ab-card-border-selected);
50741
- box-shadow: 0 0 0 3px var(--ab-input-focus-ring);
51055
+ border-color: var(--ab-card-border-selected, rgb(var(--tb-primary, 17 24 39)));
51056
+ box-shadow: 0 0 0 3px var(--ab-input-focus-ring, rgba(var(--tb-primary, 17 24 39), 0.3));
50742
51057
  }
50743
51058
 
50744
51059
  /* Buttons */
@@ -50747,31 +51062,31 @@ var containerResponsiveThemeCss = `/*
50747
51062
  align-items: center;
50748
51063
  justify-content: center;
50749
51064
  padding: 0.5rem 1.5rem;
50750
- border-radius: var(--rb-block-radius);
51065
+ border-radius: var(--ab-button-radius, var(--rb-button-radius, var(--rb-block-radius, 1rem)));
50751
51066
  font-size: 0.875rem;
50752
51067
  font-weight: 500;
50753
51068
  cursor: pointer;
50754
- transition: background-color var(--rb-block-transition) ease, border-color var(--rb-block-transition) ease;
51069
+ transition: background-color var(--rb-block-transition, 150ms) ease, border-color var(--rb-block-transition, 150ms) ease;
50755
51070
  }
50756
51071
 
50757
51072
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--primary {
50758
51073
  flex: 1;
50759
- background-color: var(--ab-btn-primary-bg);
50760
- color: var(--ab-btn-primary-text);
51074
+ background-color: var(--ab-btn-primary-bg, rgb(var(--tb-primary, 17 24 39)));
51075
+ color: var(--ab-btn-primary-text, rgb(var(--tb-primaryForeground, 255 255 255)));
50761
51076
  border: none;
50762
51077
  }
50763
51078
 
50764
51079
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--primary:hover:not(:disabled) {
50765
- background-color: var(--ab-btn-primary-hover);
51080
+ background-color: var(--ab-btn-primary-hover, rgba(var(--tb-primary, 17 24 39), 0.9));
50766
51081
  }
50767
51082
 
50768
51083
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--secondary {
50769
51084
  background: transparent;
50770
- border: 1px solid var(--ab-btn-secondary-border);
51085
+ border: 1px solid var(--ab-btn-secondary-border, rgb(var(--tb-border, 226 232 240)));
50771
51086
  }
50772
51087
 
50773
51088
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--secondary:hover:not(:disabled) {
50774
- background-color: var(--ab-btn-secondary-hover);
51089
+ background-color: var(--ab-btn-secondary-hover, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
50775
51090
  }
50776
51091
 
50777
51092
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-btn--link {
@@ -50801,8 +51116,8 @@ var containerResponsiveThemeCss = `/*
50801
51116
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-skeleton {
50802
51117
  height: 2.5rem;
50803
51118
  width: 100%;
50804
- background-color: var(--ab-muted-bg);
50805
- border-radius: var(--rb-block-radius);
51119
+ background-color: var(--ab-muted-bg, rgba(var(--tb-foreground, var(--tb-text, 15 23 42)), 0.05));
51120
+ border-radius: var(--ab-card-radius, var(--rb-block-radius, 1rem));
50806
51121
  animation: ab-pulse 1.5s ease-in-out infinite;
50807
51122
  }
50808
51123
 
@@ -50831,7 +51146,7 @@ var containerResponsiveThemeCss = `/*
50831
51146
  :where(.theme-scope) :where([data-block="appointment-booking"]) .ab-link {
50832
51147
  display: inline;
50833
51148
  margin-left: 0.5rem;
50834
- color: rgb(var(--tb-primary));
51149
+ color: rgb(var(--tb-primary, 17 24 39));
50835
51150
  background: none;
50836
51151
  border: none;
50837
51152
  padding: 0;
@@ -56439,7 +56754,7 @@ var SimpleCache = class {
56439
56754
  };
56440
56755
 
56441
56756
  // src/version.ts
56442
- var SDK_VERSION = "0.64.0";
56757
+ var SDK_VERSION = "0.68.0";
56443
56758
 
56444
56759
  // src/client/error.ts
56445
56760
  var RiverbankApiError = class _RiverbankApiError extends Error {