@aglyn/plugins-ai 1.0.0-beta.233 → 1.0.0-beta.235

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 (199) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.d.ts +25 -0
  3. package/src/lib/activity/ai-activity-actions.js +85 -4
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-brief-dialog.component.js +46 -2
  6. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  7. package/src/lib/components/ai-campaign-create.component.js +1 -1
  8. package/src/lib/components/ai-campaign-create.component.js.map +1 -1
  9. package/src/lib/components/ai-credits-card.component.js +3 -3
  10. package/src/lib/components/ai-credits-card.component.js.map +1 -1
  11. package/src/lib/components/ai-crm-email-draft.component.js +1 -1
  12. package/src/lib/components/ai-crm-email-draft.component.js.map +1 -1
  13. package/src/lib/components/ai-crm-import-mapping.component.js +1 -1
  14. package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -1
  15. package/src/lib/components/ai-crm-record-card.component.js +1 -1
  16. package/src/lib/components/ai-crm-record-card.component.js.map +1 -1
  17. package/src/lib/components/ai-describe-automation.component.js +4 -2
  18. package/src/lib/components/ai-describe-automation.component.js.map +1 -1
  19. package/src/lib/components/ai-describe-org-automation.component.js +1 -1
  20. package/src/lib/components/ai-describe-org-automation.component.js.map +1 -1
  21. package/src/lib/components/ai-experiment-cards.component.js +2 -2
  22. package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
  23. package/src/lib/components/ai-explain-automation.component.js +1 -1
  24. package/src/lib/components/ai-explain-automation.component.js.map +1 -1
  25. package/src/lib/components/ai-insight-card.component.js +3 -1
  26. package/src/lib/components/ai-insight-card.component.js.map +1 -1
  27. package/src/lib/components/ai-job-links.d.ts +6 -0
  28. package/src/lib/components/ai-job-links.js +9 -0
  29. package/src/lib/components/ai-job-links.js.map +1 -1
  30. package/src/lib/components/ai-jobs-list-page.component.d.ts +6 -1
  31. package/src/lib/components/ai-jobs-list-page.component.js +15 -2
  32. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
  33. package/src/lib/components/ai-logic.component.js +5 -3
  34. package/src/lib/components/ai-logic.component.js.map +1 -1
  35. package/src/lib/components/ai-media-create.component.js +88 -16
  36. package/src/lib/components/ai-media-create.component.js.map +1 -1
  37. package/src/lib/components/ai-model-selector.component.js +8 -0
  38. package/src/lib/components/ai-model-selector.component.js.map +1 -1
  39. package/src/lib/components/ai-overlay-cards.component.js +2 -2
  40. package/src/lib/components/ai-overlay-cards.component.js.map +1 -1
  41. package/src/lib/components/ai-product-copy-card.component.js +2 -1
  42. package/src/lib/components/ai-product-copy-card.component.js.map +1 -1
  43. package/src/lib/components/ai-products-hub-card.component.js +2 -1
  44. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  45. package/src/lib/components/ai-revise-automation.component.js +1 -1
  46. package/src/lib/components/ai-revise-automation.component.js.map +1 -1
  47. package/src/lib/components/ai-seo-fields-card.component.js +7 -3
  48. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
  49. package/src/lib/components/ai-site-batch-card.component.js +7 -4
  50. package/src/lib/components/ai-site-batch-card.component.js.map +1 -1
  51. package/src/lib/components/ai-site-build-page.component.js +48 -6
  52. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  53. package/src/lib/components/ai-site-seo-start-card.component.js +7 -4
  54. package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -1
  55. package/src/lib/components/ai-site-start-card.component.js +152 -36
  56. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  57. package/src/lib/components/ai-theme-proposal-card.component.js +1 -0
  58. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
  59. package/src/lib/components/ai-upsell-dialog.component.js +17 -3
  60. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
  61. package/src/lib/components/ai-usage-strip.component.js +13 -2
  62. package/src/lib/components/ai-usage-strip.component.js.map +1 -1
  63. package/src/lib/components/assist-build-card.component.js +20 -3
  64. package/src/lib/components/assist-build-card.component.js.map +1 -1
  65. package/src/lib/components/assist-jobs-drawer.component.js +7 -1
  66. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  67. package/src/lib/components/billing-ai-allotments.component.js +2 -2
  68. package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
  69. package/src/lib/components/billing-ai-top-users.component.js +1 -0
  70. package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
  71. package/src/lib/components/billing-assist-overage-card.component.js +2 -2
  72. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
  73. package/src/lib/components/host-ai-allotments.component.js +2 -2
  74. package/src/lib/components/host-ai-allotments.component.js.map +1 -1
  75. package/src/lib/components/member-ai-allotment-card.component.js +2 -2
  76. package/src/lib/components/member-ai-allotment-card.component.js.map +1 -1
  77. package/src/lib/components/staff-org-ai-card.component.js +1 -0
  78. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  79. package/src/lib/components/staff-org-ai-conversations.component.d.ts +9 -3
  80. package/src/lib/components/staff-org-ai-conversations.component.js +174 -83
  81. package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -1
  82. package/src/lib/components/staff-user-ai-usage-card.component.js +2 -1
  83. package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -1
  84. package/src/lib/jobs/ai-job-admission.d.ts +2 -1
  85. package/src/lib/jobs/ai-job-admission.js.map +1 -1
  86. package/src/lib/jobs/ai-job-email-step.d.ts +39 -0
  87. package/src/lib/jobs/ai-job-email-step.js +116 -5
  88. package/src/lib/jobs/ai-job-email-step.js.map +1 -1
  89. package/src/lib/jobs/ai-job-layout-language.d.ts +3 -0
  90. package/src/lib/jobs/ai-job-layout-language.js +6 -1
  91. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  92. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +14 -0
  93. package/src/lib/jobs/ai-job-layout-site-pages.js +43 -11
  94. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
  95. package/src/lib/jobs/ai-job-layout-step.js +3 -2
  96. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  97. package/src/lib/jobs/ai-job-page-language.d.ts +26 -1
  98. package/src/lib/jobs/ai-job-page-language.js +75 -13
  99. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  100. package/src/lib/jobs/ai-job-page-step.d.ts +3 -0
  101. package/src/lib/jobs/ai-job-page-step.js +32 -7
  102. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  103. package/src/lib/jobs/ai-job-plan-step.d.ts +34 -0
  104. package/src/lib/jobs/ai-job-plan-step.js +106 -14
  105. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  106. package/src/lib/jobs/ai-job-site-content.d.ts +81 -13
  107. package/src/lib/jobs/ai-job-site-content.js +210 -43
  108. package/src/lib/jobs/ai-job-site-content.js.map +1 -1
  109. package/src/lib/jobs/ai-job-site-step.d.ts +19 -0
  110. package/src/lib/jobs/ai-job-site-step.js +152 -51
  111. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  112. package/src/lib/jobs/ai-jobs.d.ts +8 -4
  113. package/src/lib/jobs/ai-jobs.js +19 -2
  114. package/src/lib/jobs/ai-jobs.js.map +1 -1
  115. package/src/lib/jobs/ai-layout-stock-photos.d.ts +98 -0
  116. package/src/lib/jobs/ai-layout-stock-photos.js +248 -0
  117. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -0
  118. package/src/lib/jobs/ai-site-publish.d.ts +11 -0
  119. package/src/lib/jobs/ai-site-publish.js +31 -1
  120. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  121. package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.d.ts +151 -0
  122. package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.js +183 -0
  123. package/src/lib/jobs/fixtures/ai-juniper-portfolio-page-recording.js.map +1 -0
  124. package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.d.ts +27 -0
  125. package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.js +192 -0
  126. package/src/lib/jobs/fixtures/ai-slow-roads-site-plan-recording.js.map +1 -0
  127. package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.d.ts +27 -0
  128. package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.js +222 -0
  129. package/src/lib/jobs/fixtures/ai-yoga-site-plan-recording.js.map +1 -0
  130. package/src/lib/layout-language/ai-layout-compiler.d.ts +37 -0
  131. package/src/lib/layout-language/ai-layout-compiler.js +1003 -19
  132. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  133. package/src/lib/layout-language/ai-layout-design.d.ts +114 -0
  134. package/src/lib/layout-language/ai-layout-design.js +209 -0
  135. package/src/lib/layout-language/ai-layout-design.js.map +1 -0
  136. package/src/lib/layout-language/ai-layout-frame.d.ts +12 -0
  137. package/src/lib/layout-language/ai-layout-frame.js +33 -8
  138. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  139. package/src/lib/layout-language/ai-layout-gaps.js +18 -2
  140. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
  141. package/src/lib/layout-language/ai-layout-language.d.ts +2 -0
  142. package/src/lib/layout-language/ai-layout-language.js +15 -1
  143. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  144. package/src/lib/layout-language/ai-layout-links.d.ts +36 -0
  145. package/src/lib/layout-language/ai-layout-links.js +26 -2
  146. package/src/lib/layout-language/ai-layout-links.js.map +1 -1
  147. package/src/lib/layout-language/ai-layout-listings.d.ts +125 -0
  148. package/src/lib/layout-language/ai-layout-listings.js +187 -0
  149. package/src/lib/layout-language/ai-layout-listings.js.map +1 -0
  150. package/src/lib/layout-language/ai-layout-pictures.d.ts +11 -5
  151. package/src/lib/layout-language/ai-layout-pictures.js +80 -17
  152. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
  153. package/src/lib/model/ai-job-notice.d.ts +9 -1
  154. package/src/lib/model/ai-job-notice.js +23 -0
  155. package/src/lib/model/ai-job-notice.js.map +1 -1
  156. package/src/lib/model/ai-plan-capabilities.d.ts +7 -0
  157. package/src/lib/model/ai-plan-capabilities.js.map +1 -1
  158. package/src/lib/model/ai-site-build-progress.d.ts +12 -2
  159. package/src/lib/model/ai-site-build-progress.js +104 -15
  160. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  161. package/src/lib/model/ai-site-job.d.ts +236 -24
  162. package/src/lib/model/ai-site-job.js +269 -22
  163. package/src/lib/model/ai-site-job.js.map +1 -1
  164. package/src/lib/model/ai-site-kinds.d.ts +30 -8
  165. package/src/lib/model/ai-site-kinds.js +735 -116
  166. package/src/lib/model/ai-site-kinds.js.map +1 -1
  167. package/src/lib/model/ai-site-look.d.ts +21 -0
  168. package/src/lib/model/ai-site-look.js +63 -14
  169. package/src/lib/model/ai-site-look.js.map +1 -1
  170. package/src/lib/model/ai-site-start-seo.d.ts +30 -0
  171. package/src/lib/model/ai-site-start-seo.js +132 -11
  172. package/src/lib/model/ai-site-start-seo.js.map +1 -1
  173. package/src/lib/model/ai-site-start.d.ts +2 -2
  174. package/src/lib/model/ai-site-start.js +3 -3
  175. package/src/lib/model/ai-site-start.js.map +1 -1
  176. package/src/lib/plugin.js +15 -3
  177. package/src/lib/plugin.js.map +1 -1
  178. package/src/lib/runtime/ai-doctrine-validators.d.ts +32 -1
  179. package/src/lib/runtime/ai-doctrine-validators.js +227 -4
  180. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  181. package/src/lib/runtime/ai-doctrine.js +5 -3
  182. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  183. package/src/lib/runtime/ai-palette.generated.d.ts +2 -0
  184. package/src/lib/runtime/ai-palette.generated.js +31 -5
  185. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  186. package/src/lib/server/ai-admin-conversations.d.ts +9 -0
  187. package/src/lib/server/ai-admin-conversations.js +151 -9
  188. package/src/lib/server/ai-admin-conversations.js.map +1 -1
  189. package/src/lib/server/ai-jobs-resume.js.map +1 -1
  190. package/src/lib/server/ai-jobs-route.js +15 -3
  191. package/src/lib/server/ai-jobs-route.js.map +1 -1
  192. package/src/lib/server/assist-edit.js +5 -2
  193. package/src/lib/server/assist-edit.js.map +1 -1
  194. package/src/lib/usage/free-ai-credits-left.d.ts +54 -0
  195. package/src/lib/usage/free-ai-credits-left.js +62 -0
  196. package/src/lib/usage/free-ai-credits-left.js.map +1 -0
  197. package/src/lib/usage/staff-org-ai-conversations.d.ts +23 -0
  198. package/src/lib/usage/staff-org-ai-conversations.js +45 -0
  199. package/src/lib/usage/staff-org-ai-conversations.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-look.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n contrastRatio,\n validateThemeForPublish,\n} from '@aglyn/aglyn/app-utils/site-theme'\nimport { DEFAULT_SITE_THEME } from '@aglyn/aglyn/app-utils/default-site'\nimport type {\n HostTheme,\n HostThemeComponentOverride,\n HostThemeSchemeColors,\n HostThemeTypographyVariant,\n HostThemeTypographyVariantKey,\n} from '@aglyn/shared-data-types'\nimport { writeThemeFonts } from '@aglyn/shared-ui-theme/util/theme-editor-fields'\nimport type { AiTool } from '../runtime/ai-runtime'\nimport {\n AI_SITE_BASES,\n AI_SITE_CORNERS,\n AI_SITE_FONT_PAIRINGS,\n AI_SITE_GROUNDS,\n AI_SITE_RHYTHMS,\n aiSiteFontPairing,\n type AiSiteBase,\n type AiSiteButtons,\n type AiSiteChroma,\n type AiSiteCorners,\n type AiSiteDensity,\n type AiSiteGround,\n type AiSiteKind,\n type AiSiteRhythm,\n} from './ai-site-kinds'\n\n/**\n * A site's look (AGL-3660): one of the platform's base themes, and this\n * site's own customizations layered over it as the site theme's override —\n * the same base-and-edits shape a person's pick on Setup → Theme is stored\n * as, so the Theme page names the base it came from and every edit there\n * starts from what the AI chose.\n *\n * Everything the look decides lives in the THEME, never on a node: palette,\n * fonts, type scale, corners, spacing, and the component defaults and styles\n * of buttons, cards, fields, eyebrows, the header bar and the FAQ. So a Card\n * or a Button a person drags in later looks like the rest of the site, and\n * the layout compiler emits plain components.\n *\n * Three inputs decide it:\n * - the KIND (`ai-site-kinds.ts`): the family of looks that suit the site;\n * - the MODEL's choices for this business (`submit_site_look`), any of\n * which may be missing;\n * - the per-job SEED, which fills what the model left out from the kind's\n * options and nudges every hue, chroma and size, so two jobs with the same\n * brief and the same answers still produce two different themes.\n *\n * Colors are built in OKLCH and held to WCAG: body text 4.5:1 on its ground\n * and on paper, every button label 4.5:1 on its fill, the brand color 3:1 on\n * the page — then the whole theme passes `validateThemeForPublish`, or its\n * colors fall back to the starter theme's.\n */\n\n// ── The tokens ───────────────────────────────────────────────────────────\n\n/** How cards are drawn. */\nexport const AI_SITE_CARDS = ['flat', 'outlined', 'elevated', 'tinted', 'rule'] as const\nexport type AiSiteCards = (typeof AI_SITE_CARDS)[number]\n/** The form field style. */\nexport const AI_SITE_FIELDS = ['outlined', 'filled', 'standard'] as const\nexport type AiSiteFields = (typeof AI_SITE_FIELDS)[number]\n/** How an eyebrow above a heading is set. */\nexport const AI_SITE_EYEBROWS = ['caps', 'small', 'rule'] as const\nexport type AiSiteEyebrow = (typeof AI_SITE_EYEBROWS)[number]\n/** What sets a plain header bar off the page. */\nexport const AI_SITE_HEADERS = ['line', 'shadow', 'flat'] as const\nexport type AiSiteHeader = (typeof AI_SITE_HEADERS)[number]\n/** Button shapes and casing; `link` draws quiet buttons as underlined links. */\nexport const AI_SITE_BUTTONS: readonly AiSiteButtons[] = ['rounded', 'pill', 'square', 'caps', 'link']\nconst DENSITIES: readonly AiSiteDensity[] = ['compact', 'regular', 'airy']\n\n/**\n * A site's style tokens: everything its theme was built from. Stored with the\n * site (`hosts/{id}.siteStyle`) so a later AI edit keeps the look.\n */\nexport interface AiSiteStyle {\n v: 1\n kind: string\n base: AiSiteBase\n seed: number\n hue: number\n accent: number\n chroma: AiSiteChroma\n ground: AiSiteGround\n fonts: string\n corners: AiSiteCorners\n buttons: AiSiteButtons\n cards: AiSiteCards\n fields: AiSiteFields\n eyebrow: AiSiteEyebrow\n header: AiSiteHeader\n /** The header's arrangement: brand at the start and links after it, or both centered. */\n headerAlign: 'start' | 'center'\n /** How the pages alternate their bands. */\n rhythm: AiSiteRhythm\n headingScale: number\n density: AiSiteDensity\n /** A brand color the brief gave, used as the primary color. */\n brand: string | null\n}\n\n/** What the model may choose, every field optional. */\nexport type AiSiteLookAnswer = Partial<\n Pick<\n AiSiteStyle,\n 'base' | 'hue' | 'accent' | 'ground' | 'fonts' | 'corners' | 'buttons' | 'cards' | 'fields' | 'eyebrow' | 'header' | 'brand'\n >\n>\n\n// ── The seed ─────────────────────────────────────────────────────────────\n\n/** A job's seed: FNV-1a over its id. */\nexport function aiSiteSeed(jobId: string): number {\n let hash = 0x811c9dc5\n for (let index = 0; index < jobId.length; index += 1) {\n hash ^= jobId.charCodeAt(index)\n hash = Math.imul(hash, 0x01000193)\n }\n return hash >>> 0\n}\n\n/** A small deterministic generator over a seed (mulberry32). */\nfunction random(seed: number): () => number {\n let state = seed >>> 0\n return () => {\n state = (state + 0x6d2b79f5) >>> 0\n let t = state\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nconst pick = <T,>(next: () => number, list: readonly T[]): T => list[Math.floor(next() * list.length) % list.length] as T\n\n// ── The model's answer ───────────────────────────────────────────────────\n\nexport const AI_SITE_LOOK_TOOL_NAME = 'submit_site_look'\n\nconst enumOf = (values: readonly string[], description: string) => ({ type: 'string', enum: [...values], description })\n\n/** The strict tool the look is answered with; every field is required and the reader is lenient. */\nexport const AI_SITE_LOOK_TOOL: AiTool = {\n name: AI_SITE_LOOK_TOOL_NAME,\n description: \"Submit this website's look: the base theme it starts from and the choices that make it this business's own.\",\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['base', 'hue', 'accent', 'ground', 'fonts', 'corners', 'buttons', 'cards', 'fields', 'eyebrow', 'header', 'brand'],\n properties: {\n base: enumOf(AI_SITE_BASES, 'The base theme to start from, from the list in the request.'),\n hue: { type: 'integer', description: 'The brand color as a hue from 0 to 359 (0 red, 30 orange, 55 gold, 140 green, 190 teal, 220 blue, 270 violet, 330 pink).' },\n accent: { type: 'integer', description: 'The accent color as a hue from 0 to 359, chosen to sit well beside the brand hue.' },\n ground: enumOf(AI_SITE_GROUNDS, 'The page background: white, warm (cream), cool (gray-blue) or tinted (a whisper of the brand color).'),\n fonts: enumOf(AI_SITE_FONT_PAIRINGS.map((pairing) => pairing.id), 'A font pairing from the list in the request.'),\n corners: enumOf(AI_SITE_CORNERS, 'Corner rounding for cards and fields.'),\n buttons: enumOf(AI_SITE_BUTTONS, 'Buttons: rounded, pill, square, caps (capitals) or link (quiet buttons drawn as underlined links).'),\n cards: enumOf(AI_SITE_CARDS, 'Cards: flat, outlined, elevated (a soft shadow), tinted (a wash of the brand color) or rule (a colored line on top).'),\n fields: enumOf(AI_SITE_FIELDS, 'Form fields: outlined, filled or standard (underlined).'),\n eyebrow: enumOf(AI_SITE_EYEBROWS, 'The small label above headings: caps (spaced capitals), small (quiet small text) or rule (capitals after a short line).'),\n header: enumOf(AI_SITE_HEADERS, 'What sets the header bar off the page: a line, a shadow, or flat.'),\n brand: { anyOf: [{ type: 'string' }, { type: 'null' }], description: 'A hex brand color the brief gives, exactly as written, or null.' },\n },\n },\n}\n\nconst oneOf = <T extends string>(value: unknown, values: readonly T[]): T | undefined =>\n typeof value === 'string' && (values as readonly string[]).includes(value) ? (value as T) : undefined\n\nconst hueOf = (value: unknown): number | undefined =>\n typeof value === 'number' && Number.isFinite(value) ? ((Math.round(value) % 360) + 360) % 360 : undefined\n\n/** A brand color as a six-digit hex, or `null`. */\nexport function aiSiteBrandHex(value: unknown): string | null {\n if (typeof value !== 'string') return null\n const match = /#?([0-9a-f]{6}|[0-9a-f]{3})\\b/i.exec(value.trim())\n if (!match) return null\n const hex = match[1] as string\n const full = hex.length === 3 ? [...hex].map((digit) => digit + digit).join('') : hex\n return `#${full.toLowerCase()}`\n}\n\n/** The model's answer, read leniently: a value outside its vocabulary is left for the seed. */\nexport function aiReadSiteLook(answer: unknown): AiSiteLookAnswer {\n const raw = (answer && typeof answer === 'object' ? answer : {}) as Record<string, unknown>\n const look: AiSiteLookAnswer = {}\n const base = oneOf(raw['base'], AI_SITE_BASES)\n if (base) look.base = base\n const hue = hueOf(raw['hue'])\n if (hue !== undefined) look.hue = hue\n const accent = hueOf(raw['accent'])\n if (accent !== undefined) look.accent = accent\n const ground = oneOf(raw['ground'], AI_SITE_GROUNDS)\n if (ground) look.ground = ground\n if (aiSiteFontPairing(raw['fonts'])) look.fonts = raw['fonts'] as string\n const corners = oneOf(raw['corners'], AI_SITE_CORNERS)\n if (corners) look.corners = corners\n const buttons = oneOf(raw['buttons'], AI_SITE_BUTTONS)\n if (buttons) look.buttons = buttons\n const cards = oneOf(raw['cards'], AI_SITE_CARDS)\n if (cards) look.cards = cards\n const fields = oneOf(raw['fields'], AI_SITE_FIELDS)\n if (fields) look.fields = fields\n const eyebrow = oneOf(raw['eyebrow'], AI_SITE_EYEBROWS)\n if (eyebrow) look.eyebrow = eyebrow\n const header = oneOf(raw['header'], AI_SITE_HEADERS)\n if (header) look.header = header\n const brand = aiSiteBrandHex(raw['brand'])\n if (brand) look.brand = brand\n return look\n}\n\n// ── Kind, model and seed into tokens ─────────────────────────────────────\n\n/** The building-block styles a kind leans to, before the model or the seed choose. */\nconst BLOCK_BIAS: Partial<\n Record<string, { cards: readonly AiSiteCards[]; eyebrow: readonly AiSiteEyebrow[]; header: readonly AiSiteHeader[]; fields: readonly AiSiteFields[] }>\n> = {\n portfolio: { cards: ['rule', 'flat', 'outlined'], eyebrow: ['small', 'rule', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'outlined', 'filled'] },\n studio: { cards: ['flat', 'rule', 'outlined'], eyebrow: ['rule', 'small', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'outlined', 'filled'] },\n photography: { cards: ['flat', 'rule', 'outlined'], eyebrow: ['small', 'rule', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'outlined', 'filled'] },\n blog: { cards: ['rule', 'outlined', 'flat', 'tinted'], eyebrow: ['small', 'caps', 'rule'], header: ['line', 'flat', 'shadow'], fields: ['outlined', 'standard', 'filled'] },\n trades: { cards: ['elevated', 'outlined', 'rule', 'flat', 'tinted'], eyebrow: ['caps', 'rule', 'small'], header: ['shadow', 'line', 'flat'], fields: ['outlined', 'filled', 'standard'] },\n fitness: { cards: ['elevated', 'flat', 'rule', 'outlined'], eyebrow: ['caps', 'rule', 'small'], header: ['shadow', 'flat', 'line'], fields: ['filled', 'outlined', 'standard'] },\n professional: { cards: ['outlined', 'rule', 'flat', 'elevated'], eyebrow: ['caps', 'rule', 'small'], header: ['line', 'flat', 'shadow'], fields: ['outlined', 'standard', 'filled'] },\n wellness: { cards: ['tinted', 'flat', 'elevated', 'outlined'], eyebrow: ['small', 'caps', 'rule'], header: ['flat', 'line', 'shadow'], fields: ['filled', 'outlined', 'standard'] },\n yoga: { cards: ['tinted', 'flat', 'outlined'], eyebrow: ['small', 'rule', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['filled', 'standard', 'outlined'] },\n restaurant: { cards: ['flat', 'elevated', 'tinted', 'rule'], eyebrow: ['caps', 'rule', 'small'], header: ['flat', 'shadow', 'line'], fields: ['outlined', 'filled', 'standard'] },\n beauty: { cards: ['tinted', 'flat', 'outlined', 'rule'], eyebrow: ['rule', 'small', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'filled', 'outlined'] },\n music: { cards: ['flat', 'rule', 'elevated'], eyebrow: ['caps', 'rule', 'small'], header: ['flat', 'shadow', 'line'], fields: ['filled', 'standard', 'outlined'] },\n}\nconst ANY_BLOCKS = { cards: AI_SITE_CARDS, eyebrow: AI_SITE_EYEBROWS, header: AI_SITE_HEADERS, fields: AI_SITE_FIELDS }\n\n/** The hue family a hue is in: twelve families of thirty degrees, 0 the reds. */\nexport function aiSiteHueFamily(hue: number): number {\n return Math.floor((((hue + 15) % 360) + 360) % 360 / 30)\n}\n\n/** Which of a kind's hue ranges a hue falls in, or -1. */\nfunction rangeOf(hue: number, kind: AiSiteKind): number {\n return kind.look.hues.findIndex(([from, to]) => (from <= to ? hue >= from && hue <= to : hue >= from || hue <= to))\n}\n\n/** The look dimensions two sites are compared by (`ai-site-look.spec.ts`). */\nexport const AI_SITE_LOOK_DIMENSIONS = [\n 'base',\n 'hueFamily',\n 'fonts',\n 'buttons',\n 'cards',\n 'corners',\n 'ground',\n 'eyebrow',\n 'header',\n 'fields',\n 'headerAlign',\n 'rhythm',\n] as const\n\n/** A style's value on each tracked dimension. */\nexport function aiSiteLookSignature(style: AiSiteStyle): Record<(typeof AI_SITE_LOOK_DIMENSIONS)[number], string> {\n return {\n base: style.base,\n hueFamily: String(aiSiteHueFamily(style.hue)),\n fonts: style.fonts,\n buttons: style.buttons,\n cards: style.cards,\n corners: style.corners,\n ground: style.ground,\n eyebrow: style.eyebrow,\n header: style.header,\n fields: style.fields,\n headerAlign: style.headerAlign,\n rhythm: style.rhythm,\n }\n}\n\n/**\n * The style tokens for a site of this kind (AGL-3660). Every dimension is\n * the SEED's choice among what suits the kind, with the model's choice for\n * this business as a favored candidate — kept at a given chance, not always\n * — so the brief steers the look and two jobs with the same brief and the\n * same answer still come out as two sites: another base, another hue family,\n * another pairing, other buttons. A brand color the brief gives is always\n * kept.\n */\nexport function aiSiteStyleFor(input: {\n kind: AiSiteKind\n answer: AiSiteLookAnswer\n seed: number\n brand?: string | null\n /**\n * The looks of the workspace's other sites (AGL-3660): a look that shares\n * one's base, hue family, heading font and buttons, or differs from one in\n * fewer than three tracked dimensions, is drawn again from the next seed.\n */\n avoid?: readonly AiSiteStyle[]\n}): AiSiteStyle {\n const avoid = input.avoid ?? []\n if (!avoid.length) return styleOnce(input, input.seed)\n const signatures = avoid.map(aiSiteLookSignature)\n let best: { style: AiSiteStyle; least: number } | null = null\n for (let attempt = 0; attempt < AI_SITE_LOOK_DRAWS; attempt += 1) {\n const style = styleOnce(input, attempt === 0 ? input.seed : (Math.imul(input.seed ^ 0x5bd1e995, attempt + 1) >>> 0))\n const own = aiSiteLookSignature(style)\n const least = Math.min(\n ...signatures.map((other) =>\n TUPLE.every((dimension) => own[dimension] === other[dimension])\n ? -1\n : AI_SITE_LOOK_DIMENSIONS.filter((dimension) => own[dimension] !== other[dimension]).length,\n ),\n )\n if (least >= AI_SITE_LOOK_LEAST_DIFFERENCES) return style\n if (!best || least > best.least) best = { style, least }\n }\n return (best as { style: AiSiteStyle }).style\n}\n\n/** How many seeds a look draws before it settles for the most different. */\nexport const AI_SITE_LOOK_DRAWS = 32\n/** The fewest tracked dimensions in which two of a workspace's sites differ. */\nexport const AI_SITE_LOOK_LEAST_DIFFERENCES = 3\n/** The dimensions no two of a workspace's sites share all of. */\nconst TUPLE = ['base', 'hueFamily', 'fonts', 'buttons'] as const\n\nfunction styleOnce(\n input: { kind: AiSiteKind; answer: AiSiteLookAnswer; brand?: string | null },\n seed: number,\n): AiSiteStyle {\n const { kind, answer } = input\n const next = random(seed)\n const family = kind.look\n const blocks = BLOCK_BIAS[kind.id] ?? ANY_BLOCKS\n /** The model's choice at a chance of `keep`, else the seed's among `options`. */\n const choose = <T,>(model: T | undefined, options: readonly T[], keep: number): T =>\n model !== undefined && next() < keep ? model : pick(next, options)\n\n // The hue: a family among the kind's (the brief's industry), the model's\n // own family favored, and a hue within it.\n const modelRange = answer.hue === undefined ? -1 : rangeOf(answer.hue, kind)\n const keepHue = modelRange !== -1 && next() < 0.3\n const range = keepHue ? modelRange : Math.floor(next() * family.hues.length) % family.hues.length\n const [from, to] = family.hues[range] as readonly [number, number]\n const span = from <= to ? to - from : 360 - from + to\n const hue = keepHue\n ? ((answer.hue as number) + (next() < 0.5 ? -1 : 1) * Math.round(4 + next() * 8) + 360) % 360\n : Math.round(from + next() * span) % 360\n const accentFrom = answer.accent !== undefined && next() < 0.4 ? answer.accent : (hue + pick(next, [30, 150, 180, 210, 330])) % 360\n const accent = (accentFrom + (next() < 0.5 ? -1 : 1) * Math.round(8 + next() * 16) + 360) % 360\n\n const bases = [...new Set([...(answer.base ? [answer.base] : []), ...family.bases])]\n return {\n v: 1,\n kind: kind.id,\n base: choose(answer.base, bases, 0.3),\n seed,\n hue,\n accent,\n chroma: family.chroma,\n ground: choose(answer.ground, family.grounds, 0.35),\n fonts: choose(answer.fonts, family.fonts, 0.3),\n corners: choose(answer.corners, family.corners, 0.35),\n buttons: choose(answer.buttons, [family.buttons, ...AI_SITE_BUTTONS], 0.3),\n cards: choose(answer.cards, blocks.cards, 0.35),\n fields: choose(answer.fields, blocks.fields, 0.35),\n eyebrow: choose(answer.eyebrow, blocks.eyebrow, 0.35),\n header: choose(answer.header, blocks.header, 0.35),\n headerAlign: pick(next, family.headerAligns ?? ['start', 'start', 'center']),\n rhythm: pick(next, family.rhythms ?? AI_SITE_RHYTHMS),\n headingScale: Math.round(family.headingScale * (0.94 + next() * 0.12) * 100) / 100,\n density: family.density === 'regular' && next() < 0.25 ? pick(next, DENSITIES) : family.density,\n brand: aiSiteBrandHex(input.brand) ?? answer.brand ?? null,\n }\n}\n\n// ── Color ────────────────────────────────────────────────────────────────\n\ntype Rgb = [number, number, number]\n\nfunction oklabToLinear(L: number, a: number, b: number): Rgb {\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ]\n}\n\nconst toSrgb = (channel: number) =>\n channel <= 0.0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - 0.055\nconst fromSrgb = (channel: number) =>\n channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4\n\n/** An OKLCH color as hex, its chroma reduced until it fits sRGB. */\nexport function aiOklchHex(L: number, C: number, h: number): string {\n const lightness = Math.min(1, Math.max(0, L))\n let chroma = Math.max(0, C)\n for (;;) {\n const radians = (h * Math.PI) / 180\n const linear = oklabToLinear(lightness, chroma * Math.cos(radians), chroma * Math.sin(radians))\n const fits = linear.every((channel) => channel >= -0.0005 && channel <= 1.0005)\n if (fits || chroma <= 0) {\n return `#${linear\n .map((channel) => Math.round(Math.min(1, Math.max(0, toSrgb(Math.min(1, Math.max(0, channel))))) * 255))\n .map((value) => value.toString(16).padStart(2, '0'))\n .join('')}`\n }\n chroma = Math.max(0, chroma - 0.004)\n }\n}\n\n/** A hex color in OKLCH. */\nexport function aiHexOklch(hex: string): { L: number; C: number; h: number } {\n const value = hex.replace('#', '')\n const [r, g, b] = [0, 2, 4].map((at) => fromSrgb(parseInt(value.slice(at, at + 2), 16) / 255)) as Rgb\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b)\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b)\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b)\n const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s\n const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s\n const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s\n return { L, C: Math.hypot(A, B), h: ((Math.atan2(B, A) * 180) / Math.PI + 360) % 360 }\n}\n\nconst ratio = (a: string, b: string) => contrastRatio(a, b) ?? 1\n\n/** The lightness, stepped from `L` toward `toward`, at which `hex(L)` first reaches `min` against `against`. */\nfunction untilContrast(L: number, C: number, h: number, against: string, min: number, toward: 0 | 1): number {\n let lightness = L\n for (let step = 0; step < 60; step += 1) {\n if (ratio(aiOklchHex(lightness, C, h), against) >= min) return lightness\n lightness += toward ? 0.012 : -0.012\n if (lightness <= 0.05 || lightness >= 0.98) break\n }\n return lightness\n}\n\n/** The label color of a fill: white or a deep ink of its hue, whichever reads at 4.5:1, or better. */\nfunction labelOn(fill: string, h: number): string {\n const white = '#ffffff'\n const ink = aiOklchHex(0.2, 0.04, h)\n return ratio(white, fill) >= 4.5 ? white : ratio(ink, fill) >= 4.5 ? ink : ratio(white, fill) > ratio(ink, fill) ? white : '#000000'\n}\n\nconst CHROMA: Record<AiSiteChroma, number> = { neutral: 0.15, muted: 0.085, balanced: 0.135, vivid: 0.185 }\nconst START_L: Record<AiSiteChroma, number> = { neutral: 0.52, muted: 0.48, balanced: 0.52, vivid: 0.56 }\n\n/** Both schemes' colors for a style. */\nexport function aiSiteColors(style: AiSiteStyle): { light: HostThemeSchemeColors; dark: HostThemeSchemeColors } {\n const next = random(style.seed ^ 0x9e3779b9)\n const neutral = style.chroma === 'neutral'\n const brand = style.brand ? aiHexOklch(style.brand) : null\n const h = brand?.h ?? style.hue\n const chroma = brand?.C ?? CHROMA[style.chroma] * (0.9 + next() * 0.2)\n const groundChroma = neutral ? 0.3 : 1\n const white = '#ffffff'\n\n // The page grounds.\n const grounds: Record<AiSiteGround, { L: number; C: number; h: number; paper: [number, number] }> = {\n white: { L: 0.985, C: 0.004, h, paper: [1, 0] },\n warm: { L: 0.972, C: 0.016, h: 78, paper: [0.993, 0.007] },\n cool: { L: 0.974, C: 0.009, h: 250, paper: [1, 0] },\n tinted: { L: 0.968, C: 0.02, h, paper: [0.994, 0.006] },\n }\n const ground = grounds[style.ground]\n const background = aiOklchHex(ground.L, ground.C * groundChroma, ground.h)\n const paper = aiOklchHex(ground.paper[0], ground.paper[1] * groundChroma, ground.h)\n\n // The brand color: a button label reads on it, so it reads on the page too.\n let primaryMain: string\n let primaryL: number\n if (brand && ratio(white, style.brand as string) >= 4.5) {\n primaryMain = style.brand as string\n primaryL = brand.L\n } else {\n primaryL = untilContrast(brand ? Math.min(brand.L, START_L[style.chroma]) : START_L[style.chroma] + (next() - 0.5) * 0.06, chroma, h, white, 4.6, 0)\n primaryMain = aiOklchHex(primaryL, chroma, h)\n }\n const accentChroma = neutral ? 0.17 : Math.max(0.07, chroma * 0.95)\n\n // The secondary color fills a button ON a brand band, so it stands apart from the brand color.\n const secondary = neutral\n ? { main: aiOklchHex(0.24, 0.012, h), h }\n : (() => {\n // A light wash of the accent rather than the accent at full strength:\n // it reads on the brand color without fighting it.\n const washChroma = Math.min(accentChroma, 0.08)\n let L = 0.9\n let main = aiOklchHex(L, washChroma, style.accent)\n while (ratio(main, primaryMain) < 3 && L < 0.96) {\n L += 0.02\n main = aiOklchHex(L, washChroma, style.accent)\n }\n return { main, h: style.accent }\n })()\n const tertiaryHue = (style.accent + 60) % 360\n const tertiaryL = untilContrast(0.52, 0.12, tertiaryHue, white, 4.6, 0)\n const tertiary = aiOklchHex(tertiaryL, 0.12, tertiaryHue)\n const textChroma = neutral ? 0.006 : 0.02\n\n const light: HostThemeSchemeColors = {\n primary: {\n main: primaryMain,\n light: aiOklchHex(Math.min(0.92, primaryL + 0.12), chroma, h),\n dark: aiOklchHex(Math.max(0.15, primaryL - 0.1), chroma, h),\n contrastText: labelOn(primaryMain, h),\n },\n secondary: {\n main: secondary.main,\n light: aiOklchHex(0.93, accentChroma * 0.6, secondary.h),\n dark: aiOklchHex(0.42, accentChroma, secondary.h),\n contrastText: labelOn(secondary.main, secondary.h),\n },\n tertiary: {\n main: tertiary,\n light: aiOklchHex(Math.min(0.9, tertiaryL + 0.14), 0.12, tertiaryHue),\n dark: aiOklchHex(Math.max(0.15, tertiaryL - 0.1), 0.12, tertiaryHue),\n contrastText: labelOn(tertiary, tertiaryHue),\n },\n surface: { main: aiOklchHex(0.955, 0.012 * groundChroma, h), contrastText: aiOklchHex(0.22, textChroma, h) },\n background: { default: background, paper },\n text: {\n primary: aiOklchHex(0.22, textChroma, h),\n secondary: aiOklchHex(0.45, textChroma + 0.005, h),\n disabled: aiOklchHex(0.68, 0.01, h),\n },\n tint: {\n primary: aiOklchHex(0.955, neutral ? 0.03 : 0.035, neutral ? style.accent : h),\n secondary: aiOklchHex(0.955, 0.035, style.accent),\n tertiary: aiOklchHex(0.955, 0.03, tertiaryHue),\n },\n divider: aiOklchHex(0.9, 0.012 * groundChroma, h),\n }\n\n const darkGround = style.ground === 'tinted' ? 0.024 : style.ground === 'warm' ? 0.014 : 0.012\n const darkBackground = aiOklchHex(0.17, darkGround * groundChroma, style.ground === 'warm' ? 60 : h)\n const darkPaper = aiOklchHex(0.215, darkGround * groundChroma, style.ground === 'warm' ? 60 : h)\n const darkChroma = Math.min(chroma, 0.14)\n const darkPrimaryL = untilContrast(0.78, darkChroma, h, darkBackground, 4.5, 1)\n const darkPrimary = aiOklchHex(darkPrimaryL, darkChroma, h)\n const darkSecondary = neutral ? aiOklchHex(0.93, 0.01, h) : aiOklchHex(0.45, accentChroma * 0.85, style.accent)\n const darkTertiary = aiOklchHex(0.8, 0.1, tertiaryHue)\n const dark: HostThemeSchemeColors = {\n primary: {\n main: darkPrimary,\n light: aiOklchHex(Math.min(0.94, darkPrimaryL + 0.08), darkChroma, h),\n dark: aiOklchHex(darkPrimaryL - 0.1, darkChroma, h),\n contrastText: labelOn(darkPrimary, h),\n },\n secondary: {\n main: darkSecondary,\n light: aiOklchHex(0.6, accentChroma * 0.7, secondary.h),\n dark: aiOklchHex(0.35, accentChroma * 0.7, secondary.h),\n contrastText: labelOn(darkSecondary, secondary.h),\n },\n tertiary: {\n main: darkTertiary,\n light: aiOklchHex(0.88, 0.08, tertiaryHue),\n dark: aiOklchHex(0.7, 0.1, tertiaryHue),\n contrastText: labelOn(darkTertiary, tertiaryHue),\n },\n surface: { main: aiOklchHex(0.25, 0.014 * groundChroma, h), contrastText: aiOklchHex(0.95, 0.01, h) },\n background: { default: darkBackground, paper: darkPaper },\n text: {\n primary: aiOklchHex(0.95, 0.008, h),\n secondary: aiOklchHex(0.77, 0.014, h),\n disabled: aiOklchHex(0.52, 0.01, h),\n },\n tint: {\n primary: aiOklchHex(0.27, 0.05, neutral ? style.accent : h),\n secondary: aiOklchHex(0.27, 0.05, style.accent),\n tertiary: aiOklchHex(0.27, 0.04, tertiaryHue),\n },\n divider: aiOklchHex(0.32, 0.015 * groundChroma, h),\n }\n return { light, dark }\n}\n\n// ── The theme ────────────────────────────────────────────────────────────\n\nconst RADIUS: Record<AiSiteCorners, number> = { sharp: 2, soft: 6, round: 12, pill: 18 }\nconst SPACING: Record<AiSiteDensity, number> = { compact: 7, regular: 8, airy: 9 }\n\n/** How much of the heading scale each style takes: a display line grows most, small headings not at all. */\nconst SCALE_SHARE: Partial<Record<HostThemeTypographyVariantKey, { size: number; share: number }>> = {\n displayXl: { size: 4, share: 1.2 },\n h1: { size: 3.25, share: 1 },\n h2: { size: 2.25, share: 0.8 },\n h3: { size: 1.75, share: 0.5 },\n h4: { size: 1.5, share: 0.3 },\n h5: { size: 1.25, share: 0 },\n h6: { size: 1.125, share: 0 },\n}\n\nconst rem = (value: number) => `${Math.round(value * 1000) / 1000}rem`\n\n/** The type a style sets: headings at its scale, weight and tracking, and the eyebrow and button styles. */\nfunction typographyFor(style: AiSiteStyle): HostTheme['typography'] {\n const pairing = aiSiteFontPairing(style.fonts) ?? (AI_SITE_FONT_PAIRINGS[0] as NonNullable<ReturnType<typeof aiSiteFontPairing>>)\n const variants: Partial<Record<HostThemeTypographyVariantKey, HostThemeTypographyVariant>> = {\n ...(DEFAULT_SITE_THEME.typography?.variants ?? {}),\n }\n for (const [key, { size, share }] of Object.entries(SCALE_SHARE) as Array<[HostThemeTypographyVariantKey, { size: number; share: number }]>) {\n const big = key === 'displayXl' || key === 'h1' || key === 'h2'\n const variant: HostThemeTypographyVariant = {\n fontSize: rem(size * (1 + (style.headingScale - 1) * share) * (pairing.caps && big ? 0.92 : 1)),\n fontWeight: big ? pairing.heading.weight : pairing.heading.sub,\n lineHeight: big ? (pairing.caps ? 1.05 : 1.1) : 1.25,\n }\n if (pairing.tracking !== undefined && (big || key === 'h3')) variant.letterSpacing = `${pairing.tracking}em`\n if (pairing.caps && (big || key === 'h3')) variant.textTransform = 'uppercase'\n variants[key] = variant\n }\n const bodyBold = pairing.body.weights.includes(600) ? 600 : 700\n variants.overline =\n style.eyebrow === 'small'\n ? { fontSize: '0.875rem', fontWeight: bodyBold, letterSpacing: '0.01em', textTransform: 'none' }\n : { fontSize: '0.78rem', fontWeight: 700, letterSpacing: style.eyebrow === 'rule' ? '0.16em' : '0.12em', textTransform: 'uppercase' }\n variants.button = {\n fontWeight: style.buttons === 'caps' ? 700 : bodyBold,\n textTransform: style.buttons === 'caps' ? 'uppercase' : 'none',\n ...(style.buttons === 'caps' ? { letterSpacing: '0.06em' } : {}),\n }\n return { variants }\n}\n\n/** The card's look, in theme terms only: palette paths, shadow indexes and border widths. */\nfunction cardSx(cards: AiSiteCards): Record<string, unknown> {\n switch (cards) {\n case 'flat':\n return { boxShadow: 0, border: 0, bgcolor: 'surface.main' }\n case 'outlined':\n return { boxShadow: 0, border: 1, borderColor: 'divider', bgcolor: 'background.paper' }\n case 'elevated':\n return { boxShadow: 3, border: 0, bgcolor: 'background.paper' }\n case 'tinted':\n return { boxShadow: 0, border: 0, bgcolor: 'tint.primary' }\n case 'rule':\n return { boxShadow: 0, border: 0, borderTop: 3, borderColor: 'primary.main', borderRadius: 0, bgcolor: 'background.paper' }\n }\n}\n\n/** The component defaults and styles a style sets: buttons, cards, fields, eyebrows, the header bar and the FAQ. */\nfunction componentsFor(style: AiSiteStyle): Record<string, HostThemeComponentOverride> {\n const radius = RADIUS[style.corners]\n const buttonRadius = style.buttons === 'pill' ? 999 : style.buttons === 'square' ? 2 : radius\n const card = cardSx(style.cards)\n return {\n MuiButton: {\n defaultProps: { disableElevation: true },\n // 44px: the touch target a visitor's thumb needs.\n styleOverrides: { root: { borderRadius: buttonRadius, minHeight: 44, boxShadow: 'none' } },\n ...(style.buttons === 'link'\n ? {\n variants: [\n {\n props: { variant: 'text' },\n style: { textDecoration: 'underline', textUnderlineOffset: '0.3em', textDecorationThickness: '2px' },\n },\n ],\n }\n : {}),\n },\n MuiCard: {\n defaultProps:\n style.cards === 'outlined'\n ? { variant: 'outlined' }\n : { variant: 'elevation', elevation: style.cards === 'elevated' ? 3 : 0 },\n styleOverrides: { root: { borderRadius: style.cards === 'rule' ? 0 : Math.max(radius, 4) } },\n sx: { root: card },\n },\n MuiAccordion: {\n defaultProps: { disableGutters: true, elevation: 0 },\n sx: {\n root: {\n ...card,\n borderTop: style.cards === 'rule' ? 1 : card['borderTop'] ?? card['border'],\n '&::before': { display: 'none' },\n '&:not(:last-of-type)': { mb: 1 },\n },\n },\n },\n MuiTextField: { defaultProps: { variant: style.fields } },\n MuiOutlinedInput: { styleOverrides: { root: { borderRadius: radius } } },\n MuiFilledInput: { styleOverrides: { root: { borderTopLeftRadius: radius, borderTopRightRadius: radius } } },\n MuiChip: { styleOverrides: { root: { borderRadius: style.corners === 'sharp' ? 2 : 999 } } },\n MuiAppBar: {\n defaultProps: { elevation: 0 },\n variants: [\n {\n props: { color: 'inherit' },\n sx:\n style.header === 'line'\n ? { boxShadow: 0, borderBottom: 1, borderColor: 'divider' }\n : style.header === 'shadow'\n ? { boxShadow: 2, borderBottom: 0 }\n : { boxShadow: 0, borderBottom: 0 },\n },\n ],\n },\n ...(style.eyebrow === 'rule'\n ? {\n MuiTypography: {\n variants: [\n {\n props: { variant: 'overline' },\n // A short line in the eyebrow's own color, so it reads on any band.\n style: {\n '&::before': {\n content: '\"\"',\n display: 'inline-block',\n width: '1.75em',\n height: '2px',\n marginRight: '0.75em',\n verticalAlign: 'middle',\n backgroundColor: 'currentColor',\n },\n },\n },\n ],\n },\n }\n : {}),\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** `over` merged into `under`, objects key by key, anything else replaced. */\nfunction merged<T>(under: T, over: unknown): T {\n if (!isRecord(under) || !isRecord(over)) return (over === undefined ? under : over) as T\n const out: Record<string, unknown> = { ...under }\n for (const [key, value] of Object.entries(over)) out[key] = key in out ? merged(out[key], value) : value\n return out as T\n}\n\n/** Whether a theme passes the publish check and the brand-on-page contrast the doctrine asks. */\nfunction themeReads(theme: HostTheme): boolean {\n if (!validateThemeForPublish(theme).ok) return false\n for (const scheme of ['light', 'dark'] as const) {\n const colors = theme.colorSchemes?.[scheme]\n const main = colors?.primary?.main\n const page = colors?.background?.default\n if (!main || !page || ratio(main, page) < 3) return false\n for (const key of ['primary', 'secondary', 'tertiary'] as const) {\n const fill = colors?.[key]\n if (fill?.main && fill.contrastText && ratio(fill.contrastText, fill.main) < 4.5) return false\n }\n }\n return true\n}\n\n/**\n * The site's theme: the base theme with this style layered over it. Colors,\n * type, corners, spacing and the building blocks' component styles are the\n * site's own; whatever the base sets beyond them — its focus rings, its menu\n * and dialog styles, its control heights — stays the base's.\n */\nexport function aiSiteTheme(style: AiSiteStyle, base: HostTheme): HostTheme {\n const pairing = aiSiteFontPairing(style.fonts) ?? (AI_SITE_FONT_PAIRINGS[0] as NonNullable<ReturnType<typeof aiSiteFontPairing>>)\n const colors = aiSiteColors(style)\n const keep = (scheme: 'light' | 'dark') => {\n const own = base.colorSchemes?.[scheme] ?? {}\n // The status colors stay the base's: they mean the same thing on every site.\n return {\n ...(own.error ? { error: own.error } : {}),\n ...(own.warning ? { warning: own.warning } : {}),\n ...(own.info ? { info: own.info } : {}),\n ...(own.success ? { success: own.success } : {}),\n ...colors[scheme],\n }\n }\n let theme: HostTheme = {\n ...base,\n colorSchemes: { light: keep('light'), dark: keep('dark') },\n typography: merged(base.typography ?? {}, typographyFor(style)),\n shape: { ...(base.shape ?? {}), borderRadius: RADIUS[style.corners] },\n spacing: SPACING[style.density],\n components: merged(base.components ?? {}, componentsFor(style)),\n }\n delete theme.darkScheme\n const sameFamily = pairing.heading.family === pairing.body.family\n theme = writeThemeFonts(theme, {\n body: { family: pairing.body.family, category: pairing.body.category, weights: [...pairing.body.weights], source: 'google' },\n heading: sameFamily\n ? null\n : {\n family: pairing.heading.family,\n category: pairing.heading.category,\n weights: [...new Set([pairing.heading.weight, pairing.heading.sub])].sort((a, b) => a - b),\n source: 'google',\n },\n })\n // A pairing whose heading is the body family loads the heading weights too.\n if (sameFamily && theme.fonts?.[0]) {\n theme.fonts[0] = {\n ...theme.fonts[0],\n weights: [...new Set([...(theme.fonts[0].weights ?? []), pairing.heading.weight, pairing.heading.sub])].sort((a, b) => a - b),\n }\n }\n if (!themeReads(theme)) {\n // Never a theme that fails the reading checks: the starter's colors, with everything else kept.\n theme = { ...theme, colorSchemes: DEFAULT_SITE_THEME.colorSchemes }\n }\n return theme\n}\n"],"names":["contrastRatio","validateThemeForPublish","DEFAULT_SITE_THEME","writeThemeFonts","AI_SITE_BASES","AI_SITE_CORNERS","AI_SITE_FONT_PAIRINGS","AI_SITE_GROUNDS","AI_SITE_RHYTHMS","aiSiteFontPairing","AI_SITE_CARDS","AI_SITE_FIELDS","AI_SITE_EYEBROWS","AI_SITE_HEADERS","AI_SITE_BUTTONS","DENSITIES","aiSiteSeed","jobId","hash","index","length","charCodeAt","Math","imul","random","seed","state","t","pick","next","list","floor","AI_SITE_LOOK_TOOL_NAME","enumOf","values","description","type","enum","AI_SITE_LOOK_TOOL","name","strict","inputSchema","additionalProperties","required","properties","base","hue","accent","ground","fonts","map","pairing","id","corners","buttons","cards","fields","eyebrow","header","brand","anyOf","oneOf","value","includes","undefined","hueOf","Number","isFinite","round","aiSiteBrandHex","match","exec","trim","hex","full","digit","join","toLowerCase","aiReadSiteLook","answer","raw","look","BLOCK_BIAS","portfolio","studio","photography","blog","trades","fitness","professional","wellness","yoga","restaurant","beauty","music","ANY_BLOCKS","aiSiteHueFamily","rangeOf","kind","hues","findIndex","from","to","AI_SITE_LOOK_DIMENSIONS","aiSiteLookSignature","style","hueFamily","String","headerAlign","rhythm","aiSiteStyleFor","input","avoid","styleOnce","signatures","best","attempt","AI_SITE_LOOK_DRAWS","own","least","min","other","TUPLE","every","dimension","filter","AI_SITE_LOOK_LEAST_DIFFERENCES","family","blocks","choose","model","options","keep","modelRange","keepHue","range","span","accentFrom","bases","Set","v","chroma","grounds","headerAligns","rhythms","headingScale","density","oklabToLinear","L","a","b","l","m","s","toSrgb","channel","fromSrgb","aiOklchHex","C","h","lightness","max","radians","PI","linear","cos","sin","fits","toString","padStart","aiHexOklch","replace","r","g","at","parseInt","slice","cbrt","A","B","hypot","atan2","ratio","untilContrast","against","toward","step","labelOn","fill","white","ink","CHROMA","neutral","muted","balanced","vivid","START_L","aiSiteColors","groundChroma","paper","warm","cool","tinted","background","primaryMain","primaryL","accentChroma","secondary","main","washChroma","tertiaryHue","tertiaryL","tertiary","textChroma","light","primary","dark","contrastText","surface","default","text","disabled","tint","divider","darkGround","darkBackground","darkPaper","darkChroma","darkPrimaryL","darkPrimary","darkSecondary","darkTertiary","RADIUS","sharp","soft","pill","SPACING","compact","regular","airy","SCALE_SHARE","displayXl","size","share","h1","h2","h3","h4","h5","h6","rem","typographyFor","variants","typography","key","Object","entries","big","variant","fontSize","caps","fontWeight","heading","weight","sub","lineHeight","tracking","letterSpacing","textTransform","bodyBold","body","weights","overline","button","cardSx","boxShadow","border","bgcolor","borderColor","borderTop","borderRadius","componentsFor","card","radius","buttonRadius","MuiButton","defaultProps","disableElevation","styleOverrides","root","minHeight","props","textDecoration","textUnderlineOffset","textDecorationThickness","MuiCard","elevation","sx","MuiAccordion","disableGutters","display","mb","MuiTextField","MuiOutlinedInput","MuiFilledInput","borderTopLeftRadius","borderTopRightRadius","MuiChip","MuiAppBar","color","borderBottom","MuiTypography","content","width","height","marginRight","verticalAlign","backgroundColor","isRecord","Array","isArray","merged","under","over","out","themeReads","theme","ok","scheme","colors","colorSchemes","page","aiSiteTheme","error","warning","info","success","shape","spacing","components","darkScheme","sameFamily","category","source","sort"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-look.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n contrastRatio,\n validateThemeForPublish,\n} from '@aglyn/aglyn/app-utils/site-theme'\nimport { DEFAULT_SITE_THEME } from '@aglyn/aglyn/app-utils/default-site'\nimport type {\n HostTheme,\n HostThemeComponentOverride,\n HostThemeSchemeColors,\n HostThemeTypographyVariant,\n HostThemeTypographyVariantKey,\n} from '@aglyn/shared-data-types'\nimport { writeThemeFonts } from '@aglyn/shared-ui-theme/util/theme-editor-fields'\nimport type { AiTool } from '../runtime/ai-runtime'\nimport {\n AI_SITE_BASES,\n AI_SITE_CORNERS,\n AI_SITE_FONT_PAIRINGS,\n AI_SITE_GROUNDS,\n AI_SITE_RHYTHMS,\n aiSiteFontPairing,\n type AiSiteBase,\n type AiSiteButtons,\n type AiSiteChroma,\n type AiSiteCorners,\n type AiSiteDensity,\n type AiSiteGround,\n type AiSiteKind,\n type AiSiteRhythm,\n} from './ai-site-kinds'\n\n/**\n * A site's look (AGL-3660): one of the platform's base themes, and this\n * site's own customizations layered over it as the site theme's override —\n * the same base-and-edits shape a person's pick on Setup → Theme is stored\n * as, so the Theme page names the base it came from and every edit there\n * starts from what the AI chose.\n *\n * Everything the look decides lives in the THEME, never on a node: palette,\n * fonts, type scale, corners, spacing, and the component defaults and styles\n * of buttons, cards, fields, eyebrows, the header bar and the FAQ. So a Card\n * or a Button a person drags in later looks like the rest of the site, and\n * the layout compiler emits plain components.\n *\n * Three inputs decide it:\n * - the KIND (`ai-site-kinds.ts`): the family of looks that suit the site;\n * - the MODEL's choices for this business (`submit_site_look`), any of\n * which may be missing;\n * - the per-job SEED, which fills what the model left out from the kind's\n * options and nudges every hue, chroma and size, so two jobs with the same\n * brief and the same answers still produce two different themes.\n *\n * Colors are built in OKLCH and held to WCAG: body text 4.5:1 on its ground\n * and on paper, every button label 4.5:1 on its fill, the brand color 3:1 on\n * the page — then the whole theme passes `validateThemeForPublish`, or its\n * colors fall back to the starter theme's.\n */\n\n// ── The tokens ───────────────────────────────────────────────────────────\n\n/** How cards are drawn. */\nexport const AI_SITE_CARDS = ['flat', 'outlined', 'elevated', 'tinted', 'rule'] as const\nexport type AiSiteCards = (typeof AI_SITE_CARDS)[number]\n/** The form field style. */\nexport const AI_SITE_FIELDS = ['outlined', 'filled', 'standard'] as const\nexport type AiSiteFields = (typeof AI_SITE_FIELDS)[number]\n/** How an eyebrow above a heading is set. */\nexport const AI_SITE_EYEBROWS = ['caps', 'small', 'rule'] as const\nexport type AiSiteEyebrow = (typeof AI_SITE_EYEBROWS)[number]\n/** What sets a plain header bar off the page. */\nexport const AI_SITE_HEADERS = ['line', 'shadow', 'flat'] as const\nexport type AiSiteHeader = (typeof AI_SITE_HEADERS)[number]\n/** Button shapes and casing; `link` draws quiet buttons as underlined links. */\nexport const AI_SITE_BUTTONS: readonly AiSiteButtons[] = ['rounded', 'pill', 'square', 'caps', 'link']\nconst DENSITIES: readonly AiSiteDensity[] = ['compact', 'regular', 'airy']\n\n/**\n * A site's style tokens: everything its theme was built from. Stored with the\n * site (`hosts/{id}.siteStyle`) so a later AI edit keeps the look.\n */\nexport interface AiSiteStyle {\n v: 1\n kind: string\n base: AiSiteBase\n seed: number\n hue: number\n accent: number\n chroma: AiSiteChroma\n ground: AiSiteGround\n fonts: string\n corners: AiSiteCorners\n buttons: AiSiteButtons\n cards: AiSiteCards\n fields: AiSiteFields\n eyebrow: AiSiteEyebrow\n header: AiSiteHeader\n /** The header's arrangement: brand at the start and links after it, or both centered. */\n headerAlign: 'start' | 'center'\n /** How the pages alternate their bands. */\n rhythm: AiSiteRhythm\n headingScale: number\n density: AiSiteDensity\n /** A brand color the brief gave, used as the primary color. */\n brand: string | null\n}\n\n/** What the model may choose, every field optional. */\nexport type AiSiteLookAnswer = Partial<\n Pick<\n AiSiteStyle,\n 'base' | 'hue' | 'accent' | 'ground' | 'fonts' | 'corners' | 'buttons' | 'cards' | 'fields' | 'eyebrow' | 'header' | 'brand'\n >\n>\n\n// ── The seed ─────────────────────────────────────────────────────────────\n\n/** A job's seed: FNV-1a over its id. */\nexport function aiSiteSeed(jobId: string): number {\n let hash = 0x811c9dc5\n for (let index = 0; index < jobId.length; index += 1) {\n hash ^= jobId.charCodeAt(index)\n hash = Math.imul(hash, 0x01000193)\n }\n return hash >>> 0\n}\n\n/** A small deterministic generator over a seed (mulberry32). */\nfunction random(seed: number): () => number {\n let state = seed >>> 0\n return () => {\n state = (state + 0x6d2b79f5) >>> 0\n let t = state\n t = Math.imul(t ^ (t >>> 15), t | 1)\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61)\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\nconst pick = <T,>(next: () => number, list: readonly T[]): T => list[Math.floor(next() * list.length) % list.length] as T\n\n// ── The model's answer ───────────────────────────────────────────────────\n\nexport const AI_SITE_LOOK_TOOL_NAME = 'submit_site_look'\n\nconst enumOf = (values: readonly string[], description: string) => ({ type: 'string', enum: [...values], description })\n\n/** The strict tool the look is answered with; every field is required and the reader is lenient. */\nexport const AI_SITE_LOOK_TOOL: AiTool = {\n name: AI_SITE_LOOK_TOOL_NAME,\n description: \"Submit this website's look: the base theme it starts from and the choices that make it this business's own.\",\n strict: true,\n inputSchema: {\n type: 'object',\n additionalProperties: false,\n required: ['base', 'hue', 'accent', 'ground', 'fonts', 'corners', 'buttons', 'cards', 'fields', 'eyebrow', 'header', 'brand'],\n properties: {\n base: enumOf(AI_SITE_BASES, 'The base theme to start from, from the list in the request.'),\n hue: { type: 'integer', description: 'The brand color as a hue from 0 to 359 (0 red, 30 orange, 55 gold, 140 green, 190 teal, 220 blue, 270 violet, 330 pink).' },\n accent: { type: 'integer', description: 'The accent color as a hue from 0 to 359, chosen to sit well beside the brand hue.' },\n ground: enumOf(AI_SITE_GROUNDS, 'The page background: white, warm (cream), cool (gray-blue) or tinted (a whisper of the brand color).'),\n fonts: enumOf(AI_SITE_FONT_PAIRINGS.map((pairing) => pairing.id), 'A font pairing from the list in the request.'),\n corners: enumOf(AI_SITE_CORNERS, 'Corner rounding for cards and fields.'),\n buttons: enumOf(AI_SITE_BUTTONS, 'Buttons: rounded, pill, square, caps (capitals) or link (quiet buttons drawn as underlined links).'),\n cards: enumOf(AI_SITE_CARDS, 'Cards: flat, outlined, elevated (a soft shadow), tinted (a wash of the brand color) or rule (a colored line on top).'),\n fields: enumOf(AI_SITE_FIELDS, 'Form fields: outlined, filled or standard (underlined).'),\n eyebrow: enumOf(AI_SITE_EYEBROWS, 'The small label above headings: caps (spaced capitals), small (quiet small text) or rule (capitals after a short line).'),\n header: enumOf(AI_SITE_HEADERS, 'What sets the header bar off the page: a line, a shadow, or flat.'),\n brand: { anyOf: [{ type: 'string' }, { type: 'null' }], description: 'A hex brand color the brief gives, exactly as written, or null.' },\n },\n },\n}\n\nconst oneOf = <T extends string>(value: unknown, values: readonly T[]): T | undefined =>\n typeof value === 'string' && (values as readonly string[]).includes(value) ? (value as T) : undefined\n\nconst hueOf = (value: unknown): number | undefined =>\n typeof value === 'number' && Number.isFinite(value) ? ((Math.round(value) % 360) + 360) % 360 : undefined\n\n/** A brand color as a six-digit hex, or `null`. */\nexport function aiSiteBrandHex(value: unknown): string | null {\n if (typeof value !== 'string') return null\n const match = /#?([0-9a-f]{6}|[0-9a-f]{3})\\b/i.exec(value.trim())\n if (!match) return null\n const hex = match[1] as string\n const full = hex.length === 3 ? [...hex].map((digit) => digit + digit).join('') : hex\n return `#${full.toLowerCase()}`\n}\n\n/** The model's answer, read leniently: a value outside its vocabulary is left for the seed. */\nexport function aiReadSiteLook(answer: unknown): AiSiteLookAnswer {\n const raw = (answer && typeof answer === 'object' ? answer : {}) as Record<string, unknown>\n const look: AiSiteLookAnswer = {}\n const base = oneOf(raw['base'], AI_SITE_BASES)\n if (base) look.base = base\n const hue = hueOf(raw['hue'])\n if (hue !== undefined) look.hue = hue\n const accent = hueOf(raw['accent'])\n if (accent !== undefined) look.accent = accent\n const ground = oneOf(raw['ground'], AI_SITE_GROUNDS)\n if (ground) look.ground = ground\n if (aiSiteFontPairing(raw['fonts'])) look.fonts = raw['fonts'] as string\n const corners = oneOf(raw['corners'], AI_SITE_CORNERS)\n if (corners) look.corners = corners\n const buttons = oneOf(raw['buttons'], AI_SITE_BUTTONS)\n if (buttons) look.buttons = buttons\n const cards = oneOf(raw['cards'], AI_SITE_CARDS)\n if (cards) look.cards = cards\n const fields = oneOf(raw['fields'], AI_SITE_FIELDS)\n if (fields) look.fields = fields\n const eyebrow = oneOf(raw['eyebrow'], AI_SITE_EYEBROWS)\n if (eyebrow) look.eyebrow = eyebrow\n const header = oneOf(raw['header'], AI_SITE_HEADERS)\n if (header) look.header = header\n const brand = aiSiteBrandHex(raw['brand'])\n if (brand) look.brand = brand\n return look\n}\n\n// ── Kind, model and seed into tokens ─────────────────────────────────────\n\n/** The building-block styles a kind leans to, before the model or the seed choose. */\nconst BLOCK_BIAS: Partial<\n Record<string, { cards: readonly AiSiteCards[]; eyebrow: readonly AiSiteEyebrow[]; header: readonly AiSiteHeader[]; fields: readonly AiSiteFields[] }>\n> = {\n portfolio: { cards: ['rule', 'flat', 'outlined'], eyebrow: ['small', 'rule', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'outlined', 'filled'] },\n studio: { cards: ['flat', 'rule', 'outlined'], eyebrow: ['rule', 'small', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'outlined', 'filled'] },\n photography: { cards: ['flat', 'rule', 'outlined'], eyebrow: ['small', 'rule', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'outlined', 'filled'] },\n blog: { cards: ['rule', 'outlined', 'flat', 'tinted'], eyebrow: ['small', 'caps', 'rule'], header: ['line', 'flat', 'shadow'], fields: ['outlined', 'standard', 'filled'] },\n trades: { cards: ['elevated', 'outlined', 'rule', 'flat', 'tinted'], eyebrow: ['caps', 'rule', 'small'], header: ['shadow', 'line', 'flat'], fields: ['outlined', 'filled', 'standard'] },\n fitness: { cards: ['elevated', 'flat', 'rule', 'outlined'], eyebrow: ['caps', 'rule', 'small'], header: ['shadow', 'flat', 'line'], fields: ['filled', 'outlined', 'standard'] },\n professional: { cards: ['outlined', 'rule', 'flat', 'elevated'], eyebrow: ['caps', 'rule', 'small'], header: ['line', 'flat', 'shadow'], fields: ['outlined', 'standard', 'filled'] },\n wellness: { cards: ['tinted', 'flat', 'elevated', 'outlined'], eyebrow: ['small', 'caps', 'rule'], header: ['flat', 'line', 'shadow'], fields: ['filled', 'outlined', 'standard'] },\n yoga: { cards: ['tinted', 'flat', 'outlined'], eyebrow: ['small', 'rule', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['filled', 'standard', 'outlined'] },\n restaurant: { cards: ['flat', 'elevated', 'tinted', 'rule'], eyebrow: ['caps', 'rule', 'small'], header: ['flat', 'shadow', 'line'], fields: ['outlined', 'filled', 'standard'] },\n beauty: { cards: ['tinted', 'flat', 'outlined', 'rule'], eyebrow: ['rule', 'small', 'caps'], header: ['flat', 'line', 'shadow'], fields: ['standard', 'filled', 'outlined'] },\n music: { cards: ['flat', 'rule', 'elevated'], eyebrow: ['caps', 'rule', 'small'], header: ['flat', 'shadow', 'line'], fields: ['filled', 'standard', 'outlined'] },\n}\nconst ANY_BLOCKS = { cards: AI_SITE_CARDS, eyebrow: AI_SITE_EYEBROWS, header: AI_SITE_HEADERS, fields: AI_SITE_FIELDS }\n\n/** The hue family a hue is in: twelve families of thirty degrees, 0 the reds. */\nexport function aiSiteHueFamily(hue: number): number {\n return Math.floor((((hue + 15) % 360) + 360) % 360 / 30)\n}\n\n/** Which of a kind's hue ranges a hue falls in, or -1. */\nfunction rangeOf(hue: number, kind: AiSiteKind): number {\n return kind.look.hues.findIndex(([from, to]) => (from <= to ? hue >= from && hue <= to : hue >= from || hue <= to))\n}\n\n/** The look dimensions two sites are compared by (`ai-site-look.spec.ts`). */\nexport const AI_SITE_LOOK_DIMENSIONS = [\n 'base',\n 'hueFamily',\n 'fonts',\n 'buttons',\n 'cards',\n 'corners',\n 'ground',\n 'eyebrow',\n 'header',\n 'fields',\n 'headerAlign',\n 'rhythm',\n] as const\n\n/** A style's value on each tracked dimension. */\nexport function aiSiteLookSignature(style: AiSiteStyle): Record<(typeof AI_SITE_LOOK_DIMENSIONS)[number], string> {\n return {\n base: style.base,\n hueFamily: String(aiSiteHueFamily(style.hue)),\n fonts: style.fonts,\n buttons: style.buttons,\n cards: style.cards,\n corners: style.corners,\n ground: style.ground,\n eyebrow: style.eyebrow,\n header: style.header,\n fields: style.fields,\n headerAlign: style.headerAlign,\n rhythm: style.rhythm,\n }\n}\n\n/**\n * The style tokens for a site of this kind (AGL-3660). Every dimension is\n * the SEED's choice among what suits the kind, with the model's choice for\n * this business as a favored candidate — kept at a given chance, not always\n * — so the brief steers the look and two jobs with the same brief and the\n * same answer still come out as two sites: another base, another hue family,\n * another pairing, other buttons. A brand color the brief gives is always\n * kept.\n */\nexport function aiSiteStyleFor(input: {\n kind: AiSiteKind\n answer: AiSiteLookAnswer\n seed: number\n brand?: string | null\n /**\n * The looks of the workspace's other sites (AGL-3660): a look that shares\n * one's base, hue family, heading font and buttons, or differs from one in\n * fewer than three tracked dimensions, is drawn again from the next seed.\n */\n avoid?: readonly AiSiteStyle[]\n}): AiSiteStyle {\n const avoid = input.avoid ?? []\n if (!avoid.length) return styleOnce(input, input.seed)\n const signatures = avoid.map(aiSiteLookSignature)\n let best: { style: AiSiteStyle; least: number } | null = null\n for (let attempt = 0; attempt < AI_SITE_LOOK_DRAWS; attempt += 1) {\n const style = styleOnce(input, attempt === 0 ? input.seed : (Math.imul(input.seed ^ 0x5bd1e995, attempt + 1) >>> 0))\n const own = aiSiteLookSignature(style)\n const least = Math.min(\n ...signatures.map((other) =>\n TUPLE.every((dimension) => own[dimension] === other[dimension])\n ? -1\n : AI_SITE_LOOK_DIMENSIONS.filter((dimension) => own[dimension] !== other[dimension]).length,\n ),\n )\n if (least >= AI_SITE_LOOK_LEAST_DIFFERENCES) return style\n if (!best || least > best.least) best = { style, least }\n }\n return (best as { style: AiSiteStyle }).style\n}\n\n/** How many seeds a look draws before it settles for the most different. */\nexport const AI_SITE_LOOK_DRAWS = 32\n/** The fewest tracked dimensions in which two of a workspace's sites differ. */\nexport const AI_SITE_LOOK_LEAST_DIFFERENCES = 3\n/** The dimensions no two of a workspace's sites share all of. */\nconst TUPLE = ['base', 'hueFamily', 'fonts', 'buttons'] as const\n\nfunction styleOnce(\n input: { kind: AiSiteKind; answer: AiSiteLookAnswer; brand?: string | null },\n seed: number,\n): AiSiteStyle {\n const { kind, answer } = input\n const next = random(seed)\n const family = kind.look\n const blocks = BLOCK_BIAS[kind.id] ?? ANY_BLOCKS\n /** The model's choice at a chance of `keep`, else the seed's among `options`. */\n const choose = <T,>(model: T | undefined, options: readonly T[], keep: number): T =>\n model !== undefined && next() < keep ? model : pick(next, options)\n\n // The hue: a family among the kind's (the brief's industry), the model's\n // own family favored, and a hue within it.\n const modelRange = answer.hue === undefined ? -1 : rangeOf(answer.hue, kind)\n const keepHue = modelRange !== -1 && next() < 0.3\n const range = keepHue ? modelRange : Math.floor(next() * family.hues.length) % family.hues.length\n const [from, to] = family.hues[range] as readonly [number, number]\n const span = from <= to ? to - from : 360 - from + to\n const hue = keepHue\n ? ((answer.hue as number) + (next() < 0.5 ? -1 : 1) * Math.round(4 + next() * 8) + 360) % 360\n : Math.round(from + next() * span) % 360\n const accentFrom = answer.accent !== undefined && next() < 0.4 ? answer.accent : (hue + pick(next, [30, 150, 180, 210, 330])) % 360\n const accent = (accentFrom + (next() < 0.5 ? -1 : 1) * Math.round(8 + next() * 16) + 360) % 360\n\n const bases = [...new Set([...(answer.base ? [answer.base] : []), ...family.bases])]\n return {\n v: 1,\n kind: kind.id,\n base: choose(answer.base, bases, 0.3),\n seed,\n hue,\n accent,\n chroma: family.chroma,\n ground: choose(answer.ground, family.grounds, 0.35),\n fonts: choose(answer.fonts, family.fonts, 0.3),\n corners: choose(answer.corners, family.corners, 0.35),\n buttons: choose(answer.buttons, [family.buttons, ...AI_SITE_BUTTONS], 0.3),\n cards: choose(answer.cards, blocks.cards, 0.35),\n fields: choose(answer.fields, blocks.fields, 0.35),\n eyebrow: choose(answer.eyebrow, blocks.eyebrow, 0.35),\n header: choose(answer.header, blocks.header, 0.35),\n headerAlign: pick(next, family.headerAligns ?? ['start', 'start', 'center']),\n rhythm: pick(next, family.rhythms ?? AI_SITE_RHYTHMS),\n headingScale: Math.round(family.headingScale * (0.94 + next() * 0.12) * 100) / 100,\n density: family.density === 'regular' && next() < 0.25 ? pick(next, DENSITIES) : family.density,\n brand: aiSiteBrandHex(input.brand) ?? answer.brand ?? null,\n }\n}\n\n// ── Color ────────────────────────────────────────────────────────────────\n\ntype Rgb = [number, number, number]\n\nfunction oklabToLinear(L: number, a: number, b: number): Rgb {\n const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3\n const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3\n const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3\n return [\n 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s,\n -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s,\n -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s,\n ]\n}\n\nconst toSrgb = (channel: number) =>\n channel <= 0.0031308 ? 12.92 * channel : 1.055 * channel ** (1 / 2.4) - 0.055\nconst fromSrgb = (channel: number) =>\n channel <= 0.04045 ? channel / 12.92 : ((channel + 0.055) / 1.055) ** 2.4\n\n/** An OKLCH color as hex, its chroma reduced until it fits sRGB. */\nexport function aiOklchHex(L: number, C: number, h: number): string {\n const lightness = Math.min(1, Math.max(0, L))\n let chroma = Math.max(0, C)\n for (;;) {\n const radians = (h * Math.PI) / 180\n const linear = oklabToLinear(lightness, chroma * Math.cos(radians), chroma * Math.sin(radians))\n const fits = linear.every((channel) => channel >= -0.0005 && channel <= 1.0005)\n if (fits || chroma <= 0) {\n return `#${linear\n .map((channel) => Math.round(Math.min(1, Math.max(0, toSrgb(Math.min(1, Math.max(0, channel))))) * 255))\n .map((value) => value.toString(16).padStart(2, '0'))\n .join('')}`\n }\n chroma = Math.max(0, chroma - 0.004)\n }\n}\n\n/** A hex color in OKLCH. */\nexport function aiHexOklch(hex: string): { L: number; C: number; h: number } {\n const value = hex.replace('#', '')\n const [r, g, b] = [0, 2, 4].map((at) => fromSrgb(parseInt(value.slice(at, at + 2), 16) / 255)) as Rgb\n const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b)\n const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b)\n const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b)\n const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s\n const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s\n const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s\n return { L, C: Math.hypot(A, B), h: ((Math.atan2(B, A) * 180) / Math.PI + 360) % 360 }\n}\n\nconst ratio = (a: string, b: string) => contrastRatio(a, b) ?? 1\n\n/** The lightness, stepped from `L` toward `toward`, at which `hex(L)` first reaches `min` against `against`. */\nfunction untilContrast(L: number, C: number, h: number, against: string, min: number, toward: 0 | 1): number {\n let lightness = L\n for (let step = 0; step < 60; step += 1) {\n if (ratio(aiOklchHex(lightness, C, h), against) >= min) return lightness\n lightness += toward ? 0.012 : -0.012\n if (lightness <= 0.05 || lightness >= 0.98) break\n }\n return lightness\n}\n\n/** The label color of a fill: white or a deep ink of its hue, whichever reads at 4.5:1, or better. */\nfunction labelOn(fill: string, h: number): string {\n const white = '#ffffff'\n const ink = aiOklchHex(0.2, 0.04, h)\n return ratio(white, fill) >= 4.5 ? white : ratio(ink, fill) >= 4.5 ? ink : ratio(white, fill) > ratio(ink, fill) ? white : '#000000'\n}\n\n/** How far apart two hues sit on the wheel, in degrees: 0 to 180. */\nexport function aiHueGap(a: number, b: number): number {\n const d = Math.abs(a - b) % 360\n return Math.min(d, 360 - d)\n}\n\n/**\n * The widest gap an accent may keep from the brand hue and still color a\n * button beside it (AGL-3660). Past it the accent clashes: a live portfolio of\n * green (hue 131) and magenta (323) showed its outlined buttons as a pink wash\n * and its footer button as purple under green words, on a Cupertino base.\n */\nexport const AI_SITE_ACCENT_CLASH_DEGREES = 60\n\nconst CHROMA: Record<AiSiteChroma, number> = { neutral: 0.15, muted: 0.085, balanced: 0.135, vivid: 0.185 }\nconst START_L: Record<AiSiteChroma, number> = { neutral: 0.52, muted: 0.48, balanced: 0.52, vivid: 0.56 }\n\n/** Both schemes' colors for a style. */\nexport function aiSiteColors(style: AiSiteStyle): { light: HostThemeSchemeColors; dark: HostThemeSchemeColors } {\n const next = random(style.seed ^ 0x9e3779b9)\n const neutral = style.chroma === 'neutral'\n const brand = style.brand ? aiHexOklch(style.brand) : null\n const h = brand?.h ?? style.hue\n const chroma = brand?.C ?? CHROMA[style.chroma] * (0.9 + next() * 0.2)\n const groundChroma = neutral ? 0.3 : 1\n const white = '#ffffff'\n\n // The page grounds.\n const grounds: Record<AiSiteGround, { L: number; C: number; h: number; paper: [number, number] }> = {\n white: { L: 0.985, C: 0.004, h, paper: [1, 0] },\n warm: { L: 0.972, C: 0.016, h: 78, paper: [0.993, 0.007] },\n cool: { L: 0.974, C: 0.009, h: 250, paper: [1, 0] },\n tinted: { L: 0.968, C: 0.02, h, paper: [0.994, 0.006] },\n }\n const ground = grounds[style.ground]\n const background = aiOklchHex(ground.L, ground.C * groundChroma, ground.h)\n const paper = aiOklchHex(ground.paper[0], ground.paper[1] * groundChroma, ground.h)\n\n // The brand color: a button label reads on it, so it reads on the page too.\n let primaryMain: string\n let primaryL: number\n if (brand && ratio(white, style.brand as string) >= 4.5) {\n primaryMain = style.brand as string\n primaryL = brand.L\n } else {\n primaryL = untilContrast(brand ? Math.min(brand.L, START_L[style.chroma]) : START_L[style.chroma] + (next() - 0.5) * 0.06, chroma, h, white, 4.6, 0)\n primaryMain = aiOklchHex(primaryL, chroma, h)\n }\n const accentChroma = neutral ? 0.17 : Math.max(0.07, chroma * 0.95)\n // A button's colors come from the brand hue where the accent clashes with\n // it (AGL-3660); the accent keeps its tint and the tertiary.\n const buttonHue = aiHueGap(style.accent, h) > AI_SITE_ACCENT_CLASH_DEGREES ? h : style.accent\n\n // The secondary color fills a button ON a brand band, so it stands apart from the brand color.\n const secondary = neutral\n ? (() => {\n // Ink or paper, whichever stands further from the brand color (AGL-3660).\n const ink = aiOklchHex(0.24, 0.012, h)\n const paper = aiOklchHex(0.97, 0.008, h)\n return { main: ratio(ink, primaryMain) >= ratio(paper, primaryMain) ? ink : paper, h }\n })()\n : (() => {\n // A light wash of the accent rather than the accent at full strength:\n // it reads on the brand color without fighting it.\n const washChroma = Math.min(accentChroma, 0.08)\n let L = 0.9\n let main = aiOklchHex(L, washChroma, buttonHue)\n while (ratio(main, primaryMain) < 3 && L < 0.96) {\n L += 0.02\n main = aiOklchHex(L, washChroma, buttonHue)\n }\n return { main, h: buttonHue }\n })()\n const tertiaryHue = (style.accent + 60) % 360\n const tertiaryL = untilContrast(0.52, 0.12, tertiaryHue, white, 4.6, 0)\n const tertiary = aiOklchHex(tertiaryL, 0.12, tertiaryHue)\n const textChroma = neutral ? 0.006 : 0.02\n\n const light: HostThemeSchemeColors = {\n primary: {\n main: primaryMain,\n light: aiOklchHex(Math.min(0.92, primaryL + 0.12), chroma, h),\n dark: aiOklchHex(Math.max(0.15, primaryL - 0.1), chroma, h),\n contrastText: labelOn(primaryMain, h),\n },\n secondary: {\n main: secondary.main,\n light: aiOklchHex(0.93, accentChroma * 0.6, secondary.h),\n dark: aiOklchHex(0.42, accentChroma, secondary.h),\n contrastText: labelOn(secondary.main, secondary.h),\n },\n tertiary: {\n main: tertiary,\n light: aiOklchHex(Math.min(0.9, tertiaryL + 0.14), 0.12, tertiaryHue),\n dark: aiOklchHex(Math.max(0.15, tertiaryL - 0.1), 0.12, tertiaryHue),\n contrastText: labelOn(tertiary, tertiaryHue),\n },\n surface: { main: aiOklchHex(0.955, 0.012 * groundChroma, h), contrastText: aiOklchHex(0.22, textChroma, h) },\n background: { default: background, paper },\n text: {\n primary: aiOklchHex(0.22, textChroma, h),\n secondary: aiOklchHex(0.45, textChroma + 0.005, h),\n disabled: aiOklchHex(0.68, 0.01, h),\n },\n // The primary's tint is the brand's own wash (AGL-3660): a base fills an\n // outlined or tinted button with it, under the primary's dark words.\n tint: {\n primary: aiOklchHex(0.955, neutral ? 0.03 : 0.035, h),\n secondary: aiOklchHex(0.955, 0.035, buttonHue),\n tertiary: aiOklchHex(0.955, 0.03, tertiaryHue),\n },\n divider: aiOklchHex(0.9, 0.012 * groundChroma, h),\n }\n\n const darkGround = style.ground === 'tinted' ? 0.024 : style.ground === 'warm' ? 0.014 : 0.012\n const darkBackground = aiOklchHex(0.17, darkGround * groundChroma, style.ground === 'warm' ? 60 : h)\n const darkPaper = aiOklchHex(0.215, darkGround * groundChroma, style.ground === 'warm' ? 60 : h)\n const darkChroma = Math.min(chroma, 0.14)\n const darkPrimaryL = untilContrast(0.78, darkChroma, h, darkBackground, 4.5, 1)\n const darkPrimary = aiOklchHex(darkPrimaryL, darkChroma, h)\n const darkSecondary = neutral ? aiOklchHex(0.93, 0.01, h) : aiOklchHex(0.45, accentChroma * 0.85, buttonHue)\n const darkTertiary = aiOklchHex(0.8, 0.1, tertiaryHue)\n const dark: HostThemeSchemeColors = {\n primary: {\n main: darkPrimary,\n light: aiOklchHex(Math.min(0.94, darkPrimaryL + 0.08), darkChroma, h),\n dark: aiOklchHex(darkPrimaryL - 0.1, darkChroma, h),\n contrastText: labelOn(darkPrimary, h),\n },\n secondary: {\n main: darkSecondary,\n light: aiOklchHex(0.6, accentChroma * 0.7, secondary.h),\n dark: aiOklchHex(0.35, accentChroma * 0.7, secondary.h),\n contrastText: labelOn(darkSecondary, secondary.h),\n },\n tertiary: {\n main: darkTertiary,\n light: aiOklchHex(0.88, 0.08, tertiaryHue),\n dark: aiOklchHex(0.7, 0.1, tertiaryHue),\n contrastText: labelOn(darkTertiary, tertiaryHue),\n },\n surface: { main: aiOklchHex(0.25, 0.014 * groundChroma, h), contrastText: aiOklchHex(0.95, 0.01, h) },\n background: { default: darkBackground, paper: darkPaper },\n text: {\n primary: aiOklchHex(0.95, 0.008, h),\n secondary: aiOklchHex(0.77, 0.014, h),\n disabled: aiOklchHex(0.52, 0.01, h),\n },\n tint: {\n primary: aiOklchHex(0.27, 0.05, h),\n secondary: aiOklchHex(0.27, 0.05, buttonHue),\n tertiary: aiOklchHex(0.27, 0.04, tertiaryHue),\n },\n divider: aiOklchHex(0.32, 0.015 * groundChroma, h),\n }\n return { light, dark }\n}\n\n// ── The theme ────────────────────────────────────────────────────────────\n\nconst RADIUS: Record<AiSiteCorners, number> = { sharp: 2, soft: 6, round: 12, pill: 18 }\nconst SPACING: Record<AiSiteDensity, number> = { compact: 7, regular: 8, airy: 9 }\n\n/** How much of the heading scale each style takes: a display line grows most, small headings not at all. */\nconst SCALE_SHARE: Partial<Record<HostThemeTypographyVariantKey, { size: number; share: number }>> = {\n displayXl: { size: 4, share: 1.2 },\n h1: { size: 3.25, share: 1 },\n h2: { size: 2.25, share: 0.8 },\n h3: { size: 1.75, share: 0.5 },\n h4: { size: 1.5, share: 0.3 },\n h5: { size: 1.25, share: 0 },\n h6: { size: 1.125, share: 0 },\n}\n\nconst rem = (value: number) => `${Math.round(value * 1000) / 1000}rem`\n\n/**\n * The kinds whose titles are their design (AGL-3660): a portfolio's or a\n * studio's statement, a photographer's name over a cover, a publication's\n * masthead are set larger than a business site's, the way the designer\n * templates set them. The display line grows most, the page title a little,\n * and nothing under it; a phone still steps every size down\n * (`responsiveFontSizes`).\n */\nexport const AI_SITE_DISPLAY_BOOST: Readonly<Record<string, { display: number; title: number }>> = {\n portfolio: { display: 1.25, title: 1.1 },\n studio: { display: 1.3, title: 1.1 },\n photography: { display: 1.2, title: 1.08 },\n blog: { display: 1.25, title: 1.1 },\n}\n\n/** The type a style sets: headings at its scale, weight and tracking, and the eyebrow and button styles. */\nfunction typographyFor(style: AiSiteStyle): HostTheme['typography'] {\n const pairing = aiSiteFontPairing(style.fonts) ?? (AI_SITE_FONT_PAIRINGS[0] as NonNullable<ReturnType<typeof aiSiteFontPairing>>)\n const variants: Partial<Record<HostThemeTypographyVariantKey, HostThemeTypographyVariant>> = {\n ...(DEFAULT_SITE_THEME.typography?.variants ?? {}),\n }\n const boost = AI_SITE_DISPLAY_BOOST[style.kind]\n for (const [key, { size, share }] of Object.entries(SCALE_SHARE) as Array<[HostThemeTypographyVariantKey, { size: number; share: number }]>) {\n const big = key === 'displayXl' || key === 'h1' || key === 'h2'\n const boosted = key === 'displayXl' ? (boost?.display ?? 1) : key === 'h1' ? (boost?.title ?? 1) : 1\n const variant: HostThemeTypographyVariant = {\n fontSize: rem(size * (1 + (style.headingScale - 1) * share) * (pairing.caps && big ? 0.92 : 1) * boosted),\n fontWeight: big ? pairing.heading.weight : pairing.heading.sub,\n // A display line set larger sets tighter.\n lineHeight: big ? (pairing.caps ? 1.05 : key === 'displayXl' && boost ? 1.02 : 1.1) : 1.25,\n }\n if (pairing.tracking !== undefined && (big || key === 'h3')) variant.letterSpacing = `${pairing.tracking}em`\n if (pairing.caps && (big || key === 'h3')) variant.textTransform = 'uppercase'\n variants[key] = variant\n }\n const bodyBold = pairing.body.weights.includes(600) ? 600 : 700\n variants.overline =\n style.eyebrow === 'small'\n ? { fontSize: '0.875rem', fontWeight: bodyBold, letterSpacing: '0.01em', textTransform: 'none' }\n : { fontSize: '0.78rem', fontWeight: 700, letterSpacing: style.eyebrow === 'rule' ? '0.16em' : '0.12em', textTransform: 'uppercase' }\n variants.button = {\n fontWeight: style.buttons === 'caps' ? 700 : bodyBold,\n textTransform: style.buttons === 'caps' ? 'uppercase' : 'none',\n ...(style.buttons === 'caps' ? { letterSpacing: '0.06em' } : {}),\n }\n return { variants }\n}\n\n/** The card's look, in theme terms only: palette paths, shadow indexes and border widths. */\nfunction cardSx(cards: AiSiteCards): Record<string, unknown> {\n switch (cards) {\n case 'flat':\n return { boxShadow: 0, border: 0, bgcolor: 'surface.main' }\n case 'outlined':\n return { boxShadow: 0, border: 1, borderColor: 'divider', bgcolor: 'background.paper' }\n case 'elevated':\n return { boxShadow: 3, border: 0, bgcolor: 'background.paper' }\n case 'tinted':\n return { boxShadow: 0, border: 0, bgcolor: 'tint.primary' }\n case 'rule':\n return { boxShadow: 0, border: 0, borderTop: 3, borderColor: 'primary.main', borderRadius: 0, bgcolor: 'background.paper' }\n }\n}\n\n/** The component defaults and styles a style sets: buttons, cards, fields, eyebrows, the header bar and the FAQ. */\nfunction componentsFor(style: AiSiteStyle): Record<string, HostThemeComponentOverride> {\n const radius = RADIUS[style.corners]\n const buttonRadius = style.buttons === 'pill' ? 999 : style.buttons === 'square' ? 2 : radius\n const card = cardSx(style.cards)\n return {\n MuiButton: {\n defaultProps: { disableElevation: true },\n // 44px: the touch target a visitor's thumb needs.\n styleOverrides: { root: { borderRadius: buttonRadius, minHeight: 44, boxShadow: 'none' } },\n ...(style.buttons === 'link'\n ? {\n variants: [\n {\n props: { variant: 'text' },\n style: { textDecoration: 'underline', textUnderlineOffset: '0.3em', textDecorationThickness: '2px' },\n },\n ],\n }\n : {}),\n },\n MuiCard: {\n defaultProps:\n style.cards === 'outlined'\n ? { variant: 'outlined' }\n : { variant: 'elevation', elevation: style.cards === 'elevated' ? 3 : 0 },\n styleOverrides: { root: { borderRadius: style.cards === 'rule' ? 0 : Math.max(radius, 4) } },\n sx: { root: card },\n },\n MuiAccordion: {\n defaultProps: { disableGutters: true, elevation: 0 },\n sx: {\n root: {\n ...card,\n borderTop: style.cards === 'rule' ? 1 : card['borderTop'] ?? card['border'],\n '&::before': { display: 'none' },\n '&:not(:last-of-type)': { mb: 1 },\n },\n },\n },\n MuiTextField: { defaultProps: { variant: style.fields } },\n MuiOutlinedInput: { styleOverrides: { root: { borderRadius: radius } } },\n MuiFilledInput: { styleOverrides: { root: { borderTopLeftRadius: radius, borderTopRightRadius: radius } } },\n MuiChip: { styleOverrides: { root: { borderRadius: style.corners === 'sharp' ? 2 : 999 } } },\n MuiAppBar: {\n defaultProps: { elevation: 0 },\n variants: [\n {\n props: { color: 'inherit' },\n sx:\n style.header === 'line'\n ? { boxShadow: 0, borderBottom: 1, borderColor: 'divider' }\n : style.header === 'shadow'\n ? { boxShadow: 2, borderBottom: 0 }\n : { boxShadow: 0, borderBottom: 0 },\n },\n ],\n },\n ...(style.eyebrow === 'rule'\n ? {\n MuiTypography: {\n variants: [\n {\n props: { variant: 'overline' },\n // A short line in the eyebrow's own color, so it reads on any band.\n style: {\n '&::before': {\n content: '\"\"',\n display: 'inline-block',\n width: '1.75em',\n height: '2px',\n marginRight: '0.75em',\n verticalAlign: 'middle',\n backgroundColor: 'currentColor',\n },\n },\n },\n ],\n },\n }\n : {}),\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** `over` merged into `under`, objects key by key, anything else replaced. */\nfunction merged<T>(under: T, over: unknown): T {\n if (!isRecord(under) || !isRecord(over)) return (over === undefined ? under : over) as T\n const out: Record<string, unknown> = { ...under }\n for (const [key, value] of Object.entries(over)) out[key] = key in out ? merged(out[key], value) : value\n return out as T\n}\n\n/** Whether a theme passes the publish check and the brand-on-page contrast the doctrine asks. */\nfunction themeReads(theme: HostTheme): boolean {\n if (!validateThemeForPublish(theme).ok) return false\n for (const scheme of ['light', 'dark'] as const) {\n const colors = theme.colorSchemes?.[scheme]\n const main = colors?.primary?.main\n const page = colors?.background?.default\n if (!main || !page || ratio(main, page) < 3) return false\n for (const key of ['primary', 'secondary', 'tertiary'] as const) {\n const fill = colors?.[key]\n if (fill?.main && fill.contrastText && ratio(fill.contrastText, fill.main) < 4.5) return false\n }\n }\n return true\n}\n\n/**\n * The site's theme: the base theme with this style layered over it. Colors,\n * type, corners, spacing and the building blocks' component styles are the\n * site's own; whatever the base sets beyond them — its focus rings, its menu\n * and dialog styles, its control heights — stays the base's.\n */\nexport function aiSiteTheme(style: AiSiteStyle, base: HostTheme): HostTheme {\n const pairing = aiSiteFontPairing(style.fonts) ?? (AI_SITE_FONT_PAIRINGS[0] as NonNullable<ReturnType<typeof aiSiteFontPairing>>)\n const colors = aiSiteColors(style)\n const keep = (scheme: 'light' | 'dark') => {\n const own = base.colorSchemes?.[scheme] ?? {}\n // The status colors stay the base's: they mean the same thing on every site.\n return {\n ...(own.error ? { error: own.error } : {}),\n ...(own.warning ? { warning: own.warning } : {}),\n ...(own.info ? { info: own.info } : {}),\n ...(own.success ? { success: own.success } : {}),\n ...colors[scheme],\n }\n }\n let theme: HostTheme = {\n ...base,\n colorSchemes: { light: keep('light'), dark: keep('dark') },\n typography: merged(base.typography ?? {}, typographyFor(style)),\n shape: { ...(base.shape ?? {}), borderRadius: RADIUS[style.corners] },\n spacing: SPACING[style.density],\n components: merged(base.components ?? {}, componentsFor(style)),\n }\n delete theme.darkScheme\n const sameFamily = pairing.heading.family === pairing.body.family\n theme = writeThemeFonts(theme, {\n body: { family: pairing.body.family, category: pairing.body.category, weights: [...pairing.body.weights], source: 'google' },\n heading: sameFamily\n ? null\n : {\n family: pairing.heading.family,\n category: pairing.heading.category,\n weights: [...new Set([pairing.heading.weight, pairing.heading.sub])].sort((a, b) => a - b),\n source: 'google',\n },\n })\n // A pairing whose heading is the body family loads the heading weights too.\n if (sameFamily && theme.fonts?.[0]) {\n theme.fonts[0] = {\n ...theme.fonts[0],\n weights: [...new Set([...(theme.fonts[0].weights ?? []), pairing.heading.weight, pairing.heading.sub])].sort((a, b) => a - b),\n }\n }\n if (!themeReads(theme)) {\n // Never a theme that fails the reading checks: the starter's colors, with everything else kept.\n theme = { ...theme, colorSchemes: DEFAULT_SITE_THEME.colorSchemes }\n }\n return theme\n}\n"],"names":["contrastRatio","validateThemeForPublish","DEFAULT_SITE_THEME","writeThemeFonts","AI_SITE_BASES","AI_SITE_CORNERS","AI_SITE_FONT_PAIRINGS","AI_SITE_GROUNDS","AI_SITE_RHYTHMS","aiSiteFontPairing","AI_SITE_CARDS","AI_SITE_FIELDS","AI_SITE_EYEBROWS","AI_SITE_HEADERS","AI_SITE_BUTTONS","DENSITIES","aiSiteSeed","jobId","hash","index","length","charCodeAt","Math","imul","random","seed","state","t","pick","next","list","floor","AI_SITE_LOOK_TOOL_NAME","enumOf","values","description","type","enum","AI_SITE_LOOK_TOOL","name","strict","inputSchema","additionalProperties","required","properties","base","hue","accent","ground","fonts","map","pairing","id","corners","buttons","cards","fields","eyebrow","header","brand","anyOf","oneOf","value","includes","undefined","hueOf","Number","isFinite","round","aiSiteBrandHex","match","exec","trim","hex","full","digit","join","toLowerCase","aiReadSiteLook","answer","raw","look","BLOCK_BIAS","portfolio","studio","photography","blog","trades","fitness","professional","wellness","yoga","restaurant","beauty","music","ANY_BLOCKS","aiSiteHueFamily","rangeOf","kind","hues","findIndex","from","to","AI_SITE_LOOK_DIMENSIONS","aiSiteLookSignature","style","hueFamily","String","headerAlign","rhythm","aiSiteStyleFor","input","avoid","styleOnce","signatures","best","attempt","AI_SITE_LOOK_DRAWS","own","least","min","other","TUPLE","every","dimension","filter","AI_SITE_LOOK_LEAST_DIFFERENCES","family","blocks","choose","model","options","keep","modelRange","keepHue","range","span","accentFrom","bases","Set","v","chroma","grounds","headerAligns","rhythms","headingScale","density","oklabToLinear","L","a","b","l","m","s","toSrgb","channel","fromSrgb","aiOklchHex","C","h","lightness","max","radians","PI","linear","cos","sin","fits","toString","padStart","aiHexOklch","replace","r","g","at","parseInt","slice","cbrt","A","B","hypot","atan2","ratio","untilContrast","against","toward","step","labelOn","fill","white","ink","aiHueGap","d","abs","AI_SITE_ACCENT_CLASH_DEGREES","CHROMA","neutral","muted","balanced","vivid","START_L","aiSiteColors","groundChroma","paper","warm","cool","tinted","background","primaryMain","primaryL","accentChroma","buttonHue","secondary","main","washChroma","tertiaryHue","tertiaryL","tertiary","textChroma","light","primary","dark","contrastText","surface","default","text","disabled","tint","divider","darkGround","darkBackground","darkPaper","darkChroma","darkPrimaryL","darkPrimary","darkSecondary","darkTertiary","RADIUS","sharp","soft","pill","SPACING","compact","regular","airy","SCALE_SHARE","displayXl","size","share","h1","h2","h3","h4","h5","h6","rem","AI_SITE_DISPLAY_BOOST","display","title","typographyFor","variants","typography","boost","key","Object","entries","big","boosted","variant","fontSize","caps","fontWeight","heading","weight","sub","lineHeight","tracking","letterSpacing","textTransform","bodyBold","body","weights","overline","button","cardSx","boxShadow","border","bgcolor","borderColor","borderTop","borderRadius","componentsFor","card","radius","buttonRadius","MuiButton","defaultProps","disableElevation","styleOverrides","root","minHeight","props","textDecoration","textUnderlineOffset","textDecorationThickness","MuiCard","elevation","sx","MuiAccordion","disableGutters","mb","MuiTextField","MuiOutlinedInput","MuiFilledInput","borderTopLeftRadius","borderTopRightRadius","MuiChip","MuiAppBar","color","borderBottom","MuiTypography","content","width","height","marginRight","verticalAlign","backgroundColor","isRecord","Array","isArray","merged","under","over","out","themeReads","theme","ok","scheme","colors","colorSchemes","page","aiSiteTheme","error","warning","info","success","shape","spacing","components","darkScheme","sameFamily","category","source","sort"],"mappings":"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"}
