@aglyn/plugins-ai 1.0.0-beta.292 → 1.0.0-beta.296

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 (203) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/ai-job-links.d.ts +15 -2
  3. package/src/lib/components/ai-job-links.js +24 -3
  4. package/src/lib/components/ai-job-links.js.map +1 -1
  5. package/src/lib/components/ai-job-requests.d.ts +9 -0
  6. package/src/lib/components/ai-job-requests.js +34 -0
  7. package/src/lib/components/ai-job-requests.js.map +1 -1
  8. package/src/lib/components/ai-site-build-page.component.js +28 -2
  9. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  10. package/src/lib/components/ai-site-import-job.component.js +5 -4
  11. package/src/lib/components/ai-site-import-job.component.js.map +1 -1
  12. package/src/lib/components/ai-site-import-start.component.js +3 -3
  13. package/src/lib/components/ai-site-import-start.component.js.map +1 -1
  14. package/src/lib/components/ai-site-start-card.component.d.ts +1 -1
  15. package/src/lib/components/ai-site-start-card.component.js +129 -29
  16. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  17. package/src/lib/components/ai-site-start-steps.component.d.ts +15 -3
  18. package/src/lib/components/ai-site-start-steps.component.js +42 -25
  19. package/src/lib/components/ai-site-start-steps.component.js.map +1 -1
  20. package/src/lib/components/ai-site-style-previews.d.ts +17 -0
  21. package/src/lib/components/ai-site-style-previews.js +26 -95
  22. package/src/lib/components/ai-site-style-previews.js.map +1 -1
  23. package/src/lib/components/assist-jobs-drawer.component.d.ts +7 -1
  24. package/src/lib/components/assist-jobs-drawer.component.js +20 -6
  25. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  26. package/src/lib/components/assist-page-change-card.component.d.ts +44 -0
  27. package/src/lib/components/assist-page-change-card.component.js +166 -0
  28. package/src/lib/components/assist-page-change-card.component.js.map +1 -0
  29. package/src/lib/components/assist-panel.component.d.ts +105 -1
  30. package/src/lib/components/assist-panel.component.js +224 -29
  31. package/src/lib/components/assist-panel.component.js.map +1 -1
  32. package/src/lib/declarations.server.js +22 -0
  33. package/src/lib/declarations.server.js.map +1 -1
  34. package/src/lib/jobs/ai-job-edit-step.d.ts +62 -16
  35. package/src/lib/jobs/ai-job-edit-step.js +172 -61
  36. package/src/lib/jobs/ai-job-edit-step.js.map +1 -1
  37. package/src/lib/jobs/ai-job-import-step.d.ts +21 -2
  38. package/src/lib/jobs/ai-job-import-step.js +179 -49
  39. package/src/lib/jobs/ai-job-import-step.js.map +1 -1
  40. package/src/lib/jobs/ai-job-layout-language.d.ts +27 -3
  41. package/src/lib/jobs/ai-job-layout-language.js +156 -113
  42. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  43. package/src/lib/jobs/ai-job-layout-step.js +56 -17
  44. package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
  45. package/src/lib/jobs/ai-job-navigation-step.js +4 -2
  46. package/src/lib/jobs/ai-job-navigation-step.js.map +1 -1
  47. package/src/lib/jobs/ai-job-page-language.d.ts +25 -15
  48. package/src/lib/jobs/ai-job-page-language.js +120 -66
  49. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  50. package/src/lib/jobs/ai-job-page-step.js +27 -7
  51. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  52. package/src/lib/jobs/ai-job-site-datasets.d.ts +12 -4
  53. package/src/lib/jobs/ai-job-site-datasets.js +36 -16
  54. package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
  55. package/src/lib/jobs/ai-jobs.js +6 -2
  56. package/src/lib/jobs/ai-jobs.js.map +1 -1
  57. package/src/lib/jobs/ai-layout-stock-photos.d.ts +50 -1
  58. package/src/lib/jobs/ai-layout-stock-photos.js +586 -35
  59. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  60. package/src/lib/jobs/ai-site-import-compile.d.ts +147 -0
  61. package/src/lib/jobs/ai-site-import-compile.js +1143 -0
  62. package/src/lib/jobs/ai-site-import-compile.js.map +1 -0
  63. package/src/lib/jobs/ai-site-import-document.d.ts +9 -36
  64. package/src/lib/jobs/ai-site-import-document.js +23 -489
  65. package/src/lib/jobs/ai-site-import-document.js.map +1 -1
  66. package/src/lib/jobs/ai-site-import-look.d.ts +54 -7
  67. package/src/lib/jobs/ai-site-import-look.js +163 -52
  68. package/src/lib/jobs/ai-site-import-look.js.map +1 -1
  69. package/src/lib/jobs/ai-site-import-publish.d.ts +7 -1
  70. package/src/lib/jobs/ai-site-import-publish.js +19 -5
  71. package/src/lib/jobs/ai-site-import-publish.js.map +1 -1
  72. package/src/lib/jobs/ai-site-late-photos.js +4 -2
  73. package/src/lib/jobs/ai-site-late-photos.js.map +1 -1
  74. package/src/lib/jobs/ai-site-publish.d.ts +10 -1
  75. package/src/lib/jobs/ai-site-publish.js +8 -3
  76. package/src/lib/jobs/ai-site-publish.js.map +1 -1
  77. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.d.ts +23 -0
  78. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js +677 -0
  79. package/src/lib/jobs/fixtures/ai-stock-photo-agl4092-1029-recordings.js.map +1 -0
  80. package/src/lib/layout-language/ai-layout-compiler.d.ts +26 -0
  81. package/src/lib/layout-language/ai-layout-compiler.js +677 -33
  82. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  83. package/src/lib/layout-language/ai-layout-frame-hollows.js +5 -1
  84. package/src/lib/layout-language/ai-layout-frame-hollows.js.map +1 -1
  85. package/src/lib/layout-language/ai-layout-frame-source.d.ts +196 -0
  86. package/src/lib/layout-language/ai-layout-frame-source.js +726 -0
  87. package/src/lib/layout-language/ai-layout-frame-source.js.map +1 -0
  88. package/src/lib/layout-language/ai-layout-frame.d.ts +22 -0
  89. package/src/lib/layout-language/ai-layout-frame.js +121 -29
  90. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  91. package/src/lib/layout-language/ai-layout-language.d.ts +103 -37
  92. package/src/lib/layout-language/ai-layout-language.js +85 -120
  93. package/src/lib/layout-language/ai-layout-language.js.map +1 -1
  94. package/src/lib/model/ai-credit-estimate.d.ts +11 -7
  95. package/src/lib/model/ai-credit-estimate.js +11 -7
  96. package/src/lib/model/ai-credit-estimate.js.map +1 -1
  97. package/src/lib/model/ai-edit-job.d.ts +33 -16
  98. package/src/lib/model/ai-edit-job.js +50 -34
  99. package/src/lib/model/ai-edit-job.js.map +1 -1
  100. package/src/lib/model/ai-job-activity.d.ts +6 -11
  101. package/src/lib/model/ai-job-activity.js +8 -15
  102. package/src/lib/model/ai-job-activity.js.map +1 -1
  103. package/src/lib/model/ai-jobs.types.d.ts +6 -0
  104. package/src/lib/model/ai-jobs.types.js.map +1 -1
  105. package/src/lib/model/ai-site-import.d.ts +307 -13
  106. package/src/lib/model/ai-site-import.js +227 -19
  107. package/src/lib/model/ai-site-import.js.map +1 -1
  108. package/src/lib/model/ai-site-inventory.d.ts +6 -0
  109. package/src/lib/model/ai-site-inventory.js.map +1 -1
  110. package/src/lib/model/ai-site-look.d.ts +65 -1
  111. package/src/lib/model/ai-site-look.js +141 -23
  112. package/src/lib/model/ai-site-look.js.map +1 -1
  113. package/src/lib/model/ai-site-photos.d.ts +2 -0
  114. package/src/lib/model/ai-site-photos.js.map +1 -1
  115. package/src/lib/model/ai-site-start-steps.d.ts +4 -3
  116. package/src/lib/model/ai-site-start-steps.js +11 -3
  117. package/src/lib/model/ai-site-start-steps.js.map +1 -1
  118. package/src/lib/model/ai-site-start.d.ts +23 -2
  119. package/src/lib/model/ai-site-start.js +25 -3
  120. package/src/lib/model/ai-site-start.js.map +1 -1
  121. package/src/lib/model/assist-edit.d.ts +18 -1
  122. package/src/lib/model/assist-edit.js +7 -0
  123. package/src/lib/model/assist-edit.js.map +1 -1
  124. package/src/lib/model/assist-page-change.d.ts +86 -0
  125. package/src/lib/model/assist-page-change.js +86 -0
  126. package/src/lib/model/assist-page-change.js.map +1 -0
  127. package/src/lib/providers/routing.d.ts +11 -0
  128. package/src/lib/providers/routing.js +23 -0
  129. package/src/lib/providers/routing.js.map +1 -1
  130. package/src/lib/runtime/ai-doctrine-validators.d.ts +4 -2
  131. package/src/lib/runtime/ai-doctrine-validators.js +7 -2
  132. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  133. package/src/lib/runtime/ai-eval.js +3 -1
  134. package/src/lib/runtime/ai-eval.js.map +1 -1
  135. package/src/lib/runtime/ai-icon-library.d.ts +4 -0
  136. package/src/lib/runtime/ai-icon-library.js +4 -0
  137. package/src/lib/runtime/ai-icon-library.js.map +1 -1
  138. package/src/lib/runtime/ai-node-tree.d.ts +5 -0
  139. package/src/lib/runtime/ai-node-tree.js +23 -4
  140. package/src/lib/runtime/ai-node-tree.js.map +1 -1
  141. package/src/lib/runtime/ai-palette.d.ts +2 -0
  142. package/src/lib/runtime/ai-palette.generated.js +19 -3
  143. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  144. package/src/lib/runtime/ai-palette.js +2 -1
  145. package/src/lib/runtime/ai-palette.js.map +1 -1
  146. package/src/lib/runtime/site-inventory.d.ts +8 -1
  147. package/src/lib/runtime/site-inventory.js +18 -0
  148. package/src/lib/runtime/site-inventory.js.map +1 -1
  149. package/src/lib/server/assist-build.js +2 -0
  150. package/src/lib/server/assist-build.js.map +1 -1
  151. package/src/lib/server/assist-chat.js +51 -2
  152. package/src/lib/server/assist-chat.js.map +1 -1
  153. package/src/lib/server/assist-edit.d.ts +54 -2
  154. package/src/lib/server/assist-edit.js +219 -30
  155. package/src/lib/server/assist-edit.js.map +1 -1
  156. package/src/lib/server/assist-page-change.d.ts +62 -0
  157. package/src/lib/server/assist-page-change.js +140 -0
  158. package/src/lib/server/assist-page-change.js.map +1 -0
  159. package/src/lib/site-import/fixtures/site-layout-recordings.d.ts +50 -0
  160. package/src/lib/site-import/fixtures/site-layout-recordings.js +86 -0
  161. package/src/lib/site-import/fixtures/site-layout-recordings.js.map +1 -0
  162. package/src/lib/site-import/site-import-crawl.d.ts +18 -1
  163. package/src/lib/site-import/site-import-crawl.js +70 -10
  164. package/src/lib/site-import/site-import-crawl.js.map +1 -1
  165. package/src/lib/site-import/site-import-css.d.ts +110 -0
  166. package/src/lib/site-import/site-import-css.js +826 -0
  167. package/src/lib/site-import/site-import-css.js.map +1 -0
  168. package/src/lib/site-import/site-import-html.d.ts +116 -1
  169. package/src/lib/site-import/site-import-html.js +538 -46
  170. package/src/lib/site-import/site-import-html.js.map +1 -1
  171. package/src/lib/site-import/site-import-layout.d.ts +79 -0
  172. package/src/lib/site-import/site-import-layout.js +1608 -0
  173. package/src/lib/site-import/site-import-layout.js.map +1 -0
  174. package/src/lib/site-import/site-import-nav.d.ts +40 -0
  175. package/src/lib/site-import/site-import-nav.js +437 -0
  176. package/src/lib/site-import/site-import-nav.js.map +1 -0
  177. package/src/lib/site-import/site-import-page.d.ts +8 -1
  178. package/src/lib/site-import/site-import-page.js +24 -2
  179. package/src/lib/site-import/site-import-page.js.map +1 -1
  180. package/src/lib/assets/site-styles/beauty.webp +0 -0
  181. package/src/lib/assets/site-styles/blog.webp +0 -0
  182. package/src/lib/assets/site-styles/business.webp +0 -0
  183. package/src/lib/assets/site-styles/coming-soon.webp +0 -0
  184. package/src/lib/assets/site-styles/education.webp +0 -0
  185. package/src/lib/assets/site-styles/events.webp +0 -0
  186. package/src/lib/assets/site-styles/fitness.webp +0 -0
  187. package/src/lib/assets/site-styles/landing.webp +0 -0
  188. package/src/lib/assets/site-styles/music.webp +0 -0
  189. package/src/lib/assets/site-styles/nonprofit.webp +0 -0
  190. package/src/lib/assets/site-styles/personal.webp +0 -0
  191. package/src/lib/assets/site-styles/photography.webp +0 -0
  192. package/src/lib/assets/site-styles/portfolio.webp +0 -0
  193. package/src/lib/assets/site-styles/professional.webp +0 -0
  194. package/src/lib/assets/site-styles/realestate.webp +0 -0
  195. package/src/lib/assets/site-styles/restaurant.webp +0 -0
  196. package/src/lib/assets/site-styles/store.webp +0 -0
  197. package/src/lib/assets/site-styles/studio.webp +0 -0
  198. package/src/lib/assets/site-styles/trades.webp +0 -0
  199. package/src/lib/assets/site-styles/wellness.webp +0 -0
  200. package/src/lib/assets/site-styles/yoga.webp +0 -0
  201. package/src/lib/site-import/site-import-review.d.ts +0 -40
  202. package/src/lib/site-import/site-import-review.js +0 -149
  203. package/src/lib/site-import/site-import-review.js.map +0 -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 {\n AI_SITE_MOTION_STYLES,\n aiSiteMotionStyle,\n aiSiteMotionStylesFor,\n type AiSiteMotionStyle,\n} from '../layout-language/ai-layout-motion'\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 * How the site's pages arrive (AGL-3941), from `ai-layout-motion.ts`'s\n * vocabulary. Absent on a style stored before the look chose motion, whose\n * pages move in its kind's mood.\n */\n motion?: AiSiteMotionStyle\n}\n\n/** What the model may choose, every field optional. */\nexport type AiSiteLookAnswer = Partial<\n Pick<\n AiSiteStyle,\n | 'base'\n | 'hue'\n | 'accent'\n | 'ground'\n | 'fonts'\n | 'corners'\n | 'buttons'\n | 'cards'\n | 'fields'\n | 'eyebrow'\n | 'header'\n | 'brand'\n | 'motion'\n >\n>\n\n/**\n * The dimensions the sites a person likes pin (AGL-3975,\n * `jobs/ai-site-inspiration.ts`): each one present is KEPT, whatever the\n * model or the seed would choose, and every other dimension is chosen as it\n * always is. A brand the person gave in the brief still wins over a pinned\n * brand color, and the hue pinned with it.\n */\nexport type AiSiteLookPins = Partial<\n Pick<\n AiSiteStyle,\n | 'brand'\n | 'hue'\n | 'accent'\n | 'ground'\n | 'fonts'\n | 'corners'\n | 'buttons'\n | 'cards'\n | 'header'\n | 'headerAlign'\n | 'density'\n | 'motion'\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', 'motion'],\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 motion: enumOf(AI_SITE_MOTION_STYLES, 'How the pages arrive as a visitor scrolls, from the motion list in the request.'),\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 const motion = aiSiteMotionStyle(raw['motion'])\n if (motion) look.motion = motion\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 /** What the sites the person likes pin (AGL-3975): kept on every draw. */\n pins?: AiSiteLookPins\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; pins?: AiSiteLookPins },\n seed: number,\n): AiSiteStyle {\n return withPins(drawOnce(input, seed), input)\n}\n\n/**\n * A drawn style with its pins laid over it (AGL-3975). Applied after the\n * draw, so every dimension is drawn the same with or without pins and an\n * unpinned job's look is exactly what it was.\n */\nfunction withPins(style: AiSiteStyle, input: { brand?: string | null; pins?: AiSiteLookPins }): AiSiteStyle {\n const pins = input.pins\n if (!pins || !Object.keys(pins).length) return style\n // The person's own brand color outranks the one their sites suggest.\n const own = aiSiteBrandHex(input.brand)\n const { brand, hue, ...rest } = pins\n const pinned = Object.fromEntries(Object.entries(rest).filter(([, value]) => value !== undefined && value !== null))\n return {\n ...style,\n ...pinned,\n ...(!own && aiSiteBrandHex(brand) ? { brand: aiSiteBrandHex(brand) } : {}),\n ...(!own && typeof hue === 'number' && Number.isFinite(hue) ? { hue: ((Math.round(hue) % 360) + 360) % 360 } : {}),\n }\n}\n\nfunction drawOnce(\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 // Drawn last, so every dimension above is drawn the same whether or not\n // the answer chose a motion. The model's choice is kept more often than\n // the other dimensions', because nothing else of the site says how it\n // moves; the seed's draw is among the styles that suit the kind.\n motion: choose(answer.motion, aiSiteMotionStylesFor(kind.id), AI_SITE_MOTION_KEEP),\n }\n}\n\n/** The chance a look keeps the motion style the model chose (AGL-3941). */\nexport const AI_SITE_MOTION_KEEP = 0.6\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_MOTION_STYLES","aiSiteMotionStyle","aiSiteMotionStylesFor","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","motion","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","withPins","drawOnce","pins","Object","keys","rest","pinned","fromEntries","entries","family","blocks","choose","model","options","keep","modelRange","keepHue","range","span","accentFrom","bases","Set","v","chroma","grounds","headerAligns","rhythms","headingScale","density","AI_SITE_MOTION_KEEP","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","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":";;AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,aAAa,EACbC,uBAAuB,QAClB,oCAAmC;AAC1C,SAASC,kBAAkB,QAAQ,sCAAqC;AAQxE,SAASC,eAAe,QAAQ,kDAAiD;AACjF,SACEC,qBAAqB,EACrBC,iBAAiB,EACjBC,qBAAqB,QAEhB,yCAAqC;AAE5C,SACEC,aAAa,EACbC,eAAe,EACfC,qBAAqB,EACrBC,eAAe,EACfC,eAAe,EACfC,iBAAiB,QASZ,qBAAiB;AAExB;;;;;;;;;;;;;;;;;;;;;;;;;CAyBC,GAED,4EAA4E;AAE5E,yBAAyB,GACzB,OAAO,MAAMC,gBAAgB;IAAC;IAAQ;IAAY;IAAY;IAAU;CAAO,CAAS;AAExF,0BAA0B,GAC1B,OAAO,MAAMC,iBAAiB;IAAC;IAAY;IAAU;CAAW,CAAS;AAEzE,2CAA2C,GAC3C,OAAO,MAAMC,mBAAmB;IAAC;IAAQ;IAAS;CAAO,CAAS;AAElE,+CAA+C,GAC/C,OAAO,MAAMC,kBAAkB;IAAC;IAAQ;IAAU;CAAO,CAAS;AAElE,8EAA8E,GAC9E,OAAO,MAAMC,kBAA4C;IAAC;IAAW;IAAQ;IAAU;IAAQ;CAAO,CAAA;AACtG,MAAMC,YAAsC;IAAC;IAAW;IAAW;CAAO;AAmF1E,4EAA4E;AAE5E,sCAAsC,GACtC,OAAO,SAASC,WAAWC,KAAa;IACtC,IAAIC,OAAO;IACX,IAAK,IAAIC,QAAQ,GAAGA,QAAQF,MAAMG,MAAM,EAAED,SAAS,EAAG;QACpDD,QAAQD,MAAMI,UAAU,CAACF;QACzBD,OAAOI,KAAKC,IAAI,CAACL,MAAM;IACzB;IACA,OAAOA,SAAS;AAClB;AAEA,8DAA8D,GAC9D,SAASM,OAAOC,IAAY;IAC1B,IAAIC,QAAQD,SAAS;IACrB,OAAO;QACLC,QAAQ,AAACA,QAAQ,eAAgB;QACjC,IAAIC,IAAID;QACRC,IAAIL,KAAKC,IAAI,CAACI,IAAKA,MAAM,IAAKA,IAAI;QAClCA,KAAKA,IAAIL,KAAKC,IAAI,CAACI,IAAKA,MAAM,GAAIA,IAAI;QACtC,OAAO,AAAC,CAAA,AAACA,CAAAA,IAAKA,MAAM,EAAE,MAAO,CAAA,IAAK;IACpC;AACF;AAEA,MAAMC,OAAO,CAAKC,MAAoBC,OAA0BA,IAAI,CAACR,KAAKS,KAAK,CAACF,SAASC,KAAKV,MAAM,IAAIU,KAAKV,MAAM,CAAC;AAEpH,4EAA4E;AAE5E,OAAO,MAAMY,yBAAyB,mBAAkB;AAExD,MAAMC,SAAS,CAACC,QAA2BC,cAAyB,CAAA;QAAEC,MAAM;QAAUC,MAAM;eAAIH;SAAO;QAAEC;IAAY,CAAA;AAErH,kGAAkG,GAClG,OAAO,MAAMG,oBAA4B;IACvCC,MAAMP;IACNG,aAAa;IACbK,QAAQ;IACRC,aAAa;QACXL,MAAM;QACNM,sBAAsB;QACtBC,UAAU;YAAC;YAAQ;YAAO;YAAU;YAAU;YAAS;YAAW;YAAW;YAAS;YAAU;YAAW;YAAU;YAAS;SAAS;QACvIC,YAAY;YACVC,MAAMZ,OAAO7B,eAAe;YAC5B0C,KAAK;gBAAEV,MAAM;gBAAWD,aAAa;YAA2H;YAChKY,QAAQ;gBAAEX,MAAM;gBAAWD,aAAa;YAAoF;YAC5Ha,QAAQf,OAAO1B,iBAAiB;YAChC0C,OAAOhB,OAAO3B,sBAAsB4C,GAAG,CAAC,CAACC,UAAYA,QAAQC,EAAE,GAAG;YAClEC,SAASpB,OAAO5B,iBAAiB;YACjCiD,SAASrB,OAAOnB,iBAAiB;YACjCyC,OAAOtB,OAAOvB,eAAe;YAC7B8C,QAAQvB,OAAOtB,gBAAgB;YAC/B8C,SAASxB,OAAOrB,kBAAkB;YAClC8C,QAAQzB,OAAOpB,iBAAiB;YAChC8C,OAAO;gBAAEC,OAAO;oBAAC;wBAAExB,MAAM;oBAAS;oBAAG;wBAAEA,MAAM;oBAAO;iBAAE;gBAAED,aAAa;YAAkE;YACvI0B,QAAQ5B,OAAOhC,uBAAuB;QACxC;IACF;AACF,EAAC;AAED,MAAM6D,QAAQ,CAAmBC,OAAgB7B,SAC/C,OAAO6B,UAAU,YAAY,AAAC7B,OAA6B8B,QAAQ,CAACD,SAAUA,QAAcE;AAE9F,MAAMC,QAAQ,CAACH,QACb,OAAOA,UAAU,YAAYI,OAAOC,QAAQ,CAACL,SAAS,AAAC,CAAA,AAACzC,KAAK+C,KAAK,CAACN,SAAS,MAAO,GAAE,IAAK,MAAME;AAElG,iDAAiD,GACjD,OAAO,SAASK,eAAeP,KAAc;IAC3C,IAAI,OAAOA,UAAU,UAAU,OAAO;IACtC,MAAMQ,QAAQ,iCAAiCC,IAAI,CAACT,MAAMU,IAAI;IAC9D,IAAI,CAACF,OAAO,OAAO;IACnB,MAAMG,MAAMH,KAAK,CAAC,EAAE;IACpB,MAAMI,OAAOD,IAAItD,MAAM,KAAK,IAAI;WAAIsD;KAAI,CAACxB,GAAG,CAAC,CAAC0B,QAAUA,QAAQA,OAAOC,IAAI,CAAC,MAAMH;IAClF,OAAO,CAAC,CAAC,EAAEC,KAAKG,WAAW,IAAI;AACjC;AAEA,6FAA6F,GAC7F,OAAO,SAASC,eAAeC,MAAe;IAC5C,MAAMC,MAAOD,UAAU,OAAOA,WAAW,WAAWA,SAAS,CAAC;IAC9D,MAAME,OAAyB,CAAC;IAChC,MAAMrC,OAAOiB,MAAMmB,GAAG,CAAC,OAAO,EAAE7E;IAChC,IAAIyC,MAAMqC,KAAKrC,IAAI,GAAGA;IACtB,MAAMC,MAAMoB,MAAMe,GAAG,CAAC,MAAM;IAC5B,IAAInC,QAAQmB,WAAWiB,KAAKpC,GAAG,GAAGA;IAClC,MAAMC,SAASmB,MAAMe,GAAG,CAAC,SAAS;IAClC,IAAIlC,WAAWkB,WAAWiB,KAAKnC,MAAM,GAAGA;IACxC,MAAMC,SAASc,MAAMmB,GAAG,CAAC,SAAS,EAAE1E;IACpC,IAAIyC,QAAQkC,KAAKlC,MAAM,GAAGA;IAC1B,IAAIvC,kBAAkBwE,GAAG,CAAC,QAAQ,GAAGC,KAAKjC,KAAK,GAAGgC,GAAG,CAAC,QAAQ;IAC9D,MAAM5B,UAAUS,MAAMmB,GAAG,CAAC,UAAU,EAAE5E;IACtC,IAAIgD,SAAS6B,KAAK7B,OAAO,GAAGA;IAC5B,MAAMC,UAAUQ,MAAMmB,GAAG,CAAC,UAAU,EAAEnE;IACtC,IAAIwC,SAAS4B,KAAK5B,OAAO,GAAGA;IAC5B,MAAMC,QAAQO,MAAMmB,GAAG,CAAC,QAAQ,EAAEvE;IAClC,IAAI6C,OAAO2B,KAAK3B,KAAK,GAAGA;IACxB,MAAMC,SAASM,MAAMmB,GAAG,CAAC,SAAS,EAAEtE;IACpC,IAAI6C,QAAQ0B,KAAK1B,MAAM,GAAGA;IAC1B,MAAMC,UAAUK,MAAMmB,GAAG,CAAC,UAAU,EAAErE;IACtC,IAAI6C,SAASyB,KAAKzB,OAAO,GAAGA;IAC5B,MAAMC,SAASI,MAAMmB,GAAG,CAAC,SAAS,EAAEpE;IACpC,IAAI6C,QAAQwB,KAAKxB,MAAM,GAAGA;IAC1B,MAAMC,QAAQW,eAAeW,GAAG,CAAC,QAAQ;IACzC,IAAItB,OAAOuB,KAAKvB,KAAK,GAAGA;IACxB,MAAME,SAAS3D,kBAAkB+E,GAAG,CAAC,SAAS;IAC9C,IAAIpB,QAAQqB,KAAKrB,MAAM,GAAGA;IAC1B,OAAOqB;AACT;AAEA,4EAA4E;AAE5E,oFAAoF,GACpF,MAAMC,aAEF;IACFC,WAAW;QAAE7B,OAAO;YAAC;YAAQ;YAAQ;SAAW;QAAEE,SAAS;YAAC;YAAS;YAAQ;SAAO;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAY;YAAY;SAAS;IAAC;IACrK6B,QAAQ;QAAE9B,OAAO;YAAC;YAAQ;YAAQ;SAAW;QAAEE,SAAS;YAAC;YAAQ;YAAS;SAAO;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAY;YAAY;SAAS;IAAC;IAClK8B,aAAa;QAAE/B,OAAO;YAAC;YAAQ;YAAQ;SAAW;QAAEE,SAAS;YAAC;YAAS;YAAQ;SAAO;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAY;YAAY;SAAS;IAAC;IACvK+B,MAAM;QAAEhC,OAAO;YAAC;YAAQ;YAAY;YAAQ;SAAS;QAAEE,SAAS;YAAC;YAAS;YAAQ;SAAO;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAY;YAAY;SAAS;IAAC;IAC1KgC,QAAQ;QAAEjC,OAAO;YAAC;YAAY;YAAY;YAAQ;YAAQ;SAAS;QAAEE,SAAS;YAAC;YAAQ;YAAQ;SAAQ;QAAEC,QAAQ;YAAC;YAAU;YAAQ;SAAO;QAAEF,QAAQ;YAAC;YAAY;YAAU;SAAW;IAAC;IACxLiC,SAAS;QAAElC,OAAO;YAAC;YAAY;YAAQ;YAAQ;SAAW;QAAEE,SAAS;YAAC;YAAQ;YAAQ;SAAQ;QAAEC,QAAQ;YAAC;YAAU;YAAQ;SAAO;QAAEF,QAAQ;YAAC;YAAU;YAAY;SAAW;IAAC;IAC/KkC,cAAc;QAAEnC,OAAO;YAAC;YAAY;YAAQ;YAAQ;SAAW;QAAEE,SAAS;YAAC;YAAQ;YAAQ;SAAQ;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAY;YAAY;SAAS;IAAC;IACpLmC,UAAU;QAAEpC,OAAO;YAAC;YAAU;YAAQ;YAAY;SAAW;QAAEE,SAAS;YAAC;YAAS;YAAQ;SAAO;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAU;YAAY;SAAW;IAAC;IAClLoC,MAAM;QAAErC,OAAO;YAAC;YAAU;YAAQ;SAAW;QAAEE,SAAS;YAAC;YAAS;YAAQ;SAAO;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAU;YAAY;SAAW;IAAC;IAClKqC,YAAY;QAAEtC,OAAO;YAAC;YAAQ;YAAY;YAAU;SAAO;QAAEE,SAAS;YAAC;YAAQ;YAAQ;SAAQ;QAAEC,QAAQ;YAAC;YAAQ;YAAU;SAAO;QAAEF,QAAQ;YAAC;YAAY;YAAU;SAAW;IAAC;IAChLsC,QAAQ;QAAEvC,OAAO;YAAC;YAAU;YAAQ;YAAY;SAAO;QAAEE,SAAS;YAAC;YAAQ;YAAS;SAAO;QAAEC,QAAQ;YAAC;YAAQ;YAAQ;SAAS;QAAEF,QAAQ;YAAC;YAAY;YAAU;SAAW;IAAC;IAC5KuC,OAAO;QAAExC,OAAO;YAAC;YAAQ;YAAQ;SAAW;QAAEE,SAAS;YAAC;YAAQ;YAAQ;SAAQ;QAAEC,QAAQ;YAAC;YAAQ;YAAU;SAAO;QAAEF,QAAQ;YAAC;YAAU;YAAY;SAAW;IAAC;AACnK;AACA,MAAMwC,aAAa;IAAEzC,OAAO7C;IAAe+C,SAAS7C;IAAkB8C,QAAQ7C;IAAiB2C,QAAQ7C;AAAe;AAEtH,+EAA+E,GAC/E,OAAO,SAASsF,gBAAgBnD,GAAW;IACzC,OAAOxB,KAAKS,KAAK,CAAC,AAAC,CAAA,AAAEe,CAAAA,MAAM,EAAC,IAAK,MAAO,GAAE,IAAK,MAAM;AACvD;AAEA,wDAAwD,GACxD,SAASoD,QAAQpD,GAAW,EAAEqD,IAAgB;IAC5C,OAAOA,KAAKjB,IAAI,CAACkB,IAAI,CAACC,SAAS,CAAC,CAAC,CAACC,MAAMC,GAAG,GAAMD,QAAQC,KAAKzD,OAAOwD,QAAQxD,OAAOyD,KAAKzD,OAAOwD,QAAQxD,OAAOyD;AACjH;AAEA,4EAA4E,GAC5E,OAAO,MAAMC,0BAA0B;IACrC;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAAS;AAEV,+CAA+C,GAC/C,OAAO,SAASC,oBAAoBC,KAAkB;IACpD,OAAO;QACL7D,MAAM6D,MAAM7D,IAAI;QAChB8D,WAAWC,OAAOX,gBAAgBS,MAAM5D,GAAG;QAC3CG,OAAOyD,MAAMzD,KAAK;QAClBK,SAASoD,MAAMpD,OAAO;QACtBC,OAAOmD,MAAMnD,KAAK;QAClBF,SAASqD,MAAMrD,OAAO;QACtBL,QAAQ0D,MAAM1D,MAAM;QACpBS,SAASiD,MAAMjD,OAAO;QACtBC,QAAQgD,MAAMhD,MAAM;QACpBF,QAAQkD,MAAMlD,MAAM;QACpBqD,aAAaH,MAAMG,WAAW;QAC9BC,QAAQJ,MAAMI,MAAM;IACtB;AACF;AAEA;;;;;;;;CAQC,GACD,OAAO,SAASC,eAAeC,KAa9B;QACeA;IAAd,MAAMC,SAAQD,eAAAA,MAAMC,KAAK,YAAXD,eAAe,EAAE;IAC/B,IAAI,CAACC,MAAM7F,MAAM,EAAE,OAAO8F,UAAUF,OAAOA,MAAMvF,IAAI;IACrD,MAAM0F,aAAaF,MAAM/D,GAAG,CAACuD;IAC7B,IAAIW,OAAqD;IACzD,IAAK,IAAIC,UAAU,GAAGA,UAAUC,oBAAoBD,WAAW,EAAG;QAChE,MAAMX,QAAQQ,UAAUF,OAAOK,YAAY,IAAIL,MAAMvF,IAAI,GAAIH,KAAKC,IAAI,CAACyF,MAAMvF,IAAI,GAAG,YAAY4F,UAAU,OAAO;QACjH,MAAME,MAAMd,oBAAoBC;QAChC,MAAMc,QAAQlG,KAAKmG,GAAG,IACjBN,WAAWjE,GAAG,CAAC,CAACwE,QACjBC,MAAMC,KAAK,CAAC,CAACC,YAAcN,GAAG,CAACM,UAAU,KAAKH,KAAK,CAACG,UAAU,IAC1D,CAAC,IACDrB,wBAAwBsB,MAAM,CAAC,CAACD,YAAcN,GAAG,CAACM,UAAU,KAAKH,KAAK,CAACG,UAAU,EAAEzG,MAAM;QAGjG,IAAIoG,SAASO,gCAAgC,OAAOrB;QACpD,IAAI,CAACU,QAAQI,QAAQJ,KAAKI,KAAK,EAAEJ,OAAO;YAAEV;YAAOc;QAAM;IACzD;IACA,OAAO,AAACJ,KAAgCV,KAAK;AAC/C;AAEA,0EAA0E,GAC1E,OAAO,MAAMY,qBAAqB,GAAE;AACpC,8EAA8E,GAC9E,OAAO,MAAMS,iCAAiC,EAAC;AAC/C,+DAA+D,GAC/D,MAAMJ,QAAQ;IAAC;IAAQ;IAAa;IAAS;CAAU;AAEvD,SAAST,UACPF,KAAmG,EACnGvF,IAAY;IAEZ,OAAOuG,SAASC,SAASjB,OAAOvF,OAAOuF;AACzC;AAEA;;;;CAIC,GACD,SAASgB,SAAStB,KAAkB,EAAEM,KAAuD;IAC3F,MAAMkB,OAAOlB,MAAMkB,IAAI;IACvB,IAAI,CAACA,QAAQ,CAACC,OAAOC,IAAI,CAACF,MAAM9G,MAAM,EAAE,OAAOsF;IAC/C,qEAAqE;IACrE,MAAMa,MAAMjD,eAAe0C,MAAMrD,KAAK;IACtC,MAAM,EAAEA,KAAK,EAAEb,GAAG,EAAW,GAAGoF,MAATG,wCAASH;;;;IAChC,MAAMI,SAASH,OAAOI,WAAW,CAACJ,OAAOK,OAAO,CAACH,MAAMP,MAAM,CAAC,CAAC,GAAG/D,MAAM,GAAKA,UAAUE,aAAaF,UAAU;IAC9G,OAAO,aACF2C,OACA4B,QACC,CAACf,OAAOjD,eAAeX,SAAS;QAAEA,OAAOW,eAAeX;IAAO,IAAI,CAAC,GACpE,CAAC4D,OAAO,OAAOzE,QAAQ,YAAYqB,OAAOC,QAAQ,CAACtB,OAAO;QAAEA,KAAK,AAAC,CAAA,AAACxB,KAAK+C,KAAK,CAACvB,OAAO,MAAO,GAAE,IAAK;IAAI,IAAI,CAAC;AAEpH;AAEA,SAASmF,SACPjB,KAA4E,EAC5EvF,IAAY;QAKG0D,qBAmCWsD,sBACLA,iBAGZnE,MAAAA;IA1CT,MAAM,EAAE6B,IAAI,EAAEnB,MAAM,EAAE,GAAGgC;IACzB,MAAMnF,OAAOL,OAAOC;IACpB,MAAMgH,SAAStC,KAAKjB,IAAI;IACxB,MAAMwD,UAASvD,sBAAAA,UAAU,CAACgB,KAAK/C,EAAE,CAAC,YAAnB+B,sBAAuBa;IACtC,+EAA+E,GAC/E,MAAM2C,SAAS,CAAKC,OAAsBC,SAAuBC,OAC/DF,UAAU3E,aAAapC,SAASiH,OAAOF,QAAQhH,KAAKC,MAAMgH;IAE5D,yEAAyE;IACzE,2CAA2C;IAC3C,MAAME,aAAa/D,OAAOlC,GAAG,KAAKmB,YAAY,CAAC,IAAIiC,QAAQlB,OAAOlC,GAAG,EAAEqD;IACvE,MAAM6C,UAAUD,eAAe,CAAC,KAAKlH,SAAS;IAC9C,MAAMoH,QAAQD,UAAUD,aAAazH,KAAKS,KAAK,CAACF,SAAS4G,OAAOrC,IAAI,CAAChF,MAAM,IAAIqH,OAAOrC,IAAI,CAAChF,MAAM;IACjG,MAAM,CAACkF,MAAMC,GAAG,GAAGkC,OAAOrC,IAAI,CAAC6C,MAAM;IACrC,MAAMC,OAAO5C,QAAQC,KAAKA,KAAKD,OAAO,MAAMA,OAAOC;IACnD,MAAMzD,MAAMkG,UACR,AAAC,CAAA,AAAChE,OAAOlC,GAAG,GAAc,AAACjB,CAAAA,SAAS,MAAM,CAAC,IAAI,CAAA,IAAKP,KAAK+C,KAAK,CAAC,IAAIxC,SAAS,KAAK,GAAE,IAAK,MACxFP,KAAK+C,KAAK,CAACiC,OAAOzE,SAASqH,QAAQ;IACvC,MAAMC,aAAanE,OAAOjC,MAAM,KAAKkB,aAAapC,SAAS,MAAMmD,OAAOjC,MAAM,GAAG,AAACD,CAAAA,MAAMlB,KAAKC,MAAM;QAAC;QAAI;QAAK;QAAK;QAAK;KAAI,CAAA,IAAK;IAChI,MAAMkB,SAAS,AAACoG,CAAAA,aAAa,AAACtH,CAAAA,SAAS,MAAM,CAAC,IAAI,CAAA,IAAKP,KAAK+C,KAAK,CAAC,IAAIxC,SAAS,MAAM,GAAE,IAAK;IAE5F,MAAMuH,QAAQ;WAAI,IAAIC,IAAI;eAAKrE,OAAOnC,IAAI,GAAG;gBAACmC,OAAOnC,IAAI;aAAC,GAAG,EAAE;eAAM4F,OAAOW,KAAK;SAAC;KAAE;IACpF,OAAO;QACLE,GAAG;QACHnD,MAAMA,KAAK/C,EAAE;QACbP,MAAM8F,OAAO3D,OAAOnC,IAAI,EAAEuG,OAAO;QACjC3H;QACAqB;QACAC;QACAwG,QAAQd,OAAOc,MAAM;QACrBvG,QAAQ2F,OAAO3D,OAAOhC,MAAM,EAAEyF,OAAOe,OAAO,EAAE;QAC9CvG,OAAO0F,OAAO3D,OAAO/B,KAAK,EAAEwF,OAAOxF,KAAK,EAAE;QAC1CI,SAASsF,OAAO3D,OAAO3B,OAAO,EAAEoF,OAAOpF,OAAO,EAAE;QAChDC,SAASqF,OAAO3D,OAAO1B,OAAO,EAAE;YAACmF,OAAOnF,OAAO;eAAKxC;SAAgB,EAAE;QACtEyC,OAAOoF,OAAO3D,OAAOzB,KAAK,EAAEmF,OAAOnF,KAAK,EAAE;QAC1CC,QAAQmF,OAAO3D,OAAOxB,MAAM,EAAEkF,OAAOlF,MAAM,EAAE;QAC7CC,SAASkF,OAAO3D,OAAOvB,OAAO,EAAEiF,OAAOjF,OAAO,EAAE;QAChDC,QAAQiF,OAAO3D,OAAOtB,MAAM,EAAEgF,OAAOhF,MAAM,EAAE;QAC7CmD,aAAajF,KAAKC,OAAM4G,uBAAAA,OAAOgB,YAAY,YAAnBhB,uBAAuB;YAAC;YAAS;YAAS;SAAS;QAC3E3B,QAAQlF,KAAKC,OAAM4G,kBAAAA,OAAOiB,OAAO,YAAdjB,kBAAkBjI;QACrCmJ,cAAcrI,KAAK+C,KAAK,CAACoE,OAAOkB,YAAY,GAAI,CAAA,OAAO9H,SAAS,IAAG,IAAK,OAAO;QAC/E+H,SAASnB,OAAOmB,OAAO,KAAK,aAAa/H,SAAS,OAAOD,KAAKC,MAAMd,aAAa0H,OAAOmB,OAAO;QAC/FjG,KAAK,GAAEW,QAAAA,kBAAAA,eAAe0C,MAAMrD,KAAK,aAA1BW,kBAA+BU,OAAOrB,KAAK,YAA3CW,OAA+C;QACtD,wEAAwE;QACxE,wEAAwE;QACxE,sEAAsE;QACtE,iEAAiE;QACjET,QAAQ8E,OAAO3D,OAAOnB,MAAM,EAAE1D,sBAAsBgG,KAAK/C,EAAE,GAAGyG;IAChE;AACF;AAEA,yEAAyE,GACzE,OAAO,MAAMA,sBAAsB,IAAG;AAMtC,SAASC,cAAcC,CAAS,EAAEC,CAAS,EAAEC,CAAS;IACpD,MAAMC,IAAI,AAACH,CAAAA,IAAI,eAAeC,IAAI,eAAeC,CAAAA,KAAM;IACvD,MAAME,IAAI,AAACJ,CAAAA,IAAI,eAAeC,IAAI,eAAeC,CAAAA,KAAM;IACvD,MAAMG,IAAI,AAACL,CAAAA,IAAI,eAAeC,IAAI,cAAcC,CAAAA,KAAM;IACtD,OAAO;QACL,eAAeC,IAAI,eAAeC,IAAI,eAAeC;QACrD,CAAC,eAAeF,IAAI,eAAeC,IAAI,eAAeC;QACtD,CAAC,eAAeF,IAAI,eAAeC,IAAI,cAAcC;KACtD;AACH;AAEA,MAAMC,SAAS,CAACC,UACdA,WAAW,YAAY,QAAQA,UAAU,QAAQA,WAAY,CAAA,IAAI,GAAE,IAAK;AAC1E,MAAMC,WAAW,CAACD,UAChBA,WAAW,UAAUA,UAAU,QAAQ,AAAC,CAAA,AAACA,CAAAA,UAAU,KAAI,IAAK,KAAI,KAAM;AAExE,kEAAkE,GAClE,OAAO,SAASE,WAAWT,CAAS,EAAEU,CAAS,EAAEC,CAAS;IACxD,MAAMC,YAAYrJ,KAAKmG,GAAG,CAAC,GAAGnG,KAAKsJ,GAAG,CAAC,GAAGb;IAC1C,IAAIR,SAASjI,KAAKsJ,GAAG,CAAC,GAAGH;IACzB,OAAS;QACP,MAAMI,UAAU,AAACH,IAAIpJ,KAAKwJ,EAAE,GAAI;QAChC,MAAMC,SAASjB,cAAca,WAAWpB,SAASjI,KAAK0J,GAAG,CAACH,UAAUtB,SAASjI,KAAK2J,GAAG,CAACJ;QACtF,MAAMK,OAAOH,OAAOnD,KAAK,CAAC,CAAC0C,UAAYA,WAAW,CAAC,UAAUA,WAAW;QACxE,IAAIY,QAAQ3B,UAAU,GAAG;YACvB,OAAO,CAAC,CAAC,EAAEwB,OACR7H,GAAG,CAAC,CAACoH,UAAYhJ,KAAK+C,KAAK,CAAC/C,KAAKmG,GAAG,CAAC,GAAGnG,KAAKsJ,GAAG,CAAC,GAAGP,OAAO/I,KAAKmG,GAAG,CAAC,GAAGnG,KAAKsJ,GAAG,CAAC,GAAGN,eAAe,MAClGpH,GAAG,CAAC,CAACa,QAAUA,MAAMoH,QAAQ,CAAC,IAAIC,QAAQ,CAAC,GAAG,MAC9CvG,IAAI,CAAC,KAAK;QACf;QACA0E,SAASjI,KAAKsJ,GAAG,CAAC,GAAGrB,SAAS;IAChC;AACF;AAEA,0BAA0B,GAC1B,OAAO,SAAS8B,WAAW3G,GAAW;IACpC,MAAMX,QAAQW,IAAI4G,OAAO,CAAC,KAAK;IAC/B,MAAM,CAACC,GAAGC,GAAGvB,EAAE,GAAG;QAAC;QAAG;QAAG;KAAE,CAAC/G,GAAG,CAAC,CAACuI,KAAOlB,SAASmB,SAAS3H,MAAM4H,KAAK,CAACF,IAAIA,KAAK,IAAI,MAAM;IACzF,MAAMvB,IAAI5I,KAAKsK,IAAI,CAAC,eAAeL,IAAI,eAAeC,IAAI,eAAevB;IACzE,MAAME,IAAI7I,KAAKsK,IAAI,CAAC,eAAeL,IAAI,eAAeC,IAAI,eAAevB;IACzE,MAAMG,IAAI9I,KAAKsK,IAAI,CAAC,eAAeL,IAAI,eAAeC,IAAI,eAAevB;IACzE,MAAMF,IAAI,eAAeG,IAAI,cAAcC,IAAI,eAAeC;IAC9D,MAAMyB,IAAI,eAAe3B,IAAI,cAAcC,IAAI,eAAeC;IAC9D,MAAM0B,IAAI,eAAe5B,IAAI,eAAeC,IAAI,cAAcC;IAC9D,OAAO;QAAEL;QAAGU,GAAGnJ,KAAKyK,KAAK,CAACF,GAAGC;QAAIpB,GAAG,AAAC,CAAA,AAACpJ,KAAK0K,KAAK,CAACF,GAAGD,KAAK,MAAOvK,KAAKwJ,EAAE,GAAG,GAAE,IAAK;IAAI;AACvF;AAEA,MAAMmB,QAAQ,CAACjC,GAAWC;QAAcpK;YAAAA,iBAAAA,cAAcmK,GAAGC,cAAjBpK,iBAAuB;;AAE/D,8GAA8G,GAC9G,SAASqM,cAAcnC,CAAS,EAAEU,CAAS,EAAEC,CAAS,EAAEyB,OAAe,EAAE1E,GAAW,EAAE2E,MAAa;IACjG,IAAIzB,YAAYZ;IAChB,IAAK,IAAIsC,OAAO,GAAGA,OAAO,IAAIA,QAAQ,EAAG;QACvC,IAAIJ,MAAMzB,WAAWG,WAAWF,GAAGC,IAAIyB,YAAY1E,KAAK,OAAOkD;QAC/DA,aAAayB,SAAS,QAAQ,CAAC;QAC/B,IAAIzB,aAAa,QAAQA,aAAa,MAAM;IAC9C;IACA,OAAOA;AACT;AAEA,oGAAoG,GACpG,SAAS2B,QAAQC,IAAY,EAAE7B,CAAS;IACtC,MAAM8B,QAAQ;IACd,MAAMC,MAAMjC,WAAW,KAAK,MAAME;IAClC,OAAOuB,MAAMO,OAAOD,SAAS,MAAMC,QAAQP,MAAMQ,KAAKF,SAAS,MAAME,MAAMR,MAAMO,OAAOD,QAAQN,MAAMQ,KAAKF,QAAQC,QAAQ;AAC7H;AAEA,mEAAmE,GACnE,OAAO,SAASE,SAAS1C,CAAS,EAAEC,CAAS;IAC3C,MAAM0C,IAAIrL,KAAKsL,GAAG,CAAC5C,IAAIC,KAAK;IAC5B,OAAO3I,KAAKmG,GAAG,CAACkF,GAAG,MAAMA;AAC3B;AAEA;;;;;CAKC,GACD,OAAO,MAAME,+BAA+B,GAAE;AAE9C,MAAMC,SAAuC;IAAEC,SAAS;IAAMC,OAAO;IAAOC,UAAU;IAAOC,OAAO;AAAM;AAC1G,MAAMC,UAAwC;IAAEJ,SAAS;IAAMC,OAAO;IAAMC,UAAU;IAAMC,OAAO;AAAK;AAExG,sCAAsC,GACtC,OAAO,SAASE,aAAa1G,KAAkB;;IAC7C,MAAM7E,OAAOL,OAAOkF,MAAMjF,IAAI,GAAG;IACjC,MAAMsL,UAAUrG,MAAM6C,MAAM,KAAK;IACjC,MAAM5F,QAAQ+C,MAAM/C,KAAK,GAAG0H,WAAW3E,MAAM/C,KAAK,IAAI;IACtD,MAAM+G,YAAI/G,yBAAAA,MAAO+G,CAAC,mBAAIhE,MAAM5D,GAAG;IAC/B,MAAMyG,kBAAS5F,yBAAAA,MAAO8G,CAAC,oBAAIqC,MAAM,CAACpG,MAAM6C,MAAM,CAAC,GAAI,CAAA,MAAM1H,SAAS,GAAE;IACpE,MAAMwL,eAAeN,UAAU,MAAM;IACrC,MAAMP,QAAQ;IAEd,oBAAoB;IACpB,MAAMhD,UAA8F;QAClGgD,OAAO;YAAEzC,GAAG;YAAOU,GAAG;YAAOC;YAAG4C,OAAO;gBAAC;gBAAG;aAAE;QAAC;QAC9CC,MAAM;YAAExD,GAAG;YAAOU,GAAG;YAAOC,GAAG;YAAI4C,OAAO;gBAAC;gBAAO;aAAM;QAAC;QACzDE,MAAM;YAAEzD,GAAG;YAAOU,GAAG;YAAOC,GAAG;YAAK4C,OAAO;gBAAC;gBAAG;aAAE;QAAC;QAClDG,QAAQ;YAAE1D,GAAG;YAAOU,GAAG;YAAMC;YAAG4C,OAAO;gBAAC;gBAAO;aAAM;QAAC;IACxD;IACA,MAAMtK,SAASwG,OAAO,CAAC9C,MAAM1D,MAAM,CAAC;IACpC,MAAM0K,aAAalD,WAAWxH,OAAO+G,CAAC,EAAE/G,OAAOyH,CAAC,GAAG4C,cAAcrK,OAAO0H,CAAC;IACzE,MAAM4C,QAAQ9C,WAAWxH,OAAOsK,KAAK,CAAC,EAAE,EAAEtK,OAAOsK,KAAK,CAAC,EAAE,GAAGD,cAAcrK,OAAO0H,CAAC;IAElF,4EAA4E;IAC5E,IAAIiD;IACJ,IAAIC;IACJ,IAAIjK,SAASsI,MAAMO,OAAO9F,MAAM/C,KAAK,KAAe,KAAK;QACvDgK,cAAcjH,MAAM/C,KAAK;QACzBiK,WAAWjK,MAAMoG,CAAC;IACpB,OAAO;QACL6D,WAAW1B,cAAcvI,QAAQrC,KAAKmG,GAAG,CAAC9D,MAAMoG,CAAC,EAAEoD,OAAO,CAACzG,MAAM6C,MAAM,CAAC,IAAI4D,OAAO,CAACzG,MAAM6C,MAAM,CAAC,GAAG,AAAC1H,CAAAA,SAAS,GAAE,IAAK,MAAM0H,QAAQmB,GAAG8B,OAAO,KAAK;QAClJmB,cAAcnD,WAAWoD,UAAUrE,QAAQmB;IAC7C;IACA,MAAMmD,eAAed,UAAU,OAAOzL,KAAKsJ,GAAG,CAAC,MAAMrB,SAAS;IAC9D,0EAA0E;IAC1E,6DAA6D;IAC7D,MAAMuE,YAAYpB,SAAShG,MAAM3D,MAAM,EAAE2H,KAAKmC,+BAA+BnC,IAAIhE,MAAM3D,MAAM;IAE7F,+FAA+F;IAC/F,MAAMgL,YAAYhB,UACd,AAAC,CAAA;QACC,0EAA0E;QAC1E,MAAMN,MAAMjC,WAAW,MAAM,OAAOE;QACpC,MAAM4C,QAAQ9C,WAAW,MAAM,OAAOE;QACtC,OAAO;YAAEsD,MAAM/B,MAAMQ,KAAKkB,gBAAgB1B,MAAMqB,OAAOK,eAAelB,MAAMa;YAAO5C;QAAE;IACvF,CAAA,MACA,AAAC,CAAA;QACC,sEAAsE;QACtE,mDAAmD;QACnD,MAAMuD,aAAa3M,KAAKmG,GAAG,CAACoG,cAAc;QAC1C,IAAI9D,IAAI;QACR,IAAIiE,OAAOxD,WAAWT,GAAGkE,YAAYH;QACrC,MAAO7B,MAAM+B,MAAML,eAAe,KAAK5D,IAAI,KAAM;YAC/CA,KAAK;YACLiE,OAAOxD,WAAWT,GAAGkE,YAAYH;QACnC;QACA,OAAO;YAAEE;YAAMtD,GAAGoD;QAAU;IAC9B,CAAA;IACJ,MAAMI,cAAc,AAACxH,CAAAA,MAAM3D,MAAM,GAAG,EAAC,IAAK;IAC1C,MAAMoL,YAAYjC,cAAc,MAAM,MAAMgC,aAAa1B,OAAO,KAAK;IACrE,MAAM4B,WAAW5D,WAAW2D,WAAW,MAAMD;IAC7C,MAAMG,aAAatB,UAAU,QAAQ;IAErC,MAAMuB,QAA+B;QACnCC,SAAS;YACPP,MAAML;YACNW,OAAO9D,WAAWlJ,KAAKmG,GAAG,CAAC,MAAMmG,WAAW,OAAOrE,QAAQmB;YAC3D8D,MAAMhE,WAAWlJ,KAAKsJ,GAAG,CAAC,MAAMgD,WAAW,MAAMrE,QAAQmB;YACzD+D,cAAcnC,QAAQqB,aAAajD;QACrC;QACAqD,WAAW;YACTC,MAAMD,UAAUC,IAAI;YACpBM,OAAO9D,WAAW,MAAMqD,eAAe,KAAKE,UAAUrD,CAAC;YACvD8D,MAAMhE,WAAW,MAAMqD,cAAcE,UAAUrD,CAAC;YAChD+D,cAAcnC,QAAQyB,UAAUC,IAAI,EAAED,UAAUrD,CAAC;QACnD;QACA0D,UAAU;YACRJ,MAAMI;YACNE,OAAO9D,WAAWlJ,KAAKmG,GAAG,CAAC,KAAK0G,YAAY,OAAO,MAAMD;YACzDM,MAAMhE,WAAWlJ,KAAKsJ,GAAG,CAAC,MAAMuD,YAAY,MAAM,MAAMD;YACxDO,cAAcnC,QAAQ8B,UAAUF;QAClC;QACAQ,SAAS;YAAEV,MAAMxD,WAAW,OAAO,QAAQ6C,cAAc3C;YAAI+D,cAAcjE,WAAW,MAAM6D,YAAY3D;QAAG;QAC3GgD,YAAY;YAAEiB,SAASjB;YAAYJ;QAAM;QACzCsB,MAAM;YACJL,SAAS/D,WAAW,MAAM6D,YAAY3D;YACtCqD,WAAWvD,WAAW,MAAM6D,aAAa,OAAO3D;YAChDmE,UAAUrE,WAAW,MAAM,MAAME;QACnC;QACA,yEAAyE;QACzE,qEAAqE;QACrEoE,MAAM;YACJP,SAAS/D,WAAW,OAAOuC,UAAU,OAAO,OAAOrC;YACnDqD,WAAWvD,WAAW,OAAO,OAAOsD;YACpCM,UAAU5D,WAAW,OAAO,MAAM0D;QACpC;QACAa,SAASvE,WAAW,KAAK,QAAQ6C,cAAc3C;IACjD;IAEA,MAAMsE,aAAatI,MAAM1D,MAAM,KAAK,WAAW,QAAQ0D,MAAM1D,MAAM,KAAK,SAAS,QAAQ;IACzF,MAAMiM,iBAAiBzE,WAAW,MAAMwE,aAAa3B,cAAc3G,MAAM1D,MAAM,KAAK,SAAS,KAAK0H;IAClG,MAAMwE,YAAY1E,WAAW,OAAOwE,aAAa3B,cAAc3G,MAAM1D,MAAM,KAAK,SAAS,KAAK0H;IAC9F,MAAMyE,aAAa7N,KAAKmG,GAAG,CAAC8B,QAAQ;IACpC,MAAM6F,eAAelD,cAAc,MAAMiD,YAAYzE,GAAGuE,gBAAgB,KAAK;IAC7E,MAAMI,cAAc7E,WAAW4E,cAAcD,YAAYzE;IACzD,MAAM4E,gBAAgBvC,UAAUvC,WAAW,MAAM,MAAME,KAAKF,WAAW,MAAMqD,eAAe,MAAMC;IAClG,MAAMyB,eAAe/E,WAAW,KAAK,KAAK0D;IAC1C,MAAMM,OAA8B;QAClCD,SAAS;YACPP,MAAMqB;YACNf,OAAO9D,WAAWlJ,KAAKmG,GAAG,CAAC,MAAM2H,eAAe,OAAOD,YAAYzE;YACnE8D,MAAMhE,WAAW4E,eAAe,KAAKD,YAAYzE;YACjD+D,cAAcnC,QAAQ+C,aAAa3E;QACrC;QACAqD,WAAW;YACTC,MAAMsB;YACNhB,OAAO9D,WAAW,KAAKqD,eAAe,KAAKE,UAAUrD,CAAC;YACtD8D,MAAMhE,WAAW,MAAMqD,eAAe,KAAKE,UAAUrD,CAAC;YACtD+D,cAAcnC,QAAQgD,eAAevB,UAAUrD,CAAC;QAClD;QACA0D,UAAU;YACRJ,MAAMuB;YACNjB,OAAO9D,WAAW,MAAM,MAAM0D;YAC9BM,MAAMhE,WAAW,KAAK,KAAK0D;YAC3BO,cAAcnC,QAAQiD,cAAcrB;QACtC;QACAQ,SAAS;YAAEV,MAAMxD,WAAW,MAAM,QAAQ6C,cAAc3C;YAAI+D,cAAcjE,WAAW,MAAM,MAAME;QAAG;QACpGgD,YAAY;YAAEiB,SAASM;YAAgB3B,OAAO4B;QAAU;QACxDN,MAAM;YACJL,SAAS/D,WAAW,MAAM,OAAOE;YACjCqD,WAAWvD,WAAW,MAAM,OAAOE;YACnCmE,UAAUrE,WAAW,MAAM,MAAME;QACnC;QACAoE,MAAM;YACJP,SAAS/D,WAAW,MAAM,MAAME;YAChCqD,WAAWvD,WAAW,MAAM,MAAMsD;YAClCM,UAAU5D,WAAW,MAAM,MAAM0D;QACnC;QACAa,SAASvE,WAAW,MAAM,QAAQ6C,cAAc3C;IAClD;IACA,OAAO;QAAE4D;QAAOE;IAAK;AACvB;AAEA,4EAA4E;AAE5E,MAAMgB,SAAwC;IAAEC,OAAO;IAAGC,MAAM;IAAGrL,OAAO;IAAIsL,MAAM;AAAG;AACvF,MAAMC,UAAyC;IAAEC,SAAS;IAAGC,SAAS;IAAGC,MAAM;AAAE;AAEjF,0GAA0G,GAC1G,MAAMC,cAA+F;IACnGC,WAAW;QAAEC,MAAM;QAAGC,OAAO;IAAI;IACjCC,IAAI;QAAEF,MAAM;QAAMC,OAAO;IAAE;IAC3BE,IAAI;QAAEH,MAAM;QAAMC,OAAO;IAAI;IAC7BG,IAAI;QAAEJ,MAAM;QAAMC,OAAO;IAAI;IAC7BI,IAAI;QAAEL,MAAM;QAAKC,OAAO;IAAI;IAC5BK,IAAI;QAAEN,MAAM;QAAMC,OAAO;IAAE;IAC3BM,IAAI;QAAEP,MAAM;QAAOC,OAAO;IAAE;AAC9B;AAEA,MAAMO,MAAM,CAAC3M,QAAkB,GAAGzC,KAAK+C,KAAK,CAACN,QAAQ,QAAQ,KAAK,GAAG,CAAC;AAEtE;;;;;;;CAOC,GACD,OAAO,MAAM4M,wBAAsF;IACjGvL,WAAW;QAAEwL,SAAS;QAAMC,OAAO;IAAI;IACvCxL,QAAQ;QAAEuL,SAAS;QAAKC,OAAO;IAAI;IACnCvL,aAAa;QAAEsL,SAAS;QAAKC,OAAO;IAAK;IACzCtL,MAAM;QAAEqL,SAAS;QAAMC,OAAO;IAAI;AACpC,EAAC;AAED,0GAA0G,GAC1G,SAASC,cAAcpK,KAAkB;QACvBjG;QAEVV;IAFN,MAAMoD,WAAU1C,qBAAAA,kBAAkBiG,MAAMzD,KAAK,aAA7BxC,qBAAmCH,qBAAqB,CAAC,EAAE;IAC3E,MAAMyQ,WAAuF,sBACvFhR,iCAAAA,mBAAmBiR,UAAU,qBAA7BjR,+BAA+BgR,QAAQ,mBAAI,CAAC;IAElD,MAAME,QAAQN,qBAAqB,CAACjK,MAAMP,IAAI,CAAC;IAC/C,KAAK,MAAM,CAAC+K,KAAK,EAAEhB,IAAI,EAAEC,KAAK,EAAE,CAAC,IAAIhI,OAAOK,OAAO,CAACwH,aAAyF;;QAC3I,MAAMmB,MAAMD,QAAQ,eAAeA,QAAQ,QAAQA,QAAQ;QAC3D,MAAME,UAAUF,QAAQ,uBAAeD,yBAAAA,MAAOL,OAAO,oBAAI,IAAKM,QAAQ,gBAAQD,yBAAAA,MAAOJ,KAAK,oBAAI,IAAK;QACnG,MAAMQ,UAAsC;YAC1CC,UAAUZ,IAAIR,OAAQ,CAAA,IAAI,AAACxJ,CAAAA,MAAMiD,YAAY,GAAG,CAAA,IAAKwG,KAAI,IAAMhN,CAAAA,QAAQoO,IAAI,IAAIJ,MAAM,OAAO,CAAA,IAAKC;YACjGI,YAAYL,MAAMhO,QAAQsO,OAAO,CAACC,MAAM,GAAGvO,QAAQsO,OAAO,CAACE,GAAG;YAC9D,0CAA0C;YAC1CC,YAAYT,MAAOhO,QAAQoO,IAAI,GAAG,OAAOL,QAAQ,eAAeD,QAAQ,OAAO,MAAO;QACxF;QACA,IAAI9N,QAAQ0O,QAAQ,KAAK5N,aAAckN,CAAAA,OAAOD,QAAQ,IAAG,GAAIG,QAAQS,aAAa,GAAG,GAAG3O,QAAQ0O,QAAQ,CAAC,EAAE,CAAC;QAC5G,IAAI1O,QAAQoO,IAAI,IAAKJ,CAAAA,OAAOD,QAAQ,IAAG,GAAIG,QAAQU,aAAa,GAAG;QACnEhB,QAAQ,CAACG,IAAI,GAAGG;IAClB;IACA,MAAMW,WAAW7O,QAAQ8O,IAAI,CAACC,OAAO,CAAClO,QAAQ,CAAC,OAAO,MAAM;IAC5D+M,SAASoB,QAAQ,GACfzL,MAAMjD,OAAO,KAAK,UACd;QAAE6N,UAAU;QAAYE,YAAYQ;QAAUF,eAAe;QAAUC,eAAe;IAAO,IAC7F;QAAET,UAAU;QAAWE,YAAY;QAAKM,eAAepL,MAAMjD,OAAO,KAAK,SAAS,WAAW;QAAUsO,eAAe;IAAY;IACxIhB,SAASqB,MAAM,GAAG;QAChBZ,YAAY9K,MAAMpD,OAAO,KAAK,SAAS,MAAM0O;QAC7CD,eAAerL,MAAMpD,OAAO,KAAK,SAAS,cAAc;OACpDoD,MAAMpD,OAAO,KAAK,SAAS;QAAEwO,eAAe;IAAS,IAAI,CAAC;IAEhE,OAAO;QAAEf;IAAS;AACpB;AAEA,2FAA2F,GAC3F,SAASsB,OAAO9O,KAAkB;IAChC,OAAQA;QACN,KAAK;YACH,OAAO;gBAAE+O,WAAW;gBAAGC,QAAQ;gBAAGC,SAAS;YAAe;QAC5D,KAAK;YACH,OAAO;gBAAEF,WAAW;gBAAGC,QAAQ;gBAAGE,aAAa;gBAAWD,SAAS;YAAmB;QACxF,KAAK;YACH,OAAO;gBAAEF,WAAW;gBAAGC,QAAQ;gBAAGC,SAAS;YAAmB;QAChE,KAAK;YACH,OAAO;gBAAEF,WAAW;gBAAGC,QAAQ;gBAAGC,SAAS;YAAe;QAC5D,KAAK;YACH,OAAO;gBAAEF,WAAW;gBAAGC,QAAQ;gBAAGG,WAAW;gBAAGD,aAAa;gBAAgBE,cAAc;gBAAGH,SAAS;YAAmB;IAC9H;AACF;AAEA,kHAAkH,GAClH,SAASI,cAAclM,KAAkB;QAiCSmM;IAhChD,MAAMC,SAAStD,MAAM,CAAC9I,MAAMrD,OAAO,CAAC;IACpC,MAAM0P,eAAerM,MAAMpD,OAAO,KAAK,SAAS,MAAMoD,MAAMpD,OAAO,KAAK,WAAW,IAAIwP;IACvF,MAAMD,OAAOR,OAAO3L,MAAMnD,KAAK;IAC/B,OAAO;QACLyP,WAAW;YACTC,cAAc;gBAAEC,kBAAkB;YAAK;YACvC,kDAAkD;YAClDC,gBAAgB;gBAAEC,MAAM;oBAAET,cAAcI;oBAAcM,WAAW;oBAAIf,WAAW;gBAAO;YAAE;WACrF5L,MAAMpD,OAAO,KAAK,SAClB;YACEyN,UAAU;gBACR;oBACEuC,OAAO;wBAAEjC,SAAS;oBAAO;oBACzB3K,OAAO;wBAAE6M,gBAAgB;wBAAaC,qBAAqB;wBAASC,yBAAyB;oBAAM;gBACrG;aACD;QACH,IACA,CAAC;QAEPC,SAAS;YACPT,cACEvM,MAAMnD,KAAK,KAAK,aACZ;gBAAE8N,SAAS;YAAW,IACtB;gBAAEA,SAAS;gBAAasC,WAAWjN,MAAMnD,KAAK,KAAK,aAAa,IAAI;YAAE;YAC5E4P,gBAAgB;gBAAEC,MAAM;oBAAET,cAAcjM,MAAMnD,KAAK,KAAK,SAAS,IAAIjC,KAAKsJ,GAAG,CAACkI,QAAQ;gBAAG;YAAE;YAC3Fc,IAAI;gBAAER,MAAMP;YAAK;QACnB;QACAgB,cAAc;YACZZ,cAAc;gBAAEa,gBAAgB;gBAAMH,WAAW;YAAE;YACnDC,IAAI;gBACFR,MAAM,aACDP;oBACHH,WAAWhM,MAAMnD,KAAK,KAAK,SAAS,KAAIsP,kBAAAA,IAAI,CAAC,YAAY,YAAjBA,kBAAqBA,IAAI,CAAC,SAAS;oBAC3E,aAAa;wBAAEjC,SAAS;oBAAO;oBAC/B,wBAAwB;wBAAEmD,IAAI;oBAAE;;YAEpC;QACF;QACAC,cAAc;YAAEf,cAAc;gBAAE5B,SAAS3K,MAAMlD,MAAM;YAAC;QAAE;QACxDyQ,kBAAkB;YAAEd,gBAAgB;gBAAEC,MAAM;oBAAET,cAAcG;gBAAO;YAAE;QAAE;QACvEoB,gBAAgB;YAAEf,gBAAgB;gBAAEC,MAAM;oBAAEe,qBAAqBrB;oBAAQsB,sBAAsBtB;gBAAO;YAAE;QAAE;QAC1GuB,SAAS;YAAElB,gBAAgB;gBAAEC,MAAM;oBAAET,cAAcjM,MAAMrD,OAAO,KAAK,UAAU,IAAI;gBAAI;YAAE;QAAE;QAC3FiR,WAAW;YACTrB,cAAc;gBAAEU,WAAW;YAAE;YAC7B5C,UAAU;gBACR;oBACEuC,OAAO;wBAAEiB,OAAO;oBAAU;oBAC1BX,IACElN,MAAMhD,MAAM,KAAK,SACb;wBAAE4O,WAAW;wBAAGkC,cAAc;wBAAG/B,aAAa;oBAAU,IACxD/L,MAAMhD,MAAM,KAAK,WACf;wBAAE4O,WAAW;wBAAGkC,cAAc;oBAAE,IAChC;wBAAElC,WAAW;wBAAGkC,cAAc;oBAAE;gBAC1C;aACD;QACH;OACI9N,MAAMjD,OAAO,KAAK,SAClB;QACEgR,eAAe;YACb1D,UAAU;gBACR;oBACEuC,OAAO;wBAAEjC,SAAS;oBAAW;oBAC7B,oEAAoE;oBACpE3K,OAAO;wBACL,aAAa;4BACXgO,SAAS;4BACT9D,SAAS;4BACT+D,OAAO;4BACPC,QAAQ;4BACRC,aAAa;4BACbC,eAAe;4BACfC,iBAAiB;wBACnB;oBACF;gBACF;aACD;QACH;IACF,IACA,CAAC;AAET;AAEA,SAASC,SAASjR,KAAc;IAC9B,OAAO,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACkR,MAAMC,OAAO,CAACnR;AACvE;AAEA,4EAA4E,GAC5E,SAASoR,OAAUC,KAAQ,EAAEC,IAAa;IACxC,IAAI,CAACL,SAASI,UAAU,CAACJ,SAASK,OAAO,OAAQA,SAASpR,YAAYmR,QAAQC;IAC9E,MAAMC,MAA+B,aAAKF;IAC1C,KAAK,MAAM,CAAClE,KAAKnN,MAAM,IAAIoE,OAAOK,OAAO,CAAC6M,MAAOC,GAAG,CAACpE,IAAI,GAAGA,OAAOoE,MAAMH,OAAOG,GAAG,CAACpE,IAAI,EAAEnN,SAASA;IACnG,OAAOuR;AACT;AAEA,+FAA+F,GAC/F,SAASC,WAAWC,KAAgB;IAClC,IAAI,CAAC1V,wBAAwB0V,OAAOC,EAAE,EAAE,OAAO;IAC/C,KAAK,MAAMC,UAAU;QAAC;QAAS;KAAO,CAAW;YAChCF,qBACFG,iBACAA;QAFb,MAAMA,UAASH,sBAAAA,MAAMI,YAAY,qBAAlBJ,mBAAoB,CAACE,OAAO;QAC3C,MAAM1H,OAAO2H,2BAAAA,kBAAAA,OAAQpH,OAAO,qBAAfoH,gBAAiB3H,IAAI;QAClC,MAAM6H,OAAOF,2BAAAA,qBAAAA,OAAQjI,UAAU,qBAAlBiI,mBAAoBhH,OAAO;QACxC,IAAI,CAACX,QAAQ,CAAC6H,QAAQ5J,MAAM+B,MAAM6H,QAAQ,GAAG,OAAO;QACpD,KAAK,MAAM3E,OAAO;YAAC;YAAW;YAAa;SAAW,CAAW;YAC/D,MAAM3E,OAAOoJ,0BAAAA,MAAQ,CAACzE,IAAI;YAC1B,IAAI3E,CAAAA,wBAAAA,KAAMyB,IAAI,KAAIzB,KAAKkC,YAAY,IAAIxC,MAAMM,KAAKkC,YAAY,EAAElC,KAAKyB,IAAI,IAAI,KAAK,OAAO;QAC3F;IACF;IACA,OAAO;AACT;AAEA;;;;;CAKC,GACD,OAAO,SAAS8H,YAAYpP,KAAkB,EAAE7D,IAAe;QAC7CpC,oBAgBKoC,kBACNA,aAEMA;QAgBH2S;IAnClB,MAAMrS,WAAU1C,qBAAAA,kBAAkBiG,MAAMzD,KAAK,aAA7BxC,qBAAmCH,qBAAqB,CAAC,EAAE;IAC3E,MAAMqV,SAASvI,aAAa1G;IAC5B,MAAMoC,OAAO,CAAC4M;;YACA7S;QAAZ,MAAM0E,eAAM1E,qBAAAA,KAAK+S,YAAY,qBAAjB/S,kBAAmB,CAAC6S,OAAO,mBAAI,CAAC;QAC5C,6EAA6E;QAC7E,OAAO,aACDnO,IAAIwO,KAAK,GAAG;YAAEA,OAAOxO,IAAIwO,KAAK;QAAC,IAAI,CAAC,GACpCxO,IAAIyO,OAAO,GAAG;YAAEA,SAASzO,IAAIyO,OAAO;QAAC,IAAI,CAAC,GAC1CzO,IAAI0O,IAAI,GAAG;YAAEA,MAAM1O,IAAI0O,IAAI;QAAC,IAAI,CAAC,GACjC1O,IAAI2O,OAAO,GAAG;YAAEA,SAAS3O,IAAI2O,OAAO;QAAC,IAAI,CAAC,GAC3CP,MAAM,CAACD,OAAO;IAErB;IACA,IAAIF,QAAmB,aAClB3S;QACH+S,cAAc;YAAEtH,OAAOxF,KAAK;YAAU0F,MAAM1F,KAAK;QAAQ;QACzDkI,YAAYmE,QAAOtS,mBAAAA,KAAKmO,UAAU,YAAfnO,mBAAmB,CAAC,GAAGiO,cAAcpK;QACxDyP,OAAO,cAAMtT,cAAAA,KAAKsT,KAAK,YAAVtT,cAAc,CAAC;YAAI8P,cAAcnD,MAAM,CAAC9I,MAAMrD,OAAO,CAAC;;QACnE+S,SAASxG,OAAO,CAAClJ,MAAMkD,OAAO,CAAC;QAC/ByM,YAAYlB,QAAOtS,mBAAAA,KAAKwT,UAAU,YAAfxT,mBAAmB,CAAC,GAAG+P,cAAclM;;IAE1D,OAAO8O,MAAMc,UAAU;IACvB,MAAMC,aAAapT,QAAQsO,OAAO,CAAChJ,MAAM,KAAKtF,QAAQ8O,IAAI,CAACxJ,MAAM;IACjE+M,QAAQxV,gBAAgBwV,OAAO;QAC7BvD,MAAM;YAAExJ,QAAQtF,QAAQ8O,IAAI,CAACxJ,MAAM;YAAE+N,UAAUrT,QAAQ8O,IAAI,CAACuE,QAAQ;YAAEtE,SAAS;mBAAI/O,QAAQ8O,IAAI,CAACC,OAAO;aAAC;YAAEuE,QAAQ;QAAS;QAC3HhF,SAAS8E,aACL,OACA;YACE9N,QAAQtF,QAAQsO,OAAO,CAAChJ,MAAM;YAC9B+N,UAAUrT,QAAQsO,OAAO,CAAC+E,QAAQ;YAClCtE,SAAS;mBAAI,IAAI7I,IAAI;oBAAClG,QAAQsO,OAAO,CAACC,MAAM;oBAAEvO,QAAQsO,OAAO,CAACE,GAAG;iBAAC;aAAE,CAAC+E,IAAI,CAAC,CAAC1M,GAAGC,IAAMD,IAAIC;YACxFwM,QAAQ;QACV;IACN;IACA,4EAA4E;IAC5E,IAAIF,gBAAcf,eAAAA,MAAMvS,KAAK,qBAAXuS,YAAa,CAAC,EAAE,GAAE;YAGNA;QAF5BA,MAAMvS,KAAK,CAAC,EAAE,GAAG,aACZuS,MAAMvS,KAAK,CAAC,EAAE;YACjBiP,SAAS;mBAAI,IAAI7I,IAAI;wBAAKmM,wBAAAA,MAAMvS,KAAK,CAAC,EAAE,CAACiP,OAAO,YAAtBsD,wBAA0B,EAAE;oBAAGrS,QAAQsO,OAAO,CAACC,MAAM;oBAAEvO,QAAQsO,OAAO,CAACE,GAAG;iBAAC;aAAE,CAAC+E,IAAI,CAAC,CAAC1M,GAAGC,IAAMD,IAAIC;;IAE/H;IACA,IAAI,CAACsL,WAAWC,QAAQ;QACtB,gGAAgG;QAChGA,QAAQ,aAAKA;YAAOI,cAAc7V,mBAAmB6V,YAAY;;IACnE;IACA,OAAOJ;AACT"}
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 HostThemeFontCategory,\n HostThemeSchemeColors,\n HostThemeTypographyVariant,\n HostThemeTypographyVariantKey,\n} from '@aglyn/shared-data-types'\nimport { writeThemeFonts } from '@aglyn/shared-ui-theme/util/theme-editor-fields'\nimport {\n AI_SITE_MOTION_STYLES,\n aiSiteMotionStyle,\n aiSiteMotionStylesFor,\n type AiSiteMotionStyle,\n} from '../layout-language/ai-layout-motion'\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 * How the site's pages arrive (AGL-3941), from `ai-layout-motion.ts`'s\n * vocabulary. Absent on a style stored before the look chose motion, whose\n * pages move in its kind's mood.\n */\n motion?: AiSiteMotionStyle\n /**\n * A site brought in's own page ground (AGL-4108), `#rrggbb`: the color its\n * source's pages sit on, where it is light enough for the theme's text.\n * Absent, the ground is drawn as `ground` says.\n */\n page?: string\n /**\n * A site brought in's own type (AGL-4108): the families its source sets\n * its body and its headings in, where the theme font catalog has them,\n * loaded in place of the pairing's. The pairing still sets the weights and\n * the scale they are drawn at. Absent on every other site, whose type is\n * the pairing's alone.\n */\n sourceFonts?: { body: AiSiteSourceFont; heading: AiSiteSourceFont | null } | null\n}\n\n/** A family a site brought in is set in (AGL-4108), with the weights the catalog says it has. */\nexport interface AiSiteSourceFont {\n family: string\n category: HostThemeFontCategory\n /** The upright weights the family offers. */\n weights: number[]\n}\n\n/** The weights of `wanted` a family offers, each the nearest it has where it lacks one. */\nexport function aiSiteFontWeightsIn(wanted: readonly number[], offered: readonly number[]): number[] {\n if (!offered.length) return [...new Set(wanted)].sort((a, b) => a - b)\n const nearest = (weight: number) => offered.reduce((best, each) => (Math.abs(each - weight) < Math.abs(best - weight) ? each : best), offered[0] as number)\n return [...new Set(wanted.map(nearest))].sort((a, b) => a - b)\n}\n\n/** What the model may choose, every field optional. */\nexport type AiSiteLookAnswer = Partial<\n Pick<\n AiSiteStyle,\n | 'base'\n | 'hue'\n | 'accent'\n | 'ground'\n | 'fonts'\n | 'corners'\n | 'buttons'\n | 'cards'\n | 'fields'\n | 'eyebrow'\n | 'header'\n | 'brand'\n | 'motion'\n >\n>\n\n/**\n * The dimensions the sites a person likes pin (AGL-3975,\n * `jobs/ai-site-inspiration.ts`): each one present is KEPT, whatever the\n * model or the seed would choose, and every other dimension is chosen as it\n * always is. A brand the person gave in the brief still wins over a pinned\n * brand color, and the hue pinned with it.\n */\nexport type AiSiteLookPins = Partial<\n Pick<\n AiSiteStyle,\n | 'brand'\n | 'hue'\n | 'accent'\n | 'ground'\n | 'fonts'\n | 'corners'\n | 'buttons'\n | 'cards'\n | 'header'\n | 'headerAlign'\n | 'density'\n | 'motion'\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', 'motion'],\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 motion: enumOf(AI_SITE_MOTION_STYLES, 'How the pages arrive as a visitor scrolls, from the motion list in the request.'),\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 const motion = aiSiteMotionStyle(raw['motion'])\n if (motion) look.motion = motion\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 /** What the sites the person likes pin (AGL-3975): kept on every draw. */\n pins?: AiSiteLookPins\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; pins?: AiSiteLookPins },\n seed: number,\n): AiSiteStyle {\n return withPins(drawOnce(input, seed), input)\n}\n\n/**\n * A drawn style with its pins laid over it (AGL-3975). Applied after the\n * draw, so every dimension is drawn the same with or without pins and an\n * unpinned job's look is exactly what it was.\n */\nfunction withPins(style: AiSiteStyle, input: { brand?: string | null; pins?: AiSiteLookPins }): AiSiteStyle {\n const pins = input.pins\n if (!pins || !Object.keys(pins).length) return style\n // The person's own brand color outranks the one their sites suggest.\n const own = aiSiteBrandHex(input.brand)\n const { brand, hue, ...rest } = pins\n const pinned = Object.fromEntries(Object.entries(rest).filter(([, value]) => value !== undefined && value !== null))\n return {\n ...style,\n ...pinned,\n ...(!own && aiSiteBrandHex(brand) ? { brand: aiSiteBrandHex(brand) } : {}),\n ...(!own && typeof hue === 'number' && Number.isFinite(hue) ? { hue: ((Math.round(hue) % 360) + 360) % 360 } : {}),\n }\n}\n\nfunction drawOnce(\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 // Drawn last, so every dimension above is drawn the same whether or not\n // the answer chose a motion. The model's choice is kept more often than\n // the other dimensions', because nothing else of the site says how it\n // moves; the seed's draw is among the styles that suit the kind.\n motion: choose(answer.motion, aiSiteMotionStylesFor(kind.id), AI_SITE_MOTION_KEEP),\n }\n}\n\n/** The chance a look keeps the motion style the model chose (AGL-3941). */\nexport const AI_SITE_MOTION_KEEP = 0.6\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 // A site brought in keeps the ground its source's pages sit on (AGL-4108), where its text reads on it.\n const own = style.page && /^#[0-9a-f]{6}$/i.test(style.page) && aiHexOklch(style.page).L >= 0.9 ? style.page.toLowerCase() : null\n const background = own ?? 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 // A site brought in is set in its source's own families (AGL-4108), at the\n // weights the pairing draws with, as near as each family has them.\n const headingWeights = [pairing.heading.weight, pairing.heading.sub]\n const source = style.sourceFonts ?? null\n const body = source?.body\n ? { family: source.body.family, category: source.body.category, weights: aiSiteFontWeightsIn(pairing.body.weights, source.body.weights) }\n : { family: pairing.body.family, category: pairing.body.category, weights: [...pairing.body.weights] }\n const heading = source\n ? source.heading\n ? { family: source.heading.family, category: source.heading.category, weights: aiSiteFontWeightsIn(headingWeights, source.heading.weights) }\n : { ...body, weights: aiSiteFontWeightsIn(headingWeights, source.body.weights) }\n : { family: pairing.heading.family, category: pairing.heading.category, weights: [...new Set(headingWeights)].sort((a, b) => a - b) }\n const sameFamily = heading.family.toLowerCase() === body.family.toLowerCase()\n theme = writeThemeFonts(theme, {\n body: { ...body, source: 'google' },\n heading: sameFamily ? null : { ...heading, source: 'google' },\n })\n // A heading in the body's 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 ?? []), ...heading.weights])].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\n// ── A kind's first look (AGL-4049) ──────────────────────────────────────────\n\n/** The midpoint of a kind's first hue range, or `null` when it spans the whole wheel (any hue suits it). */\nfunction firstHueOf(hues: AiSiteKind['look']['hues']): number | null {\n const [from, to] = hues?.[0] ?? [0, 360]\n const span = from <= to ? to - from : 360 - from + to\n if (span >= 360) return null\n return Math.round(from + span / 2) % 360\n}\n\n/** A kind's first look as a built-in theme with a brand over it, and the style answers that say the same. */\nexport interface AiSiteKindDefaultLook {\n /** The `builtin` starter theme a site created in this style starts with. */\n theme: {\n kind: 'builtin'\n base: string\n brand: { light: Record<string, string>; dark?: Record<string, string> }\n fonts: string | null\n }\n /** The same look as the AI start's style answers name it (`fp-starter-{kind}-ai`). */\n answerStyle: {\n base: string\n hue?: number\n ground: AiSiteGround\n fonts: string | null\n corners: AiSiteCorners\n buttons: AiSiteButtons\n }\n}\n\n/**\n * A kind of site's FIRST look (AGL-4049), the one a site created in that\n * style starts with and the one the platform's own starter listings carry:\n * the kind's first base theme the deployment has (`starter`, or a built-in\n * whose preset `known.presetIds` holds), its first font pairing the platform\n * has, and a brand primary from the midpoint of its first hue range, colored\n * as {@link aiSiteColors} colors one. A kind that suits any hue keeps the\n * base's own colors. One derivation, so the style a person picks in Create\n * site and the seeded `fp-starter-{kind}-base` listing look the same.\n *\n * Deterministic: no draw, the seed is the kind's id.\n */\nexport function aiSiteKindDefaultLook(\n kind: AiSiteKind,\n known: { presetIds: ReadonlySet<string>; pairingIds?: ReadonlySet<string> },\n): AiSiteKindDefaultLook {\n const family = kind.look\n const pairingIds = known.pairingIds ?? new Set(AI_SITE_FONT_PAIRINGS.map((pairing) => pairing.id))\n const base =\n family.bases.find((name) => name === 'starter' || known.presetIds.has(`theme-presets.${name}`)) ?? 'starter'\n const fonts = family.fonts.find((id) => pairingIds.has(id)) ?? null\n const hue = firstHueOf(family.hues)\n const ground = family.grounds[0] as AiSiteGround\n const corners = family.corners[0] as AiSiteCorners\n const colors =\n hue === null\n ? null\n : aiSiteColors({\n v: 1,\n kind: kind.id,\n base,\n seed: aiSiteSeed(kind.id),\n hue,\n accent: hue,\n chroma: family.chroma,\n ground,\n fonts: fonts ?? '',\n corners,\n buttons: family.buttons,\n // Not read by the colors; named so the style is whole.\n cards: 'flat',\n fields: 'outlined',\n eyebrow: 'caps',\n header: 'line',\n headerAlign: 'start',\n rhythm: 'calm',\n headingScale: family.headingScale,\n density: family.density,\n brand: null,\n })\n const primary = (scheme: 'light' | 'dark') => {\n const value = colors?.[scheme]?.primary\n return value && typeof value === 'object' && typeof (value as { main?: unknown }).main === 'string'\n ? (value as { main: string }).main\n : null\n }\n const light = primary('light')\n const dark = primary('dark')\n const brand = light && dark ? { light: { primary: light }, dark: { primary: dark } } : { light: {} }\n return {\n theme: { kind: 'builtin', base, brand, fonts },\n answerStyle: {\n base,\n ...(hue === null ? {} : { hue }),\n ground,\n fonts,\n corners,\n buttons: family.buttons,\n },\n }\n}\n"],"names":["contrastRatio","validateThemeForPublish","DEFAULT_SITE_THEME","writeThemeFonts","AI_SITE_MOTION_STYLES","aiSiteMotionStyle","aiSiteMotionStylesFor","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","aiSiteFontWeightsIn","wanted","offered","length","Set","sort","a","b","nearest","weight","reduce","best","each","Math","abs","map","aiSiteSeed","jobId","hash","index","charCodeAt","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","pairing","id","corners","buttons","cards","fields","eyebrow","header","brand","anyOf","motion","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","attempt","AI_SITE_LOOK_DRAWS","own","least","min","other","TUPLE","every","dimension","filter","AI_SITE_LOOK_LEAST_DIFFERENCES","withPins","drawOnce","pins","Object","keys","rest","pinned","fromEntries","entries","family","blocks","choose","model","options","keep","modelRange","keepHue","range","span","accentFrom","bases","v","chroma","grounds","headerAligns","rhythms","headingScale","density","AI_SITE_MOTION_KEEP","oklabToLinear","L","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","AI_SITE_ACCENT_CLASH_DEGREES","CHROMA","neutral","muted","balanced","vivid","START_L","aiSiteColors","groundChroma","paper","warm","cool","tinted","page","test","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","big","boosted","variant","fontSize","caps","fontWeight","heading","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","aiSiteTheme","error","warning","info","success","shape","spacing","components","darkScheme","headingWeights","source","sourceFonts","category","sameFamily","firstHueOf","aiSiteKindDefaultLook","known","pairingIds","find","presetIds","has","answerStyle"],"mappings":"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"}
@@ -77,6 +77,8 @@ export interface AiSiteListRecord {
77
77
  /** The library photo it shows, with its size and words; absent on a starter. */
78
78
  photo?: AiLayoutPicturePhoto;
79
79
  refused?: AiStockRefusedPicks;
80
+ /** A record of a thing of its own (AGL-4092): its own photo or its starter, never another record's or the job's. */
81
+ itsOwn?: true;
80
82
  }
81
83
  /** A pictured list of the start, one of whose records holds a starter photo. */
82
84
  export interface AiSiteStarterList {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-photos.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 type { StockPhotoSearchRequest } from '@aglyn/aglyn/plugin-manager/stock-photo-provider'\nimport type { AiLayoutPicturePhoto, AiLayoutPictureRole } from '../layout-language/ai-layout-pictures'\n\n/**\n * THE PICTURES A SITE START LEFT ON A STARTER PHOTO (AGL-3988).\n *\n * A guided start's pages and its datasets' records are each built in a pass\n * of their own, minutes apart. A picture the stock library could not fill in\n * its pass took a starter photo there: its picks' downloads refused by the\n * library's image hosts in a burst, or no photo of the job's own to take\n * yet. The v1.0.0-beta.271 Laurel Fork Photography start (2026-10-19 23:05Z)\n * filed all twelve \"Gallery collections\" covers and its home hero under an\n * office team and a desk: pixabay.com's Cloudflare answered 429 to 22\n * downloads while the covers were built, before the job had copied any\n * photo, and to 11 more on the home page, the first page built.\n *\n * Each such picture is written down here, with the picks the hosts refused,\n * on the job, by the machine, in the write that records its pass. The site\n * step's late photo pass (`jobs/ai-site-late-photos.ts`) reads it once every\n * page is built and before the site is published: it asks the refused picks\n * for again, a minute after the refusal, and gives every picture still on a\n * starter one of the photos the job copied. Pure.\n */\n\n/** Where a starter photo is served from: the platform's own files, on every site's origin. */\nexport const AI_SITE_STARTER_PREFIX = '/_static/starter/'\n\n/** Whether an address is a starter photo's. */\nexport function aiSiteIsStarterSrc(src: unknown): boolean {\n return typeof src === 'string' && src.startsWith(AI_SITE_STARTER_PREFIX)\n}\n\n/** The picks a slot kept in hand whose downloads the library's image hosts refused, to ask for again. */\nexport interface AiStockRefusedPicks {\n /** The search they came from, as it was sent: asked again, the provider's cache answers it. */\n request: StockPhotoSearchRequest\n /** The picks' source keys (`pixabay:5401602`), best first. */\n keys: string[]\n /** When the last of them was refused, ISO. */\n at: string\n}\n\n/** A picture of one of the start's pages that holds a starter photo. */\nexport interface AiSiteStarterSlot {\n /** The `image` node. */\n image: string\n /** What the picture was to show, in the slot's own words: a starter's alt text is the starter's. */\n words: string\n role: AiLayoutPictureRole\n /** The frame's shape, width over height. */\n aspect: number\n refused?: AiStockRefusedPicks\n}\n\n/** A page of the start with the pictures it left on a starter. */\nexport interface AiSiteStarterPage {\n /** The page's draft. */\n screen: string\n slots: AiSiteStarterSlot[]\n}\n\n/** A record of a pictured list, as its photo was written. */\nexport interface AiSiteListRecord {\n /** The record's name: its first field's value. */\n name: string\n /** What the list files it under, where it files its records (AGL-3856). */\n category?: string\n /** The value its photo field holds: a starter's path, or the library photo's CDN path. */\n value: string\n /** The library photo it shows, with its size and words; absent on a starter. */\n photo?: AiLayoutPicturePhoto\n refused?: AiStockRefusedPicks\n}\n\n/** A pictured list of the start, one of whose records holds a starter photo. */\nexport interface AiSiteStarterList {\n /** The dataset. */\n dataset: string\n /** Its photo field, by id. */\n imageField: string\n /** The field its records keep what their photo shows in, by id (AGL-3856). */\n altField?: string\n /** A list of the business's people: a record of it never takes a photo of anything but a person. */\n people?: boolean\n /** Every record, in order, so a record's neighbors are known. */\n records: AiSiteListRecord[]\n}\n\n/** What a site job holds on its pictures that took a starter, until its late photo pass. */\nexport interface AiSitePhotos {\n pages: AiSiteStarterPage[]\n lists: AiSiteStarterList[]\n /**\n * The late photo passes that ran out of time and handed this back (AGL-3988).\n * The site step publishes on the last pass its bound gives them, whatever\n * the pictures hold then, so a burst that never clears never holds a site\n * back.\n */\n latePasses?: number\n}\n\n/** The most of each a job keeps: a site's pages, each one's pictures, and its lists' records. */\nconst PAGES_MAX = 12\nconst SLOTS_MAX = 16\nconst LISTS_MAX = 8\nconst RECORDS_MAX = 24\nconst KEYS_MAX = 3\n\n/** An entry with its refused picks bounded, and none where it has none. */\nfunction withPicks<T extends { refused?: AiStockRefusedPicks }>(entry: T): T {\n const copy = { ...entry }\n delete copy.refused\n const keys = entry.refused?.keys.slice(0, KEYS_MAX) ?? []\n return entry.refused && keys.length ? { ...copy, refused: { ...entry.refused, keys } } : copy\n}\n\n/** A page's starters as a job keeps them: bounded, and none without a picture. */\nfunction pageOf(page: AiSiteStarterPage): AiSiteStarterPage | null {\n const slots = page.slots.slice(0, SLOTS_MAX).map(withPicks)\n return page.screen && slots.length ? { screen: page.screen, slots } : null\n}\n\n/** Whether a list still holds a starter on any record. */\nfunction listHoldsStarters(list: AiSiteStarterList): boolean {\n return list.records.some((record) => aiSiteIsStarterSrc(record.value))\n}\n\n/**\n * The job's photos state once a unit reported its own (AGL-3988): a page's\n * or a list's entry replaces the one it had, by its draft or its dataset;\n * every other entry stays. `null` where neither holds anything.\n */\nexport function aiSiteMergePhotos(\n previous: AiSitePhotos | null | undefined,\n next: Partial<AiSitePhotos> | null | undefined,\n): AiSitePhotos | null {\n const pages = new Map((previous?.pages ?? []).map((page) => [page.screen, page]))\n for (const page of next?.pages ?? []) {\n const kept = pageOf(page)\n if (kept) pages.set(kept.screen, kept)\n else pages.delete(page.screen)\n }\n const lists = new Map((previous?.lists ?? []).map((list) => [list.dataset, list]))\n for (const list of next?.lists ?? []) {\n if (list.dataset && list.imageField && listHoldsStarters(list)) {\n lists.set(list.dataset, { ...list, records: list.records.slice(0, RECORDS_MAX).map(withPicks) })\n } else lists.delete(list.dataset)\n }\n const merged: AiSitePhotos = { pages: [...pages.values()].slice(0, PAGES_MAX), lists: [...lists.values()].slice(0, LISTS_MAX) }\n const latePasses = next?.latePasses ?? previous?.latePasses\n if (latePasses) merged.latePasses = latePasses\n return merged.pages.length || merged.lists.length ? merged : null\n}\n\n/**\n * Whether a site job owes its late photo pass: a page picture or a list\n * record it left on a starter. With `pageIds`, only a picture of one of\n * those pages counts: a page that was not built is never published.\n */\nexport function aiSitePhotosOwed(photos: AiSitePhotos | null | undefined, pageIds?: readonly string[]): boolean {\n const built = pageIds ? new Set(pageIds) : null\n return Boolean(\n photos?.pages.some((page) => page.slots.length && (!built || built.has(page.screen))) || photos?.lists.some(listHoldsStarters),\n )\n}\n\n/** When the newest refusal the state holds was made, in ms; `null` where none was. */\nexport function aiSitePhotosLastRefusalMs(photos: AiSitePhotos | null | undefined): number | null {\n const times = [\n ...(photos?.pages ?? []).flatMap((page) => page.slots.map((slot) => slot.refused?.at)),\n ...(photos?.lists ?? []).flatMap((list) => list.records.map((record) => record.refused?.at)),\n ]\n .map((at) => (at ? Date.parse(at) : NaN))\n .filter((ms) => Number.isFinite(ms))\n return times.length ? Math.max(...times) : null\n}\n"],"names":["AI_SITE_STARTER_PREFIX","aiSiteIsStarterSrc","src","startsWith","PAGES_MAX","SLOTS_MAX","LISTS_MAX","RECORDS_MAX","KEYS_MAX","withPicks","entry","copy","refused","keys","slice","length","pageOf","page","slots","map","screen","listHoldsStarters","list","records","some","record","value","aiSiteMergePhotos","previous","next","pages","Map","kept","set","delete","lists","dataset","imageField","merged","values","latePasses","aiSitePhotosOwed","photos","pageIds","built","Set","Boolean","has","aiSitePhotosLastRefusalMs","times","flatMap","slot","at","Date","parse","NaN","filter","ms","Number","isFinite","Math","max"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/model/ai-site-photos.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 type { StockPhotoSearchRequest } from '@aglyn/aglyn/plugin-manager/stock-photo-provider'\nimport type { AiLayoutPicturePhoto, AiLayoutPictureRole } from '../layout-language/ai-layout-pictures'\n\n/**\n * THE PICTURES A SITE START LEFT ON A STARTER PHOTO (AGL-3988).\n *\n * A guided start's pages and its datasets' records are each built in a pass\n * of their own, minutes apart. A picture the stock library could not fill in\n * its pass took a starter photo there: its picks' downloads refused by the\n * library's image hosts in a burst, or no photo of the job's own to take\n * yet. The v1.0.0-beta.271 Laurel Fork Photography start (2026-10-19 23:05Z)\n * filed all twelve \"Gallery collections\" covers and its home hero under an\n * office team and a desk: pixabay.com's Cloudflare answered 429 to 22\n * downloads while the covers were built, before the job had copied any\n * photo, and to 11 more on the home page, the first page built.\n *\n * Each such picture is written down here, with the picks the hosts refused,\n * on the job, by the machine, in the write that records its pass. The site\n * step's late photo pass (`jobs/ai-site-late-photos.ts`) reads it once every\n * page is built and before the site is published: it asks the refused picks\n * for again, a minute after the refusal, and gives every picture still on a\n * starter one of the photos the job copied. Pure.\n */\n\n/** Where a starter photo is served from: the platform's own files, on every site's origin. */\nexport const AI_SITE_STARTER_PREFIX = '/_static/starter/'\n\n/** Whether an address is a starter photo's. */\nexport function aiSiteIsStarterSrc(src: unknown): boolean {\n return typeof src === 'string' && src.startsWith(AI_SITE_STARTER_PREFIX)\n}\n\n/** The picks a slot kept in hand whose downloads the library's image hosts refused, to ask for again. */\nexport interface AiStockRefusedPicks {\n /** The search they came from, as it was sent: asked again, the provider's cache answers it. */\n request: StockPhotoSearchRequest\n /** The picks' source keys (`pixabay:5401602`), best first. */\n keys: string[]\n /** When the last of them was refused, ISO. */\n at: string\n}\n\n/** A picture of one of the start's pages that holds a starter photo. */\nexport interface AiSiteStarterSlot {\n /** The `image` node. */\n image: string\n /** What the picture was to show, in the slot's own words: a starter's alt text is the starter's. */\n words: string\n role: AiLayoutPictureRole\n /** The frame's shape, width over height. */\n aspect: number\n refused?: AiStockRefusedPicks\n}\n\n/** A page of the start with the pictures it left on a starter. */\nexport interface AiSiteStarterPage {\n /** The page's draft. */\n screen: string\n slots: AiSiteStarterSlot[]\n}\n\n/** A record of a pictured list, as its photo was written. */\nexport interface AiSiteListRecord {\n /** The record's name: its first field's value. */\n name: string\n /** What the list files it under, where it files its records (AGL-3856). */\n category?: string\n /** The value its photo field holds: a starter's path, or the library photo's CDN path. */\n value: string\n /** The library photo it shows, with its size and words; absent on a starter. */\n photo?: AiLayoutPicturePhoto\n refused?: AiStockRefusedPicks\n /** A record of a thing of its own (AGL-4092): its own photo or its starter, never another record's or the job's. */\n itsOwn?: true\n}\n\n/** A pictured list of the start, one of whose records holds a starter photo. */\nexport interface AiSiteStarterList {\n /** The dataset. */\n dataset: string\n /** Its photo field, by id. */\n imageField: string\n /** The field its records keep what their photo shows in, by id (AGL-3856). */\n altField?: string\n /** A list of the business's people: a record of it never takes a photo of anything but a person. */\n people?: boolean\n /** Every record, in order, so a record's neighbors are known. */\n records: AiSiteListRecord[]\n}\n\n/** What a site job holds on its pictures that took a starter, until its late photo pass. */\nexport interface AiSitePhotos {\n pages: AiSiteStarterPage[]\n lists: AiSiteStarterList[]\n /**\n * The late photo passes that ran out of time and handed this back (AGL-3988).\n * The site step publishes on the last pass its bound gives them, whatever\n * the pictures hold then, so a burst that never clears never holds a site\n * back.\n */\n latePasses?: number\n}\n\n/** The most of each a job keeps: a site's pages, each one's pictures, and its lists' records. */\nconst PAGES_MAX = 12\nconst SLOTS_MAX = 16\nconst LISTS_MAX = 8\nconst RECORDS_MAX = 24\nconst KEYS_MAX = 3\n\n/** An entry with its refused picks bounded, and none where it has none. */\nfunction withPicks<T extends { refused?: AiStockRefusedPicks }>(entry: T): T {\n const copy = { ...entry }\n delete copy.refused\n const keys = entry.refused?.keys.slice(0, KEYS_MAX) ?? []\n return entry.refused && keys.length ? { ...copy, refused: { ...entry.refused, keys } } : copy\n}\n\n/** A page's starters as a job keeps them: bounded, and none without a picture. */\nfunction pageOf(page: AiSiteStarterPage): AiSiteStarterPage | null {\n const slots = page.slots.slice(0, SLOTS_MAX).map(withPicks)\n return page.screen && slots.length ? { screen: page.screen, slots } : null\n}\n\n/** Whether a list still holds a starter on any record. */\nfunction listHoldsStarters(list: AiSiteStarterList): boolean {\n return list.records.some((record) => aiSiteIsStarterSrc(record.value))\n}\n\n/**\n * The job's photos state once a unit reported its own (AGL-3988): a page's\n * or a list's entry replaces the one it had, by its draft or its dataset;\n * every other entry stays. `null` where neither holds anything.\n */\nexport function aiSiteMergePhotos(\n previous: AiSitePhotos | null | undefined,\n next: Partial<AiSitePhotos> | null | undefined,\n): AiSitePhotos | null {\n const pages = new Map((previous?.pages ?? []).map((page) => [page.screen, page]))\n for (const page of next?.pages ?? []) {\n const kept = pageOf(page)\n if (kept) pages.set(kept.screen, kept)\n else pages.delete(page.screen)\n }\n const lists = new Map((previous?.lists ?? []).map((list) => [list.dataset, list]))\n for (const list of next?.lists ?? []) {\n if (list.dataset && list.imageField && listHoldsStarters(list)) {\n lists.set(list.dataset, { ...list, records: list.records.slice(0, RECORDS_MAX).map(withPicks) })\n } else lists.delete(list.dataset)\n }\n const merged: AiSitePhotos = { pages: [...pages.values()].slice(0, PAGES_MAX), lists: [...lists.values()].slice(0, LISTS_MAX) }\n const latePasses = next?.latePasses ?? previous?.latePasses\n if (latePasses) merged.latePasses = latePasses\n return merged.pages.length || merged.lists.length ? merged : null\n}\n\n/**\n * Whether a site job owes its late photo pass: a page picture or a list\n * record it left on a starter. With `pageIds`, only a picture of one of\n * those pages counts: a page that was not built is never published.\n */\nexport function aiSitePhotosOwed(photos: AiSitePhotos | null | undefined, pageIds?: readonly string[]): boolean {\n const built = pageIds ? new Set(pageIds) : null\n return Boolean(\n photos?.pages.some((page) => page.slots.length && (!built || built.has(page.screen))) || photos?.lists.some(listHoldsStarters),\n )\n}\n\n/** When the newest refusal the state holds was made, in ms; `null` where none was. */\nexport function aiSitePhotosLastRefusalMs(photos: AiSitePhotos | null | undefined): number | null {\n const times = [\n ...(photos?.pages ?? []).flatMap((page) => page.slots.map((slot) => slot.refused?.at)),\n ...(photos?.lists ?? []).flatMap((list) => list.records.map((record) => record.refused?.at)),\n ]\n .map((at) => (at ? Date.parse(at) : NaN))\n .filter((ms) => Number.isFinite(ms))\n return times.length ? Math.max(...times) : null\n}\n"],"names":["AI_SITE_STARTER_PREFIX","aiSiteIsStarterSrc","src","startsWith","PAGES_MAX","SLOTS_MAX","LISTS_MAX","RECORDS_MAX","KEYS_MAX","withPicks","entry","copy","refused","keys","slice","length","pageOf","page","slots","map","screen","listHoldsStarters","list","records","some","record","value","aiSiteMergePhotos","previous","next","pages","Map","kept","set","delete","lists","dataset","imageField","merged","values","latePasses","aiSitePhotosOwed","photos","pageIds","built","Set","Boolean","has","aiSitePhotosLastRefusalMs","times","flatMap","slot","at","Date","parse","NaN","filter","ms","Number","isFinite","Math","max"],"mappings":"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"}
