@aglyn/plugins-ai 1.0.0-beta.234 → 1.0.0-beta.236

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 (137) hide show
  1. package/package.json +17 -17
  2. package/src/lib/activity/ai-activity-actions.d.ts +25 -0
  3. package/src/lib/activity/ai-activity-actions.js +85 -4
  4. package/src/lib/activity/ai-activity-actions.js.map +1 -1
  5. package/src/lib/components/ai-brief-dialog.component.js +46 -2
  6. package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
  7. package/src/lib/components/ai-campaign-create.component.js +1 -1
  8. package/src/lib/components/ai-campaign-create.component.js.map +1 -1
  9. package/src/lib/components/ai-credits-card.component.js +3 -3
  10. package/src/lib/components/ai-credits-card.component.js.map +1 -1
  11. package/src/lib/components/ai-crm-email-draft.component.js +1 -1
  12. package/src/lib/components/ai-crm-email-draft.component.js.map +1 -1
  13. package/src/lib/components/ai-crm-import-mapping.component.js +1 -1
  14. package/src/lib/components/ai-crm-import-mapping.component.js.map +1 -1
  15. package/src/lib/components/ai-crm-record-card.component.js +1 -1
  16. package/src/lib/components/ai-crm-record-card.component.js.map +1 -1
  17. package/src/lib/components/ai-describe-automation.component.js +4 -2
  18. package/src/lib/components/ai-describe-automation.component.js.map +1 -1
  19. package/src/lib/components/ai-describe-org-automation.component.js +1 -1
  20. package/src/lib/components/ai-describe-org-automation.component.js.map +1 -1
  21. package/src/lib/components/ai-experiment-cards.component.js +2 -2
  22. package/src/lib/components/ai-experiment-cards.component.js.map +1 -1
  23. package/src/lib/components/ai-explain-automation.component.js +1 -1
  24. package/src/lib/components/ai-explain-automation.component.js.map +1 -1
  25. package/src/lib/components/ai-insight-card.component.js +3 -1
  26. package/src/lib/components/ai-insight-card.component.js.map +1 -1
  27. package/src/lib/components/ai-jobs-list-page.component.d.ts +6 -1
  28. package/src/lib/components/ai-jobs-list-page.component.js +15 -2
  29. package/src/lib/components/ai-jobs-list-page.component.js.map +1 -1
  30. package/src/lib/components/ai-logic.component.js +5 -3
  31. package/src/lib/components/ai-logic.component.js.map +1 -1
  32. package/src/lib/components/ai-media-create.component.js +88 -16
  33. package/src/lib/components/ai-media-create.component.js.map +1 -1
  34. package/src/lib/components/ai-model-selector.component.js +8 -0
  35. package/src/lib/components/ai-model-selector.component.js.map +1 -1
  36. package/src/lib/components/ai-overlay-cards.component.js +2 -2
  37. package/src/lib/components/ai-overlay-cards.component.js.map +1 -1
  38. package/src/lib/components/ai-product-copy-card.component.js +2 -1
  39. package/src/lib/components/ai-product-copy-card.component.js.map +1 -1
  40. package/src/lib/components/ai-products-hub-card.component.js +2 -1
  41. package/src/lib/components/ai-products-hub-card.component.js.map +1 -1
  42. package/src/lib/components/ai-revise-automation.component.js +1 -1
  43. package/src/lib/components/ai-revise-automation.component.js.map +1 -1
  44. package/src/lib/components/ai-seo-fields-card.component.js +7 -3
  45. package/src/lib/components/ai-seo-fields-card.component.js.map +1 -1
  46. package/src/lib/components/ai-site-batch-card.component.js +7 -4
  47. package/src/lib/components/ai-site-batch-card.component.js.map +1 -1
  48. package/src/lib/components/ai-site-build-page.component.js +7 -3
  49. package/src/lib/components/ai-site-build-page.component.js.map +1 -1
  50. package/src/lib/components/ai-site-seo-start-card.component.js +7 -4
  51. package/src/lib/components/ai-site-seo-start-card.component.js.map +1 -1
  52. package/src/lib/components/ai-site-start-card.component.js +62 -29
  53. package/src/lib/components/ai-site-start-card.component.js.map +1 -1
  54. package/src/lib/components/ai-theme-proposal-card.component.js +1 -0
  55. package/src/lib/components/ai-theme-proposal-card.component.js.map +1 -1
  56. package/src/lib/components/ai-upsell-dialog.component.js +17 -3
  57. package/src/lib/components/ai-upsell-dialog.component.js.map +1 -1
  58. package/src/lib/components/ai-usage-strip.component.js +13 -2
  59. package/src/lib/components/ai-usage-strip.component.js.map +1 -1
  60. package/src/lib/components/assist-build-card.component.js +20 -3
  61. package/src/lib/components/assist-build-card.component.js.map +1 -1
  62. package/src/lib/components/assist-jobs-drawer.component.js +7 -1
  63. package/src/lib/components/assist-jobs-drawer.component.js.map +1 -1
  64. package/src/lib/components/billing-ai-allotments.component.js +2 -2
  65. package/src/lib/components/billing-ai-allotments.component.js.map +1 -1
  66. package/src/lib/components/billing-ai-top-users.component.js +1 -0
  67. package/src/lib/components/billing-ai-top-users.component.js.map +1 -1
  68. package/src/lib/components/billing-assist-overage-card.component.js +2 -2
  69. package/src/lib/components/billing-assist-overage-card.component.js.map +1 -1
  70. package/src/lib/components/host-ai-allotments.component.js +2 -2
  71. package/src/lib/components/host-ai-allotments.component.js.map +1 -1
  72. package/src/lib/components/member-ai-allotment-card.component.js +2 -2
  73. package/src/lib/components/member-ai-allotment-card.component.js.map +1 -1
  74. package/src/lib/components/staff-org-ai-card.component.js +1 -0
  75. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  76. package/src/lib/components/staff-org-ai-conversations.component.d.ts +9 -3
  77. package/src/lib/components/staff-org-ai-conversations.component.js +174 -83
  78. package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -1
  79. package/src/lib/components/staff-user-ai-usage-card.component.js +2 -1
  80. package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -1
  81. package/src/lib/jobs/ai-job-layout-language.js +4 -1
  82. package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
  83. package/src/lib/jobs/ai-job-layout-site-pages.d.ts +12 -0
  84. package/src/lib/jobs/ai-job-layout-site-pages.js +20 -0
  85. package/src/lib/jobs/ai-job-layout-site-pages.js.map +1 -1
  86. package/src/lib/jobs/ai-job-page-language.d.ts +10 -1
  87. package/src/lib/jobs/ai-job-page-language.js +41 -8
  88. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  89. package/src/lib/jobs/ai-job-page-step.js +14 -3
  90. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  91. package/src/lib/jobs/ai-job-site-content.d.ts +75 -7
  92. package/src/lib/jobs/ai-job-site-content.js +205 -32
  93. package/src/lib/jobs/ai-job-site-content.js.map +1 -1
  94. package/src/lib/jobs/ai-job-site-step.d.ts +8 -0
  95. package/src/lib/jobs/ai-job-site-step.js +61 -12
  96. package/src/lib/jobs/ai-job-site-step.js.map +1 -1
  97. package/src/lib/layout-language/ai-layout-compiler.d.ts +8 -0
  98. package/src/lib/layout-language/ai-layout-compiler.js +308 -10
  99. package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
  100. package/src/lib/layout-language/ai-layout-design.d.ts +7 -0
  101. package/src/lib/layout-language/ai-layout-design.js +23 -11
  102. package/src/lib/layout-language/ai-layout-design.js.map +1 -1
  103. package/src/lib/layout-language/ai-layout-frame.d.ts +6 -0
  104. package/src/lib/layout-language/ai-layout-frame.js +12 -3
  105. package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
  106. package/src/lib/layout-language/ai-layout-gaps.js +18 -2
  107. package/src/lib/layout-language/ai-layout-gaps.js.map +1 -1
  108. package/src/lib/layout-language/ai-layout-links.d.ts +26 -1
  109. package/src/lib/layout-language/ai-layout-links.js +24 -4
  110. package/src/lib/layout-language/ai-layout-links.js.map +1 -1
  111. package/src/lib/layout-language/ai-layout-listings.d.ts +125 -0
  112. package/src/lib/layout-language/ai-layout-listings.js +187 -0
  113. package/src/lib/layout-language/ai-layout-listings.js.map +1 -0
  114. package/src/lib/model/ai-site-build-progress.js +27 -12
  115. package/src/lib/model/ai-site-build-progress.js.map +1 -1
  116. package/src/lib/model/ai-site-job.d.ts +33 -8
  117. package/src/lib/model/ai-site-job.js +38 -18
  118. package/src/lib/model/ai-site-job.js.map +1 -1
  119. package/src/lib/model/ai-site-kinds.d.ts +30 -8
  120. package/src/lib/model/ai-site-kinds.js +731 -117
  121. package/src/lib/model/ai-site-kinds.js.map +1 -1
  122. package/src/lib/model/ai-site-start-seo.d.ts +30 -0
  123. package/src/lib/model/ai-site-start-seo.js +132 -11
  124. package/src/lib/model/ai-site-start-seo.js.map +1 -1
  125. package/src/lib/model/ai-site-start.d.ts +2 -2
  126. package/src/lib/model/ai-site-start.js +3 -3
  127. package/src/lib/model/ai-site-start.js.map +1 -1
  128. package/src/lib/plugin.js +15 -3
  129. package/src/lib/plugin.js.map +1 -1
  130. package/src/lib/runtime/ai-palette.generated.js +13 -3
  131. package/src/lib/runtime/ai-palette.generated.js.map +1 -1
  132. package/src/lib/server/ai-admin-conversations.d.ts +9 -0
  133. package/src/lib/server/ai-admin-conversations.js +151 -9
  134. package/src/lib/server/ai-admin-conversations.js.map +1 -1
  135. package/src/lib/usage/staff-org-ai-conversations.d.ts +23 -0
  136. package/src/lib/usage/staff-org-ai-conversations.js +45 -0
  137. package/src/lib/usage/staff-org-ai-conversations.js.map +1 -1
