@riverbankcms/sdk 0.64.0 → 0.67.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 (78) hide show
  1. package/dist/_dts/api/src/aiPlayground.d.ts +18 -11
  2. package/dist/_dts/api/src/apiEndpointTypes.d.ts +12 -0
  3. package/dist/_dts/api/src/bookingOperations.d.ts +1 -1
  4. package/dist/_dts/api/src/endpoints.d.ts +25 -0
  5. package/dist/_dts/api/src/sdkConfig/contracts.d.ts +0 -40
  6. package/dist/_dts/api/src/sdkContracts.d.ts +1 -1
  7. package/dist/_dts/api/src/siteMembers.d.ts +1 -1
  8. package/dist/_dts/api/src/siteOperations.d.ts +1 -1
  9. package/dist/_dts/billing/src/plans/types.d.ts +1 -1
  10. package/dist/_dts/blocks/src/bindings/index.d.ts +1 -1
  11. package/dist/_dts/blocks/src/system/node/validation-constants.d.ts +1 -1
  12. package/dist/_dts/blocks/src/system/transforms/registry/formatting.d.ts +1 -0
  13. package/dist/_dts/blocks/src/system/transforms/typed.d.ts +2 -1
  14. package/dist/_dts/db/src/generated/supabase/database.types.d.ts +81 -0
  15. package/dist/_dts/preview-next/src/client/blocks/pageDesignRuntimePreview.d.ts +7 -3
  16. package/dist/_dts/preview-next/src/client/blocks/previewProjection/runtimeContentDecoration.d.ts +2 -2
  17. package/dist/_dts/sdk/src/cli/commands/push/execute/footer.d.ts +33 -0
  18. package/dist/_dts/sdk/src/cli/commands/push-execute.d.ts +2 -1
  19. package/dist/_dts/sdk/src/cli/env.d.ts +2 -1
  20. package/dist/_dts/sdk/src/cli/merge-remote/entryMergePush.d.ts +2 -1
  21. package/dist/_dts/sdk/src/cli/site-commands/commandKeys.d.ts +13 -0
  22. package/dist/_dts/sdk/src/cli/site-commands/commandRuntime.d.ts +114 -0
  23. package/dist/_dts/sdk/src/cli/site-commands/entryCommands.d.ts +26 -48
  24. package/dist/_dts/sdk/src/cli/site-commands/footerCommands.d.ts +50 -0
  25. package/dist/_dts/sdk/src/cli/site-commands/formCommands.d.ts +57 -0
  26. package/dist/_dts/sdk/src/cli/site-commands/index.d.ts +5 -0
  27. package/dist/_dts/sdk/src/cli/site-commands/navigationCommands.d.ts +57 -0
  28. package/dist/_dts/sdk/src/cli/site-commands/pageCommands.d.ts +83 -0
  29. package/dist/_dts/sdk/src/cli/site-commands/pushExecution.d.ts +67 -14
  30. package/dist/_dts/sdk/src/cli/sync/executor.d.ts +10 -28
  31. package/dist/_dts/sdk/src/cli/sync/index.d.ts +1 -1
  32. package/dist/_dts/sdk/src/config/dashboard-validation.d.ts +0 -48
  33. package/dist/_dts/sdk/src/config/types.d.ts +1 -1
  34. package/dist/_dts/sdk/src/version.d.ts +1 -1
  35. package/dist/_dts/site-commands/src/adapter.d.ts +2 -2
  36. package/dist/_dts/site-commands/src/commands.d.ts +410 -13
  37. package/dist/_dts/site-commands/src/domain.d.ts +3 -3
  38. package/dist/_dts/site-commands/src/exposure.d.ts +41 -0
  39. package/dist/_dts/site-commands/src/index.d.ts +1 -0
  40. package/dist/_dts/site-commands/src/metadata.d.ts +93 -2
  41. package/dist/_dts/site-commands/src/planner.d.ts +13 -6
  42. package/dist/_dts/site-commands/src/refs.d.ts +13 -1
  43. package/dist/_dts/theme-core/src/palette/utils/index.d.ts +1 -0
  44. package/dist/_dts/theme-core/src/palette/utils/onColor.d.ts +2 -0
  45. package/dist/_dts/theme-core/src/site-styles/accessibleSurfaces.d.ts +83 -0
  46. package/dist/_dts/theme-core/src/site-styles/contentTemplateRuntimeCompiler.d.ts +2 -1
  47. package/dist/_dts/theme-core/src/site-styles/curatedSiteStyles.d.ts +89 -12
  48. package/dist/_dts/theme-core/src/site-styles/generatedSchemas.d.ts +8 -2
  49. package/dist/_dts/theme-core/src/site-styles/index.d.ts +1 -0
  50. package/dist/_dts/theme-core/src/site-styles/previewCompiler.d.ts +3 -2
  51. package/dist/_dts/theme-core/src/site-styles/runtimeCompiler.d.ts +9 -6
  52. package/dist/_dts/ui/src/callout.d.ts +1 -1
  53. package/dist/cli/index.mjs +4290 -2513
  54. package/dist/client/client.mjs +598 -372
  55. package/dist/client/hooks.mjs +311 -123
  56. package/dist/client/rendering/client.mjs +209 -68
  57. package/dist/client/rendering/islands.mjs +281 -150
  58. package/dist/client/rendering.mjs +416 -190
  59. package/dist/preview-next/before-render.mjs +61 -13
  60. package/dist/preview-next/client/runtime.mjs +930 -376
  61. package/dist/preview-next/middleware.mjs +61 -13
  62. package/dist/server/components.mjs +526 -325
  63. package/dist/server/config-validation.mjs +313 -125
  64. package/dist/server/config.mjs +313 -125
  65. package/dist/server/data.mjs +311 -123
  66. package/dist/server/index.mjs +78 -16
  67. package/dist/server/next.mjs +527 -326
  68. package/dist/server/page-converter.mjs +159 -41
  69. package/dist/server/prebuild.mjs +1 -1
  70. package/dist/server/rendering/server.mjs +526 -325
  71. package/dist/server/rendering.mjs +526 -325
  72. package/dist/server/routing.mjs +392 -131
  73. package/dist/server/server.mjs +312 -124
  74. package/dist/server/theme-bridge.mjs +155 -48
  75. package/package.json +1 -1
  76. package/dist/_dts/path-utils/src/index.d.ts +0 -8
  77. package/dist/_dts/path-utils/src/redirectPaths.d.ts +0 -26
  78. package/dist/_dts/path-utils/src/safeAppPath.d.ts +0 -26
@@ -188,6 +188,21 @@ var init_previewAuthStore = __esm({
188
188
  }
189
189
  });
190
190
 
191
+ // ../api/src/apiEndpointTypes.ts
192
+ function blockedDemoMutationPolicy(classification, publicMessage) {
193
+ if (publicMessage.trim() === "") {
194
+ throw new Error(`Demo mutation policy ${classification} requires publicMessage.`);
195
+ }
196
+ return {
197
+ classification,
198
+ publicMessage
199
+ };
200
+ }
201
+ var init_apiEndpointTypes = __esm({
202
+ "../api/src/apiEndpointTypes.ts"() {
203
+ }
204
+ });
205
+
191
206
  // ../api/src/cache-tags.ts
192
207
  var TAG_TEMPLATES;