@@ -23,8 +23,9 @@ import { type AiSiteStartAnswers, type AiSiteStartExtraKey } from './ai-site-sta
23
23
  * Splitting the questions changes nothing they become. Every step writes the
24
24
  * same {@link AiSiteStartAnswers} the single form did, and only the review's
25
25
  * "Plan my site" turns them into the job's brief and inputs, through the same
26
- * `aiSiteStartBrief` / `aiSiteStartInputs`. Which answers are required is
27
- * unchanged too: only what kind of site it is.
26
+ * `aiSiteStartBrief` / `aiSiteStartInputs`. Two answers are required: what
27
+ * kind of site it is, and a style card clicked (AGL-4049; "Pick for me" is
28
+ * one), since nothing is chosen for a person.
28
29
  *
29
30
  * Pure: ids, titles, which answers each step holds, and each step's reasons
30
31
  * not to go forward, worded as `aiSiteStartRefusal` words them.
@@ -35,7 +36,7 @@ export type AiSiteStartStep = (typeof AI_SITE_START_STEPS)[number];
35
36
  /** Each step's short name, as the progress indicator shows it. */
36
37
  export declare const AI_SITE_START_STEP_LABELS: Readonly<Record<AiSiteStartStep, string>>;
37
38
  /** An answer a step asks for, by its key on {@link AiSiteStartAnswers}. */
