@aglyn/plugins-ai 1.0.0-beta.269 → 1.0.0-beta.271

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 (237) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.d.ts +1 -1
  3. package/src/lib/activity/ai-activity-actions.js +1 -0
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/assets/site-styles/beauty.webp +0 -0
  6. package/src/lib/assets/site-styles/blog.webp +0 -0
  7. package/src/lib/assets/site-styles/business.webp +0 -0
  8. package/src/lib/assets/site-styles/coming-soon.webp +0 -0
  9. package/src/lib/assets/site-styles/education.webp +0 -0
  10. package/src/lib/assets/site-styles/events.webp +0 -0
  11. package/src/lib/assets/site-styles/fitness.webp +0 -0
  12. package/src/lib/assets/site-styles/landing.webp +0 -0
  13. package/src/lib/assets/site-styles/music.webp +0 -0
  14. package/src/lib/assets/site-styles/nonprofit.webp +0 -0
  15. package/src/lib/assets/site-styles/personal.webp +0 -0
  16. package/src/lib/assets/site-styles/photography.webp +0 -0
  17. package/src/lib/assets/site-styles/portfolio.webp +0 -0
  18. package/src/lib/assets/site-styles/professional.webp +0 -0
  19. package/src/lib/assets/site-styles/realestate.webp +0 -0
  20. package/src/lib/assets/site-styles/restaurant.webp +0 -0
  21. package/src/lib/assets/site-styles/store.webp +0 -0
  22. package/src/lib/assets/site-styles/studio.webp +0 -0
  23. package/src/lib/assets/site-styles/trades.webp +0 -0
  24. package/src/lib/assets/site-styles/wellness.webp +0 -0
  25. package/src/lib/assets/site-styles/yoga.webp +0 -0
  26. package/src/lib/components/ai-credits-card.component.d.ts +8 -6
  27. package/src/lib/components/ai-credits-card.component.js +39 -22
  28. package/src/lib/components/ai-credits-card.component.js.map +1 -1
  29. package/src/lib/components/ai-job-input-form.component.d.ts +36 -0
  30. package/src/lib/components/ai-job-input-form.component.js +100 -0
  31. package/src/lib/components/ai-job-input-form.component.js.map +1 -0
  32. package/src/lib/components/ai-job-links.d.ts +6 -0
  33. package/src/lib/components/ai-job-links.js +9 -0
  34. package/src/lib/components/ai-job-links.js.map +1 -1
  35. package/src/lib/components/ai-job-requests.d.ts +4 -0
  36. package/src/lib/components/ai-job-requests.js +4 -0
  37. package/src/lib/components/ai-job-requests.js.map +1 -1
  38. package/src/lib/components/ai-products-hub-card.component.d.ts +6 -0
  39. package/src/lib/components/ai-products-hub-card.component.js +21 -6
  40. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  41. package/src/lib/components/ai-site-build-page.component.js +3 -2
  42. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  43. package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
  44. package/src/lib/components/ai-site-start-card.component.js +99 -31
  45. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  46. package/src/lib/components/ai-site-start-steps.component.d.ts +43 -2
  47. package/src/lib/components/ai-site-start-steps.component.js +651 -15
  48. package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
  49. package/src/lib/components/ai-site-start-tracking.d.ts +10 -0
  50. package/src/lib/components/ai-site-start-tracking.js +14 -0
  51. package/src/lib/components/ai-site-start-tracking.js.map +1 -1
  52. package/src/lib/components/ai-site-style-previews.js +26 -22
  53. package/src/lib/components/ai-site-style-previews.js.map +1 -1
  54. package/src/lib/components/ai-store-finish-card.component.d.ts +14 -3
  55. package/src/lib/components/ai-store-finish-card.component.js +67 -9
  56. package/src/lib/components/ai-store-finish-card.component.js.map +1 -1
  57. package/src/lib/components/ai-upsell-dialog.component.d.ts +7 -5
  58. package/src/lib/components/ai-upsell-dialog.component.js +8 -6
  59. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
  60. package/src/lib/components/assist-build-card.component.js +14 -3
  61. package/src/lib/components/assist-build-card.component.js.map +1 -1
  62. package/src/lib/components/assist-jobs-drawer.component.js +9 -1
  63. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  64. package/src/lib/components/assist-panel.component.js +8 -4
  65. package/src/lib/components/assist-panel.component.js.map +1 -1
  66. package/src/lib/components/staff-org-ai-card.component.js +4 -7
  67. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  68. package/src/lib/declarations.d.ts +2 -2
  69. package/src/lib/declarations.js +9 -5
  70. package/src/lib/declarations.js.map +1 -1
  71. package/src/lib/jobs/ai-build-capabilities.js +3 -1
  72. package/src/lib/jobs/ai-build-capabilities.js.map +1 -1
  73. package/src/lib/jobs/ai-business-profile-prefill.d.ts +1 -1
  74. package/src/lib/jobs/ai-business-profile-prefill.js +14 -3
  75. package/src/lib/jobs/ai-business-profile-prefill.js.map +1 -1
  76. package/src/lib/jobs/ai-job-build-step.d.ts +3 -0
  77. package/src/lib/jobs/ai-job-build-step.js +13 -5
  78. package/src/lib/jobs/ai-job-build-step.js.map +1 -1
  79. package/src/lib/jobs/ai-job-form-step.d.ts +24 -1
  80. package/src/lib/jobs/ai-job-form-step.js +93 -7
  81. package/src/lib/jobs/ai-job-form-step.js.map +1 -1
  82. package/src/lib/jobs/ai-job-page-language.d.ts +35 -11
  83. package/src/lib/jobs/ai-job-page-language.js +68 -2
  84. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  85. package/src/lib/jobs/ai-job-page-step.d.ts +17 -0
  86. package/src/lib/jobs/ai-job-page-step.js +40 -17
  87. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  88. package/src/lib/jobs/ai-job-plan-step.d.ts +25 -2
  89. package/src/lib/jobs/ai-job-plan-step.js +103 -29
  90. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  91. package/src/lib/jobs/ai-job-settings-step.js +4 -3
  92. package/src/lib/jobs/ai-job-settings-step.js.map +1 -1
  93. package/src/lib/jobs/ai-job-site-datasets.d.ts +27 -0
  94. package/src/lib/jobs/ai-job-site-datasets.js +140 -14
  95. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  96. package/src/lib/jobs/ai-job-site-look.js +18 -5
  97. package/src/lib/jobs/ai-job-site-look.js.map +1 -1
  98. package/src/lib/jobs/ai-job-site-step.d.ts +16 -1
  99. package/src/lib/jobs/ai-job-site-step.js +95 -22
  100. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  101. package/src/lib/jobs/ai-job-text-step.d.ts +8 -1
  102. package/src/lib/jobs/ai-job-text-step.js.map +1 -1
  103. package/src/lib/jobs/ai-job-tracking-step.d.ts +14 -3
  104. package/src/lib/jobs/ai-job-tracking-step.js +28 -5
  105. package/src/lib/jobs/ai-job-tracking-step.js.map +1 -1
  106. package/src/lib/jobs/ai-jobs.d.ts +8 -1
  107. package/src/lib/jobs/ai-jobs.js +63 -8
  108. package/src/lib/jobs/ai-jobs.js.map +1 -1
  109. package/src/lib/jobs/ai-layout-owner-photos.d.ts +57 -0
  110. package/src/lib/jobs/ai-layout-owner-photos.js +110 -0
  111. package/src/lib/jobs/ai-layout-owner-photos.js.map +1 -0
  112. package/src/lib/jobs/ai-layout-stock-photos.d.ts +62 -4
  113. package/src/lib/jobs/ai-layout-stock-photos.js +523 -72
  114. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  115. package/src/lib/jobs/ai-site-inspiration-signals.d.ts +98 -0
  116. package/src/lib/jobs/ai-site-inspiration-signals.js +585 -0
  117. package/src/lib/jobs/ai-site-inspiration-signals.js.map +1 -0
  118. package/src/lib/jobs/ai-site-inspiration.d.ts +157 -0
  119. package/src/lib/jobs/ai-site-inspiration.js +346 -0
  120. package/src/lib/jobs/ai-site-inspiration.js.map +1 -0
  121. package/src/lib/jobs/ai-site-publish.d.ts +26 -1
  122. package/src/lib/jobs/ai-site-publish.js +162 -13
  123. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  124. package/src/lib/jobs/ai-theme-brand-inputs.d.ts +16 -0
  125. package/src/lib/jobs/ai-theme-brand-inputs.js +18 -4
  126. package/src/lib/jobs/ai-theme-brand-inputs.js.map +1 -1
  127. package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.d.ts +97 -0
  128. package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js +137 -0
  129. package/src/lib/jobs/fixtures/ai-candle-shop-free-plan-recording.js.map +1 -0
  130. package/src/lib/jobs/fixtures/ai-site-inspiration-pages.d.ts +38 -0
  131. package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js +103 -0
  132. package/src/lib/jobs/fixtures/ai-site-inspiration-pages.js.map +1 -0
  133. package/src/lib/jobs/fixtures/ai-stock-photo-agl3942-recordings.d.ts +29 -0
  134. package/src/lib/jobs/fixtures/ai-stock-photo-agl3942-recordings.js +291 -0
  135. package/src/lib/jobs/fixtures/ai-stock-photo-agl3942-recordings.js.map +1 -0
  136. package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.d.ts +25 -0
  137. package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js +174 -0
  138. package/src/lib/jobs/fixtures/ai-stock-photo-agl3988-recordings.js.map +1 -0
  139. package/src/lib/layout-language/ai-layout-compiler.d.ts +1 -1
  140. package/src/lib/layout-language/ai-layout-compiler.js +438 -25
  141. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  142. package/src/lib/layout-language/ai-layout-contact.d.ts +57 -0
  143. package/src/lib/layout-language/ai-layout-contact.js +137 -0
  144. package/src/lib/layout-language/ai-layout-contact.js.map +1 -0
  145. package/src/lib/layout-language/ai-layout-copy.d.ts +12 -0
  146. package/src/lib/layout-language/ai-layout-copy.js +34 -2
  147. package/src/lib/layout-language/ai-layout-copy.js.map +1 -1
  148. package/src/lib/layout-language/ai-layout-design.d.ts +65 -8
  149. package/src/lib/layout-language/ai-layout-design.js +411 -97
  150. package/src/lib/layout-language/ai-layout-design.js.map +1 -1
  151. package/src/lib/layout-language/ai-layout-frame.js +23 -0
  152. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  153. package/src/lib/layout-language/ai-layout-labels.d.ts +2 -0
  154. package/src/lib/layout-language/ai-layout-labels.js +12 -6
  155. package/src/lib/layout-language/ai-layout-labels.js.map +1 -1
  156. package/src/lib/layout-language/ai-layout-language.d.ts +3 -2
  157. package/src/lib/layout-language/ai-layout-language.js +4 -3
  158. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  159. package/src/lib/layout-language/ai-layout-links.d.ts +13 -0
  160. package/src/lib/layout-language/ai-layout-links.js +30 -0
  161. package/src/lib/layout-language/ai-layout-links.js.map +1 -1
  162. package/src/lib/layout-language/ai-layout-pictures.d.ts +49 -6
  163. package/src/lib/layout-language/ai-layout-pictures.js +145 -22
  164. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
  165. package/src/lib/model/ai-build-job.d.ts +16 -1
  166. package/src/lib/model/ai-build-job.js +40 -0
  167. package/src/lib/model/ai-build-job.js.map +1 -1
  168. package/src/lib/model/ai-job-input.d.ts +33 -0
  169. package/src/lib/model/ai-job-input.js +59 -0
  170. package/src/lib/model/ai-job-input.js.map +1 -0
  171. package/src/lib/model/ai-job-notice.d.ts +4 -0
  172. package/src/lib/model/ai-job-notice.js +11 -1
  173. package/src/lib/model/ai-job-notice.js.map +1 -1
  174. package/src/lib/model/ai-jobs.types.d.ts +40 -1
  175. package/src/lib/model/ai-jobs.types.js.map +1 -1
  176. package/src/lib/model/ai-site-details.d.ts +122 -0
  177. package/src/lib/model/ai-site-details.js +300 -0
  178. package/src/lib/model/ai-site-details.js.map +1 -0
  179. package/src/lib/model/ai-site-entity.d.ts +181 -0
  180. package/src/lib/model/ai-site-entity.js +390 -0
  181. package/src/lib/model/ai-site-entity.js.map +1 -0
  182. package/src/lib/model/ai-site-inspiration.d.ts +72 -0
  183. package/src/lib/model/ai-site-inspiration.js +109 -0
  184. package/src/lib/model/ai-site-inspiration.js.map +1 -0
  185. package/src/lib/model/ai-site-job.d.ts +13 -1
  186. package/src/lib/model/ai-site-job.js +15 -2
  187. package/src/lib/model/ai-site-job.js.map +1 -1
  188. package/src/lib/model/ai-site-kinds.js +109 -21
  189. package/src/lib/model/ai-site-kinds.js.map +1 -1
  190. package/src/lib/model/ai-site-look.d.ts +10 -0
  191. package/src/lib/model/ai-site-look.js +24 -0
  192. package/src/lib/model/ai-site-look.js.map +1 -1
  193. package/src/lib/model/ai-site-start-seo.d.ts +19 -5
  194. package/src/lib/model/ai-site-start-seo.js +25 -7
  195. package/src/lib/model/ai-site-start-seo.js.map +1 -1
  196. package/src/lib/model/ai-site-start-steps.d.ts +9 -3
  197. package/src/lib/model/ai-site-start-steps.js +67 -5
  198. package/src/lib/model/ai-site-start-steps.js.map +1 -1
  199. package/src/lib/model/ai-site-start.d.ts +68 -4
  200. package/src/lib/model/ai-site-start.js +166 -13
  201. package/src/lib/model/ai-site-start.js.map +1 -1
  202. package/src/lib/model/ai-upsell-copy.js +4 -1
  203. package/src/lib/model/ai-upsell-copy.js.map +1 -1
  204. package/src/lib/native-nav.d.ts +26 -0
  205. package/src/lib/native-nav.js +58 -0
  206. package/src/lib/native-nav.js.map +1 -0
  207. package/src/lib/plan-entitlements.d.ts +4 -3
  208. package/src/lib/plan-entitlements.js +3 -8
  209. package/src/lib/plan-entitlements.js.map +1 -1
  210. package/src/lib/runtime/ai-dataset-generation.d.ts +8 -1
  211. package/src/lib/runtime/ai-dataset-generation.js +12 -2
  212. package/src/lib/runtime/ai-dataset-generation.js.map +1 -1
  213. package/src/lib/runtime/ai-doctrine-validators.d.ts +26 -33
  214. package/src/lib/runtime/ai-doctrine-validators.js +54 -44
  215. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  216. package/src/lib/runtime/ai-doctrine.js +1 -1
  217. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  218. package/src/lib/runtime/ai-node-tree.d.ts +7 -0
  219. package/src/lib/runtime/ai-node-tree.js +9 -1
  220. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  221. package/src/lib/server/ai-create-route.d.ts +1 -1
  222. package/src/lib/server/ai-create-route.js +3 -4
  223. package/src/lib/server/ai-create-route.js.map +1 -1
  224. package/src/lib/server/ai-jobs-resume.js +27 -3
  225. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  226. package/src/lib/server/ai-jobs-route.js +7 -0
  227. package/src/lib/server/ai-jobs-route.js.map +1 -1
  228. package/src/lib/usage/assist-credits.d.ts +4 -4
  229. package/src/lib/usage/assist-credits.js +4 -4
  230. package/src/lib/usage/assist-credits.js.map +1 -1
  231. package/src/lib/usage/staff-org-ai-view.js +6 -3
  232. package/src/lib/usage/staff-org-ai-view.js.map +1 -1
  233. package/src/lib/usage/staff-org-ai.d.ts +4 -2
  234. package/src/lib/usage/staff-org-ai.js +7 -7
  235. package/src/lib/usage/staff-org-ai.js.map +1 -1
  236. package/src/lib/usage/staff-org-usage-ai.js +2 -2
  237. package/src/lib/usage/staff-org-usage-ai.js.map +1 -1