@@ -570,16 +570,41 @@ const ALL_HUES = [
570
570
  blurb: 'Say what you do, why choose you, and how to reach you',
571
571
  icon: 'briefcase',
572
572
  keywords: [
573
- 'cleaning',
573
+ 'cleaning service',
574
+ 'cleaning company',
575
+ 'house cleaning',
574
576
  'cleaner',
575
577
  'janitorial',
576
- 'pet',
578
+ 'maid',
577
579
  'groomer',
578
580
  'grooming',
579
- 'dog',
581
+ 'dog walker',
582
+ 'dog walking',
583
+ 'pet sitter',
584
+ 'pet sitting',
585
+ 'dog trainer',
586
+ 'dog training',
580
587
  'staffing',
588
+ 'print shop',
581
589
  'printing',
582
- 'courier'
590
+ 'courier',
591
+ 'laundromat',
592
+ 'dry cleaner',
593
+ 'tailor',
594
+ 'alterations',
595
+ 'car wash',
596
+ 'detailing',
597
+ 'small business'
598
+ ],
599
+ hints: [
600
+ 'business',
601
+ 'company',
602
+ 'service',
603
+ 'local',
604
+ 'pet',
605
+ 'dog',
606
+ 'cleaning',
607
+ 'customers'
583
608
  ],
584
609
  starter: 'business',
585
610
  look: {
@@ -628,30 +653,67 @@ const ALL_HUES = [
628
653
  'plumber',
629
654
  'plumbing',
630
655
  'electrician',
656
+ 'electrical',
631
657
  'hvac',
658
+ 'heating and cooling',
632
659
  'towing',
633
- 'tow',
660
+ 'tow truck',
661
+ 'roadside assistance',
634
662
  'landscaping',
635
663
  'landscaper',
664
+ 'lawn care',
636
665
  'contractor',
666
+ 'general contractor',
637
667
  'construction',
638
668
  'handyman',
639
- 'painter',
640
- 'painting',
641
- 'mover',
642
- 'moving',
643
- 'pest',
669
+ 'house painter',
670
+ 'house painting',
671
+ 'movers',
672
+ 'moving company',
673
+ 'exterminator',
674
+ 'pest control',
644
675
  'remodeling',
645
- 'repair',
676
+ 'renovation',
646
677
  'mechanic',
647
- 'auto',
648
- 'trades',
649
- 'trade',
650
- 'garage',
678
+ 'auto repair',
679
+ 'auto body',
651
680
  'locksmith',
652
681
  'flooring',
653
682
  'fencing',
654
- 'pool'
683
+ 'pool cleaning',
684
+ 'pool service',
685
+ 'welder',
686
+ 'welding',
687
+ 'carpenter',
688
+ 'carpentry',
689
+ 'masonry',
690
+ 'concrete',
691
+ 'drywall',
692
+ 'gutter',
693
+ 'siding',
694
+ 'garage door',
695
+ 'tree service',
696
+ 'arborist',
697
+ 'junk removal',
698
+ 'septic',
699
+ 'pressure washing',
700
+ 'power washing',
701
+ 'appliance repair'
702
+ ],
703
+ hints: [
704
+ 'repair',
705
+ 'auto',
706
+ 'garage',
707
+ 'painting',
708
+ 'painter',
709
+ 'pool',
710
+ 'moving',
711
+ 'trade',
712
+ 'trades',
713
+ 'homeowner',
714
+ 'pest',
715
+ 'installation',
716
+ 'emergency'
655
717
  ],
656
718
  starter: 'business',
657
719
  look: {
@@ -717,22 +779,36 @@ const ALL_HUES = [
717
779
  icon: 'scale',
718
780
  keywords: [
719
781
  'law',
782
+ 'law firm',
720
783
  'lawyer',
721
784
  'attorney',
722
785
  'legal',
723
- 'firm',
786
+ 'paralegal',
724
787
  'accountant',
725
788
  'accounting',
726
789
  'cpa',
727
790
  'tax',
728
791
  'bookkeeping',
792
+ 'bookkeeper',
729
793
  'financial',
794
+ 'financial advisor',
795
+ 'wealth management',
730
796
  'advisor',
731
797
  'adviser',
798
+ 'advisory',
732
799
  'consulting',
800
+ 'consultant',
733
801
  'insurance',
734
802
  'notary',
735
- 'mediator'
803
+ 'mediator',
804
+ 'mediation',
805
+ 'estate planning'
806
+ ],
807
+ hints: [
808
+ 'firm',
809
+ 'practice',
810
+ 'clients',
811
+ 'compliance'
736
812
  ],
737
813
  starter: 'business',
738
814
  look: {
@@ -796,26 +872,52 @@ const ALL_HUES = [
796
872
  'counseling',
797
873
  'counselling',
798
874
  'psychologist',
875
+ 'psychiatrist',
876
+ 'psychotherapy',
799
877
  'dentist',
800
878
  'dental',
879
+ 'orthodontist',
801
880
  'clinic',
802
881
  'doctor',
882
+ 'physician',
883
+ 'pediatrician',
884
+ 'optometrist',
803
885
  'chiropractor',
886
+ 'chiropractic',
804
887
  'massage',
805
888
  'wellness',
806
- 'health',
807
889
  'nutrition',
808
890
  'nutritionist',
891
+ 'dietitian',
809
892
  'acupuncture',
810
893
  'physio',
811
894
  'physiotherapy',
895
+ 'physical therapy',
896
+ 'mental health',
897
+ 'medical',
898
+ 'vet',
899
+ 'veterinary',
900
+ 'veterinarian',
901
+ 'animal hospital',
902
+ 'midwife',
903
+ 'doula',
904
+ 'naturopath',
905
+ 'life coach',
906
+ 'health coach',
907
+ 'wellness coach',
908
+ 'home care',
909
+ 'senior care'
910
+ ],
911
+ hints: [
912
+ 'health',
913
+ 'healing',
812
914
  'coach',
813
915
  'coaching',
814
- 'healing',
916
+ 'patient',
917
+ 'care',
918
+ 'practice',
815
919
  'mental',
816
- 'medical',
817
- 'vet',
818
- 'veterinary'
920
+ 'anxiety'
819
921
  ],
820
922
  starter: 'business',
821
923
  look: {
@@ -875,23 +977,62 @@ const ALL_HUES = [
875
977
  keywords: [
876
978
  'restaurant',
877
979
  'cafe',
878
- 'café',
879
980
  'coffee',
981
+ 'coffee shop',
982
+ 'coffee house',
880
983
  'bakery',
881
- 'bar',
882
- 'pub',
984
+ 'baker',
985
+ 'pastry',
986
+ 'cake',
987
+ 'cupcake',
883
988
  'bistro',
884
989
  'diner',
885
990
  'pizzeria',
886
991
  'pizza',
887
- 'food',
888
992
  'catering',
993
+ 'caterer',
889
994
  'brewery',
890
995
  'winery',
996
+ 'wine bar',
997
+ 'distillery',
998
+ 'taproom',
999
+ 'food truck',
1000
+ 'deli',
1001
+ 'chef',
1002
+ 'personal chef',
1003
+ 'tavern',
1004
+ 'pub',
1005
+ 'eatery',
1006
+ 'tea room',
1007
+ 'tea house',
1008
+ 'ice cream',
1009
+ 'creamery',
1010
+ 'donut',
1011
+ 'bagel',
1012
+ 'taqueria',
1013
+ 'sushi',
1014
+ 'bbq',
1015
+ 'barbecue',
1016
+ 'ramen',
1017
+ 'cocktail',
1018
+ 'juice bar',
1019
+ 'brunch'
1020
+ ],
1021
+ hints: [
1022
+ 'food',
891
1023
  'kitchen',
892
- 'truck',
1024
+ 'bar',
893
1025
  'tea',
894
- 'deli'
1026
+ 'truck',
1027
+ 'breakfast',
1028
+ 'lunch',
1029
+ 'dinner',
1030
+ 'dining',
1031
+ 'menu',
1032
+ 'drinks',
1033
+ 'meal',
1034
+ 'wine',
1035
+ 'beer'
895
1036
  ],
896
1037
  starter: 'business',
897
1038
  look: {
@@ -943,21 +1084,48 @@ const ALL_HUES = [
943
1084
  blurb: 'Product-first pages for things you sell',
944
1085
  icon: 'bag',
945
1086
  keywords: [
946
- 'store',
947
- 'shop',
1087
+ 'online store',
1088
+ 'online shop',
1089
+ 'web shop',
948
1090
  'boutique',
949
1091
  'ecommerce',
950
1092
  'e-commerce',
951
- 'products',
952
- 'sell',
953
- 'selling',
954
1093
  'merch',
1094
+ 'merchandise',
955
1095
  'jewelry',
1096
+ 'jewellery',
956
1097
  'clothing',
957
1098
  'apparel',
958
- 'candles',
1099
+ 'candle',
959
1100
  'soap',
960
- 'brand'
1101
+ 'etsy',
1102
+ 'gift shop',
1103
+ 'bookstore',
1104
+ 'bookshop',
1105
+ 'florist',
1106
+ 'flower shop',
1107
+ 'plant shop',
1108
+ 'retail',
1109
+ 'wholesale',
1110
+ 'subscription box',
1111
+ 'thrift',
1112
+ 'sneakers'
1113
+ ],
1114
+ hints: [
1115
+ 'store',
1116
+ 'shop',
1117
+ 'market',
1118
+ 'product',
1119
+ 'sell',
1120
+ 'selling',
1121
+ 'buy',
1122
+ 'order',
1123
+ 'brand',
1124
+ 'handmade',
1125
+ 'goods',
1126
+ 'gifts',
1127
+ 'collection',
1128
+ 'shipping'
961
1129
  ],
962
1130
  starter: 'physical-shop',
963
1131
  look: {
@@ -999,20 +1167,39 @@ const ALL_HUES = [
999
1167
  keywords: [
1000
1168
  'portfolio',
1001
1169
  'illustrator',
1170
+ 'illustration',
1002
1171
  'artist',
1003
- 'art',
1172
+ 'visual artist',
1004
1173
  'architect',
1005
1174
  'architecture',
1175
+ 'software engineer',
1006
1176
  'developer',
1007
- 'engineer',
1008
- 'writer',
1009
1177
  'copywriter',
1010
1178
  'animator',
1011
1179
  'freelance',
1012
1180
  'freelancer',
1013
- 'maker',
1014
1181
  'ceramics',
1015
- 'sculptor'
1182
+ 'ceramicist',
1183
+ 'potter',
1184
+ 'pottery',
1185
+ 'sculptor',
1186
+ 'sculpture',
1187
+ 'woodworker',
1188
+ 'woodworking',
1189
+ 'printmaker',
1190
+ 'textile artist'
1191
+ ],
1192
+ hints: [
1193
+ 'art',
1194
+ 'maker',
1195
+ 'work',
1196
+ 'gallery',
1197
+ 'painter',
1198
+ 'paintings',
1199
+ 'commissions',
1200
+ 'writer',
1201
+ 'engineer',
1202
+ 'projects'
1016
1203
  ],
1017
1204
  starter: 'portfolio',
1018
1205
  look: {
@@ -1050,18 +1237,43 @@ const ALL_HUES = [
1050
1237
  blurb: 'Bold type and case studies for creative teams',
1051
1238
  icon: 'sparkle',
1052
1239
  keywords: [
1053
- 'design',
1054
- 'designer',
1055
- 'agency',
1056
- 'creative',
1240
+ 'design studio',
1241
+ 'creative studio',
1242
+ 'creative agency',
1243
+ 'design agency',
1244
+ 'marketing agency',
1245
+ 'digital agency',
1246
+ 'ad agency',
1247
+ 'branding agency',
1057
1248
  'branding',
1249
+ 'brand identity',
1058
1250
  'marketing',
1251
+ 'digital marketing',
1059
1252
  'advertising',
1060
- 'web',
1253
+ 'web design',
1254
+ 'web designer',
1255
+ 'web development',
1256
+ 'graphic design',
1257
+ 'graphic designer',
1258
+ 'motion design',
1259
+ 'video production',
1260
+ 'production company',
1261
+ 'animation',
1262
+ 'seo'
1263
+ ],
1264
+ hints: [
1265
+ 'agency',
1266
+ 'design',
1267
+ 'designer',
1268
+ 'creative',
1269
+ 'studio',
1061
1270
  'digital',
1062
- 'production',
1271
+ 'web',
1063
1272
  'video',
1064
- 'animation'
1273
+ 'production',
1274
+ 'brand',
1275
+ 'campaign',
1276
+ 'case studies'
1065
1277
  ],
1066
1278
  starter: 'portfolio',
1067
1279
  look: {
@@ -1101,11 +1313,22 @@ const ALL_HUES = [
1101
1313
  keywords: [
1102
1314
  'photographer',
1103
1315
  'photography',
1104
- 'photo',
1105
- 'photos',
1106
1316
  'videographer',
1317
+ 'videography',
1107
1318
  'wedding photographer',
1108
- 'portraits'
1319
+ 'wedding photography',
1320
+ 'portrait',
1321
+ 'headshot',
1322
+ 'photo studio',
1323
+ 'photo booth'
1324
+ ],
1325
+ hints: [
1326
+ 'photo',
1327
+ 'gallery',
1328
+ 'shoot',
1329
+ 'sessions',
1330
+ 'prints',
1331
+ 'camera'
1109
1332
  ],
1110
1333
  starter: 'portfolio',
1111
1334
  look: {
@@ -1144,15 +1367,37 @@ const ALL_HUES = [
1144
1367
  keywords: [
1145
1368
  'blog',
1146
1369
  'blogger',
1147
- 'writing',
1370
+ 'food blog',
1371
+ 'travel blog',
1148
1372
  'journal',
1149
1373
  'magazine',
1150
1374
  'newsletter',
1151
1375
  'podcast',
1152
- 'stories',
1376
+ 'podcaster',
1153
1377
  'essays',
1154
1378
  'author',
1155
- 'publication'
1379
+ 'novelist',
1380
+ 'poet',
1381
+ 'poetry',
1382
+ 'publication',
1383
+ 'zine',
1384
+ 'columnist',
1385
+ 'substack'
1386
+ ],
1387
+ hints: [
1388
+ 'writing',
1389
+ 'stories',
1390
+ 'reading',
1391
+ 'readers',
1392
+ 'articles',
1393
+ 'posts',
1394
+ 'recipes',
1395
+ 'reviews',
1396
+ 'guides',
1397
+ 'tips',
1398
+ 'writer',
1399
+ 'episodes',
1400
+ 'listeners'
1156
1401
  ],
1157
1402
  starter: 'business',
1158
1403
  look: {
@@ -1190,20 +1435,40 @@ const ALL_HUES = [
1190
1435
  blurb: 'Dates, places and the details guests need',
1191
1436
  icon: 'calendar',
1192
1437
  keywords: [
1193
- 'event',
1194
- 'events',
1195
1438
  'wedding',
1196
1439
  'conference',
1197
1440
  'festival',
1198
- 'party',
1199
1441
  'gala',
1200
- 'meetup',
1201
1442
  'summit',
1202
- 'concert',
1443
+ 'event venue',
1444
+ 'wedding venue',
1445
+ 'venue',
1446
+ 'event planner',
1447
+ 'wedding planner',
1448
+ 'event planning',
1449
+ 'reunion',
1450
+ 'trade show',
1451
+ 'expo',
1452
+ 'hackathon',
1453
+ 'convention',
1454
+ 'birthday party',
1455
+ 'banquet',
1456
+ 'party rentals'
1457
+ ],
1458
+ hints: [
1459
+ 'event',
1460
+ 'party',
1461
+ 'meetup',
1203
1462
  'retreat',
1204
1463
  'workshop',
1205
- 'venue',
1206
- 'planner'
1464
+ 'planner',
1465
+ 'rsvp',
1466
+ 'tickets',
1467
+ 'celebration',
1468
+ 'guests',
1469
+ 'schedule',
1470
+ 'concert',
1471
+ 'fundraiser'
1207
1472
  ],
1208
1473
  starter: 'landing',
1209
1474
  look: {
@@ -1266,21 +1531,67 @@ const ALL_HUES = [
1266
1531
  keywords: [
1267
1532
  'gym',
1268
1533
  'fitness',
1269
- 'trainer',
1270
- 'training',
1271
1534
  'personal trainer',
1535
+ 'personal training',
1536
+ 'trainer',
1272
1537
  'crossfit',
1273
1538
  'boxing',
1539
+ 'kickboxing',
1540
+ 'martial arts',
1274
1541
  'martial',
1275
1542
  'karate',
1543
+ 'judo',
1544
+ 'jiu jitsu',
1545
+ 'taekwondo',
1546
+ 'mma',
1276
1547
  'pilates',
1548
+ 'bootcamp',
1549
+ 'boot camp',
1277
1550
  'sports',
1551
+ 'sport',
1278
1552
  'running',
1553
+ 'runner',
1554
+ 'marathon',
1555
+ 'triathlon',
1556
+ 'cycling',
1279
1557
  'climbing',
1558
+ 'bouldering',
1280
1559
  'dance',
1281
1560
  'swim',
1561
+ 'swimming',
1562
+ 'soccer',
1563
+ 'football',
1564
+ 'basketball',
1565
+ 'baseball',
1566
+ 'softball',
1567
+ 'volleyball',
1568
+ 'tennis',
1569
+ 'pickleball',
1570
+ 'golf',
1571
+ 'hockey',
1572
+ 'rugby',
1573
+ 'lacrosse',
1574
+ 'wrestling',
1575
+ 'gymnastics',
1576
+ 'athletics',
1577
+ 'athlete',
1578
+ 'strength training',
1579
+ 'weightlifting',
1580
+ 'powerlifting',
1581
+ 'health club',
1582
+ 'league'
1583
+ ],
1584
+ hints: [
1585
+ 'training',
1282
1586
  'team',
1283
- 'club'
1587
+ 'workout',
1588
+ 'coach',
1589
+ 'coaching',
1590
+ 'studio',
1591
+ 'members',
1592
+ 'race',
1593
+ 'game',
1594
+ 'tournament'
1284
1595
  ],
1285
1596
  starter: 'business',
1286
1597
  look: {
@@ -1341,9 +1652,18 @@ const ALL_HUES = [
1341
1652
  'mindfulness',
1342
1653
  'breathwork',
1343
1654
  'reiki',
1344
- 'spa',
1655
+ 'sound bath',
1656
+ 'sound healing',
1657
+ 'tai chi',
1658
+ 'qigong'
1659
+ ],
1660
+ hints: [
1345
1661
  'retreat',
1346
- 'sound'
1662
+ 'spa',
1663
+ 'calm',
1664
+ 'studio',
1665
+ 'healing',
1666
+ 'stillness'
1347
1667
  ],
1348
1668
  starter: 'business',
1349
1669
  look: {
@@ -1401,20 +1721,37 @@ const ALL_HUES = [
1401
1721
  icon: 'scissors',
1402
1722
  keywords: [
1403
1723
  'salon',
1724
+ 'hair salon',
1404
1725
  'hair',
1405
1726
  'hairdresser',
1727
+ 'hairstylist',
1406
1728
  'barber',
1407
1729
  'barbershop',
1408
1730
  'nails',
1409
- 'nail',
1731
+ 'nail salon',
1410
1732
  'beauty',
1411
1733
  'makeup',
1412
1734
  'lashes',
1413
1735
  'brows',
1414
1736
  'esthetician',
1737
+ 'aesthetician',
1415
1738
  'skincare',
1739
+ 'skin care',
1740
+ 'facial',
1741
+ 'waxing',
1416
1742
  'tattoo',
1417
- 'stylist'
1743
+ 'piercing',
1744
+ 'stylist',
1745
+ 'spa',
1746
+ 'day spa',
1747
+ 'med spa',
1748
+ 'blowout'
1749
+ ],
1750
+ hints: [
1751
+ 'studio',
1752
+ 'glam',
1753
+ 'appointments',
1754
+ 'cosmetics'
1418
1755
  ],
1419
1756
  starter: 'business',
1420
1757
  look: {
@@ -1475,17 +1812,30 @@ const ALL_HUES = [
1475
1812
  'real estate',
1476
1813
  'realtor',
1477
1814
  'realty',
1815
+ 'brokerage',
1478
1816
  'broker',
1479
1817
  'property',
1480
- 'properties',
1481
- 'homes',
1818
+ 'property management',
1482
1819
  'rentals',
1483
- 'rental',
1484
1820
  'apartment',
1485
- 'apartments',
1486
1821
  'mortgage',
1487
1822
  'airbnb',
1488
- 'vacation'
1823
+ 'vacation rental',
1824
+ 'short term rental',
1825
+ 'listings',
1826
+ 'condo',
1827
+ 'home builder',
1828
+ 'homebuilder'
1829
+ ],
1830
+ hints: [
1831
+ 'homes',
1832
+ 'house',
1833
+ 'buyers',
1834
+ 'sellers',
1835
+ 'vacation',
1836
+ 'cabin',
1837
+ 'neighborhoods',
1838
+ 'investors'
1489
1839
  ],
1490
1840
  starter: 'business',
1491
1841
  look: {
@@ -1542,20 +1892,41 @@ const ALL_HUES = [
1542
1892
  icon: 'school',
1543
1893
  keywords: [
1544
1894
  'course',
1545
- 'courses',
1895
+ 'online course',
1546
1896
  'school',
1547
1897
  'tutoring',
1548
1898
  'tutor',
1549
1899
  'teacher',
1900
+ 'teaching',
1550
1901
  'lessons',
1551
1902
  'academy',
1552
1903
  'education',
1904
+ 'educational',
1553
1905
  'learning',
1554
- 'training',
1555
1906
  'daycare',
1907
+ 'day care',
1556
1908
  'preschool',
1909
+ 'kindergarten',
1557
1910
  'music lessons',
1558
- 'driving'
1911
+ 'piano lessons',
1912
+ 'driving school',
1913
+ 'driving lessons',
1914
+ 'language school',
1915
+ 'coding bootcamp',
1916
+ 'curriculum',
1917
+ 'homeschool',
1918
+ 'montessori',
1919
+ 'summer camp'
1920
+ ],
1921
+ hints: [
1922
+ 'classes',
1923
+ 'students',
1924
+ 'learn',
1925
+ 'kids',
1926
+ 'training',
1927
+ 'camp',
1928
+ 'workshop',
1929
+ 'beginners'
1559
1930
  ],
1560
1931
  starter: 'business',
1561
1932
  look: {
@@ -1615,18 +1986,68 @@ const ALL_HUES = [
1615
1986
  'nonprofit',
1616
1987
  'non-profit',
1617
1988
  'charity',
1989
+ 'charitable',
1618
1990
  'foundation',
1619
1991
  'church',
1620
- 'community',
1992
+ 'parish',
1993
+ 'congregation',
1994
+ 'mosque',
1995
+ 'synagogue',
1996
+ 'temple',
1997
+ 'ministry',
1998
+ 'food bank',
1999
+ 'food pantry',
2000
+ 'pantry',
2001
+ 'shelter',
2002
+ 'animal shelter',
2003
+ 'animal rescue',
2004
+ 'rescue',
1621
2005
  'volunteer',
1622
- 'volunteers',
1623
2006
  'association',
2007
+ 'homeowners association',
2008
+ 'neighborhood association',
2009
+ 'hoa',
2010
+ 'pta',
2011
+ 'pto',
2012
+ 'parent teacher association',
1624
2013
  'ngo',
2014
+ 'donate',
2015
+ 'donation',
2016
+ 'fundraising',
2017
+ 'mutual aid',
2018
+ 'community center',
2019
+ 'senior center',
2020
+ 'makerspace',
2021
+ 'hackerspace',
2022
+ 'guild',
2023
+ 'rotary',
2024
+ 'advocacy',
2025
+ 'coalition',
2026
+ 'civic',
2027
+ 'veterans'
2028
+ ],
2029
+ hints: [
2030
+ 'community',
2031
+ 'club',
2032
+ 'group',
2033
+ 'troupe',
2034
+ 'circle',
2035
+ 'society',
2036
+ 'collective',
2037
+ 'members',
2038
+ 'neighbors',
2039
+ 'neighborhood',
2040
+ 'join',
2041
+ 'meetup',
2042
+ 'gathering',
1625
2043
  'mission',
1626
- 'ministry',
1627
- 'rescue',
1628
- 'shelter',
1629
- 'cause'
2044
+ 'cause',
2045
+ 'together',
2046
+ 'fellowship',
2047
+ 'faith',
2048
+ 'fundraiser',
2049
+ 'residents',
2050
+ 'families'
1630
2051
  ],
1631
2052
  starter: 'business',
1632
2053
  look: {
@@ -1687,12 +2108,37 @@ const ALL_HUES = [
1687
2108
  'music',
1688
2109
  'dj',
1689
2110
  'singer',
2111
+ 'songwriter',
2112
+ 'singer-songwriter',
1690
2113
  'rapper',
1691
- 'producer',
2114
+ 'music producer',
2115
+ 'recording studio',
2116
+ 'record label',
1692
2117
  'orchestra',
1693
2118
  'choir',
1694
2119
  'composer',
1695
- 'artist music'
2120
+ 'jazz',
2121
+ 'ensemble',
2122
+ 'quartet',
2123
+ 'pianist',
2124
+ 'guitarist',
2125
+ 'drummer',
2126
+ 'violinist',
2127
+ 'tour dates',
2128
+ 'album',
2129
+ 'live music',
2130
+ 'music artist'
2131
+ ],
2132
+ hints: [
2133
+ 'concert',
2134
+ 'gig',
2135
+ 'tour',
2136
+ 'song',
2137
+ 'shows',
2138
+ 'tracks',
2139
+ 'producer',
2140
+ 'fans',
2141
+ 'listen'
1696
2142
  ],
1697
2143
  starter: 'landing',
1698
2144
  look: {
@@ -1729,21 +2175,30 @@ const ALL_HUES = [
1729
2175
  label: 'Personal & resume',
1730
2176
  blurb: 'A simple page about you and your work',
1731
2177
  icon: 'person',
1732
- // "Personal" only as a site about the person (AGL-3660): as a bare word it
1733
- // is the adjective in "a personal travel blog", which it beat on length.
1734
2178
  keywords: [
1735
2179
  'personal site',
1736
2180
  'personal website',
1737
2181
  'personal page',
2182
+ 'personal homepage',
1738
2183
  'about me',
1739
2184
  'resume',
1740
2185
  'cv',
2186
+ 'online resume',
2187
+ 'job seeker',
2188
+ 'job search',
2189
+ 'candidate',
2190
+ 'speaker',
2191
+ 'public speaker',
2192
+ 'link in bio'
2193
+ ],
2194
+ hints: [
1741
2195
  'me',
1742
2196
  'myself',
1743
2197
  'profile',
1744
2198
  'job',
1745
- 'candidate',
1746
- 'speaker'
2199
+ 'career',
2200
+ 'hire',
2201
+ 'recruiters'
1747
2202
  ],
1748
2203
  starter: 'portfolio',
1749
2204
  look: {
@@ -1784,18 +2239,32 @@ const ALL_HUES = [
1784
2239
  blurb: 'One page that leads to one action',
1785
2240
  icon: 'rocket',
1786
2241
  keywords: [
2242
+ 'landing page',
1787
2243
  'landing',
1788
- 'launch',
1789
2244
  'app',
2245
+ 'mobile app',
1790
2246
  'startup',
1791
2247
  'saas',
1792
2248
  'software',
1793
- 'product',
1794
2249
  'waitlist',
2250
+ 'wait list',
2251
+ 'ebook',
2252
+ 'webinar',
2253
+ 'lead magnet',
2254
+ 'product launch',
2255
+ 'signup page',
2256
+ 'sign-up page'
2257
+ ],
2258
+ hints: [
2259
+ 'product',
2260
+ 'launch',
1795
2261
  'campaign',
1796
2262
  'offer',
1797
- 'ebook',
1798
- 'webinar'
2263
+ 'users',
2264
+ 'download',
2265
+ 'platform',
2266
+ 'tool',
2267
+ 'beta'
1799
2268
  ],
1800
2269
  starter: 'landing',
1801
2270
  look: {
@@ -1836,11 +2305,15 @@ const ALL_HUES = [
1836
2305
  icon: 'clock',
1837
2306
  keywords: [
1838
2307
  'coming soon',
1839
- 'soon',
1840
2308
  'prelaunch',
1841
2309
  'pre-launch',
1842
2310
  'under construction',
1843
- 'placeholder'
2311
+ 'placeholder',
2312
+ 'opening soon',
2313
+ 'launching soon'
2314
+ ],
2315
+ hints: [
2316
+ 'soon'
1844
2317
  ],
1845
2318
  starter: 'landing',
1846
2319
  look: {
@@ -1884,37 +2357,178 @@ const ALL_HUES = [
1884
2357
  if (typeof id !== 'string' || !id) return null;
1885
2358
  return (_AI_SITE_FONT_PAIRINGS_find = AI_SITE_FONT_PAIRINGS.find((pairing)=>pairing.id === id)) != null ? _AI_SITE_FONT_PAIRINGS_find : null;
1886
2359
  }
1887
- const words = (text)=>` ${text.toLowerCase().replace(/[^a-z0-9é&'-]+/g, ' ')} `;
2360
+ /** One word as the classifier compares it: lower case, unaccented, singular. */ const stem = (word)=>{
2361
+ if (word.length <= 3) return word;
2362
+ if (word.endsWith('ies')) return `${word.slice(0, -3)}y`;
2363
+ if (/(?:ss|x|ch|sh)es$/.test(word)) return word.slice(0, -2);
2364
+ if (word.endsWith('s') && !/(?:ss|us|is)$/.test(word)) return word.slice(0, -1);
2365
+ return word;
2366
+ };
2367
+ /** A text as the classifier's words ("Cafés & non-profits" → cafe, &, non, profit). */ const tokens = (text)=>text.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().replace(/'s\b/g, '').split(/[^a-z0-9&]+/).filter(Boolean).map(stem);
1888
2368
  /**
1889
- * The kind a "what kind of site" answer suggests, or `business` when nothing
1890
- * in it matches: the card the guided start selects until the person picks
1891
- * another. A longer keyword wins over a shorter one ("wedding photographer"
1892
- * is photography, not events), and of two as long the later one wins, since
1893
- * English puts the noun last ("a food blog" is a blog).
1894
- */ export function aiSiteKindFor(siteType) {
1895
- var _ref;
1896
- const text = words(siteType);
1897
- let best = null;
1898
- for (const kind of AI_SITE_KINDS){
1899
- for (const keyword of kind.keywords){
1900
- const at = text.lastIndexOf(words(keyword));
1901
- if (at === -1) continue;
1902
- if (!best || keyword.length > best.length || keyword.length === best.length && at > best.at) {
1903
- best = {
1904
- kind,
1905
- length: keyword.length,
1906
- at
1907
- };
2369
+ * Where the head of an answer ends: at its first punctuation or the first
2370
+ * word that starts a modifier ("a bookstore WITH author events", "a food blog
2371
+ * ABOUT cooking", "a pottery studio: stoneware…"). What comes before is what
2372
+ * the site IS; what follows describes it.
2373
+ */ const HEAD_END = /[:;,.()—–]|\s-\s|\b(?:with|for|about|that|who|which|where|in|on|at|of|offering|selling|serving|near|from|by|to)\b/i;
2374
+ /**
2375
+ * What a match is worth. A specific one-word keyword picks a kind alone; a
2376
+ * phrase is worth more than its words (it is the more specific reading, and
2377
+ * it claims its words so "wedding photographer" never also counts as a
2378
+ * wedding); a hint only leans. The last keyword in the head of the answer —
2379
+ * its noun — gets a bonus, so the thing the site is beats what it mentions.
2380
+ */ const KEYWORD_WEIGHT = 3;
2381
+ const PHRASE_WEIGHT_PER_WORD = 2;
2382
+ const HINT_WEIGHT = 1;
2383
+ const HEAD_NOUN_BONUS = 2;
2384
+ /** A generic head noun with nothing specific said: enough to clear {@link MIN_SCORE} alone, never to beat a keyword. */ const HEAD_HINT_BONUS = 1;
2385
+ /** "Who it's for" describes the people, not the site, so it counts half. */ const AUDIENCE_SHARE = 0.5;
2386
+ /** Below this no kind is meant: one stray hint is not a reason to pick a narrow vertical. */ const MIN_SCORE = 1.5;
2387
+ /**
2388
+ * Every keyword and hint once per kind (a plural and its singular are one
2389
+ * term), longest phrase first so a phrase claims its words before they count
2390
+ * alone.
2391
+ */ const TERMS = AI_SITE_KINDS.flatMap((kind)=>{
2392
+ const seen = new Set();
2393
+ const terms = [];
2394
+ const add = (term, keyword)=>{
2395
+ const words = tokens(term);
2396
+ const key = words.join(' ');
2397
+ if (!words.length || seen.has(key)) return;
2398
+ seen.add(key);
2399
+ const weight = !keyword ? HINT_WEIGHT : words.length > 1 ? PHRASE_WEIGHT_PER_WORD * words.length : KEYWORD_WEIGHT;
2400
+ terms.push({
2401
+ kind,
2402
+ words,
2403
+ weight,
2404
+ keyword
2405
+ });
2406
+ };
2407
+ for (const keyword of kind.keywords)add(keyword, true);
2408
+ for (const hint of kind.hints)add(hint, false);
2409
+ return terms;
2410
+ }).sort((a, b)=>b.words.length - a.words.length);
2411
+ /** Adds what one text says for each kind to `scores`; returns every term it found. */ function aiSiteKindScores(text, share, scores) {
2412
+ const words = tokens(text);
2413
+ const matches = [];
2414
+ // Words a longer term has matched; terms of one length share their words
2415
+ // (two kinds may both have "studio"), and a shorter term never reuses them.
2416
+ const claimed = new Array(words.length).fill(false);
2417
+ const pending = new Set();
2418
+ const counted = new Set();
2419
+ let length = 0;
2420
+ for (const term of TERMS){
2421
+ if (term.words.length !== length) {
2422
+ length = term.words.length;
2423
+ for (const index of pending)claimed[index] = true;
2424
+ pending.clear();
2425
+ }
2426
+ for(let start = 0; start + term.words.length <= words.length; start++){
2427
+ var _scores_get;
2428
+ if (!term.words.every((word, offset)=>words[start + offset] === word && !claimed[start + offset])) continue;
2429
+ const end = start + term.words.length;
2430
+ for(let index = start; index < end; index++)pending.add(index);
2431
+ const entry = (_scores_get = scores.get(term.kind)) != null ? _scores_get : {
2432
+ score: 0,
2433
+ at: -1
2434
+ };
2435
+ if (!counted.has(term)) {
2436
+ counted.add(term);
2437
+ entry.score += term.weight * share;
1908
2438
  }
2439
+ entry.at = Math.max(entry.at, end);
2440
+ scores.set(term.kind, entry);
2441
+ matches.push({
2442
+ kind: term.kind,
2443
+ end,
2444
+ keyword: term.keyword
2445
+ });
2446
+ }
2447
+ }
2448
+ return matches;
2449
+ }
2450
+ /**
2451
+ * The kind the head of an answer names, if any. Its last keyword when it has
2452
+ * one. When nothing specific is said anywhere, its last generic word that
2453
+ * belongs to exactly one kind: "a pet store" is a store, "a writers group" a
2454
+ * community, "a cooking class studio" a class (studio says nothing, since
2455
+ * four kinds share it). A generic word outside the head never counts here.
2456
+ */ function aiSiteHeadKind(head, specific) {
2457
+ const keywords = head.filter((match)=>match.keyword);
2458
+ if (keywords.length) return keywords.reduce((last, match)=>match.end > last.end ? match : last).kind;
2459
+ if (specific) return null;
2460
+ const ends = [
2461
+ ...new Set(head.map((match)=>match.end))
2462
+ ].sort((a, b)=>b - a);
2463
+ for (const end of ends){
2464
+ const kinds = new Set(head.filter((match)=>match.end === end).map((match)=>match.kind));
2465
+ if (kinds.size === 1) return [
2466
+ ...kinds
2467
+ ][0];
2468
+ }
2469
+ return null;
2470
+ }
2471
+ /**
2472
+ * The kind a "what kind of site" answer suggests, read with "who it's for"
2473
+ * when there is one: the card the guided start selects until the person
2474
+ * picks another. Deterministic and local, no model call (AGL-3660).
2475
+ *
2476
+ * Every kind scores what it finds. A specific keyword ("roofer", "food bank")
2477
+ * is enough alone; a phrase outweighs its words and claims them ("wedding
2478
+ * photographer" is photography, not events); a generic hint ("club",
2479
+ * "studio", "classes", "shop") only leans, so "a neighborhood book club" is
2480
+ * community, built from club + neighborhood + meetups + neighbors, and never
2481
+ * fitness on "club". The head noun — the last keyword before the answer's
2482
+ * first modifier — earns a bonus ("a bookstore with author events" is a
2483
+ * store); when the answer and audience name nothing specific, a generic head
2484
+ * noun that only one kind has may decide ("a bike shop" is a store, "a hiking
2485
+ * group" a community). The audience counts half. The highest score wins; of two equal,
2486
+ * the one named later, since English puts the noun last ("a food blog" is a
2487
+ * blog). A best score of no more than a stray hint, or a tie that order
2488
+ * cannot settle, is `business`, the most general kind.
2489
+ */ export function aiSiteKindFor(siteType, audience = '') {
2490
+ var _siteType_split_;
2491
+ const general = AI_SITE_KINDS[0];
2492
+ const scores = new Map();
2493
+ const found = aiSiteKindScores(siteType, 1, scores);
2494
+ const fromAudience = new Map();
2495
+ if (audience) found.push(...aiSiteKindScores(audience, AUDIENCE_SHARE, fromAudience));
2496
+ const head = aiSiteKindScores((_siteType_split_ = siteType.split(HEAD_END)[0]) != null ? _siteType_split_ : '', 0, new Map());
2497
+ const headKind = aiSiteHeadKind(head, found.some((match)=>match.keyword));
2498
+ const headEntry = headKind ? scores.get(headKind) : undefined;
2499
+ if (headEntry) headEntry.score += head.some((match)=>match.keyword) ? HEAD_NOUN_BONUS : HEAD_HINT_BONUS;
2500
+ for (const [kind, { score }] of fromAudience){
2501
+ var _scores_get;
2502
+ const entry = (_scores_get = scores.get(kind)) != null ? _scores_get : {
2503
+ score: 0,
2504
+ at: -1
2505
+ };
2506
+ entry.score += score;
2507
+ scores.set(kind, entry);
2508
+ }
2509
+ let best = null;
2510
+ let tied = false;
2511
+ for (const [kind, { score, at }] of scores){
2512
+ if (!best || score > best.score || score === best.score && at > best.at) {
2513
+ tied = false;
2514
+ best = {
2515
+ kind,
2516
+ score,
2517
+ at
2518
+ };
2519
+ } else if (score === best.score && at === best.at) {
2520
+ tied = true;
1909
2521
  }
1910
2522
  }
1911
- return (_ref = best == null ? void 0 : best.kind) != null ? _ref : AI_SITE_KINDS[0];
2523
+ if (!best || best.score < MIN_SCORE || tied) return general;
2524
+ return best.kind;
1912
2525
  }
1913
- /** The kind a job's inputs name, else the one its business type suggests; `null` for a job that names neither. */ export function aiSiteKindOfInputs(inputs) {
2526
+ /** The kind a job's inputs name, else the one its business type and audience suggest; `null` for a job that names neither. */ export function aiSiteKindOfInputs(inputs) {
1914
2527
  const named = aiSiteKind(inputs == null ? void 0 : inputs['siteKind']);
1915
2528
  if (named) return named;
1916
2529
  const type = inputs == null ? void 0 : inputs['businessType'];
1917
- return typeof type === 'string' && type.trim() ? aiSiteKindFor(type) : null;
2530
+ const audience = inputs == null ? void 0 : inputs['audience'];
2531
+ return typeof type === 'string' && type.trim() ? aiSiteKindFor(type, typeof audience === 'string' ? audience : '') : null;
1918
2532
  }
1919
2533
  /** What each band rhythm asks of a page's sections. */ const RHYTHM_WORDS = {
1920
2534
  calm: 'mostly plain bands with one soft band, and a brand or dark band only for the closing call to action',