38
- export type AiSiteStartField = 'siteType' | 'audience' | 'kind' | 'inspiration' | 'pages' | 'submissions' | 'welcomeEmail' | AiSiteStartExtraKey;
39
+ export type AiSiteStartField = 'siteType' | 'audience' | 'style' | 'kind' | 'inspiration' | 'pages' | 'submissions' | 'welcomeEmail' | AiSiteStartExtraKey;
39
40
  /**
40
41
  * The extras each step's "More details" offers (AGL-3979), in the order it
41
42
  * draws them. The phone number and the email are on the Details step itself,
@@ -15,7 +15,7 @@ import { _ as _extends } from "@swc/helpers/_/_extends";
15
15
  * See the License for the specific language governing permissions and
16
16
  * limitations under the License.
17
17
  */ import { AI_SITE_INPUT_MAX_CHARS, AI_SITE_SUBMISSIONS, aiSitePagesBand } from "./ai-site-job.js";
18
- import { aiSiteStartExtraProblem, aiSiteStartInspirationRefusal } from "./ai-site-start.js";
18
+ import { AI_SITE_START_STYLE_REQUIRED, aiSiteStartExtraProblem, aiSiteStartInspirationRefusal } from "./ai-site-start.js";
19
19
  /**
20
20
  * The guided start's steps (AGL-3898): the same questions `ai-site-start.ts`
21
21
  * asks, one decision to a step, so a person answers one thing at a time and
@@ -24,8 +24,9 @@ import { aiSiteStartExtraProblem, aiSiteStartInspirationRefusal } from "./ai-sit
24
24
  * Splitting the questions changes nothing they become. Every step writes the
25
25
  * same {@link AiSiteStartAnswers} the single form did, and only the review's
26
26
  * "Plan my site" turns them into the job's brief and inputs, through the same
27
- * `aiSiteStartBrief` / `aiSiteStartInputs`. Which answers are required is
28
- * unchanged too: only what kind of site it is.
27
+ * `aiSiteStartBrief` / `aiSiteStartInputs`. Two answers are required: what
28
+ * kind of site it is, and a style card clicked (AGL-4049; "Pick for me" is
29
+ * one), since nothing is chosen for a person.
29
30
  *
30
31
  * Pure: ids, titles, which answers each step holds, and each step's reasons
31
32
  * not to go forward, worded as `aiSiteStartRefusal` words them.
@@ -86,6 +87,7 @@ import { aiSiteStartExtraProblem, aiSiteStartInspirationRefusal } from "./ai-sit
86
87
  ],
87
88
  // The sites they like sit under the style cards (AGL-3975), when asked.
88
89
  style: [
90
+ 'style',
89
91
  'kind',
90
92
  'inspiration',
91
93
  ...AI_SITE_START_MORE_FIELDS.style
@@ -131,6 +133,11 @@ import { aiSiteStartExtraProblem, aiSiteStartInspirationRefusal } from "./ai-sit
131
133
  code: 'too_long'
132
134
  };
133
135
  }
136
+ // Nothing is chosen for a person (AGL-4049): a card, "Pick for me" included.
137
+ if (answers.style === null) errors.style = {
138
+ message: AI_SITE_START_STYLE_REQUIRED,
139
+ code: 'required'
140
+ };
134
141
  const band = aiSitePagesBand(options.freeTaste);
135
142
  if (!Number.isInteger(answers.pages) || answers.pages < band.min || answers.pages > band.max) {
136
143
  errors.pages = {
@@ -161,6 +168,7 @@ import { aiSiteStartExtraProblem, aiSiteStartInspirationRefusal } from "./ai-sit
161
168
  const CORE_FIELDS = new Set([
162
169
  'siteType',
163
170
  'audience',
171
+ 'style',
164
172
  'kind',
165
173
  'inspiration',
166
174
  'pages',