@@ -22,9 +22,10 @@ import { AI_INSTANCE_REF_PROP } from "../runtime/ai-node-tree.js";
22
22
  import { aiPageScrollInteraction } from "../runtime/ai-page-links.js";
23
23
  import { aiLayoutFitText, aiLayoutQuoteGap, aiLayoutWords } from "./ai-layout-copy.js";
24
24
  import { AI_LAYOUT_GROUP_KINDS, AI_LAYOUT_MAX_ITEMS } from "./ai-layout-language.js";
25
- import { aiLayoutDesignChoices, aiLayoutFamily, aiLayoutGroupVariant } from "./ai-layout-design.js";
25
+ import { AI_LAYOUT_HALF_HEROES, aiLayoutDesignChoices, aiLayoutFamily, aiLayoutGroupVariant } from "./ai-layout-design.js";
26
26
  import { AI_LAYOUT_FEATURED_RECORDS, AI_LAYOUT_LISTING_ELEMENTS, aiLayoutIsRecordImageAlt, aiLayoutListingAt, aiLayoutRecordHref, aiLayoutRecordImageAltField, aiLayoutRepeatFilterOf } from "./ai-layout-listings.js";
27
27
  import { aiStorefrontItemIcons } from "./ai-layout-storefront.js";
28
+ import { aiLayoutContactLabel, aiLayoutWithContactLines } from "./ai-layout-contact.js";
28
29
  import { AI_LAYOUT_LABELS_EN, aiLayoutLabel } from "./ai-layout-labels.js";