193
208
  var init_cache_tags = __esm({
@@ -223,10 +238,23 @@ var init_cache_tags = __esm({
223
238
  });
224
239
 
225
240
  // ../api/src/endpoints.ts
226
- var ENDPOINT_DEFINITIONS, API_ENDPOINTS;
241
+ var DEMO_MUTATION_BLOCKED_HIDDEN, DEMO_MUTATION_BLOCKED_DISABLED, DEMO_MUTATION_INTERNAL_ONLY, ENDPOINT_DEFINITIONS, API_ENDPOINTS;
227
242
  var init_endpoints = __esm({
228
243
  "../api/src/endpoints.ts"() {
244
+ init_apiEndpointTypes();
229
245
  init_cache_tags();
246
+ DEMO_MUTATION_BLOCKED_HIDDEN = blockedDemoMutationPolicy(
247
+ "blocked-hidden",
248
+ "This action is not available in demo sites."
249
+ );
250
+ DEMO_MUTATION_BLOCKED_DISABLED = blockedDemoMutationPolicy(
251
+ "blocked-disabled",
252
+ "This setting is disabled in demo sites."
253
+ );
254
+ DEMO_MUTATION_INTERNAL_ONLY = blockedDemoMutationPolicy(
255
+ "internal-only",
256
+ "This internal operation is not available in demo sites."
257
+ );
230
258
  ENDPOINT_DEFINITIONS = {
231
259
  // AI endpoints - no cache due to dynamic nature
232
260
  aiContentUpdateChat: {
@@ -343,7 +371,8 @@ var init_endpoints = __esm({
343
371
  path: "/sites/{siteId}/ai/generate",
344
372
  method: "POST",
345
373
  auth: "user",
346
- responseKind: "json"
374
+ responseKind: "json",
375
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
347
376
  },
348
377
  getOnboardingPreviewStatus: {
349
378
  path: "/public/sites/{siteId}/onboarding/preview-status",
@@ -364,7 +393,8 @@ var init_endpoints = __esm({
364
393
  method: "POST",
365
394
  auth: "user",
366
395
  errors: [],
367
- responseKind: "json"
396
+ responseKind: "json",
397
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED
368
398
  },
369
399
  goLiveSite: {
370
400
  path: "/sites/{siteId}/launch/go-live",
@@ -433,20 +463,23 @@ var init_endpoints = __esm({
433
463
  path: "/sites/{siteId}/ai/site-wizard/goals",
434
464
  method: "POST",
435
465
  auth: "user",
436
- responseKind: "json"
466
+ responseKind: "json",
467
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
437
468
  },
438
469
  aiSiteWizardIntakeTriage: {
439
470
  path: "/sites/{siteId}/ai/site-wizard/intake-triage",
440
471
  method: "POST",
441
472
  auth: "user",
442
- responseKind: "json"
473
+ responseKind: "json",
474
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
443
475
  },
444
476
  aiSiteWizardTelemetry: {
445
477
  path: "/sites/{siteId}/ai/site-wizard/telemetry",
446
478
  method: "POST",
447
479
  auth: "user",
448
480
  errors: [],
449
- responseKind: "json"
481
+ responseKind: "json",
482
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
450
483
  },
451
484
  // Admin SEO
452
485
  listGscPropertiesAdmin: {
@@ -653,7 +686,7 @@ var init_endpoints = __esm({
653
686
  responseKind: "json",
654
687
  errors: ["resource:not_found", "server:internal_error"]
655
688
  },
656
- // Ops (event hosts/admins)
689
+ // Ops (staff event operators/admins)
657
690
  opsListUpcomingEventOccurrences: {
658
691
  path: "/ops/sites/{siteId}/events",
659
692
  method: "GET",
@@ -671,6 +704,7 @@ var init_endpoints = __esm({
671
704
  method: "POST",
672
705
  auth: "user",
673
706
  responseKind: "json",
707
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
674
708
  errors: [
675
709
  "validation:invalid_input",
676
710
  "auth:forbidden",
@@ -683,6 +717,7 @@ var init_endpoints = __esm({
683
717
  method: "POST",
684
718
  auth: "user",
685
719
  responseKind: "json",
720
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
686
721
  errors: [
687
722
  "validation:invalid_input",
688
723
  "auth:forbidden",
@@ -701,6 +736,7 @@ var init_endpoints = __esm({
701
736
  method: "POST",
702
737
  auth: "user",
703
738
  responseKind: "json",
739
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
704
740
  errors: [
705
741
  "validation:invalid_input",
706
742
  "auth:forbidden",
@@ -734,6 +770,7 @@ var init_endpoints = __esm({
734
770
  method: "POST",
735
771
  auth: "user",
736
772
  responseKind: "json",
773
+ demoMutation: DEMO_MUTATION_INTERNAL_ONLY,
737
774
  errors: [
738
775
  "validation:invalid_input",
739
776
  "auth:forbidden",
@@ -762,7 +799,8 @@ var init_endpoints = __esm({
762
799
  method: "POST",
763
800
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteEmailSettings],
764
801
  auth: "user",
765
- responseKind: "json"
802
+ responseKind: "json",
803
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
766
804
  },
767
805
  previewEmailTemplate: {
768
806
  path: "/sites/{siteId}/settings/emails/preview",
@@ -813,14 +851,16 @@ var init_endpoints = __esm({
813
851
  method: "POST",
814
852
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
815
853
  auth: "user",
816
- responseKind: "json"
854
+ responseKind: "json",
855
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
817
856
  },
818
857
  createNewsletterSubscribersImportUploadUrl: {
819
858
  path: "/sites/{siteId}/newsletter/subscribers/import-url",
820
859
  method: "POST",
821
860
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
822
861
  auth: "user",
823
- responseKind: "json"
862
+ responseKind: "json",
863
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
824
864
  },
825
865
  exportNewsletterSubscribersCsv: {
826
866
  path: "/sites/{siteId}/newsletter/subscribers/export.csv",
@@ -1017,14 +1057,16 @@ var init_endpoints = __esm({
1017
1057
  method: "POST",
1018
1058
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
1019
1059
  auth: "user",
1020
- responseKind: "json"
1060
+ responseKind: "json",
1061
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
1021
1062
  },
1022
1063
  testSendNewsletterCampaign: {
1023
1064
  path: "/sites/{siteId}/newsletter/campaigns/{campaignId}/test-send",
1024
1065
  method: "POST",
1025
1066
  tags: [TAG_TEMPLATES.site, TAG_TEMPLATES.siteNewsletter],
1026
1067
  auth: "user",
1027
- responseKind: "json"
1068
+ responseKind: "json",
1069
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
1028
1070
  },
1029
1071
  listNewsletterSendJobs: {
1030
1072
  path: "/sites/{siteId}/newsletter/jobs",
@@ -1712,7 +1754,8 @@ var init_endpoints = __esm({
1712
1754
  method: "DELETE",
1713
1755
  tags: ["site", "site-{siteId}"],
1714
1756
  auth: "user",
1715
- responseKind: "json"
1757
+ responseKind: "json",
1758
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
1716
1759
  },
1717
1760
  listSiteMembers: {
1718
1761
  path: "/sites/{siteId}/members",
@@ -2168,7 +2211,8 @@ var init_endpoints = __esm({
2168
2211
  method: "POST",
2169
2212
  tags: ["site-{siteId}", "content-{siteId}-{type}"],
2170
2213
  auth: "user",
2171
- responseKind: "json"
2214
+ responseKind: "json",
2215
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN
2172
2216
  },
2173
2217
  updateSiteGeneralSettings: {
2174
2218
  path: "/sites/{siteId}/settings/general",
@@ -4407,6 +4451,7 @@ var init_endpoints = __esm({
4407
4451
  method: "POST",
4408
4452
  tags: ["site-{siteId}"],
4409
4453
  auth: "user",
4454
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
4410
4455
  errors: [
4411
4456
  "validation:invalid_input",
4412
4457
  "auth:forbidden",
@@ -4421,6 +4466,7 @@ var init_endpoints = __esm({
4421
4466
  method: "POST",
4422
4467
  tags: ["site-{siteId}"],
4423
4468
  auth: "user",
4469
+ demoMutation: DEMO_MUTATION_BLOCKED_HIDDEN,
4424
4470
  errors: [
4425
4471
  "validation:invalid_input",
4426
4472
  "auth:forbidden",
@@ -4730,6 +4776,7 @@ var init_endpoints = __esm({
4730
4776
  tags: ["site-{siteId}", "passes-{siteId}"],
4731
4777
  auth: "user",
4732
4778
  responseKind: "json",
4779
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4733
4780
  errors: ["validation:invalid_input", "server:internal_error"]
4734
4781
  },
4735
4782
  getBookingPass: {
@@ -4745,6 +4792,7 @@ var init_endpoints = __esm({
4745
4792
  tags: ["site-{siteId}", "passes-{siteId}"],
4746
4793
  auth: "user",
4747
4794
  responseKind: "json",
4795
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4748
4796
  errors: [
4749
4797
  "validation:invalid_input",
4750
4798
  "resource:not_found",
@@ -4757,6 +4805,7 @@ var init_endpoints = __esm({
4757
4805
  tags: ["site-{siteId}", "passes-{siteId}"],
4758
4806
  auth: "user",
4759
4807
  responseKind: "json",
4808
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4760
4809
  errors: [
4761
4810
  "validation:invalid_input",
4762
4811
  "resource:not_found",
@@ -4812,6 +4861,7 @@ var init_endpoints = __esm({
4812
4861
  tags: ["site-{siteId}", "memberships-{siteId}"],
4813
4862
  auth: "user",
4814
4863
  responseKind: "json",
4864
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4815
4865
  errors: ["validation:invalid_input", "server:internal_error"]
4816
4866
  },
4817
4867
  getBookingMembership: {
@@ -4827,6 +4877,7 @@ var init_endpoints = __esm({
4827
4877
  tags: ["site-{siteId}", "memberships-{siteId}"],
4828
4878
  auth: "user",
4829
4879
  responseKind: "json",
4880
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4830
4881
  errors: [
4831
4882
  "validation:invalid_input",
4832
4883
  "resource:not_found",
@@ -4839,6 +4890,7 @@ var init_endpoints = __esm({
4839
4890
  tags: ["site-{siteId}", "memberships-{siteId}"],
4840
4891
  auth: "user",
4841
4892
  responseKind: "json",
4893
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
4842
4894
  errors: [
4843
4895
  "validation:invalid_input",
4844
4896
  "resource:not_found",
@@ -5055,6 +5107,7 @@ var init_endpoints = __esm({
5055
5107
  tags: ["site-{siteId}", "customers-{siteId}"],
5056
5108
  auth: "user",
5057
5109
  responseKind: "json",
5110
+ demoMutation: DEMO_MUTATION_BLOCKED_DISABLED,
5058
5111
  errors: [
5059
5112
  "validation:invalid_input",
5060
5113
  "auth:forbidden",
@@ -100288,6 +100341,7 @@ var init_validation_constants = __esm({
100288
100341
  "date.formatShort",
100289
100342
  "array.length",
100290
100343
  "value.jsonArray",
100344
+ "value.csv",
100291
100345
  "array.marqueeLoop",
100292
100346
  // Layout (layout.ts)
100293
100347
  "layout.maxWidthClass",
@@ -101968,6 +102022,436 @@ var init_manifest = __esm({
101968
102022
  }
101969
102023
  });
101970
102024
 
102025
+ // ../theme-core/src/palette/utils/colorConversion.ts
102026
+ function hexToRgb(hex) {
102027
+ const h2 = hex.replace(/^#/, "");
102028
+ const m2 = h2.length === 3 ? h2.split("").map((c4) => c4 + c4).join("") : h2;
102029
+ if (m2.length !== 6) throw new Error("Bad hex");
102030
+ const int = parseInt(m2, 16);
102031
+ return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
102032
+ }
102033
+ function rgbToHex(r4, g2, b3) {
102034
+ const to2 = (n3) => Math.round(n3).toString(16).padStart(2, "0");
102035
+ return `#${to2(r4)}${to2(g2)}${to2(b3)}`;
102036
+ }
102037
+ function srgbToLinear(u3) {
102038
+ const x2 = u3 / 255;
102039
+ return x2 <= 0.04045 ? x2 / 12.92 : Math.pow((x2 + 0.055) / 1.055, 2.4);
102040
+ }
102041
+ function linearToSrgb(x2) {
102042
+ const y2 = x2 <= 31308e-7 ? 12.92 * x2 : 1.055 * Math.pow(x2, 1 / 2.4) - 0.055;
102043
+ return clamp01(y2) * 255;
102044
+ }
102045
+ function rgbToHsl(r4, g2, b3) {
102046
+ const R3 = r4 / 255, G2 = g2 / 255, B = b3 / 255;
102047
+ const max3 = Math.max(R3, G2, B), min3 = Math.min(R3, G2, B);
102048
+ const d2 = max3 - min3;
102049
+ let h2 = 0;
102050
+ if (d2 !== 0) {
102051
+ switch (max3) {
102052
+ case R3:
102053
+ h2 = (G2 - B) / d2 + (G2 < B ? 6 : 0);
102054
+ break;
102055
+ case G2:
102056
+ h2 = (B - R3) / d2 + 2;
102057
+ break;
102058
+ case B:
102059
+ h2 = (R3 - G2) / d2 + 4;
102060
+ break;
102061
+ }
102062
+ h2 *= 60;
102063
+ }
102064
+ const l2 = (max3 + min3) / 2;
102065
+ const s2 = d2 === 0 ? 0 : d2 / (1 - Math.abs(2 * l2 - 1));
102066
+ return { h: h2, s: s2, l: l2 };
102067
+ }
102068
+ function srgbToOklab(r4, g2, b3) {
102069
+ const R3 = srgbToLinear(r4), G2 = srgbToLinear(g2), B = srgbToLinear(b3);
102070
+ const l2 = 0.4122214708 * R3 + 0.5363325363 * G2 + 0.0514459929 * B;
102071
+ const m2 = 0.2119034982 * R3 + 0.6806995451 * G2 + 0.1073969566 * B;
102072
+ const s2 = 0.0883024619 * R3 + 0.2817188376 * G2 + 0.6299787005 * B;
102073
+ const l_ = Math.cbrt(l2), m_ = Math.cbrt(m2), s_ = Math.cbrt(s2);
102074
+ const L3 = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
102075
+ const a2 = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
102076
+ const b22 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
102077
+ return { L: L3, a: a2, b: b22 };
102078
+ }
102079
+ function oklabToSrgb(L3, a2, b3) {
102080
+ const l_ = Math.pow(L3 + 0.3963377774 * a2 + 0.2158037573 * b3, 3);
102081
+ const m_ = Math.pow(L3 - 0.1055613458 * a2 - 0.0638541728 * b3, 3);
102082
+ const s_ = Math.pow(L3 - 0.0894841775 * a2 - 1.291485548 * b3, 3);
102083
+ const R3 = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
102084
+ const G2 = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
102085
+ const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
102086
+ return { r: linearToSrgb(R3), g: linearToSrgb(G2), b: linearToSrgb(B) };
102087
+ }
102088
+ function oklabToOklch(L3, a2, b3) {
102089
+ const C2 = Math.sqrt(a2 * a2 + b3 * b3);
102090
+ const h2 = C2 < 1e-7 ? 0 : deg(Math.atan2(b3, a2) * 180 / Math.PI);
102091
+ return { L: L3, C: C2, h: h2 };
102092
+ }
102093
+ function oklchToOklab(L3, C2, h2) {
102094
+ const hr = h2 * Math.PI / 180;
102095
+ const a2 = C2 * Math.cos(hr);
102096
+ const b3 = C2 * Math.sin(hr);
102097
+ return { L: L3, a: a2, b: b3 };
102098
+ }
102099
+ function inSRGB(r4, g2, b3) {
102100
+ return r4 >= 0 && r4 <= 255 && g2 >= 0 && g2 <= 255 && b3 >= 0 && b3 <= 255;
102101
+ }
102102
+ function oklchToHexGamut(L3, C2, h2) {
102103
+ let lo2 = 0, hi = C2, best = 0;
102104
+ for (let i2 = 0; i2 < 18; i2++) {
102105
+ const mid = (lo2 + hi) / 2;
102106
+ const { a: a3, b: b4 } = oklchToOklab(L3, mid, h2);
102107
+ const { r: r5, g: g3, b: bb2 } = oklabToSrgb(L3, a3, b4);
102108
+ if (inSRGB(r5, g3, bb2)) {
102109
+ best = mid;
102110
+ lo2 = mid;
102111
+ } else {
102112
+ hi = mid;
102113
+ }
102114
+ }
102115
+ const { a: a2, b: b3 } = oklchToOklab(L3, best, h2);
102116
+ const { r: r4, g: g2, b: bb } = oklabToSrgb(L3, a2, b3);
102117
+ return rgbToHex(r4, g2, bb);
102118
+ }
102119
+ function featuresFromHex(hex) {
102120
+ const { r: r4, g: g2, b: b3 } = hexToRgb(hex);
102121
+ const { h: h2, s: s2, l: l2 } = rgbToHsl(r4, g2, b3);
102122
+ const { L: L3, a: a2, b: b22 } = srgbToOklab(r4, g2, b3);
102123
+ const { L: okL, C: okC, h: okH } = oklabToOklch(L3, a2, b22);
102124
+ const max3 = Math.max(r4, g2, b3);
102125
+ const v2 = max3 / 255;
102126
+ const Y2 = 0.2126 * srgbToLinear(r4) + 0.7152 * srgbToLinear(g2) + 0.0722 * srgbToLinear(b3);
102127
+ const chroma = s2;
102128
+ return { r: r4, g: g2, b: b3, h: h2, s: s2, l: l2, v: v2, Y: Y2, chroma, okL, okC, okH, hex };
102129
+ }
102130
+ var clamp01, mod, deg;
102131
+ var init_colorConversion = __esm({
102132
+ "../theme-core/src/palette/utils/colorConversion.ts"() {
102133
+ clamp01 = (x2) => Math.max(0, Math.min(1, x2));
102134
+ mod = (a2, n3) => (a2 % n3 + n3) % n3;
102135
+ deg = (x2) => mod(x2, 360);
102136
+ }
102137
+ });
102138
+
102139
+ // ../theme-core/src/palette/utils/contrast.ts
102140
+ function relativeLuminance(r4, g2, b3) {
102141
+ const R3 = srgbToLinear(r4), G2 = srgbToLinear(g2), B = srgbToLinear(b3);
102142
+ return 0.2126 * R3 + 0.7152 * G2 + 0.0722 * B;
102143
+ }
102144
+ function contrastRatio(hex1, hex2) {
102145
+ const { r: r1, g: g1, b: b1 } = hexToRgb(hex1);
102146
+ const { r: r22, g: g2, b: b22 } = hexToRgb(hex2);
102147
+ const L1 = relativeLuminance(r1, g1, b1);
102148
+ const L22 = relativeLuminance(r22, g2, b22);
102149
+ const [hi, lo2] = L1 >= L22 ? [L1, L22] : [L22, L1];
102150
+ return (hi + 0.05) / (lo2 + 0.05);
102151
+ }
102152
+ var init_contrast2 = __esm({
102153
+ "../theme-core/src/palette/utils/contrast.ts"() {
102154
+ init_colorConversion();
102155
+ }
102156
+ });
102157
+
102158
+ // ../theme-core/src/palette/utils/onColor.ts
102159
+ function onColorTokenName(backgroundToken) {
102160
+ return `on${backgroundToken.split("-").filter((part) => part.length > 0).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("")}`;
102161
+ }
102162
+ function isOnColorBackgroundCandidateToken(token) {
102163
+ const role = token.match(/^(.*?)(?:-\d{2,3})?$/)?.[1] ?? token;
102164
+ return BACKGROUND_ROLE_NAMES.has(role);
102165
+ }
102166
+ var BACKGROUND_ROLE_NAMES;
102167
+ var init_onColor = __esm({
102168
+ "../theme-core/src/palette/utils/onColor.ts"() {
102169
+ BACKGROUND_ROLE_NAMES = /* @__PURE__ */ new Set([
102170
+ "primary",
102171
+ "secondary",
102172
+ "accent",
102173
+ "success",
102174
+ "warning",
102175
+ "destructive",
102176
+ "info",
102177
+ "background",
102178
+ "surface",
102179
+ "surfaceAlt",
102180
+ "muted",
102181
+ "neutral"
102182
+ ]);
102183
+ }
102184
+ });
102185
+
102186
+ // ../theme-core/src/site-styles/accessibleSurfaces.ts
102187
+ function toAccessibleColorSurfaceIntent(surface) {
102188
+ switch (surface) {
102189
+ case "base":
102190
+ case "muted-band":
102191
+ case "accent-band":
102192
+ case "brand-depth-band":
102193
+ return surface;
102194
+ case "hero-image":
102195
+ return null;
102196
+ default:
102197
+ return assertNeverSurface(surface);
102198
+ }
102199
+ }
102200
+ function resolveAccessibleSurface(input) {
102201
+ const rejectedCandidates = [];
102202
+ const recipe = surfaceRecipes[input.surface];
102203
+ const threshold = contrastThresholdByPolicy[input.policy ?? "body-aa"];
102204
+ for (const backgroundToken of recipe.backgroundCandidates) {
102205
+ const backgroundHex = readPaletteHex(input.palette, backgroundToken);
102206
+ if (!backgroundHex) {
102207
+ rejectedCandidates.push({
102208
+ kind: "background-candidate",
102209
+ token: backgroundToken,
102210
+ reason: "missing-token"
102211
+ });
102212
+ continue;
102213
+ }
102214
+ const heading = resolveRequiredForeground({
102215
+ role: "heading",
102216
+ candidates: recipe.headingCandidates,
102217
+ backgroundToken,
102218
+ backgroundHex,
102219
+ palette: input.palette,
102220
+ threshold,
102221
+ rejectedCandidates
102222
+ });
102223
+ const text2 = resolveRequiredForeground({
102224
+ role: "text",
102225
+ candidates: recipe.textCandidates,
102226
+ backgroundToken,
102227
+ backgroundHex,
102228
+ palette: input.palette,
102229
+ threshold,
102230
+ rejectedCandidates
102231
+ });
102232
+ if (!heading || !text2) continue;
102233
+ const supporting = resolveSupportingForeground({
102234
+ candidates: recipe.supportingCandidates,
102235
+ backgroundToken,
102236
+ backgroundHex,
102237
+ text: text2,
102238
+ palette: input.palette,
102239
+ threshold,
102240
+ rejectedCandidates
102241
+ });
102242
+ return {
102243
+ kind: "resolved-accessible-surface",
102244
+ surface: input.surface,
102245
+ background: {
102246
+ token: asAccessibleSurfaceToken(backgroundToken),
102247
+ hex: backgroundHex,
102248
+ inherited: recipe.inheritedBackground
102249
+ },
102250
+ heading,
102251
+ text: text2,
102252
+ supporting,
102253
+ rejectedCandidates
102254
+ };
102255
+ }
102256
+ return {
102257
+ kind: "accessible-surface-resolution-failure",
102258
+ surface: input.surface,
102259
+ reason: surfaceResolutionFailureReason(rejectedCandidates),
102260
+ rejectedCandidates
102261
+ };
102262
+ }
102263
+ function resolveAccessibleSurfaceOrTerminalFallback(input) {
102264
+ const result = resolveAccessibleSurface(input);
102265
+ if (result.kind === "resolved-accessible-surface") {
102266
+ return result;
102267
+ }
102268
+ return terminalFallbackSurface({
102269
+ surface: input.surface,
102270
+ rejectedCandidates: result.rejectedCandidates
102271
+ });
102272
+ }
102273
+ function resolveRequiredForeground(input) {
102274
+ return resolveSafeToken({
102275
+ role: input.role,
102276
+ candidates: input.candidates,
102277
+ backgroundToken: input.backgroundToken,
102278
+ backgroundHex: input.backgroundHex,
102279
+ palette: input.palette,
102280
+ threshold: input.threshold,
102281
+ rejectedCandidates: input.rejectedCandidates
102282
+ });
102283
+ }
102284
+ function resolveSupportingForeground(input) {
102285
+ const resolved = resolveSafeToken({
102286
+ role: "supporting",
102287
+ candidates: input.candidates,
102288
+ backgroundToken: input.backgroundToken,
102289
+ backgroundHex: input.backgroundHex,
102290
+ palette: input.palette,
102291
+ threshold: input.threshold,
102292
+ rejectedCandidates: input.rejectedCandidates
102293
+ });
102294
+ if (resolved) return resolved;
102295
+ return {
102296
+ kind: "fallback-to-text",
102297
+ role: "supporting",
102298
+ token: input.text.token,
102299
+ hex: input.text.hex,
102300
+ contrastRatio: input.text.contrastRatio,
102301
+ reason: "supporting-token-unsafe"
102302
+ };
102303
+ }
102304
+ function resolveSafeToken(input) {
102305
+ for (const candidate of expandForegroundCandidates(input.candidates, input.backgroundToken)) {
102306
+ const foregroundHex = readPaletteHex(input.palette, candidate);
102307
+ if (!foregroundHex) {
102308
+ input.rejectedCandidates.push({
102309
+ kind: "foreground-candidate",
102310
+ role: input.role,
102311
+ token: candidate,
102312
+ reason: "missing-token"
102313
+ });
102314
+ continue;
102315
+ }
102316
+ const ratio2 = contrastRatio(foregroundHex, input.backgroundHex);
102317
+ if (ratio2 < input.threshold) {
102318
+ input.rejectedCandidates.push({
102319
+ kind: "foreground-candidate",
102320
+ role: input.role,
102321
+ token: candidate,
102322
+ reason: "contrast-too-low",
102323
+ contrastRatio: ratio2
102324
+ });
102325
+ continue;
102326
+ }
102327
+ return {
102328
+ kind: "safe-token",
102329
+ role: input.role,
102330
+ token: asAccessibleSurfaceToken(candidate),
102331
+ hex: foregroundHex,
102332
+ contrastRatio: ratio2
102333
+ };
102334
+ }
102335
+ return null;
102336
+ }
102337
+ function expandForegroundCandidates(candidates, backgroundToken) {
102338
+ const seen = /* @__PURE__ */ new Set();
102339
+ const expanded = [];
102340
+ for (const candidate of candidates) {
102341
+ const token = expandForegroundCandidate(candidate, backgroundToken);
102342
+ if (seen.has(token)) continue;
102343
+ seen.add(token);
102344
+ expanded.push(token);
102345
+ }
102346
+ return expanded;
102347
+ }
102348
+ function expandForegroundCandidate(candidate, backgroundToken) {
102349
+ if (typeof candidate === "string") {
102350
+ return candidate;
102351
+ }
102352
+ switch (candidate.kind) {
102353
+ case "on-background":
102354
+ return onColorTokenName(backgroundToken);
102355
+ }
102356
+ }
102357
+ function readPaletteHex(palette, token) {
102358
+ const value = palette[token];
102359
+ return typeof value === "string" && value.trim().length > 0 ? value : null;
102360
+ }
102361
+ function asAccessibleSurfaceToken(token) {
102362
+ if (token.length === 0) {
102363
+ throw new Error("AccessibleSurfaceToken must be non-empty.");
102364
+ }
102365
+ return token;
102366
+ }
102367
+ function surfaceResolutionFailureReason(rejectedCandidates) {
102368
+ return rejectedCandidates.some((candidate) => candidate.kind === "foreground-candidate") ? "no-safe-foreground-candidate" : "no-background-candidate";
102369
+ }
102370
+ function terminalFallbackSurface(input) {
102371
+ const contrast = contrastRatio(
102372
+ terminalFallbackTokens.foreground,
102373
+ terminalFallbackTokens.background
102374
+ );
102375
+ const foreground = {
102376
+ kind: "safe-token",
102377
+ token: asAccessibleSurfaceToken(terminalFallbackTokens.foreground),
102378
+ hex: terminalFallbackTokens.foreground,
102379
+ contrastRatio: contrast
102380
+ };
102381
+ return {
102382
+ kind: "resolved-accessible-surface",
102383
+ surface: input.surface,
102384
+ background: {
102385
+ token: asAccessibleSurfaceToken(terminalFallbackTokens.background),
102386
+ hex: terminalFallbackTokens.background,
102387
+ inherited: false
102388
+ },
102389
+ heading: {
102390
+ ...foreground,
102391
+ role: "heading"
102392
+ },
102393
+ text: {
102394
+ ...foreground,
102395
+ role: "text"
102396
+ },
102397
+ supporting: {
102398
+ ...foreground,
102399
+ role: "supporting"
102400
+ },
102401
+ rejectedCandidates: input.rejectedCandidates
102402
+ };
102403
+ }
102404
+ function assertNeverSurface(value) {
102405
+ throw new Error(`Unhandled Theme V2 surface intent: ${String(value)}`);
102406
+ }
102407
+ var ON_BACKGROUND, contrastThresholdByPolicy, surfaceRecipes, terminalFallbackTokens;
102408
+ var init_accessibleSurfaces = __esm({
102409
+ "../theme-core/src/site-styles/accessibleSurfaces.ts"() {
102410
+ init_contrast2();
102411
+ init_onColor();
102412
+ ON_BACKGROUND = { kind: "on-background" };
102413
+ contrastThresholdByPolicy = {
102414
+ "body-aa": 4.5,
102415
+ "large-text-aa": 3,
102416
+ decorative: 1
102417
+ };
102418
+ surfaceRecipes = {
102419
+ base: {
102420
+ backgroundCandidates: ["background", "surface"],
102421
+ headingCandidates: ["text", ON_BACKGROUND, "neutral-950", "neutral-50"],
102422
+ textCandidates: ["text", ON_BACKGROUND, "neutral-950", "neutral-50"],
102423
+ supportingCandidates: ["mutedText"],
102424
+ inheritedBackground: true
102425
+ },
102426
+ "muted-band": {
102427
+ backgroundCandidates: ["muted", "surfaceAlt", "surface", "background"],
102428
+ headingCandidates: [ON_BACKGROUND, "text", "neutral-950", "neutral-50"],
102429
+ textCandidates: [ON_BACKGROUND, "text", "neutral-950", "neutral-50"],
102430
+ supportingCandidates: ["mutedText", "secondary", ON_BACKGROUND],
102431
+ inheritedBackground: false
102432
+ },
102433
+ "accent-band": {
102434
+ backgroundCandidates: ["primary", "accent", "secondary"],
102435
+ headingCandidates: [ON_BACKGROUND, "primaryForeground", "background", "surface", "neutral-50", "neutral-950"],
102436
+ textCandidates: [ON_BACKGROUND, "primaryForeground", "background", "surface", "neutral-50", "neutral-950"],
102437
+ supportingCandidates: [ON_BACKGROUND, "primaryForeground", "background", "surface"],
102438
+ inheritedBackground: false
102439
+ },
102440
+ "brand-depth-band": {
102441
+ backgroundCandidates: ["primary-800", "primary-900", "primary-700", "primary"],
102442
+ headingCandidates: [ON_BACKGROUND, "primaryForeground", "background", "surface", "neutral-50", "neutral-950"],
102443
+ textCandidates: [ON_BACKGROUND, "primaryForeground", "background", "surface", "neutral-50", "neutral-950"],
102444
+ supportingCandidates: [ON_BACKGROUND, "primaryForeground", "background", "surface"],
102445
+ inheritedBackground: false
102446
+ }
102447
+ };
102448
+ terminalFallbackTokens = {
102449
+ background: "#ffffff",
102450
+ foreground: "#000000"
102451
+ };
102452
+ }
102453
+ });
102454
+
101971
102455
  // ../theme-core/src/site-styles/appearancePresetResolution.ts
101972
102456
  function assertValidOptionGroups(preset2) {
101973
102457
  preset2.optionGroups?.forEach((group) => {
@@ -105366,7 +105850,7 @@ function getContrastingTextColorToken(backgroundToken, theme) {
105366
105850
  }
105367
105851
  return isLightTheme ? "neutral-50" : "neutral-950";
105368
105852
  }
105369
- var init_contrast2 = __esm({
105853
+ var init_contrast3 = __esm({
105370
105854
  "../theme-core/src/buttons/utils/contrast.ts"() {
105371
105855
  }
105372
105856
  });
@@ -105445,7 +105929,7 @@ function generateDefaultButtonSystem(theme) {
105445
105929
  var BORDER_WIDTH_TO_CLASS_MAP, VALID_CORNER_STYLES, VALID_SHADOW_SIZES;
105446
105930
  var init_generateDefaultButtonSystem = __esm({
105447
105931
  "../theme-core/src/buttons/generateDefaultButtonSystem.ts"() {
105448
- init_contrast2();
105932
+ init_contrast3();
105449
105933
  BORDER_WIDTH_TO_CLASS_MAP = {
105450
105934
  none: "border-0",
105451
105935
  // 0px
@@ -108368,7 +108852,8 @@ function defineCuratedSiteStyle(input) {
108368
108852
  name: input.name,
108369
108853
  description: input.description,
108370
108854
  generationBrief: input.generationBrief,
108371
- selectionKeywords: input.selectionKeywords ?? [],
108855
+ selectionKeywordRules: input.selectionKeywordRules ?? [],
108856
+ siteCreatorSelection: input.siteCreatorSelection ?? { kind: "explicit_only" },
108372
108857
  template: {
108373
108858
  id: asDesignSystemTemplateId(`template:${input.id.replace("site-style:", "")}`),
108374
108859
  name: input.name,
@@ -108415,6 +108900,9 @@ var init_curatedSiteStyles = __esm({
108415
108900
  "site-style:bright-community",
108416
108901
  "site-style:quiet-luxury",
108417
108902
  "site-style:practical-services",
108903
+ "site-style:quiet-practice",
108904
+ "site-style:personal-retreat-journal",
108905
+ "site-style:tactile-workshop",
108418
108906
  "site-style:modern-wellness",
108419
108907
  "site-style:bold-launch",
108420
108908
  "site-style:south-west-twerk-school"
@@ -108598,12 +109086,13 @@ var init_curatedSiteStyles = __esm({
108598
109086
  name: "Quiet Luxury",
108599
109087
  description: "Minimal, confident, and refined for premium experiences and private services.",
108600
109088
  generationBrief: "Use fewer claims, more specificity, and restrained sensory detail. Favor elegant media and low repetition over dense panels.",
108601
- selectionKeywords: [
108602
- "luxury",
108603
- "premium",
108604
- "boutique",
108605
- "bespoke",
108606
- "exclusive"
109089
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 20 },
109090
+ selectionKeywordRules: [
109091
+ { kind: "word", value: "luxury" },
109092
+ { kind: "word", value: "premium" },
109093
+ { kind: "word", value: "boutique" },
109094
+ { kind: "word", value: "bespoke" },
109095
+ { kind: "word", value: "exclusive" }
108607
109096
  ],
108608
109097
  tokenRecipes: {
108609
109098
  palette: "high-contrast",
@@ -108632,13 +109121,14 @@ var init_curatedSiteStyles = __esm({
108632
109121
  name: "Practical Services",
108633
109122
  description: "Efficient, plainspoken, and conversion-focused for trades and everyday services.",
108634
109123
  generationBrief: "Make services, location, trust signals, and contact paths obvious. Keep copy brief and avoid ornate visual treatments.",
108635
- selectionKeywords: [
108636
- "repair",
108637
- "plumb",
108638
- "electric",
108639
- "cleaning",
108640
- "landscap",
108641
- "contractor"
109124
+ siteCreatorSelection: { kind: "primary_goal_support" },
109125
+ selectionKeywordRules: [
109126
+ { kind: "word", value: "repair" },
109127
+ { kind: "substring", value: "plumb" },
109128
+ { kind: "substring", value: "electric" },
109129
+ { kind: "word", value: "cleaning" },
109130
+ { kind: "substring", value: "landscap" },
109131
+ { kind: "substring", value: "contractor" }
108642
109132
  ],
108643
109133
  tokenRecipes: {
108644
109134
  palette: "brand-led",
@@ -108689,18 +109179,134 @@ var init_curatedSiteStyles = __esm({
108689
109179
  paletteChoice("warm-neutral-forest")
108690
109180
  ]
108691
109181
  }),
109182
+ defineCuratedSiteStyle({
109183
+ id: "site-style:quiet-practice",
109184
+ name: "Quiet Practice",
109185
+ description: "Grounded, calm, and practical for small appointment-first practices.",
109186
+ 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.",
109187
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 30 },
109188
+ selectionKeywordRules: [
109189
+ { kind: "substring", value: "massage" },
109190
+ { kind: "word", value: "bodywork" },
109191
+ { kind: "phrase", value: "appointment practice" },
109192
+ { kind: "phrase", value: "appointment-first" },
109193
+ { kind: "substring", value: "practitioner" },
109194
+ { kind: "substring", value: "therap" },
109195
+ { kind: "substring", value: "clinic" },
109196
+ { kind: "phrase", value: "wellness practice" }
109197
+ ],
109198
+ tokenRecipes: {
109199
+ palette: "soft-natural",
109200
+ contrast: "standard",
109201
+ radius: "soft",
109202
+ shadow: "subtle",
109203
+ typography: "clean-sans",
109204
+ spacing: "regular",
109205
+ motion: "subtle"
109206
+ },
109207
+ compositionBudget: quietBudget,
109208
+ recommendedHeaderLookIds: ["practical-utility", "clean-base", "centered-calm"],
109209
+ buttonPersonalityChoices: [
109210
+ buttonChoice("pebble"),
109211
+ buttonChoice("soft-pill"),
109212
+ buttonChoice("editorial-link")
109213
+ ],
109214
+ paletteVariantChoices: [
109215
+ paletteChoice("soft-natural-stone"),
109216
+ paletteChoice("soft-natural-sage"),
109217
+ paletteChoice("warm-neutral-clay")
109218
+ ]
109219
+ }),
109220
+ defineCuratedSiteStyle({
109221
+ id: "site-style:personal-retreat-journal",
109222
+ name: "Personal Retreat Journal",
109223
+ description: "Warm, story-led, and readable for solo practitioners with mixed offers.",
109224
+ 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.",
109225
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 40 },
109226
+ selectionKeywordRules: [
109227
+ { kind: "substring", value: "retreat" },
109228
+ { kind: "phrase", value: "solo practitioner" },
109229
+ { kind: "phrase", value: "personal brand" },
109230
+ { kind: "substring", value: "teacher" },
109231
+ { kind: "substring", value: "coach" },
109232
+ { kind: "phrase", value: "retreat resources" },
109233
+ { kind: "substring", value: "journal" }
109234
+ ],
109235
+ tokenRecipes: {
109236
+ palette: "warm-neutral",
109237
+ contrast: "standard",
109238
+ radius: "soft",
109239
+ shadow: "subtle",
109240
+ typography: "serif-editorial",
109241
+ spacing: "airy",
109242
+ motion: "subtle"
109243
+ },
109244
+ compositionBudget: balancedBudget,
109245
+ recommendedHeaderLookIds: ["editorial-line", "centered-calm", "minimal-transparent"],
109246
+ buttonPersonalityChoices: [
109247
+ buttonChoice("editorial-link"),
109248
+ buttonChoice("soft-pill"),
109249
+ buttonChoice("brushed-wash")
109250
+ ],
109251
+ paletteVariantChoices: [
109252
+ paletteChoice("warm-neutral-forest"),
109253
+ paletteChoice("warm-neutral-clay"),
109254
+ paletteChoice("soft-natural-stone")
109255
+ ]
109256
+ }),
109257
+ defineCuratedSiteStyle({
109258
+ id: "site-style:tactile-workshop",
109259
+ name: "Tactile Workshop",
109260
+ description: "Bright, hands-on, and image-led for maker studios, workshops, and creative classes.",
109261
+ 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.",
109262
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 50 },
109263
+ selectionKeywordRules: [
109264
+ { kind: "substring", value: "ceramic" },
109265
+ { kind: "word", value: "pottery" },
109266
+ { kind: "phrase", value: "maker studio" },
109267
+ { kind: "phrase", value: "craft class" },
109268
+ { kind: "phrase", value: "craft workshop" },
109269
+ { kind: "word", value: "clay" },
109270
+ { kind: "word", value: "kiln" }
109271
+ ],
109272
+ tokenRecipes: {
109273
+ palette: "brand-led",
109274
+ contrast: "standard",
109275
+ radius: "soft",
109276
+ shadow: "subtle",
109277
+ typography: "friendly-sans",
109278
+ spacing: "regular",
109279
+ motion: "subtle"
109280
+ },
109281
+ compositionBudget: balancedBudget,
109282
+ recommendedHeaderLookIds: ["brand-solid", "practical-utility", "clean-base"],
109283
+ recommendedFooterLookIds: ["site-footer-brand-two-band", "footer-muted-grounding"],
109284
+ buttonPersonalityChoices: [
109285
+ buttonChoice("pebble"),
109286
+ buttonChoice("confident-chip"),
109287
+ buttonChoice("ink-stamp"),
109288
+ buttonChoice("editorial-link")
109289
+ ],
109290
+ paletteVariantChoices: [
109291
+ paletteChoice("brand-led-warm"),
109292
+ paletteChoice("brand-led-cool"),
109293
+ paletteChoice("soft-natural-watercolor"),
109294
+ paletteChoice("warm-neutral-clay")
109295
+ ]
109296
+ }),
108692
109297
  defineCuratedSiteStyle({
108693
109298
  id: "site-style:bold-launch",
108694
109299
  name: "Bold Launch",
108695
109300
  description: "High-energy and punchy for launches, campaigns, and creative offers.",
108696
109301
  generationBrief: "Use crisp positioning, bold hero structure, strong calls to action, and confident visual rhythm. Keep it precise, not shouty.",
108697
- selectionKeywords: [
108698
- "launch",
108699
- "campaign",
108700
- "preorder",
108701
- "pre-order",
108702
- "waitlist",
108703
- "drop"
109302
+ siteCreatorSelection: { kind: "site_creator_keyword_heuristic", priority: 10 },
109303
+ selectionKeywordRules: [
109304
+ { kind: "substring", value: "launch" },
109305
+ { kind: "substring", value: "campaign" },
109306
+ { kind: "word", value: "preorder" },
109307
+ { kind: "phrase", value: "pre-order" },
109308
+ { kind: "substring", value: "waitlist" },
109309
+ { kind: "word", value: "drop" }
108704
109310
  ],
108705
109311
  tokenRecipes: {
108706
109312
  palette: "high-contrast",
@@ -108731,15 +109337,6 @@ var init_curatedSiteStyles = __esm({
108731
109337
  name: "South West Twerk School",
108732
109338
  description: "Energetic, editorial, and high-contrast for a branded dance school presence.",
108733
109339
  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.",
108734
- selectionKeywords: [
108735
- "dance",
108736
- "classes",
108737
- "workshop",
108738
- "school",
108739
- "movement",
108740
- "performance",
108741
- "community"
108742
- ],
108743
109340
  tokenRecipes: {
108744
109341
  palette: "brand-led",
108745
109342
  contrast: "maximum",
@@ -109501,6 +110098,173 @@ var init_modern_minimal = __esm({
109501
110098
  }
109502
110099
  });
109503
110100
 
110101
+ // ../theme-core/src/palette/generateShades.ts
110102
+ function generateShades(hexColor, name) {
110103
+ const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
110104
+ const base2 = featuresFromHex(hexColor);
110105
+ const hue = base2.okH;
110106
+ const baseChroma = base2.okC;
110107
+ const toneMap = {
110108
+ 50: 0.975,
110109
+ 100: 0.945,
110110
+ 200: 0.89,
110111
+ 300: 0.82,
110112
+ 400: 0.74,
110113
+ 500: 0.66,
110114
+ 600: 0.58,
110115
+ 700: 0.49,
110116
+ 800: 0.4,
110117
+ 900: 0.28,
110118
+ 950: 0.16
110119
+ };
110120
+ const shadeDefs = shadeSteps.map((step, idx) => {
110121
+ const t3 = idx / (shadeSteps.length - 1);
110122
+ const L3 = toneMap[step];
110123
+ const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t3);
110124
+ const C2 = baseChroma * chromaFactor;
110125
+ return {
110126
+ name: `${name}-${step}`,
110127
+ hex: oklchToHexGamut(L3, C2, hue)
110128
+ };
110129
+ });
110130
+ shadeDefs.push({ name, hex: hexColor });
110131
+ return shadeDefs;
110132
+ }
110133
+ var init_generateShades = __esm({
110134
+ "../theme-core/src/palette/generateShades.ts"() {
110135
+ init_colorConversion();
110136
+ }
110137
+ });
110138
+
110139
+ // ../theme-core/src/palette/neutralScale.ts
110140
+ function generateNeutralScale({
110141
+ background,
110142
+ steps: steps2 = 11,
110143
+ warm = false
110144
+ }) {
110145
+ const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
110146
+ const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
110147
+ const count3 = Math.min(steps2, shadeNames.length);
110148
+ const scale = [];
110149
+ for (let i2 = 0; i2 < count3; i2++) {
110150
+ const t3 = i2 / (count3 - 1);
110151
+ const tone = isDark ? mix(0.06, 0.92, t3) : mix(0.98, 0.1, t3);
110152
+ const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
110153
+ const name = `neutral-${shadeNames[i2]}`;
110154
+ scale.push({ name, hex });
110155
+ }
110156
+ return scale;
110157
+ }
110158
+ function mix(a2, b3, t3) {
110159
+ return a2 + (b3 - a2) * Math.max(0, Math.min(1, t3));
110160
+ }
110161
+ var init_neutralScale = __esm({
110162
+ "../theme-core/src/palette/neutralScale.ts"() {
110163
+ init_colorConversion();
110164
+ }
110165
+ });
110166
+
110167
+ // ../theme-core/src/palette/utils/textColor.ts
110168
+ function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
110169
+ const { r: r4, g: g2, b: b3 } = parseColorToRgb(background);
110170
+ const luminance = relativeLuminance(r4, g2, b3);
110171
+ const blackContrast = (luminance + 0.05) / 0.05;
110172
+ const whiteContrast = 1.05 / (luminance + 0.05);
110173
+ if (blackContrast >= minContrast && whiteContrast < minContrast) {
110174
+ return "#000000";
110175
+ }
110176
+ if (whiteContrast >= minContrast && blackContrast < minContrast) {
110177
+ return "#FFFFFF";
110178
+ }
110179
+ return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
110180
+ }
110181
+ function getTextColorForBackground(background) {
110182
+ return pickBlackOrWhiteTextColor(background);
110183
+ }
110184
+ function parseColorToRgb(input) {
110185
+ const trimmed = input.trim();
110186
+ if (trimmed.startsWith("#")) {
110187
+ return hexToRgb(trimmed);
110188
+ }
110189
+ const rgbMatch = trimmed.match(
110190
+ /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
110191
+ );
110192
+ if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
110193
+ return {
110194
+ r: clamp255(Number(rgbMatch[1])),
110195
+ g: clamp255(Number(rgbMatch[2])),
110196
+ b: clamp255(Number(rgbMatch[3]))
110197
+ };
110198
+ }
110199
+ throw new Error("Unsupported color format");
110200
+ }
110201
+ function clamp255(value) {
110202
+ if (Number.isNaN(value)) return 0;
110203
+ return Math.max(0, Math.min(255, value));
110204
+ }
110205
+ var init_textColor = __esm({
110206
+ "../theme-core/src/palette/utils/textColor.ts"() {
110207
+ init_colorConversion();
110208
+ init_contrast2();
110209
+ }
110210
+ });
110211
+
110212
+ // ../theme-core/src/palette/expandPalette.ts
110213
+ function colorsToMap(palette) {
110214
+ const map2 = {};
110215
+ for (const c4 of palette.colors) {
110216
+ map2[c4.name] = c4.hex;
110217
+ }
110218
+ return map2;
110219
+ }
110220
+ function isBackgroundDark(hex) {
110221
+ try {
110222
+ return featuresFromHex(hex).Y < 0.5;
110223
+ } catch {
110224
+ return false;
110225
+ }
110226
+ }
110227
+ function expandPalette(palette) {
110228
+ const base2 = colorsToMap(palette);
110229
+ const expanded = { ...base2 };
110230
+ const background = base2.background || base2.surface || "#ffffff";
110231
+ const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
110232
+ neutral2.forEach((n3) => {
110233
+ expanded[n3.name] = n3.hex;
110234
+ });
110235
+ for (const [name, hex] of Object.entries(base2)) {
110236
+ if (hex) {
110237
+ const shades = generateShades(hex, name);
110238
+ shades.forEach((shade) => {
110239
+ expanded[shade.name] = shade.hex;
110240
+ });
110241
+ }
110242
+ }
110243
+ if (base2.text) expanded.body = base2.text;
110244
+ if (base2.danger && !base2.destructive) {
110245
+ expanded.destructive = base2.danger;
110246
+ }
110247
+ const isDark = base2.background ? isBackgroundDark(base2.background) : false;
110248
+ const isDarkMode = palette.meta?.mode === "dark" || isDark;
110249
+ expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
110250
+ for (const [token, hex] of Object.entries({ ...expanded })) {
110251
+ if (!hex || !isOnColorBackgroundCandidateToken(token)) continue;
110252
+ const onToken = onColorTokenName(token);
110253
+ if (expanded[onToken]) continue;
110254
+ expanded[onToken] = getTextColorForBackground(hex);
110255
+ }
110256
+ return expanded;
110257
+ }
110258
+ var init_expandPalette = __esm({
110259
+ "../theme-core/src/palette/expandPalette.ts"() {
110260
+ init_generateShades();
110261
+ init_neutralScale();
110262
+ init_colorConversion();
110263
+ init_textColor();
110264
+ init_onColor();
110265
+ }
110266
+ });
110267
+
109504
110268
  // ../theme-core/src/site-styles/rawStyleFields.ts
109505
110269
  function isThemeV2NormalEditorRawStyleFieldName(fieldName) {
109506
110270
  return themeV2NormalEditorRawStyleFieldNameSet.has(fieldName);
@@ -109681,6 +110445,15 @@ function stripCompiledRuntimeStyleFields(content) {
109681
110445
  )
109682
110446
  );
109683
110447
  }
110448
+ function surfaceResolutionContextFromPalette(palette) {
110449
+ return {
110450
+ kind: "concrete-palette",
110451
+ palette
110452
+ };
110453
+ }
110454
+ function surfaceResolutionContextFromTheme(theme) {
110455
+ return surfaceResolutionContextFromPalette(expandPalette(theme.palette));
110456
+ }
109684
110457
  function defineDesignRuntimeRules(rules) {
109685
110458
  return rules;
109686
110459
  }
@@ -109696,7 +110469,9 @@ function resolveVisualSectionSurface(requestedSurface, contentFrame) {
109696
110469
  function compileSectionStyles(input) {
109697
110470
  const rule2 = input.rules.sectionSurfaces[input.surface];
109698
110471
  const background = compileSectionBackground({
110472
+ surface: input.surface,
109699
110473
  background: rule2.background,
110474
+ surfaceResolutionContext: input.surfaceResolutionContext,
109700
110475
  heroLegibility: input.heroLegibility,
109701
110476
  imageSurfaceTreatment: input.imageSurfaceTreatment,
109702
110477
  imageSurfaceMotion: input.imageSurfaceMotion,
@@ -109724,7 +110499,11 @@ function sectionMinHeightForIntent(sectionHeight, surface) {
109724
110499
  }
109725
110500
  function compileSectionBackground(input) {
109726
110501
  if (!input.background || input.background.type !== "image") {
109727
- return input.background;
110502
+ return compileColorSectionBackground(
110503
+ input.surface,
110504
+ input.background,
110505
+ input.surfaceResolutionContext
110506
+ );
109728
110507
  }
109729
110508
  const treatmentBackground = compileImageSurfaceTreatmentBackground(
109730
110509
  input.background,
@@ -109738,6 +110517,28 @@ function compileSectionBackground(input) {
109738
110517
  overlay: input.heroLegibility === "none" ? null : input.rules.heroLegibility[input.heroLegibility]
109739
110518
  }, input.imageSurfaceMotion);
109740
110519
  }
110520
+ function compileColorSectionBackground(surface, background, surfaceResolutionContext) {
110521
+ if (!background || background.type !== "color") {
110522
+ return background;
110523
+ }
110524
+ const accessibleSurface = toAccessibleColorSurfaceIntent(surface);
110525
+ if (!accessibleSurface) {
110526
+ return background;
110527
+ }
110528
+ const resolved = resolveAccessibleSurfaceOrTerminalFallback({
110529
+ surface: accessibleSurface,
110530
+ palette: surfaceResolutionContext.palette
110531
+ });
110532
+ if (resolved.background.inherited) {
110533
+ return void 0;
110534
+ }
110535
+ return {
110536
+ ...background,
110537
+ color: resolved.background.token,
110538
+ textColor: resolved.text.token,
110539
+ headingColor: resolved.heading.token
110540
+ };
110541
+ }
109741
110542
  function withImageSurfaceMotion(background, motion2) {
109742
110543
  return motion2 === "static" ? background : {
109743
110544
  ...background,
@@ -109903,6 +110704,7 @@ function compileBlockRuntimeFields(input) {
109903
110704
  _sectionStyles: compileSectionStyles({
109904
110705
  surface: visualSectionSurface,
109905
110706
  spacing: sectionSpacing,
110707
+ surfaceResolutionContext: input.surfaceResolutionContext,
109906
110708
  rules: designRules,
109907
110709
  sectionHeight: input.block.appliedSectionHeight,
109908
110710
  heroLegibility: input.block.appliedHeroLegibility,
@@ -109922,6 +110724,7 @@ function compilePageRuntimeFields(input) {
109922
110724
  return {
109923
110725
  blocks: input.resolved.blocks.map((block, index2) => compileBlockRuntimeFields({
109924
110726
  block,
110727
+ surfaceResolutionContext: input.surfaceResolutionContext,
109925
110728
  designRules: input.designRules,
109926
110729
  componentRules: input.componentRules,
109927
110730
  sectionSpacing: input.sectionSpacing,
@@ -110038,10 +110841,12 @@ var init_runtimeCompiler = __esm({
110038
110841
  "../theme-core/src/site-styles/runtimeCompiler.ts"() {
110039
110842
  init_schema4();
110040
110843
  init_modern_minimal();
110844
+ init_expandPalette();
110041
110845
  init_personalities();
110042
110846
  init_variants();
110043
110847
  init_designState();
110044
110848
  init_types5();
110849
+ init_accessibleSurfaces();
110045
110850
  compiledRuntimeStyleFieldNames = [
110046
110851
  "_frameStyles",
110047
110852
  "_sectionStyles",
@@ -110055,25 +110860,19 @@ var init_runtimeCompiler = __esm({
110055
110860
  "muted-band": {
110056
110861
  background: {
110057
110862
  type: "color",
110058
- color: "muted",
110059
- textColor: "text",
110060
- headingColor: "text"
110863
+ color: "muted"
110061
110864
  }
110062
110865
  },
110063
110866
  "accent-band": {
110064
110867
  background: {
110065
110868
  type: "color",
110066
- color: "primary",
110067
- textColor: "primaryForeground",
110068
- headingColor: "primaryForeground"
110869
+ color: "primary"
110069
110870
  }
110070
110871
  },
110071
110872
  "brand-depth-band": {
110072
110873
  background: {
110073
110874
  type: "color",
110074
- color: "primary-800",
110075
- textColor: "primaryForeground",
110076
- headingColor: "primaryForeground"
110875
+ color: "primary-800"
110077
110876
  }
110078
110877
  },
110079
110878
  "hero-image": {
@@ -110473,6 +111272,7 @@ function compileEditorModelRuntime(input) {
110473
111272
  blocks,
110474
111273
  capabilities: runtimeCapabilitiesForBlocks(blocks)
110475
111274
  }),
111275
+ surfaceResolutionContext: input.surfaceResolutionContext,
110476
111276
  designRules: input.designRules,
110477
111277
  componentRules: input.componentRules,
110478
111278
  sectionSpacing: input.sectionSpacing
@@ -110895,6 +111695,7 @@ var init_tokenRecipes = __esm({
110895
111695
  // ../theme-core/src/site-styles/index.ts
110896
111696
  var init_site_styles = __esm({
110897
111697
  "../theme-core/src/site-styles/index.ts"() {
111698
+ init_accessibleSurfaces();
110898
111699
  init_appearancePresets();
110899
111700
  init_blockFlow();
110900
111701
  init_compositionBudget();
@@ -117438,7 +118239,7 @@ var init_faq = __esm({
117438
118239
  };
117439
118240
  }
117440
118241
  });
117441
- var uppercaseTransform, fallbackTransform, dateFormatShort, arrayLengthTransform, jsonArrayTransform, marqueeLoopOptionsSchema, marqueeLoopTransform, formattingTransforms;
118242
+ var uppercaseTransform, fallbackTransform, dateFormatShort, arrayLengthTransform, jsonArrayTransform, csvTransform, marqueeLoopOptionsSchema, marqueeLoopTransform, formattingTransforms;
117442
118243
  var init_formatting = __esm({
117443
118244
  "../blocks/src/system/transforms/registry/formatting.ts"() {
117444
118245
  uppercaseTransform = {
@@ -117498,6 +118299,16 @@ var init_formatting = __esm({
117498
118299
  return "";
117499
118300
  }
117500
118301
  };
118302
+ csvTransform = {
118303
+ id: "value.csv",
118304
+ kind: "formatter",
118305
+ summary: "Normalize a string or array of strings into a comma-separated list",
118306
+ run: (value) => {
118307
+ const rawValues = Array.isArray(value) ? value : typeof value === "string" ? value.split(",") : [];
118308
+ const normalized = rawValues.filter((item) => typeof item === "string").map((item) => item.trim()).filter(Boolean);
118309
+ return normalized.length > 0 ? Array.from(new Set(normalized)).join(",") : "";
118310
+ }
118311
+ };
117501
118312
  marqueeLoopOptionsSchema = z.object({
117502
118313
  minItems: z.number().int().min(1).default(10)
117503
118314
  });
@@ -117523,6 +118334,7 @@ var init_formatting = __esm({
117523
118334
  dateFormatShort,
117524
118335
  arrayLengthTransform,
117525
118336
  jsonArrayTransform,
118337
+ csvTransform,
117526
118338
  marqueeLoopTransform
117527
118339
  ];
117528
118340
  }
@@ -118012,120 +118824,6 @@ var init_ui = __esm({
118012
118824
  ];
118013
118825
  }
118014
118826
  });
118015
-
118016
- // ../theme-core/src/palette/utils/colorConversion.ts
118017
- function hexToRgb(hex) {
118018
- const h2 = hex.replace(/^#/, "");
118019
- const m2 = h2.length === 3 ? h2.split("").map((c4) => c4 + c4).join("") : h2;
118020
- if (m2.length !== 6) throw new Error("Bad hex");
118021
- const int = parseInt(m2, 16);
118022
- return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
118023
- }
118024
- function rgbToHex(r4, g2, b3) {
118025
- const to2 = (n3) => Math.round(n3).toString(16).padStart(2, "0");
118026
- return `#${to2(r4)}${to2(g2)}${to2(b3)}`;
118027
- }
118028
- function srgbToLinear(u3) {
118029
- const x2 = u3 / 255;
118030
- return x2 <= 0.04045 ? x2 / 12.92 : Math.pow((x2 + 0.055) / 1.055, 2.4);
118031
- }
118032
- function linearToSrgb(x2) {
118033
- const y2 = x2 <= 31308e-7 ? 12.92 * x2 : 1.055 * Math.pow(x2, 1 / 2.4) - 0.055;
118034
- return clamp01(y2) * 255;
118035
- }
118036
- function rgbToHsl(r4, g2, b3) {
118037
- const R3 = r4 / 255, G2 = g2 / 255, B = b3 / 255;
118038
- const max3 = Math.max(R3, G2, B), min3 = Math.min(R3, G2, B);
118039
- const d2 = max3 - min3;
118040
- let h2 = 0;
118041
- if (d2 !== 0) {
118042
- switch (max3) {
118043
- case R3:
118044
- h2 = (G2 - B) / d2 + (G2 < B ? 6 : 0);
118045
- break;
118046
- case G2:
118047
- h2 = (B - R3) / d2 + 2;
118048
- break;
118049
- case B:
118050
- h2 = (R3 - G2) / d2 + 4;
118051
- break;
118052
- }
118053
- h2 *= 60;
118054
- }
118055
- const l2 = (max3 + min3) / 2;
118056
- const s2 = d2 === 0 ? 0 : d2 / (1 - Math.abs(2 * l2 - 1));
118057
- return { h: h2, s: s2, l: l2 };
118058
- }
118059
- function srgbToOklab(r4, g2, b3) {
118060
- const R3 = srgbToLinear(r4), G2 = srgbToLinear(g2), B = srgbToLinear(b3);
118061
- const l2 = 0.4122214708 * R3 + 0.5363325363 * G2 + 0.0514459929 * B;
118062
- const m2 = 0.2119034982 * R3 + 0.6806995451 * G2 + 0.1073969566 * B;
118063
- const s2 = 0.0883024619 * R3 + 0.2817188376 * G2 + 0.6299787005 * B;
118064
- const l_ = Math.cbrt(l2), m_ = Math.cbrt(m2), s_ = Math.cbrt(s2);
118065
- const L3 = 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_;
118066
- const a2 = 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_;
118067
- const b22 = 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_;
118068
- return { L: L3, a: a2, b: b22 };
118069
- }
118070
- function oklabToSrgb(L3, a2, b3) {
118071
- const l_ = Math.pow(L3 + 0.3963377774 * a2 + 0.2158037573 * b3, 3);
118072
- const m_ = Math.pow(L3 - 0.1055613458 * a2 - 0.0638541728 * b3, 3);
118073
- const s_ = Math.pow(L3 - 0.0894841775 * a2 - 1.291485548 * b3, 3);
118074
- const R3 = 4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_;
118075
- const G2 = -1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_;
118076
- const B = -0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_;
118077
- return { r: linearToSrgb(R3), g: linearToSrgb(G2), b: linearToSrgb(B) };
118078
- }
118079
- function oklabToOklch(L3, a2, b3) {
118080
- const C2 = Math.sqrt(a2 * a2 + b3 * b3);
118081
- const h2 = C2 < 1e-7 ? 0 : deg(Math.atan2(b3, a2) * 180 / Math.PI);
118082
- return { L: L3, C: C2, h: h2 };
118083
- }
118084
- function oklchToOklab(L3, C2, h2) {
118085
- const hr = h2 * Math.PI / 180;
118086
- const a2 = C2 * Math.cos(hr);
118087
- const b3 = C2 * Math.sin(hr);
118088
- return { L: L3, a: a2, b: b3 };
118089
- }
118090
- function inSRGB(r4, g2, b3) {
118091
- return r4 >= 0 && r4 <= 255 && g2 >= 0 && g2 <= 255 && b3 >= 0 && b3 <= 255;
118092
- }
118093
- function oklchToHexGamut(L3, C2, h2) {
118094
- let lo2 = 0, hi = C2, best = 0;
118095
- for (let i2 = 0; i2 < 18; i2++) {
118096
- const mid = (lo2 + hi) / 2;
118097
- const { a: a3, b: b4 } = oklchToOklab(L3, mid, h2);
118098
- const { r: r5, g: g3, b: bb2 } = oklabToSrgb(L3, a3, b4);
118099
- if (inSRGB(r5, g3, bb2)) {
118100
- best = mid;
118101
- lo2 = mid;
118102
- } else {
118103
- hi = mid;
118104
- }
118105
- }
118106
- const { a: a2, b: b3 } = oklchToOklab(L3, best, h2);
118107
- const { r: r4, g: g2, b: bb } = oklabToSrgb(L3, a2, b3);
118108
- return rgbToHex(r4, g2, bb);
118109
- }
118110
- function featuresFromHex(hex) {
118111
- const { r: r4, g: g2, b: b3 } = hexToRgb(hex);
118112
- const { h: h2, s: s2, l: l2 } = rgbToHsl(r4, g2, b3);
118113
- const { L: L3, a: a2, b: b22 } = srgbToOklab(r4, g2, b3);
118114
- const { L: okL, C: okC, h: okH } = oklabToOklch(L3, a2, b22);
118115
- const max3 = Math.max(r4, g2, b3);
118116
- const v2 = max3 / 255;
118117
- const Y2 = 0.2126 * srgbToLinear(r4) + 0.7152 * srgbToLinear(g2) + 0.0722 * srgbToLinear(b3);
118118
- const chroma = s2;
118119
- return { r: r4, g: g2, b: b3, h: h2, s: s2, l: l2, v: v2, Y: Y2, chroma, okL, okC, okH, hex };
118120
- }
118121
- var clamp01, mod, deg;
118122
- var init_colorConversion = __esm({
118123
- "../theme-core/src/palette/utils/colorConversion.ts"() {
118124
- clamp01 = (x2) => Math.max(0, Math.min(1, x2));
118125
- mod = (a2, n3) => (a2 % n3 + n3) % n3;
118126
- deg = (x2) => mod(x2, 360);
118127
- }
118128
- });
118129
118827
  function resolveBackgroundVisualStyles(backgroundColor, tokens, defaultToken = "surface") {
118130
118828
  const backgroundToken = typeof backgroundColor === "string" && backgroundColor.trim().length > 0 ? backgroundColor : defaultToken;
118131
118829
  if (backgroundToken === "transparent") {
@@ -123380,62 +124078,6 @@ var init_utils5 = __esm({
123380
124078
  }
123381
124079
  });
123382
124080
 
123383
- // ../theme-core/src/palette/utils/contrast.ts
123384
- function relativeLuminance(r4, g2, b3) {
123385
- const R3 = srgbToLinear(r4), G2 = srgbToLinear(g2), B = srgbToLinear(b3);
123386
- return 0.2126 * R3 + 0.7152 * G2 + 0.0722 * B;
123387
- }
123388
- var init_contrast3 = __esm({
123389
- "../theme-core/src/palette/utils/contrast.ts"() {
123390
- init_colorConversion();
123391
- }
123392
- });
123393
-
123394
- // ../theme-core/src/palette/utils/textColor.ts
123395
- function pickBlackOrWhiteTextColor(background, minContrast = 4.5) {
123396
- const { r: r4, g: g2, b: b3 } = parseColorToRgb(background);
123397
- const luminance = relativeLuminance(r4, g2, b3);
123398
- const blackContrast = (luminance + 0.05) / 0.05;
123399
- const whiteContrast = 1.05 / (luminance + 0.05);
123400
- if (blackContrast >= minContrast && whiteContrast < minContrast) {
123401
- return "#000000";
123402
- }
123403
- if (whiteContrast >= minContrast && blackContrast < minContrast) {
123404
- return "#FFFFFF";
123405
- }
123406
- return blackContrast >= whiteContrast ? "#000000" : "#FFFFFF";
123407
- }
123408
- function getTextColorForBackground(background) {
123409
- return pickBlackOrWhiteTextColor(background);
123410
- }
123411
- function parseColorToRgb(input) {
123412
- const trimmed = input.trim();
123413
- if (trimmed.startsWith("#")) {
123414
- return hexToRgb(trimmed);
123415
- }
123416
- const rgbMatch = trimmed.match(
123417
- /^rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})(?:\s*,\s*(?:0|1|0?\.\d+))?\s*\)$/i
123418
- );
123419
- if (rgbMatch?.[1] && rgbMatch[2] && rgbMatch[3]) {
123420
- return {
123421
- r: clamp255(Number(rgbMatch[1])),
123422
- g: clamp255(Number(rgbMatch[2])),
123423
- b: clamp255(Number(rgbMatch[3]))
123424
- };
123425
- }
123426
- throw new Error("Unsupported color format");
123427
- }
123428
- function clamp255(value) {
123429
- if (Number.isNaN(value)) return 0;
123430
- return Math.max(0, Math.min(255, value));
123431
- }
123432
- var init_textColor = __esm({
123433
- "../theme-core/src/palette/utils/textColor.ts"() {
123434
- init_colorConversion();
123435
- init_contrast3();
123436
- }
123437
- });
123438
-
123439
124081
  // ../blocks/src/system/media/slotContracts.ts
123440
124082
  function normalizeSlotPath(path) {
123441
124083
  return path.split(".").map((segment) => /^\d+$/.test(segment) ? "[]" : segment).join(".");
@@ -125368,7 +126010,12 @@ var init_event_listing = __esm({
125368
126010
  detailLevel: "listing",
125369
126011
  kind: { $bind: { from: "content.kind" } },
125370
126012
  eventSurface: { $bind: { from: "content.eventSurface" } },
125371
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
126013
+ eventPresets: {
126014
+ $bind: {
126015
+ from: "content.filterEventPresets",
126016
+ transforms: [{ id: "value.csv" }]
126017
+ }
126018
+ },
125372
126019
  scheduleScope: { $bind: { from: "content.scheduleScope" } }
125373
126020
  },
125374
126021
  mode: "server"
@@ -126184,7 +126831,12 @@ var init_event_calendar = __esm({
126184
126831
  // Pass filter params if configured
126185
126832
  kind: { $bind: { from: "content.kind" } },
126186
126833
  eventSurface: { $bind: { from: "content.eventSurface" } },
126187
- eventPresets: { $bind: { from: "content.filterEventPresets" } },
126834
+ eventPresets: {
126835
+ $bind: {
126836
+ from: "content.filterEventPresets",
126837
+ transforms: [{ id: "value.csv" }]
126838
+ }
126839
+ },
126188
126840
  scheduleScope: { $bind: { from: "content.scheduleScope" } },
126189
126841
  categoryIds: { $bind: { from: "content.filterCategoryIds" } },
126190
126842
  staffMemberId: { $bind: { from: "content.filterStaffMemberId" } },
@@ -137472,137 +138124,6 @@ var init_system = __esm({
137472
138124
  }
137473
138125
  });
137474
138126
 
137475
- // ../theme-core/src/palette/generateShades.ts
137476
- function generateShades(hexColor, name) {
137477
- const shadeSteps = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
137478
- const base2 = featuresFromHex(hexColor);
137479
- const hue = base2.okH;
137480
- const baseChroma = base2.okC;
137481
- const toneMap = {
137482
- 50: 0.975,
137483
- 100: 0.945,
137484
- 200: 0.89,
137485
- 300: 0.82,
137486
- 400: 0.74,
137487
- 500: 0.66,
137488
- 600: 0.58,
137489
- 700: 0.49,
137490
- 800: 0.4,
137491
- 900: 0.28,
137492
- 950: 0.16
137493
- };
137494
- const shadeDefs = shadeSteps.map((step, idx) => {
137495
- const t3 = idx / (shadeSteps.length - 1);
137496
- const L3 = toneMap[step];
137497
- const chromaFactor = 0.06 + 0.94 * Math.sin(Math.PI * t3);
137498
- const C2 = baseChroma * chromaFactor;
137499
- return {
137500
- name: `${name}-${step}`,
137501
- hex: oklchToHexGamut(L3, C2, hue)
137502
- };
137503
- });
137504
- shadeDefs.push({ name, hex: hexColor });
137505
- return shadeDefs;
137506
- }
137507
- var init_generateShades = __esm({
137508
- "../theme-core/src/palette/generateShades.ts"() {
137509
- init_colorConversion();
137510
- }
137511
- });
137512
-
137513
- // ../theme-core/src/palette/neutralScale.ts
137514
- function generateNeutralScale({
137515
- background,
137516
- steps: steps2 = 11,
137517
- warm = false
137518
- }) {
137519
- const isDark = background === "#000000" || background.startsWith("#0") || background.startsWith("#1");
137520
- const shadeNames = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
137521
- const count3 = Math.min(steps2, shadeNames.length);
137522
- const scale = [];
137523
- for (let i2 = 0; i2 < count3; i2++) {
137524
- const t3 = i2 / (count3 - 1);
137525
- const tone = isDark ? mix(0.06, 0.92, t3) : mix(0.98, 0.1, t3);
137526
- const hex = oklchToHexGamut(tone, 0.02, warm ? 85 : 250);
137527
- const name = `neutral-${shadeNames[i2]}`;
137528
- scale.push({ name, hex });
137529
- }
137530
- return scale;
137531
- }
137532
- function mix(a2, b3, t3) {
137533
- return a2 + (b3 - a2) * Math.max(0, Math.min(1, t3));
137534
- }
137535
- var init_neutralScale = __esm({
137536
- "../theme-core/src/palette/neutralScale.ts"() {
137537
- init_colorConversion();
137538
- }
137539
- });
137540
-
137541
- // ../theme-core/src/palette/expandPalette.ts
137542
- function colorsToMap(palette) {
137543
- const map2 = {};
137544
- for (const c4 of palette.colors) {
137545
- map2[c4.name] = c4.hex;
137546
- }
137547
- return map2;
137548
- }
137549
- function isBackgroundDark(hex) {
137550
- try {
137551
- return featuresFromHex(hex).Y < 0.5;
137552
- } catch {
137553
- return false;
137554
- }
137555
- }
137556
- function expandPalette(palette) {
137557
- const base2 = colorsToMap(palette);
137558
- const expanded = { ...base2 };
137559
- const background = base2.background || base2.surface || "#ffffff";
137560
- const neutral2 = generateNeutralScale({ background, steps: 11, warm: false });
137561
- neutral2.forEach((n3) => {
137562
- expanded[n3.name] = n3.hex;
137563
- });
137564
- for (const [name, hex] of Object.entries(base2)) {
137565
- if (hex) {
137566
- const shades = generateShades(hex, name);
137567
- shades.forEach((shade) => {
137568
- expanded[shade.name] = shade.hex;
137569
- });
137570
- }
137571
- }
137572
- if (base2.text) expanded.body = base2.text;
137573
- if (base2.danger && !base2.destructive) {
137574
- expanded.destructive = base2.danger;
137575
- }
137576
- const isDark = base2.background ? isBackgroundDark(base2.background) : false;
137577
- const isDarkMode = palette.meta?.mode === "dark" || isDark;
137578
- expanded.mutedText = isDarkMode ? expanded["neutral-600"] ?? "#666" : expanded["neutral-500"] ?? "#888";
137579
- const onRoles = [
137580
- { role: "primary", on: "onPrimary" },
137581
- { role: "secondary", on: "onSecondary" },
137582
- { role: "accent", on: "onAccent" },
137583
- { role: "success", on: "onSuccess" },
137584
- { role: "warning", on: "onWarning" },
137585
- { role: "destructive", on: "onDestructive" },
137586
- { role: "info", on: "onInfo" },
137587
- { role: "surface", on: "onSurface" }
137588
- ];
137589
- for (const { role, on: on2 } of onRoles) {
137590
- const bg = base2[role];
137591
- if (!bg) continue;
137592
- if (expanded[on2]) continue;
137593
- expanded[on2] = getTextColorForBackground(bg);
137594
- }
137595
- return expanded;
137596
- }
137597
- var init_expandPalette = __esm({
137598
- "../theme-core/src/palette/expandPalette.ts"() {
137599
- init_generateShades();
137600
- init_neutralScale();
137601
- init_colorConversion();
137602
- init_textColor();
137603
- }
137604
- });
137605
-
137606
138127
  // ../theme-core/src/runtime/fontFamily.ts
137607
138128
  function isGenericFamily(font) {
137608
138129
  return GENERIC_CSS_FAMILIES.includes(font.toLowerCase());
@@ -141961,7 +142482,7 @@ var init_vibrant_creative = __esm({
141961
142482
  var init_colorPlacement = __esm({
141962
142483
  "../theme-core/src/palette/utils/colorPlacement.ts"() {
141963
142484
  init_colorConversion();
141964
- init_contrast3();
142485
+ init_contrast2();
141965
142486
  }
141966
142487
  });
141967
142488
 
@@ -142079,7 +142600,7 @@ var init_allRecipes = __esm({
142079
142600
  // ../theme-core/src/palette/utils/legs.ts
142080
142601
  var init_legs = __esm({
142081
142602
  "../theme-core/src/palette/utils/legs.ts"() {
142082
- init_contrast3();
142603
+ init_contrast2();
142083
142604
  init_colorConversion();
142084
142605
  }
142085
142606
  });
@@ -142097,7 +142618,7 @@ var init_generatePalette = __esm({
142097
142618
  "../theme-core/src/palette/utils/generatePalette.ts"() {
142098
142619
  init_backgroundGeneration();
142099
142620
  init_colorConversion();
142100
- init_contrast3();
142621
+ init_contrast2();
142101
142622
  init_legs();
142102
142623
  init_supportRoles();
142103
142624
  }
@@ -142115,7 +142636,7 @@ var init_suggestRecipes = __esm({
142115
142636
  "../theme-core/src/palette/utils/suggestRecipes.ts"() {
142116
142637
  init_allRecipes();
142117
142638
  init_colorConversion();
142118
- init_contrast3();
142639
+ init_contrast2();
142119
142640
  init_generatePalette();
142120
142641
  init_classifyColor();
142121
142642
  }
@@ -142124,7 +142645,7 @@ var init_suggestRecipes = __esm({
142124
142645
  // ../theme-core/src/palette/utils/legibility.ts
142125
142646
  var init_legibility = __esm({
142126
142647
  "../theme-core/src/palette/utils/legibility.ts"() {
142127
- init_contrast3();
142648
+ init_contrast2();
142128
142649
  }
142129
142650
  });
142130
142651
 
@@ -142132,13 +142653,14 @@ var init_legibility = __esm({
142132
142653
  var init_utils6 = __esm({
142133
142654
  "../theme-core/src/palette/utils/index.ts"() {
142134
142655
  init_colorConversion();
142135
- init_contrast3();
142656
+ init_contrast2();
142136
142657
  init_colorPlacement();
142137
142658
  init_backgroundGeneration();
142138
142659
  init_suggestRecipes();
142139
142660
  init_generatePalette();
142140
142661
  init_textColor();
142141
142662
  init_legibility();
142663
+ init_onColor();
142142
142664
  }
142143
142665
  });
142144
142666
  var init_swatch = __esm({
@@ -184625,8 +185147,7 @@ var init_contracts2 = __esm({
184625
185147
  dashboardNavVisibilityRolesSchema = z.object({
184626
185148
  administrator: dashboardNavVisibilityBaseSchema.optional(),
184627
185149
  editor: dashboardNavVisibilityBaseSchema.optional(),
184628
- team_member: dashboardNavVisibilityBaseSchema.optional(),
184629
- event_host: dashboardNavVisibilityBaseSchema.optional()
185150
+ team_member: dashboardNavVisibilityBaseSchema.optional()
184630
185151
  }).strip().optional();
184631
185152
  dashboardNavVisibilitySchema = dashboardNavVisibilityBaseSchema.extend({
184632
185153
  roles: dashboardNavVisibilityRolesSchema
@@ -185422,6 +185943,21 @@ var init_appointmentSetup = __esm({
185422
185943
  timezone: z.string().trim().min(1).nullable(),
185423
185944
  payment: appointmentSetupPaymentDraftSchema,
185424
185945
  assignment: appointmentSetupServiceAssignmentDraftSchema
185946
+ }).superRefine((service, ctx) => {
185947
+ if (service.payment.priceType === "paid" && (service.priceAmount === null || service.priceAmount <= 0)) {
185948
+ ctx.addIssue({
185949
+ code: "custom",
185950
+ path: ["priceAmount"],
185951
+ message: "Paid appointment services need a positive price."
185952
+ });
185953
+ }
185954
+ if (service.payment.priceType === "free" && service.priceAmount !== null && service.priceAmount > 0) {
185955
+ ctx.addIssue({
185956
+ code: "custom",
185957
+ path: ["priceAmount"],
185958
+ message: "Free appointment services cannot carry a positive price."
185959
+ });
185960
+ }
185425
185961
  });
185426
185962
  appointmentSetupPractitionerDraftSchema = z.object({
185427
185963
  ref: appointmentSetupRefSchema,
@@ -211099,6 +211635,7 @@ function PreviewShellLayout({
211099
211635
  minRightWidth: 320,
211100
211636
  leftLabel: "Preview",
211101
211637
  rightLabel: "Editor",
211638
+ defaultTab: "right",
211102
211639
  rightPaneClassName: "h-full min-h-0 overflow-hidden",
211103
211640
  onSplitChange: (split2) => handleSidebarWidthChange(100 - split2),
211104
211641
  splitPercent: 100 - sidebarWidth
@@ -211466,11 +212003,14 @@ function cloneRecord2(value) {
211466
212003
 
211467
212004
  // ../preview-next/src/client/blocks/previewProjection/runtimeContentDecoration.ts
211468
212005
  init_previewCompiler();
211469
- function runtimeContentDecorationProjectionFromEditorModel(editorModel) {
212006
+ function runtimeContentDecorationProjectionFromEditorModel(editorModel, surfaceResolutionContext) {
211470
212007
  return {
211471
212008
  kind: "runtime-content-decoration",
211472
212009
  source: "page-design",
211473
- fieldsByBlockId: buildEditorModelRuntimeFieldsByBlockId({ editorModel })
212010
+ fieldsByBlockId: buildEditorModelRuntimeFieldsByBlockId({
212011
+ editorModel,
212012
+ surfaceResolutionContext
212013
+ })
211474
212014
  };
211475
212015
  }
211476
212016
  function applyRuntimeContentDecorationProjection(block, content, projection) {
@@ -212456,13 +212996,17 @@ function formatBlockKindLabel2(blockKind) {
212456
212996
  // ../preview-next/src/client/blocks/pageDesignRuntimePreview.ts
212457
212997
  function pageDesignRuntimeProjectionFromSource(source) {
212458
212998
  if (source.kind === "preserve-server-runtime") return null;
212459
- return runtimeContentDecorationProjectionFromEditorModel(source.editorModel);
212999
+ return runtimeContentDecorationProjectionFromEditorModel(
213000
+ source.editorModel,
213001
+ source.surfaceResolutionContext
213002
+ );
212460
213003
  }
212461
- function resolveRuntimePreviewSource(pageDesignState) {
212462
- if (pageDesignState.kind === "loaded") {
213004
+ function resolveRuntimePreviewSource(input) {
213005
+ if (input.pageDesignState.kind === "loaded" && input.surfaceResolutionContext) {
212463
213006
  return {
212464
213007
  kind: "apply-editor-model",
212465
- editorModel: pageDesignState.editorModel
213008
+ editorModel: input.pageDesignState.editorModel,
213009
+ surfaceResolutionContext: input.surfaceResolutionContext
212466
213010
  };
212467
213011
  }
212468
213012
  return { kind: "preserve-server-runtime" };
@@ -212490,9 +213034,16 @@ function EditablePageRenderer(props2) {
212490
213034
  () => previewProjectionsFromAiOverlays(uiStore.getState().aiOverlays),
212491
213035
  [uiStore, draftsVersion]
212492
213036
  );
213037
+ const surfaceResolutionContext = useMemo(
213038
+ () => hasThemePalette(props2.theme) ? surfaceResolutionContextFromTheme(props2.theme) : null,
213039
+ [props2.theme]
213040
+ );
212493
213041
  const runtimePreviewSource = useMemo(
212494
- () => resolveRuntimePreviewSource(pageDesignState),
212495
- [pageDesignState]
213042
+ () => resolveRuntimePreviewSource({
213043
+ pageDesignState,
213044
+ surfaceResolutionContext
213045
+ }),
213046
+ [pageDesignState, surfaceResolutionContext]
212496
213047
  );
212497
213048
  const runtimeProjection = useMemo(
212498
213049
  () => pageDesignRuntimeProjectionFromSource(runtimePreviewSource),
@@ -212596,6 +213147,9 @@ function EditablePageRenderer(props2) {
212596
213147
  };
212597
213148
  return /* @__PURE__ */ jsx(PageRenderer, { ...rendererProps });
212598
213149
  }
213150
+ function hasThemePalette(theme) {
213151
+ return Boolean(theme?.palette);
213152
+ }
212599
213153
  function shouldClearHeaderForBlock(blocks, blockIndex) {
212600
213154
  const block = blocks[blockIndex];
212601
213155
  if (block?.kind !== "block.hero") return false;