@@ -103,13 +103,43 @@ export declare function aiSiteSeoTitle(input: {
103
103
  * its trailing clauses; what the site is alone; then what the site is, cut
104
104
  * back the same way. Only when not even the subject fits is it clipped at a
105
105
  * word, never on a dangling one.
106
+ *
107
+ * It reads as one sentence (AGL-3660). The answers are set into it as
108
+ * phrases, not pasted as the person typed them: a real job published
109
+ * "Eastside Book Circle is A neighborhood book club: monthly meetups, the
110
+ * current read, past picks, and a way to join, for Neighbors on the east
111
+ * side." So what the site is stops at a colon (`aiSiteSeoNounPhrase`), each
112
+ * answer set inside the sentence starts in lower case where the person only
113
+ * capitalized it because it began their answer (`aiSiteSeoEmbedded`), and
114
+ * one thing takes an article ("is a neighborhood book club"). A plain noun
115
+ * phrase runs straight on into who it is for; one with clauses of its own
116
+ * keeps the comma, so "for" is not read as part of its last clause.
106
117
  */
107
118
  export declare function aiSiteSeoDescription(input: {
108
119
  name: string;
109
120
  subject: string;
110
121
  about: string;
111
122
  audience: string;
123
+ /** The city the person gave, never lowered where an answer starts with it. */
124
+ city?: string;
112
125
  }): string;
126
+ /**
127
+ * What kind of site it is, as a short noun phrase (AGL-3660): the answer up
128
+ * to a colon, since what follows one is a list of what the site will hold
129
+ * ("A neighborhood book club: monthly meetups, the current read, …"), which
130
+ * is the pages' to say, not the listing's. An answer that is nothing but its
131
+ * list is kept whole.
132
+ */
133
+ export declare function aiSiteSeoNounPhrase(about: string): string;
134
+ /**
135
+ * An answer as a phrase inside a sentence (AGL-3660): its first word in lower
136
+ * case where the person capitalized it only because it began their answer —
137
+ * "Neighbors on the east side" is "neighbors on the east side", "A
138
+ * neighborhood book club" is "a neighborhood book club". A word typed with
139
+ * capitals of its own ("McKinney", "NYC"), a city the person gave, and a
140
+ * capitalized word followed by another ("Eastside Book Club") are left alone.
141
+ */
142
+ export declare function aiSiteSeoEmbedded(phrase: string, keep?: readonly string[]): string;
113
143
  /**
114
144
  * What the listing is built from: either answer may be missing, because the
115
145
  * guided start requires only the first of them.
@@ -182,14 +182,30 @@ import { aiSiteWords } from "./ai-site-job.js";
182
182
  * its trailing clauses; what the site is alone; then what the site is, cut
183
183
  * back the same way. Only when not even the subject fits is it clipped at a
184
184
  * word, never on a dangling one.
185
+ *
186
+ * It reads as one sentence (AGL-3660). The answers are set into it as
187
+ * phrases, not pasted as the person typed them: a real job published
188
+ * "Eastside Book Circle is A neighborhood book club: monthly meetups, the
189
+ * current read, past picks, and a way to join, for Neighbors on the east
190
+ * side." So what the site is stops at a colon (`aiSiteSeoNounPhrase`), each
191
+ * answer set inside the sentence starts in lower case where the person only
192
+ * capitalized it because it began their answer (`aiSiteSeoEmbedded`), and
193
+ * one thing takes an article ("is a neighborhood book club"). A plain noun
194
+ * phrase runs straight on into who it is for; one with clauses of its own
195
+ * keeps the comma, so "for" is not read as part of its last clause.
185
196
  */ export function aiSiteSeoDescription(input) {
186
197
  const max = AI_SITE_SEO_LIMITS.description;
187
- const lead = (what)=>input.name ? `${input.name} is ${what}` : asSubject(what);
188
- const abouts = phraseForms(withoutDangling(input.about.replace(/[.!?]+$/, '')));
189
- const audiences = input.audience ? phraseForms(withoutDangling(input.audience.replace(/[.!?]+$/, ''))) : [];
198
+ const keep = input.city ? [
199
+ input.city
200
+ ] : [];
201
+ const lead = (what)=>input.name ? `${input.name} is ${withArticle(aiSiteSeoEmbedded(what, keep))}` : asSubject(what);
202
+ const abouts = phraseForms(withoutDangling(aiSiteSeoNounPhrase(input.about).replace(/[.!?]+$/, '')));
203
+ const audience = withoutDangling(input.audience.replace(/[.!?]+$/, '').replace(/^for\s+/i, ''));
204
+ const audiences = audience ? phraseForms(audience).map((form)=>aiSiteSeoEmbedded(form, keep)) : [];
190
205
  for (const about of abouts){
191
- for (const audience of audiences){
192
- const text = sentence(`${lead(about)}, for ${audience}`);
206
+ const joint = /[,;(—–]|\s-\s/.test(about) || about.search(PHRASE_BOUNDARY_ONE) > 0 ? ', for ' : ' for ';
207
+ for (const who of audiences){
208
+ const text = sentence(`${lead(about)}${joint}${who}`);
193
209
  if (text.length <= max) return text;
194
210
  }
195
211
  const text = sentence(lead(about));
@@ -197,6 +213,107 @@ import { aiSiteWords } from "./ai-site-job.js";
197
213
  }
198
214
  return clip(sentence(lead(abouts[abouts.length - 1] || input.subject)), max);
199
215
  }
216
+ /** {@link PHRASE_BOUNDARY} without the global flag, for a one-off search. */ const PHRASE_BOUNDARY_ONE = new RegExp(PHRASE_BOUNDARY.source, 'i');
217
+ /**
218
+ * What kind of site it is, as a short noun phrase (AGL-3660): the answer up
219
+ * to a colon, since what follows one is a list of what the site will hold
220
+ * ("A neighborhood book club: monthly meetups, the current read, …"), which
221
+ * is the pages' to say, not the listing's. An answer that is nothing but its
222
+ * list is kept whole.
223
+ */ export function aiSiteSeoNounPhrase(about) {
224
+ const text = about.replace(/\s+/g, ' ').trim();
225
+ const colon = text.indexOf(':');
226
+ const head = colon > 0 ? withoutDangling(text.slice(0, colon).trim()) : '';
227
+ return head || text;
228
+ }
229
+ /**
230
+ * Words an answer opens with that are lowered when it is set inside a
231
+ * sentence: articles and determiners, and the words a "who is it for" answer
232
+ * most often opens with. A word not listed is lowered too where the answer
233
+ * reads in sentence case — its next word in lower case — since that capital
234
+ * only began the person's answer.
235
+ */ const LOWERED_LEADS = new Set([
236
+ 'a',
237
+ 'an',
238
+ 'the',
239
+ 'our',
240
+ 'my',
241
+ 'your',
242
+ 'their',
243
+ 'this',
244
+ 'any',
245
+ 'all',
246
+ 'every',
247
+ 'some',
248
+ 'one',
249
+ 'anyone',
250
+ 'everyone',
251
+ 'people',
252
+ 'folks',
253
+ 'neighbors',
254
+ 'neighbours',
255
+ 'families',
256
+ 'parents',
257
+ 'kids',
258
+ 'children',
259
+ 'adults',
260
+ 'teens',
261
+ 'students',
262
+ 'seniors',
263
+ 'couples',
264
+ 'women',
265
+ 'men',
266
+ 'locals',
267
+ 'residents',
268
+ 'homeowners',
269
+ 'owners',
270
+ 'members',
271
+ 'readers',
272
+ 'customers',
273
+ 'clients',
274
+ 'businesses',
275
+ 'professionals',
276
+ 'local',
277
+ 'small',
278
+ 'busy',
279
+ 'new',
280
+ 'young',
281
+ 'independent',
282
+ 'family',
283
+ 'neighborhood',
284
+ 'neighbourhood'
285
+ ]);
286
+ /**
287
+ * An answer as a phrase inside a sentence (AGL-3660): its first word in lower
288
+ * case where the person capitalized it only because it began their answer —
289
+ * "Neighbors on the east side" is "neighbors on the east side", "A
290
+ * neighborhood book club" is "a neighborhood book club". A word typed with
291
+ * capitals of its own ("McKinney", "NYC"), a city the person gave, and a
292
+ * capitalized word followed by another ("Eastside Book Club") are left alone.
293
+ */ export function aiSiteSeoEmbedded(phrase, keep = []) {
294
+ const text = phrase.replace(/\s+/g, ' ').trim();
295
+ const [first = '', second = ''] = text.split(' ');
296
+ if (!/^[A-Z][a-z'’]*$/.test(first)) return text;
297
+ if (keep.some((word)=>word && text.toLowerCase().startsWith(word.toLowerCase()))) return text;
298
+ const listed = LOWERED_LEADS.has(first.toLowerCase());
299
+ const sentenceCase = !second || /^[a-z0-9]/.test(second);
300
+ if (!listed && !sentenceCase) return text;
301
+ return first.toLowerCase() + text.slice(first.length);
302
+ }
303
+ /** Determiners an embedded noun phrase may already open with. */ const DETERMINERS = /^(?:a|an|the|our|my|your|their|this|one|any|every|each)\b/i;
304
+ /**
305
+ * A noun phrase behind "is" (AGL-3660): "is a neighborhood book club", never
306
+ * "is neighborhood book club". A phrase that opens with its own determiner is
307
+ * kept, and one whose head is plural ("yoga classes and workshops") takes
308
+ * none.
309
+ */ function withArticle(phrase) {
310
+ var _split_filter_pop;
311
+ if (!phrase || DETERMINERS.test(phrase)) return phrase;
312
+ const boundary = phrase.search(PHRASE_BOUNDARY_ONE);
313
+ const head = (_split_filter_pop = (boundary > 0 ? phrase.slice(0, boundary) : phrase).split(/[\s,]+/).filter(Boolean).pop()) != null ? _split_filter_pop : '';
314
+ if (/[^su]s$/i.test(head) && !/ics$/i.test(head)) return phrase;
315
+ return `${/^(?:[aeio]|u(?!ni|s[eu]))/i.test(phrase) ? 'an' : 'a'} ${phrase}`;
316
+ }
200
317
  /**
201
318
  * The leading article dropped and the first letter raised: "a neighborhood
202
319
  * dog groomer" is how a person answers the question and is not how a title
@@ -219,23 +336,27 @@ import { aiSiteWords } from "./ai-site-job.js";
219
336
  * describe no site at all — a job with no `businessType` has nothing to
220
337
  * propose, and an empty proposal is worse than none.
221
338
  */ export function aiSiteSeoProposal(input) {
222
- var _input_about, _input_siteName, _input_audience, _input_about1;
223
- const subject = asSubject((_input_about = input.about) != null ? _input_about : '');
339
+ var _input_about, _input_siteName, _input_audience, _input_city;
340
+ // What the site is, up to a colon (AGL-3660): the list after one belongs to neither value.
341
+ const about = aiSiteSeoNounPhrase((_input_about = input.about) != null ? _input_about : '');
342
+ const subject = asSubject(about);
224
343
  if (!subject) return null;
225
344
  const name = ((_input_siteName = input.siteName) != null ? _input_siteName : '').replace(/\s+/g, ' ').trim();
226
345
  const audience = ((_input_audience = input.audience) != null ? _input_audience : '').replace(/\s+/g, ' ').trim();
346
+ const city = ((_input_city = input.city) != null ? _input_city : '').replace(/\s+/g, ' ').trim();
227
347
  const title = aiSiteSeoTitle({
228
348
  name,
229
349
  subject,
230
- city: input.city
350
+ city
231
351
  });
232
- const about = ((_input_about1 = input.about) != null ? _input_about1 : '').replace(/\s+/g, ' ').trim();
233
- const description = aiSiteSeoDescription({
352
+ const description = aiSiteSeoDescription(_extends({
234
353
  name,
235
354
  subject,
236
355
  about,
237
356
  audience
238
- });
357
+ }, city ? {
358
+ city
359
+ } : {}));
239
360
  return {
240
361
  kind: AI_SITE_SEO_PROPOSAL_KIND,
241
362
  values: {