29
30
  import { aiLayoutRenamedLabel, aiLayoutResolveLink } from "./ai-layout-links.js";
30
31
  import { aiLayoutSpans, AI_LAYOUT_FRAMES, AiLayoutTreeBuilder } from "./ai-layout-tree.js";
@@ -69,8 +70,12 @@ function formSectionOf(sections, plan, targets) {
69
70
  const designed = sections.findIndex((section)=>section.blocks.some((block)=>block.kind === 'form' && (!block.to || forms.has(block.to))));
70
71
  return designed === -1 ? null : designed;
71
72
  }
72
- /** Compiles a page designed in the layout language into the tree it stores. */ export function aiCompileLayoutPage(sections, plan, targets, options) {
73
+ /** Compiles a page designed in the layout language into the tree it stores. */ export function aiCompileLayoutPage(designed, plan, targets, options) {
73
74
  const tree = new AiLayoutTreeBuilder();
75
+ const formSection = formSectionOf(designed, plan, targets);
76
+ // The page a visitor opens to get in touch shows the phone and email the
77
+ // business gave, as links, wherever the design did not (AGL-3979).
78
+ const sections = aiLayoutWithContactLines(designed, formSection, targets.contact);
74
79
  const page = {
75
80
  tree,
76
81
  plan,
@@ -83,7 +88,7 @@ function formSectionOf(sections, plan, targets) {
83
88
  brand: 0,
84
89
  dark: 0
85
90
  },
86
- formSection: formSectionOf(sections, plan, targets),
91
+ formSection,
87
92
  pageIcon: pageIconOf(sections),
88
93
  formsPlaced: new Set(),
89
94
  itemIds: plan.sections.map(()=>[]),
@@ -251,7 +256,7 @@ function compileSection(page, raw, index) {
251
256
  // A row whose columns all say the same kind of thing, three or more across,
252
257
  // is a group of cards: one design, the words the columns gave.
253
258
  if (filled.length >= 3 && sameShape(filled.map((entry)=>entry.column))) {
254
- head.push(columnsAsCards(filled.map((entry)=>entry.column)));
259
+ head.push(...columnsAsCards(filled.map((entry)=>entry.column)));
255
260
  page.settled.push({
256
261
  at,
257
262
  what: `${filled.length} like columns drawn as cards`
@@ -577,19 +582,37 @@ function compileSection(page, raw, index) {
577
582
  /** The block kinds a column holds, as a column's shape is compared. */ function shapeOf(column) {
578
583
  return column.map((block)=>block.kind).join(',');
579
584
  }
580
- function sameShape(columns) {
585
+ /** What a like column may hold and still be read as a card: its words, a picture and one button. */ const CARD_COLUMN_KINDS = new Set([
586
+ 'heading',
587
+ 'text',
588
+ 'lede',
589
+ 'eyebrow',
590
+ 'image',
591
+ 'note',
592
+ 'button'
593
+ ]);
594
+ /** The words of a column a card says: its heading, or its first words. */ const WORDS_KINDS = new Set([
595
+ 'heading',
596
+ 'text',
597
+ 'lede',
598
+ 'note'
599
+ ]);
600
+ /**
601
+ * Whether a row's columns all say the same kind of thing (AGL-3660): the
602
+ * same blocks in the same order, words among them, one button at most. The
603
+ * beta.270 Sugar Hollow Galleries page (AGL-3988) was refused for rule 1,
604
+ * "The same Grid block appears 4 times": four like columns this read did not
605
+ * fold, each of them drawn as a Grid cell of its own.
606
+ */ function sameShape(columns) {
581
607
  const first = shapeOf(columns[0]);
582
- return columns.every((column)=>shapeOf(column) === first) && columns[0].some((block)=>block.kind === 'heading') && columns[0].every((block)=>[
583
- 'heading',
584
- 'text',
585
- 'lede',
586
- 'eyebrow',
587
- 'image',
588
- 'note'
589
- ].includes(block.kind));
608
+ return columns.every((column)=>shapeOf(column) === first) && columns[0].some((block)=>WORDS_KINDS.has(block.kind)) && columns[0].every((block)=>CARD_COLUMN_KINDS.has(block.kind)) && columns[0].filter((block)=>block.kind === 'button').length <= 1;
590
609
  }
591
- /** Like columns as one group of cards: each column's heading its title, its words its text. */ function columnsAsCards(columns) {
592
- return {
610
+ /**
611
+ * Like columns as one group of cards: each column's heading its title, its
612
+ * words its text. Their buttons follow the group (AGL-3988): one, where they
613
+ * all go to the same place, else a list of links, each named by its card.
614
+ */ function columnsAsCards(columns) {
615
+ const cards = {
593
616
  kind: 'cards',
594
617
  items: columns.map((column)=>{
595
618
  var _ref;
@@ -608,6 +631,52 @@ function sameShape(columns) {
608
631
  } : {});
609
632
  })
610
633
  };
634
+ const buttons = columns.flatMap((column)=>{
635
+ var _button_to;
636
+ const button = column.find((block)=>block.kind === 'button');
637
+ return (button == null ? void 0 : (_button_to = button.to) == null ? void 0 : _button_to.trim()) ? [
638
+ {
639
+ button,
640
+ column
641
+ }
642
+ ] : [];
643
+ });
644
+ if (!buttons.length) return [
645
+ cards
646
+ ];
647
+ const places = new Set(buttons.map(({ button })=>{
648
+ var _button_to;
649
+ return ((_button_to = button.to) != null ? _button_to : '').trim().toLowerCase();
650
+ }));
651
+ if (places.size === 1) {
652
+ var _button_text;
653
+ const { button } = buttons[0];
654
+ return [
655
+ cards,
656
+ _extends({
657
+ kind: 'button',
658
+ text: (_button_text = button.text) != null ? _button_text : '',
659
+ to: button.to
660
+ }, button.style ? {
661
+ style: button.style
662
+ } : {})
663
+ ];
664
+ }
665
+ return [
666
+ cards,
667
+ {
668
+ kind: 'list',
669
+ items: buttons.map(({ button, column })=>{
670
+ var _button_to;
671
+ var _column_find;
672
+ return {
673
+ title: ((_column_find = column.find((block)=>block.kind === 'heading')) == null ? void 0 : _column_find.text) || button.text || '',
674
+ text: '',
675
+ to: (_button_to = button.to) != null ? _button_to : ''
676
+ };
677
+ })
678
+ }
679
+ ];
611
680
  }
612
681
  // ── A row of columns ──────────────────────────────────────────────────────
613
682
  // Spans out of twelve live with the tree, so a frame's repair reads them without the compiler (AGL-3735).
@@ -776,7 +845,8 @@ function words(scope, block, place, variant, props, sx) {
776
845
  }
777
846
  function compileButton(scope, block) {
778
847
  var _block_style;
779
- const asked = aiLayoutFitText(block.text, 'label', scope.page.options.language);
848
+ // Words that carry the phone or the email are kept whole (AGL-3979).
849
+ const asked = aiLayoutContactLabel(block.text, scope.page.targets.contact) || aiLayoutFitText(block.text, 'label', scope.page.options.language);
780
850
  if (!asked) return null;
781
851
  const destination = aiLayoutResolveLink(block.to, asked, scope.link, scope.page.targets);
782
852
  if (!destination) {
@@ -844,6 +914,10 @@ export function destinationProps(destination) {
844
914
  if (destination.kind === 'path') return {
845
915
  href: destination.href
846
916
  };
917
+ // A call or an email opens the phone or the mail app, never a new tab (AGL-3979).
918
+ if (destination.kind === 'contact') return {
919
+ href: destination.href
920
+ };
847
921
  return {};
848
922
  }
849
923
  /**
@@ -1284,7 +1358,7 @@ function instances(scope, placed, items, perRow) {
1284
1358
  if (((_block_items = block.items) != null ? _block_items : []).some((item)=>item.to)) {
1285
1359
  var _block_items2;
1286
1360
  const links = ((_block_items2 = block.items) != null ? _block_items2 : []).flatMap((item)=>{
1287
- const label = aiLayoutFitText(item.title || item.text, 'label', scope.page.options.language);
1361
+ const label = aiLayoutContactLabel(item.title || item.text, scope.page.targets.contact) || aiLayoutFitText(item.title || item.text, 'label', scope.page.options.language);
1288
1362
  const destination = label ? aiLayoutResolveLink(item.to, label, scope.link, scope.page.targets) : null;
1289
1363
  if (!destination) return [];
1290
1364
  const id = tree.add('muiScreenLink', _extends({
@@ -1502,12 +1576,12 @@ function instances(scope, placed, items, perRow) {
1502
1576
  const _flow_lead = flow[lead], { style: _style } = _flow_lead, title = _object_without_properties_loose(_flow_lead, [
1503
1577
  "style"
1504
1578
  ]);
1505
- flow[lead] = design.choices.hero === 'split' ? title : _extends({}, title, {
1579
+ flow[lead] = AI_LAYOUT_HALF_HEROES.has(design.choices.hero) ? title : _extends({}, title, {
1506
1580
  style: 'large'
1507
1581
  });
1508
1582
  sellingHero(scope, flow);
1509
1583
  const given = images[0] ? aiLayoutFitText(images[0].text, 'alt', scope.page.options.language) : '';
1510
- return hero(scope, raw, flow, given ? {
1584
+ return hero(scope, flow, given ? {
1511
1585
  alt: given,
1512
1586
  given: true
1513
1587
  } : {
@@ -1536,32 +1610,51 @@ function instances(scope, placed, items, perRow) {
1536
1610
  const group = words[at];
1537
1611
  const tail = words.slice(at + 1);
1538
1612
  const variant = aiLayoutGroupVariant(design.input, design.choices, (_scope_words = scope.words) != null ? _scope_words : '');
1539
- if (!head.every((block)=>WORD_KINDS.has(block.kind) && block.kind !== 'button') || !head.some((block)=>speaksHeading(scope, block)) || !tail.every((block)=>WORD_KINDS.has(block.kind)) || ((_ref = (_group_items = group.items) == null ? void 0 : _group_items.length) != null ? _ref : 0) < 2 || ((_ref1 = (_group_items1 = group.items) == null ? void 0 : _group_items1.length) != null ? _ref1 : 0) > 6 || group.to || group.kind === 'cards' && variant !== 'cards' && variant !== 'ruled') {
1613
+ if (!head.every((block)=>WORD_KINDS.has(block.kind) && block.kind !== 'button') || !head.some((block)=>speaksHeading(scope, block)) || !tail.every((block)=>WORD_KINDS.has(block.kind)) || ((_ref = (_group_items = group.items) == null ? void 0 : _group_items.length) != null ? _ref : 0) < 2 || ((_ref1 = (_group_items1 = group.items) == null ? void 0 : _group_items1.length) != null ? _ref1 : 0) > 6 || group.to || group.kind === 'cards' && variant !== 'cards' && variant !== 'ruled' || // A store's making is shown as pictures across the page (AGL-3676), never
1614
+ // ruled words in half of it: set beside its heading, a seed that splits
1615
+ // headings left a storefront's "how it is made" a band of text (AGL-3985).
1616
+ group.kind === 'steps' && aiLayoutFamily(design.input.kind) === 'retail') {
1540
1617
  return null;
1541
1618
  }
1542
1619
  return splitSection(scope, head, group, tail);
1543
1620
  }
1544
- /** The first section, in the site's hero arrangement. */ function hero(scope, raw, flow, picture) {
1621
+ /** The first section, in the site's hero arrangement. */ function hero(scope, flow, picture) {
1545
1622
  const { page } = scope;
1546
1623
  const tree = page.tree;
1547
1624
  const design = page.design;
1548
1625
  const home = design.input.home;
1549
- const variant = design.choices.hero;
1626
+ // A collage holds two pictures: on a page with room for one, it is drawn split.
1627
+ const chosen = design.choices.hero;
1628
+ const variant = chosen === 'collage' && picturesLeft(page) < 2 ? 'split' : chosen;
1550
1629
  page.settled.push({
1551
1630
  at: scope.at,
1552
1631
  what: `drawn as a ${variant} hero`
1553
1632
  });
1554
- if (variant === 'cover') {
1633
+ if (variant === 'cover' || variant === 'poster') {
1555
1634
  scope.band = 'dark';
1556
- scope.centered = raw.align === 'center';
1557
- return cover(scope, flow, picture, home ? {
1635
+ // A cover sets its words at the start of the page; a poster centers them,
1636
+ // taller, as a restaurant's or a band's opening does (AGL-3985).
1637
+ scope.centered = variant === 'poster';
1638
+ const tall = variant === 'poster';
1639
+ return cover(scope, flow, picture, home ? tall ? {
1640
+ xs: '84vh',
1641
+ md: '94vh'
1642
+ } : {
1558
1643
  xs: '78vh',
1559
1644
  md: '86vh'
1645
+ } : tall ? {
1646
+ xs: '52vh',
1647
+ md: '62vh'
1560
1648
  } : {
1561
1649
  xs: '46vh',
1562
1650
  md: '54vh'
1563
1651
  });
1564
1652
  }
1653
+ if (variant === 'bleed') return bleedHero(scope, flow, picture, home);
1654
+ if (variant === 'column') return columnHero(scope, flow, picture, home);
1655
+ if (variant === 'collage') return collageHero(scope, flow, picture, home);
1656
+ if (variant === 'panel') return panelHero(scope, flow, picture, home);
1657
+ if (variant === 'portrait') return portraitHero(scope, flow, picture);
1565
1658
  const band = scope.band;
1566
1659
  scope.centered = false;
1567
1660
  if (variant === 'split') {
@@ -1724,6 +1817,326 @@ function instances(scope, placed, items, perRow) {
1724
1817
  minHeight
1725
1818
  }, true);
1726
1819
  }
1820
+ /** The surface a band paints, as a palette role: what a picture laid over another is edged in. */ function bandSurface(band) {
1821
+ if (band === 'soft') return 'background.paper';
1822
+ if (band === 'brand') return 'primary.main';
1823
+ return 'background.default';
1824
+ }
1825
+ /**
1826
+ * A bleed hero (AGL-3985): the band in two halves, a photo filling one of
1827
+ * them edge to edge, top to bottom, and the words in the other, centered in
1828
+ * its height. On a phone the photo sits over the words.
1829
+ */ function bleedHero(scope, flow, picture, home) {
1830
+ const { page } = scope;
1831
+ const tree = page.tree;
1832
+ const design = page.design;
1833
+ const band = scope.band;
1834
+ scope.centered = false;
1835
+ const words = compileFlow(scope, flow, 'half');
1836
+ const measure = tree.add('muiBox', null, {
1837
+ maxWidth: {
1838
+ xs: '100%',
1839
+ md: '88%'
1840
+ },
1841
+ px: {
1842
+ xs: 3,
1843
+ sm: 6,
1844
+ md: 8
1845
+ },
1846
+ py: {
1847
+ xs: 6,
1848
+ md: 10
1849
+ }
1850
+ }, [
1851
+ words
1852
+ ], 'measure');
1853
+ const photo = designPicture(scope, picture, {
1854
+ height: '100%',
1855
+ minHeight: home ? {
1856
+ xs: '46vh',
1857
+ md: '84vh'
1858
+ } : {
1859
+ xs: '36vh',
1860
+ md: '56vh'
1861
+ }
1862
+ }, 'bleedPhoto');
1863
+ const right = design.choices.featureLeft;
1864
+ const row = tree.add('muiGrid', {
1865
+ container: true,
1866
+ spacing: '0'
1867
+ }, {
1868
+ alignItems: 'stretch'
1869
+ }, [
1870
+ tree.add('muiGrid', {
1871
+ size: 'xs:12 md:6'
1872
+ }, right ? {
1873
+ order: {
1874
+ xs: 0,
1875
+ md: 1
1876
+ }
1877
+ } : null, [
1878
+ photo
1879
+ ], 'column'),
1880
+ tree.add('muiGrid', {
1881
+ size: 'xs:12 md:6'
1882
+ }, {
1883
+ display: 'flex',
1884
+ alignItems: 'center',
1885
+ justifyContent: right ? 'flex-end' : 'flex-start'
1886
+ }, [
1887
+ measure
1888
+ ], 'column')
1889
+ ], 'row');
1890
+ return designedRoot(scope, [
1891
+ row
1892
+ ], bandSx(band), band === 'dark');
1893
+ }
1894
+ /**
1895
+ * A masthead (AGL-3985): the words centered in a narrow column, as a journal
1896
+ * or a quiet practice opens, and a wide photo under them.
1897
+ */ function columnHero(scope, flow, picture, home) {
1898
+ const tree = scope.page.tree;
1899
+ const band = scope.band;
1900
+ scope.centered = true;
1901
+ const words = compileFlow(scope, flow, 'full');
1902
+ const measure = tree.add('muiBox', null, {
1903
+ maxWidth: {
1904
+ xs: '100%',
1905
+ md: '72%'
1906
+ },
1907
+ mx: 'auto'
1908
+ }, [
1909
+ words
1910
+ ], 'measure');
1911
+ const photo = designPicture(scope, picture, {
1912
+ aspectRatio: home ? {
1913
+ xs: '4 / 3',
1914
+ md: '16 / 7'
1915
+ } : {
1916
+ xs: '16 / 9',
1917
+ md: '3 / 1'
1918
+ },
1919
+ borderRadius: 2
1920
+ });
1921
+ const stack = tree.add('muiStack', {
1922
+ spacing: '8',
1923
+ useFlexGap: true
1924
+ }, null, [
1925
+ measure,
1926
+ photo
1927
+ ], 'content');
1928
+ const container = tree.add('muiContainer', {
1929
+ maxWidth: 'lg'
1930
+ }, {
1931
+ pt: {
1932
+ xs: 8,
1933
+ md: 12
1934
+ },
1935
+ pb: {
1936
+ xs: 6,
1937
+ md: 10
1938
+ }
1939
+ }, [
1940
+ stack
1941
+ ], 'container');
1942
+ return designedRoot(scope, [
1943
+ container
1944
+ ], bandSx(band), band === 'dark');
1945
+ }
1946
+ /**
1947
+ * A collage hero (AGL-3985): the words beside two pictures, a tall one and a
1948
+ * smaller one laid over its lower corner, edged in the band's own surface, as
1949
+ * a shop shows two of its things or an event two moments of its day.
1950
+ */ function collageHero(scope, flow, picture, home) {
1951
+ var _page_plan_sections_scope_index;
1952
+ const { page } = scope;
1953
+ const tree = page.tree;
1954
+ const design = page.design;
1955
+ const band = scope.band;
1956
+ scope.centered = false;
1957
+ const words = compileFlow(scope, flow, 'half');
1958
+ const tall = designPicture(scope, picture, {
1959
+ width: {
1960
+ xs: '78%',
1961
+ md: '76%'
1962
+ },
1963
+ aspectRatio: home ? '4 / 5' : '1 / 1',
1964
+ borderRadius: 2
1965
+ });
1966
+ const small = designPicture(scope, {
1967
+ alt: standInAlt(scope, (_page_plan_sections_scope_index = page.plan.sections[scope.index]) == null ? void 0 : _page_plan_sections_scope_index.name),
1968
+ given: false
1969
+ }, {
1970
+ position: 'absolute',
1971
+ right: 0,
1972
+ bottom: 0,
1973
+ width: {
1974
+ xs: '48%',
1975
+ md: '50%'
1976
+ },
1977
+ aspectRatio: '1 / 1',
1978
+ borderRadius: 2,
1979
+ border: 6,
1980
+ borderColor: bandSurface(band)
1981
+ }, 'collagePhoto');
1982
+ const pictures = tree.add('muiBox', null, {
1983
+ position: 'relative',
1984
+ pb: {
1985
+ xs: 6,
1986
+ md: 10
1987
+ }
1988
+ }, [
1989
+ tall,
1990
+ small
1991
+ ], 'collage');
1992
+ const right = design.choices.featureLeft;
1993
+ const row = designRow(scope, [
1994
+ _extends({
1995
+ id: words,
1996
+ size: 'xs:12 md:5'
1997
+ }, right ? {
1998
+ sx: {
1999
+ order: {
2000
+ xs: 0,
2001
+ md: 1
2002
+ }
2003
+ }
2004
+ } : {}),
2005
+ {
2006
+ id: pictures,
2007
+ size: 'xs:12 md:7'
2008
+ }
2009
+ ], '8');
2010
+ const container = tree.add('muiContainer', {
2011
+ maxWidth: 'lg'
2012
+ }, {
2013
+ py: {
2014
+ xs: 6,
2015
+ md: 10
2016
+ }
2017
+ }, [
2018
+ row
2019
+ ], 'container');
2020
+ return designedRoot(scope, [
2021
+ container
2022
+ ], bandSx(band), band === 'dark');
2023
+ }
2024
+ /**
2025
+ * A panel hero (AGL-3985): a full-bleed photo shown as it is, undimmed, and
2026
+ * the words on a card of the page's own surface over its lower corner, as an
2027
+ * agent's listing or a firm's office opens. The card carries its own colors,
2028
+ * so the words read whatever the photo is.
2029
+ */ function panelHero(scope, flow, picture, home) {
2030
+ const tree = scope.page.tree;
2031
+ // The words sit on the card, never on the band the model chose.
2032
+ scope.band = 'plain';
2033
+ scope.centered = false;
2034
+ const photo = designPicture(scope, picture, {
2035
+ position: 'absolute',
2036
+ top: 0,
2037
+ left: 0,
2038
+ width: '100%',
2039
+ height: '100%'
2040
+ }, 'panelPhoto');
2041
+ const words = compileFlow(scope, flow, 'half');
2042
+ const card = tree.add('muiBox', null, {
2043
+ bgcolor: 'background.paper',
2044
+ color: 'text.primary',
2045
+ borderRadius: 2,
2046
+ boxShadow: 3,
2047
+ p: {
2048
+ xs: 4,
2049
+ md: 6
2050
+ },
2051
+ maxWidth: {
2052
+ xs: '100%',
2053
+ md: '52%'
2054
+ }
2055
+ }, [
2056
+ words
2057
+ ], 'panel');
2058
+ const container = tree.add('muiContainer', {
2059
+ maxWidth: 'lg'
2060
+ }, {
2061
+ position: 'relative',
2062
+ zIndex: 1,
2063
+ pt: {
2064
+ xs: 28,
2065
+ md: 36
2066
+ },
2067
+ pb: {
2068
+ xs: 4,
2069
+ md: 8
2070
+ }
2071
+ }, [
2072
+ card
2073
+ ], 'container');
2074
+ return designedRoot(scope, [
2075
+ photo,
2076
+ container
2077
+ ], {
2078
+ position: 'relative',
2079
+ overflow: 'hidden',
2080
+ display: 'flex',
2081
+ alignItems: 'flex-end',
2082
+ minHeight: home ? {
2083
+ xs: '72vh',
2084
+ md: '84vh'
2085
+ } : {
2086
+ xs: '48vh',
2087
+ md: '56vh'
2088
+ }
2089
+ }, false);
2090
+ }
2091
+ /**
2092
+ * A portrait hero (AGL-3985): a person's own page opens on their round
2093
+ * photo, the words centered under it.
2094
+ */ function portraitHero(scope, flow, picture) {
2095
+ const tree = scope.page.tree;
2096
+ const band = scope.band;
2097
+ scope.centered = true;
2098
+ const photo = designPicture(scope, picture, {
2099
+ width: {
2100
+ xs: '44%',
2101
+ sm: '30%',
2102
+ md: '22%'
2103
+ },
2104
+ aspectRatio: '1 / 1',
2105
+ borderRadius: '50%',
2106
+ flexShrink: 0
2107
+ });
2108
+ const words = compileFlow(scope, flow, 'full');
2109
+ const measure = tree.add('muiBox', null, {
2110
+ maxWidth: {
2111
+ xs: '100%',
2112
+ md: '72%'
2113
+ },
2114
+ mx: 'auto'
2115
+ }, [
2116
+ words
2117
+ ], 'measure');
2118
+ const stack = tree.add('muiStack', {
2119
+ spacing: '5',
2120
+ useFlexGap: true,
2121
+ alignItems: 'center'
2122
+ }, null, [
2123
+ photo,
2124
+ measure
2125
+ ], 'content');
2126
+ const container = tree.add('muiContainer', {
2127
+ maxWidth: 'lg'
2128
+ }, {
2129
+ py: {
2130
+ xs: 8,
2131
+ md: 12
2132
+ }
2133
+ }, [
2134
+ stack
2135
+ ], 'container');
2136
+ return designedRoot(scope, [
2137
+ container
2138
+ ], bandSx(band), band === 'dark');
2139
+ }
1727
2140
  /** A closing section of words over a photo. */ function coverBand(scope, words) {
1728
2141
  scope.band = 'dark';
1729
2142
  scope.centered = true;