@vectoriox/iox-ui 5.46.0 → 5.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/design-core/index.d.ts +5 -3
  2. package/fesm2022/vectoriox-iox-ui-design-core.mjs +7 -4
  3. package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
  4. package/fesm2022/vectoriox-iox-ui-generation-core.mjs +351 -78
  5. package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
  6. package/fesm2022/vectoriox-iox-ui-harness-core.mjs +4179 -0
  7. package/fesm2022/vectoriox-iox-ui-harness-core.mjs.map +1 -0
  8. package/fesm2022/vectoriox-iox-ui.mjs +29 -1
  9. package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
  10. package/generation-core/index.d.ts +252 -18
  11. package/harness-core/index.d.ts +2498 -0
  12. package/harness-core/package.json +3 -0
  13. package/index.d.ts +22 -3
  14. package/package.json +5 -1
  15. package/src/design-core/design-apply.ts +8 -4
  16. package/src/generation-core/entrances.ts +110 -0
  17. package/src/generation-core/plan-data.ts +71 -0
  18. package/src/generation-core/public-api.ts +3 -0
  19. package/src/generation-core/shape-check.ts +92 -0
  20. package/src/generation-core/site-spec.generated.ts +131 -2
  21. package/src/generation-core/validate-site-plan.ts +9 -62
  22. package/src/harness-core/business-types.ts +141 -0
  23. package/src/harness-core/harness-spec.generated.ts +3528 -0
  24. package/src/harness-core/intake.ts +85 -0
  25. package/src/harness-core/lint.ts +94 -0
  26. package/src/harness-core/look.ts +32 -0
  27. package/src/harness-core/motion.ts +67 -0
  28. package/src/harness-core/needs.ts +42 -0
  29. package/src/harness-core/prompt-context.ts +91 -0
  30. package/src/harness-core/public-api.ts +19 -0
  31. package/src/harness-core/rank.ts +226 -0
  32. package/src/harness-core/site-analysis.ts +180 -0
@@ -0,0 +1,2498 @@
1
+ import { MotionId, MoodId, TintId, DensityId, DesignMotion, DesignChoices, DesignMode, StylePreset, AnimateId, ShapeId } from '@vectoriox/iox-ui/design-core';
2
+ import { FactKey, PathIssue } from '@vectoriox/iox-ui/generation-core';
3
+
4
+ declare const SPEC_HARNESS_SOURCE: {
5
+ readonly repo: "nextlevelbuilder/ui-ux-pro-max-skill";
6
+ readonly sha: "d14efff8ed1faa4187f004f79926f428c8074ec7";
7
+ readonly date: "2026-10-23";
8
+ readonly licence: "MIT — Copyright (c) 2024 Next Level Builder";
9
+ readonly notice: "Business-type rules adapted from UI UX Pro Max (MIT, Copyright (c) 2024 Next Level Builder).";
10
+ };
11
+ declare const SPEC_NEEDS: {
12
+ readonly collection: {
13
+ readonly label: "Your work or products";
14
+ readonly archetype: "collection";
15
+ };
16
+ readonly detail: {
17
+ readonly label: "A page for each item";
18
+ readonly archetype: "detail";
19
+ };
20
+ readonly services: {
21
+ readonly label: "Services";
22
+ readonly archetype: "services";
23
+ };
24
+ readonly prices: {
25
+ readonly label: "Prices";
26
+ readonly archetype: "services";
27
+ };
28
+ readonly menu: {
29
+ readonly label: "Menu";
30
+ readonly archetype: "collection";
31
+ };
32
+ readonly visit: {
33
+ readonly label: "Hours and how to find you";
34
+ readonly archetype: "contact";
35
+ };
36
+ readonly team: {
37
+ readonly label: "The team";
38
+ readonly archetype: "about";
39
+ };
40
+ readonly about: {
41
+ readonly label: "About you";
42
+ readonly archetype: "about";
43
+ };
44
+ readonly faq: {
45
+ readonly label: "Questions people ask";
46
+ readonly archetype: "about";
47
+ };
48
+ readonly blog: {
49
+ readonly label: "News or a journal";
50
+ readonly archetype: "collection";
51
+ };
52
+ readonly gallery: {
53
+ readonly label: "A gallery";
54
+ readonly archetype: "collection";
55
+ };
56
+ readonly "booking-request": {
57
+ readonly label: "A booking request form";
58
+ readonly archetype: "contact";
59
+ };
60
+ readonly "sign-up-form": {
61
+ readonly label: "A sign-up form";
62
+ readonly archetype: "contact";
63
+ };
64
+ readonly contact: {
65
+ readonly label: "Contact";
66
+ readonly archetype: "contact";
67
+ };
68
+ };
69
+ declare const SPEC_USER_AVOIDS: {
70
+ readonly "dark-pages": {
71
+ readonly when: {
72
+ readonly mode: readonly ["dark"];
73
+ };
74
+ readonly say: "You asked for no dark backgrounds.";
75
+ };
76
+ readonly "loud-colour": {
77
+ readonly when: {
78
+ readonly moods: readonly ["bold", "energetic"];
79
+ };
80
+ readonly say: "You asked for nothing loud.";
81
+ };
82
+ readonly "lots-of-motion": {
83
+ readonly when: {
84
+ readonly motion: readonly ["snappy", "lively"];
85
+ };
86
+ readonly say: "You asked for little movement.";
87
+ };
88
+ readonly "too-cute": {
89
+ readonly when: {
90
+ readonly moods: readonly ["playful"];
91
+ };
92
+ readonly say: "You asked for nothing cute or childish.";
93
+ };
94
+ readonly "too-corporate": {
95
+ readonly when: {
96
+ readonly moods: readonly ["trustworthy", "technical"];
97
+ };
98
+ readonly say: "You asked for nothing corporate.";
99
+ };
100
+ };
101
+ declare const SPEC_STRUCTURES: {
102
+ readonly studio: {
103
+ readonly label: "Studio";
104
+ readonly blurb: "Your work, what you do, and a way to reach you.";
105
+ readonly pages: readonly ["Home", "Work", "Project (one per project)", "About", "Contact"];
106
+ readonly shipped: true;
107
+ };
108
+ readonly practice: {
109
+ readonly label: "Practice";
110
+ readonly blurb: "Services, prices and a clear way to book.";
111
+ readonly pages: readonly ["Home", "Services", "Prices", "About", "Contact"];
112
+ readonly shipped: false;
113
+ };
114
+ readonly place: {
115
+ readonly label: "Place";
116
+ readonly blurb: "A menu, opening hours and how to find you.";
117
+ readonly pages: readonly ["Home", "Menu", "Visit (hours + map)", "About", "Contact"];
118
+ readonly shipped: false;
119
+ };
120
+ };
121
+ declare const SPEC_BUSINESS_TYPES: readonly [{
122
+ readonly id: "photographer";
123
+ readonly label: "Photographer";
124
+ readonly he: "צלם/ת";
125
+ readonly group: "Creative work";
126
+ readonly uupm: "53 Photography Studio";
127
+ readonly match: readonly ["photographer", "photography", "photo studio", "צלם", "צילום"];
128
+ readonly good: readonly [{
129
+ readonly preset: "night-gallery";
130
+ readonly reason: "Pictures sit on black, as in a darkened gallery.";
131
+ }, {
132
+ readonly preset: "gallery-minimal";
133
+ readonly reason: "White space and a quiet serif keep every eye on the photos.";
134
+ }, {
135
+ readonly preset: "frosted-portfolio";
136
+ readonly reason: "Soft grey glass frames the pictures without competing.";
137
+ }, {
138
+ readonly preset: "swiss-grid";
139
+ readonly reason: "A strict grid lines your photos up like contact sheets.";
140
+ }];
141
+ readonly colour: {
142
+ readonly mood: "black, white and one quiet accent";
143
+ readonly swatches: readonly ["#18181B", "#3F4A5A", "#8B9BB4"];
144
+ };
145
+ readonly fonts: "elegant and minimal";
146
+ readonly tone: "Few words. Let the pictures speak; one line per project.";
147
+ readonly motion: "calm";
148
+ readonly moves: {
149
+ readonly scroll: "extra";
150
+ readonly animate: "subtle";
151
+ readonly between: "cinematic";
152
+ };
153
+ readonly imagery: "Your own photos only, large and uncropped; never stock.";
154
+ readonly pages: readonly ["home", "work (collection)", "project (detail)", "about", "contact"];
155
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
156
+ readonly home: readonly ["hero.full-bleed-media", "collection.masonry-gallery", "proof.testimonial-single", "cta.banner"];
157
+ readonly avoid: readonly [{
158
+ readonly when: {
159
+ readonly moods: readonly ["playful"];
160
+ };
161
+ readonly say: "Loud colour and bouncy shapes fight the photos for attention.";
162
+ }, {
163
+ readonly check: "needs-family";
164
+ readonly family: "collection";
165
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
166
+ }, {
167
+ readonly check: "image-hero";
168
+ readonly say: "Lead with a picture: the first screen should show the place or the work, not only words.";
169
+ }, {
170
+ readonly check: "copy-length";
171
+ readonly max: "standard";
172
+ readonly say: "Heavy text buries the pictures.";
173
+ }];
174
+ readonly words: readonly ["capturing memories", "stunning", "passionate"];
175
+ readonly structure: "studio";
176
+ readonly slice: true;
177
+ readonly stock: false;
178
+ readonly booking: "sometimes";
179
+ }, {
180
+ readonly id: "interior-design";
181
+ readonly label: "Interior designer";
182
+ readonly he: "מעצב/ת פנים";
183
+ readonly group: "Creative work";
184
+ readonly uupm: "161 Home Decoration & Interior Design · 84 Architecture / Interior";
185
+ readonly match: readonly ["interior", "interiors", "עיצוב פנים", "decor"];
186
+ readonly good: readonly [{
187
+ readonly preset: "gallery-minimal";
188
+ readonly reason: "Calm white rooms let the materials show.";
189
+ }, {
190
+ readonly preset: "quiet-luxury";
191
+ readonly reason: "Warm bronze says considered and high-end.";
192
+ }, {
193
+ readonly preset: "warm-editorial";
194
+ readonly reason: "Reads like a design magazine feature about your rooms.";
195
+ }, {
196
+ readonly preset: "frosted-portfolio";
197
+ readonly reason: "Light, airy panels around big project photos.";
198
+ }];
199
+ readonly colour: {
200
+ readonly mood: "warm neutrals with one material accent";
201
+ readonly swatches: readonly ["#7A5B36", "#78716C", "#5E6B3A"];
202
+ };
203
+ readonly fonts: "architectural and elegant";
204
+ readonly tone: "Calm and specific: materials, light, the brief.";
205
+ readonly motion: "calm";
206
+ readonly moves: {
207
+ readonly scroll: "extra";
208
+ readonly animate: "subtle";
209
+ readonly between: "cinematic";
210
+ };
211
+ readonly imagery: "Wide, bright room shots; details of materials.";
212
+ readonly pages: readonly ["home", "projects (collection)", "project (detail)", "services", "about", "contact"];
213
+ readonly needs: readonly ["collection", "detail", "services", "about", "contact"];
214
+ readonly home: readonly ["hero.split", "collection.card-grid", "feature.triad", "proof.testimonial-carousel", "cta.banner"];
215
+ readonly avoid: readonly [{
216
+ readonly when: {
217
+ readonly moods: readonly ["playful"];
218
+ };
219
+ readonly say: "Playful shapes cheapen a portfolio of finished rooms.";
220
+ }, {
221
+ readonly when: {
222
+ readonly density: readonly ["compact"];
223
+ };
224
+ readonly say: "A cramped page is the opposite of a well-designed room.";
225
+ }, {
226
+ readonly check: "needs-family";
227
+ readonly family: "collection";
228
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
229
+ }, {
230
+ readonly check: "image-hero";
231
+ readonly say: "Lead with a picture: the first screen should show the place or the work, not only words.";
232
+ }];
233
+ readonly words: readonly ["dream home", "luxurious", "stunning"];
234
+ readonly structure: "studio";
235
+ readonly slice: true;
236
+ readonly stock: false;
237
+ readonly booking: "none";
238
+ }, {
239
+ readonly id: "architecture";
240
+ readonly label: "Architect";
241
+ readonly he: "אדריכל/ית";
242
+ readonly group: "Creative work";
243
+ readonly uupm: "84 Architecture / Interior · 51 Construction/Architecture";
244
+ readonly match: readonly ["architect", "architecture", "אדריכל"];
245
+ readonly good: readonly [{
246
+ readonly preset: "swiss-grid";
247
+ readonly reason: "A strict grid and clean type, like a drawing set.";
248
+ }, {
249
+ readonly preset: "gallery-minimal";
250
+ readonly reason: "Big images and generous margins, like a monograph.";
251
+ }, {
252
+ readonly preset: "night-gallery";
253
+ readonly reason: "Buildings at dusk on a dark page.";
254
+ }, {
255
+ readonly preset: "frosted-portfolio";
256
+ readonly reason: "Soft glass over large project photos.";
257
+ }];
258
+ readonly colour: {
259
+ readonly mood: "monochrome and one accent";
260
+ readonly swatches: readonly ["#171717", "#3F4A5A", "#A16207"];
261
+ };
262
+ readonly fonts: "architectural, precise";
263
+ readonly tone: "Precise and brief: the project, the place, the year.";
264
+ readonly motion: "calm";
265
+ readonly moves: {
266
+ readonly scroll: "smooth";
267
+ readonly animate: "subtle";
268
+ readonly between: "fade";
269
+ };
270
+ readonly imagery: "Large project photos and drawings.";
271
+ readonly pages: readonly ["home", "projects (collection)", "project (detail)", "about", "contact"];
272
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
273
+ readonly home: readonly ["hero.full-bleed-media", "collection.card-grid", "story.quote-break", "cta.banner"];
274
+ readonly avoid: readonly [{
275
+ readonly when: {
276
+ readonly moods: readonly ["playful"];
277
+ };
278
+ readonly say: "Playful shapes undercut the precision clients pay for.";
279
+ }, {
280
+ readonly check: "brand-hue";
281
+ readonly from: 270;
282
+ readonly to: 335;
283
+ readonly minChroma: 0.12;
284
+ readonly say: "A purple-pink brand is the colour of AI tools right now; on this kind of site it can read as generic.";
285
+ }, {
286
+ readonly check: "needs-family";
287
+ readonly family: "collection";
288
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
289
+ }, {
290
+ readonly check: "image-hero";
291
+ readonly say: "Lead with a picture: the first screen should show the place or the work, not only words.";
292
+ }];
293
+ readonly words: readonly ["iconic", "world-class", "cutting-edge"];
294
+ readonly structure: "studio";
295
+ readonly slice: false;
296
+ readonly stock: false;
297
+ readonly booking: "none";
298
+ }, {
299
+ readonly id: "creative-studio";
300
+ readonly label: "Design or branding studio";
301
+ readonly he: "סטודיו לעיצוב";
302
+ readonly group: "Creative work";
303
+ readonly uupm: "10 Creative Agency";
304
+ readonly match: readonly ["design studio", "branding", "agency", "graphic design", "סטודיו לעיצוב", "מיתוג"];
305
+ readonly good: readonly [{
306
+ readonly preset: "zine";
307
+ readonly reason: "Shows you take risks with type and colour.";
308
+ }, {
309
+ readonly preset: "tech-studio";
310
+ readonly reason: "Dark and exact, for digital work.";
311
+ }, {
312
+ readonly preset: "bold-maker";
313
+ readonly reason: "Loud outlines that clients remember.";
314
+ }, {
315
+ readonly preset: "swiss-grid";
316
+ readonly reason: "Confident, classic design-studio grid.";
317
+ }];
318
+ readonly colour: {
319
+ readonly mood: "bold primaries, artistic freedom";
320
+ readonly swatches: readonly ["#3D5AFE", "#FF5C39", "#111827"];
321
+ };
322
+ readonly fonts: "bold and expressive";
323
+ readonly tone: "Confident, short, a little witty.";
324
+ readonly motion: "standard";
325
+ readonly moves: {
326
+ readonly scroll: "smooth";
327
+ readonly animate: "lively";
328
+ readonly between: "slide";
329
+ };
330
+ readonly imagery: "Case-study images of your own work.";
331
+ readonly pages: readonly ["home", "work (collection)", "case study (detail)", "services", "about", "contact"];
332
+ readonly needs: readonly ["collection", "detail", "services", "about", "contact"];
333
+ readonly home: readonly ["hero.stacked-editorial", "collection.card-grid", "feature.triad", "proof.logo-strip", "cta.banner"];
334
+ readonly avoid: readonly [{
335
+ readonly check: "needs-family";
336
+ readonly family: "collection";
337
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
338
+ }, {
339
+ readonly check: "no-pattern";
340
+ readonly pattern: "pricing.tiers";
341
+ readonly say: "Studios that sell projects rarely list fixed prices; a price table can undersell you.";
342
+ }];
343
+ readonly words: readonly ["synergy", "cutting-edge", "solutions"];
344
+ readonly structure: "studio";
345
+ readonly slice: false;
346
+ readonly stock: false;
347
+ readonly booking: "none";
348
+ }, {
349
+ readonly id: "artist";
350
+ readonly label: "Artist or illustrator";
351
+ readonly he: "אמן/ית";
352
+ readonly group: "Creative work";
353
+ readonly uupm: "11 Portfolio/Personal · Museum/Gallery";
354
+ readonly match: readonly ["artist", "painter", "illustrator", "אמנית", "אמן", "ציור", "איור"];
355
+ readonly good: readonly [{
356
+ readonly preset: "zine";
357
+ readonly reason: "Hand-made energy that suits an illustrator.";
358
+ }, {
359
+ readonly preset: "gallery-minimal";
360
+ readonly reason: "A white-cube gallery for your pieces.";
361
+ }, {
362
+ readonly preset: "night-gallery";
363
+ readonly reason: "Work glowing on a dark wall.";
364
+ }, {
365
+ readonly preset: "warm-editorial";
366
+ readonly reason: "Like a catalogue from a small gallery.";
367
+ }];
368
+ readonly colour: {
369
+ readonly mood: "your work's own palette; a neutral page";
370
+ readonly swatches: readonly ["#3D5AFE", "#3F4A5A", "#9A4F2B"];
371
+ };
372
+ readonly fonts: "expressive";
373
+ readonly tone: "Personal, first person, short.";
374
+ readonly motion: "calm";
375
+ readonly moves: {
376
+ readonly scroll: "smooth";
377
+ readonly animate: "standard";
378
+ readonly between: "fade";
379
+ };
380
+ readonly imagery: "Your pieces, photographed flat and true to colour.";
381
+ readonly pages: readonly ["home", "works (collection)", "work (detail)", "about", "contact"];
382
+ readonly needs: readonly ["collection", "about", "contact"];
383
+ readonly home: readonly ["hero.split", "collection.masonry-gallery", "about.story", "cta.banner"];
384
+ readonly avoid: readonly [{
385
+ readonly when: {
386
+ readonly moods: readonly ["trustworthy"];
387
+ readonly flavor: readonly ["crisp"];
388
+ };
389
+ readonly say: "A corporate look makes an artist look like a firm.";
390
+ }, {
391
+ readonly check: "needs-family";
392
+ readonly family: "collection";
393
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
394
+ }];
395
+ readonly words: readonly ["unique", "passionate"];
396
+ readonly structure: "studio";
397
+ readonly slice: false;
398
+ readonly stock: false;
399
+ readonly booking: "none";
400
+ }, {
401
+ readonly id: "makers";
402
+ readonly label: "Ceramics, crafts and makers";
403
+ readonly he: "קרמיקה ויוצרים";
404
+ readonly group: "Creative work";
405
+ readonly uupm: "no row — nearest: Nature Distilled, Anti-Polish styles; Indie/Craft pairing";
406
+ readonly match: readonly ["ceramic", "ceramics", "pottery", "stoneware", "handmade", "crafts", "maker", "workshop", "קרמיקה", "כלי חרס", "עבודת יד", "סדנ"];
407
+ readonly good: readonly [{
408
+ readonly preset: "warm-editorial";
409
+ readonly reason: "Cream and terracotta echo clay; a serif with a hand-made feel.";
410
+ }, {
411
+ readonly preset: "bold-maker";
412
+ readonly reason: "Proud, chunky outlines for a maker with a voice.";
413
+ }, {
414
+ readonly preset: "corner-cafe";
415
+ readonly reason: "Friendly and round for workshops and classes.";
416
+ }, {
417
+ readonly preset: "gallery-minimal";
418
+ readonly reason: "Pieces shown like objects in a gallery.";
419
+ }];
420
+ readonly colour: {
421
+ readonly mood: "earth, clay and glaze";
422
+ readonly swatches: readonly ["#9A4F2B", "#5E6B3A", "#7A5B36"];
423
+ };
424
+ readonly fonts: "warm, hand-made";
425
+ readonly tone: "Warm and plain; how it is made, who makes it.";
426
+ readonly motion: "calm";
427
+ readonly moves: {
428
+ readonly scroll: "normal";
429
+ readonly animate: "lively";
430
+ readonly between: "slide";
431
+ };
432
+ readonly imagery: "Your pieces and hands at work; natural light.";
433
+ readonly pages: readonly ["home", "pieces (collection)", "piece (detail)", "workshops", "about", "contact"];
434
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
435
+ readonly home: readonly ["hero.split", "collection.card-grid", "feature.triad", "cta.banner"];
436
+ readonly avoid: readonly [{
437
+ readonly when: {
438
+ readonly moods: readonly ["technical"];
439
+ };
440
+ readonly say: "A cold, technical look hides the hand that made the work.";
441
+ }, {
442
+ readonly check: "needs-family";
443
+ readonly family: "collection";
444
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
445
+ }];
446
+ readonly words: readonly ["perfect", "premium quality", "mass-produced"];
447
+ readonly structure: "studio";
448
+ readonly slice: true;
449
+ readonly stock: false;
450
+ readonly booking: "sometimes";
451
+ }, {
452
+ readonly id: "jewellery";
453
+ readonly label: "Jewellery";
454
+ readonly he: "תכשיטים";
455
+ readonly group: "Creative work";
456
+ readonly uupm: "33 Luxury/Premium Brand · 4 E-commerce Luxury";
457
+ readonly match: readonly ["jewel", "jewellery", "jewelry", "rings", "תכשיט"];
458
+ readonly good: readonly [{
459
+ readonly preset: "quiet-luxury";
460
+ readonly reason: "Bronze and serif: precious without shouting.";
461
+ }, {
462
+ readonly preset: "gallery-minimal";
463
+ readonly reason: "Each piece alone on white, like a vitrine.";
464
+ }, {
465
+ readonly preset: "night-gallery";
466
+ readonly reason: "Metal and stones shine on black.";
467
+ }, {
468
+ readonly preset: "frosted-portfolio";
469
+ readonly reason: "Soft glass, clean and premium.";
470
+ }];
471
+ readonly colour: {
472
+ readonly mood: "black, gold, white";
473
+ readonly swatches: readonly ["#7A5B36", "#1C1917", "#3F4A5A"];
474
+ };
475
+ readonly fonts: "elegant, refined";
476
+ readonly tone: "Few, exact words: the metal, the stone, the making.";
477
+ readonly motion: "calm";
478
+ readonly moves: {
479
+ readonly scroll: "extra";
480
+ readonly animate: "subtle";
481
+ readonly between: "cinematic";
482
+ };
483
+ readonly imagery: "Close-ups on a plain ground.";
484
+ readonly pages: readonly ["home", "collection", "piece (detail)", "about", "contact"];
485
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
486
+ readonly home: readonly ["hero.split", "collection.card-grid", "about.story", "cta.banner"];
487
+ readonly avoid: readonly [{
488
+ readonly when: {
489
+ readonly moods: readonly ["playful"];
490
+ };
491
+ readonly say: "Playful colours read as costume jewellery.";
492
+ }, {
493
+ readonly when: {
494
+ readonly motion: readonly ["snappy", "lively"];
495
+ };
496
+ readonly say: "Fast animation feels cheap next to fine pieces.";
497
+ }];
498
+ readonly words: readonly ["cheap", "bargain", "bling"];
499
+ readonly structure: "studio";
500
+ readonly slice: false;
501
+ readonly stock: false;
502
+ readonly booking: "none";
503
+ }, {
504
+ readonly id: "tattoo";
505
+ readonly label: "Tattoo or barber studio";
506
+ readonly he: "סטודיו קעקועים / ברבר";
507
+ readonly group: "Creative work";
508
+ readonly uupm: "no row";
509
+ readonly match: readonly ["tattoo", "barber", "piercing", "קעקוע", "ברבר", "מספרה לגברים"];
510
+ readonly good: readonly [{
511
+ readonly preset: "ink-studio";
512
+ readonly reason: "Black, sharp and orange: a studio with attitude.";
513
+ }, {
514
+ readonly preset: "after-dark";
515
+ readonly reason: "Dark and bold, open late.";
516
+ }, {
517
+ readonly preset: "zine";
518
+ readonly reason: "Flash-sheet energy.";
519
+ }, {
520
+ readonly preset: "night-gallery";
521
+ readonly reason: "Your work on black, like a portfolio book.";
522
+ }];
523
+ readonly colour: {
524
+ readonly mood: "black and one hot accent";
525
+ readonly swatches: readonly ["#EA580C", "#DB2777", "#111827"];
526
+ };
527
+ readonly fonts: "bold, condensed";
528
+ readonly tone: "Direct, a bit of attitude.";
529
+ readonly motion: "snappy";
530
+ readonly moves: {
531
+ readonly scroll: "normal";
532
+ readonly animate: "standard";
533
+ readonly between: "slide";
534
+ };
535
+ readonly imagery: "Healed work, clean photos.";
536
+ readonly pages: readonly ["home", "work (collection)", "artists", "faq", "contact"];
537
+ readonly needs: readonly ["collection", "faq", "contact"];
538
+ readonly home: readonly ["hero.full-bleed-media", "collection.masonry-gallery", "faq.accordion", "cta.banner"];
539
+ readonly avoid: readonly [{
540
+ readonly when: {
541
+ readonly moods: readonly ["romantic"];
542
+ };
543
+ readonly say: "Soft pastels don't match the shop people expect.";
544
+ }, {
545
+ readonly check: "needs-family";
546
+ readonly family: "collection";
547
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
548
+ }];
549
+ readonly words: readonly ["cheap", "walk-ins guaranteed"];
550
+ readonly structure: "studio";
551
+ readonly slice: false;
552
+ readonly stock: false;
553
+ readonly booking: "must";
554
+ }, {
555
+ readonly id: "spa";
556
+ readonly label: "Spa and massage";
557
+ readonly he: "ספא ועיסוי";
558
+ readonly group: "Wellness and beauty";
559
+ readonly uupm: "32 Beauty/Spa/Wellness Service";
560
+ readonly match: readonly ["spa", "massage", "wellness", "ספא", "עיסוי", "טיפולי"];
561
+ readonly good: readonly [{
562
+ readonly preset: "soft-spa";
563
+ readonly reason: "Rose cream, a fine serif and slow motion: calm before they arrive.";
564
+ }, {
565
+ readonly preset: "morning-glass";
566
+ readonly reason: "Fresh, frosted and light.";
567
+ }, {
568
+ readonly preset: "quiet-luxury";
569
+ readonly reason: "For a high-end spa: bronze and space.";
570
+ }, {
571
+ readonly preset: "garden-party";
572
+ readonly reason: "Soft and warm, for a friendly day spa.";
573
+ }];
574
+ readonly colour: {
575
+ readonly mood: "soft pastels — pink, sage, cream — with gold";
576
+ readonly swatches: readonly ["#7D4E5E", "#5E6B3A", "#7A5B36"];
577
+ };
578
+ readonly fonts: "elegant and calming";
579
+ readonly tone: "Soft, unhurried, second person.";
580
+ readonly motion: "calm";
581
+ readonly moves: {
582
+ readonly scroll: "smooth";
583
+ readonly animate: "subtle";
584
+ readonly between: "fade";
585
+ };
586
+ readonly imagery: "Rooms, textures, hands; no faces needed.";
587
+ readonly pages: readonly ["home", "treatments (services)", "prices", "about", "contact"];
588
+ readonly needs: readonly ["services", "prices", "about", "contact"];
589
+ readonly home: readonly ["hero.split", "feature.triad", "proof.testimonial-carousel", "cta.banner"];
590
+ readonly avoid: readonly [{
591
+ readonly when: {
592
+ readonly mode: readonly ["dark"];
593
+ };
594
+ readonly say: "Dark pages feel like a night club, not a place to rest.";
595
+ }, {
596
+ readonly when: {
597
+ readonly moods: readonly ["bold", "energetic"];
598
+ };
599
+ readonly say: "Loud, bright colour is the opposite of a quiet room.";
600
+ }, {
601
+ readonly when: {
602
+ readonly motion: readonly ["snappy", "lively"];
603
+ };
604
+ readonly say: "Fast, bouncy motion works against the calm people come for.";
605
+ }, {
606
+ readonly check: "needs-fact";
607
+ readonly fact: "hours";
608
+ readonly say: "People look for your opening hours first; a site without them sends them elsewhere.";
609
+ }];
610
+ readonly words: readonly ["deal", "hurry", "cheap"];
611
+ readonly structure: "practice";
612
+ readonly slice: true;
613
+ readonly stock: true;
614
+ readonly booking: "must";
615
+ }, {
616
+ readonly id: "salon";
617
+ readonly label: "Hair and beauty salon";
618
+ readonly he: "מספרה וסלון יופי";
619
+ readonly group: "Wellness and beauty";
620
+ readonly uupm: "32 Beauty/Spa/Wellness Service (salon keyword)";
621
+ readonly match: readonly ["salon", "hair", "nails", "beauty", "lashes", "מספרה", "סלון", "ציפורניים", "קוסמטיקה"];
622
+ readonly good: readonly [{
623
+ readonly preset: "soft-spa";
624
+ readonly reason: "Elegant and soft for a beauty salon.";
625
+ }, {
626
+ readonly preset: "coral-studio";
627
+ readonly reason: "Bright and fun for a busy hair studio.";
628
+ }, {
629
+ readonly preset: "garden-party";
630
+ readonly reason: "Warm, friendly and a little romantic.";
631
+ }, {
632
+ readonly preset: "gallery-minimal";
633
+ readonly reason: "Minimal and chic, lets the cuts speak.";
634
+ }];
635
+ readonly colour: {
636
+ readonly mood: "soft pinks or warm coral";
637
+ readonly swatches: readonly ["#7D4E5E", "#E5484D", "#7D5260"];
638
+ };
639
+ readonly fonts: "elegant or friendly";
640
+ readonly tone: "Friendly, upbeat, short.";
641
+ readonly motion: "standard";
642
+ readonly moves: {
643
+ readonly scroll: "smooth";
644
+ readonly animate: "standard";
645
+ readonly between: "fade";
646
+ };
647
+ readonly imagery: "Your own before-and-after photos.";
648
+ readonly pages: readonly ["home", "services", "prices", "gallery", "contact"];
649
+ readonly needs: readonly ["services", "prices", "gallery", "contact"];
650
+ readonly home: readonly ["hero.split", "feature.triad", "collection.masonry-gallery", "cta.banner"];
651
+ readonly avoid: readonly [{
652
+ readonly when: {
653
+ readonly moods: readonly ["technical"];
654
+ };
655
+ readonly say: "A technical look feels clinical in a salon.";
656
+ }, {
657
+ readonly check: "needs-family";
658
+ readonly family: "collection";
659
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
660
+ }, {
661
+ readonly check: "needs-fact";
662
+ readonly fact: "hours";
663
+ readonly say: "People look for your opening hours first; a site without them sends them elsewhere.";
664
+ }];
665
+ readonly words: readonly ["cheap", "flawless"];
666
+ readonly structure: "practice";
667
+ readonly slice: true;
668
+ readonly stock: true;
669
+ readonly booking: "must";
670
+ }, {
671
+ readonly id: "yoga";
672
+ readonly label: "Yoga or pilates studio";
673
+ readonly he: "סטודיו ליוגה / פילאטיס";
674
+ readonly group: "Wellness and beauty";
675
+ readonly uupm: "141 Yoga & Stretching Guide (app)";
676
+ readonly match: readonly ["yoga", "pilates", "meditation", "יוגה", "פילאטיס", "מדיטציה"];
677
+ readonly good: readonly [{
678
+ readonly preset: "morning-glass";
679
+ readonly reason: "Fresh air and soft light, like a morning class.";
680
+ }, {
681
+ readonly preset: "soft-spa";
682
+ readonly reason: "Calm and warm.";
683
+ }, {
684
+ readonly preset: "kind-community";
685
+ readonly reason: "Open and welcoming for a community studio.";
686
+ }, {
687
+ readonly preset: "fresh-practice";
688
+ readonly reason: "Light and gentle.";
689
+ }];
690
+ readonly colour: {
691
+ readonly mood: "sage, terracotta, cream";
692
+ readonly swatches: readonly ["#0E8A89", "#5E6B3A", "#9A4F2B"];
693
+ };
694
+ readonly fonts: "warm, humanist";
695
+ readonly tone: "Gentle and inviting; who it is for.";
696
+ readonly motion: "calm";
697
+ readonly moves: {
698
+ readonly scroll: "extra";
699
+ readonly animate: "subtle";
700
+ readonly between: "fade";
701
+ };
702
+ readonly imagery: "The room, real classes, daylight.";
703
+ readonly pages: readonly ["home", "classes", "schedule", "teachers", "prices", "contact"];
704
+ readonly needs: readonly ["prices", "contact"];
705
+ readonly home: readonly ["hero.split", "feature.triad", "pricing.tiers", "faq.accordion", "cta.banner"];
706
+ readonly avoid: readonly [{
707
+ readonly when: {
708
+ readonly moods: readonly ["bold"];
709
+ };
710
+ readonly say: "Bold, loud design fights the calm a class promises.";
711
+ }, {
712
+ readonly when: {
713
+ readonly motion: readonly ["snappy", "lively"];
714
+ };
715
+ readonly say: "Fast, bouncy motion works against the calm people come for.";
716
+ }];
717
+ readonly words: readonly ["burn fat", "no pain no gain"];
718
+ readonly structure: "practice";
719
+ readonly slice: false;
720
+ readonly stock: true;
721
+ readonly booking: "must";
722
+ }, {
723
+ readonly id: "fitness";
724
+ readonly label: "Trainer, gym or dance";
725
+ readonly he: "מאמן/ת, חדר כושר, מחול";
726
+ readonly group: "Wellness and beauty";
727
+ readonly uupm: "35 Fitness/Gym App";
728
+ readonly match: readonly ["gym", "fitness", "trainer", "crossfit", "dance", "boxing", "כושר", "מאמן", "מחול", "ריקוד"];
729
+ readonly good: readonly [{
730
+ readonly preset: "coral-studio";
731
+ readonly reason: "Warm, energetic and bouncy.";
732
+ }, {
733
+ readonly preset: "fresh-market";
734
+ readonly reason: "Bright green energy.";
735
+ }, {
736
+ readonly preset: "after-dark";
737
+ readonly reason: "Dark and intense for a serious gym.";
738
+ }, {
739
+ readonly preset: "bold-maker";
740
+ readonly reason: "Loud and direct.";
741
+ }, {
742
+ readonly preset: "festival";
743
+ readonly reason: "Poster energy for a dance or boxing studio.";
744
+ }];
745
+ readonly colour: {
746
+ readonly mood: "energetic orange or green";
747
+ readonly swatches: readonly ["#E5484D", "#00B86B", "#EA580C"];
748
+ };
749
+ readonly fonts: "bold, motivational";
750
+ readonly tone: "Short, motivating, active verbs.";
751
+ readonly motion: "lively";
752
+ readonly moves: {
753
+ readonly scroll: "normal";
754
+ readonly animate: "lively";
755
+ readonly between: "slide";
756
+ };
757
+ readonly imagery: "Real people training; movement.";
758
+ readonly pages: readonly ["home", "classes", "prices", "coaches", "contact"];
759
+ readonly needs: readonly ["prices", "contact"];
760
+ readonly home: readonly ["hero.full-bleed-media", "feature.triad", "pricing.tiers", "proof.testimonial-carousel", "cta.banner"];
761
+ readonly avoid: readonly [{
762
+ readonly when: {
763
+ readonly motion: readonly ["off", "calm"];
764
+ };
765
+ readonly say: "A still, slow site feels low-energy for training.";
766
+ }, {
767
+ readonly when: {
768
+ readonly moods: readonly ["luxurious"];
769
+ };
770
+ readonly say: "Hushed luxury can feel unwelcoming to beginners.";
771
+ }];
772
+ readonly words: readonly ["guaranteed results", "lose 10 kilos"];
773
+ readonly structure: "practice";
774
+ readonly slice: false;
775
+ readonly stock: true;
776
+ readonly booking: "must";
777
+ }, {
778
+ readonly id: "therapist";
779
+ readonly label: "Therapist or counsellor";
780
+ readonly he: "מטפל/ת";
781
+ readonly group: "Wellness and beauty";
782
+ readonly uupm: "22 Mental Health App (nearest)";
783
+ readonly match: readonly ["therapist", "therapy", "psychologist", "counsellor", "counselor", "מטפל", "פסיכולוג", "טיפול רגשי"];
784
+ readonly good: readonly [{
785
+ readonly preset: "fresh-practice";
786
+ readonly reason: "Soft and reassuring; nothing sharp.";
787
+ }, {
788
+ readonly preset: "morning-glass";
789
+ readonly reason: "Calm, light and open.";
790
+ }, {
791
+ readonly preset: "clear-care";
792
+ readonly reason: "Clear and professional.";
793
+ }, {
794
+ readonly preset: "kind-community";
795
+ readonly reason: "Warm and human.";
796
+ }];
797
+ readonly colour: {
798
+ readonly mood: "calm pastels and trust colours";
799
+ readonly swatches: readonly ["#0284C7", "#0E8A89", "#3B6939"];
800
+ };
801
+ readonly fonts: "calming, readable";
802
+ readonly tone: "Gentle, plain, never salesy.";
803
+ readonly motion: "calm";
804
+ readonly moves: {
805
+ readonly scroll: "normal";
806
+ readonly animate: "subtle";
807
+ readonly between: "none";
808
+ };
809
+ readonly imagery: "A calm room, daylight; your portrait.";
810
+ readonly pages: readonly ["home", "how I work", "about", "faq", "contact"];
811
+ readonly needs: readonly ["collection", "about", "faq", "contact"];
812
+ readonly home: readonly ["hero.split", "feature.triad", "faq.accordion", "cta.banner"];
813
+ readonly avoid: readonly [{
814
+ readonly when: {
815
+ readonly moods: readonly ["bold", "energetic"];
816
+ };
817
+ readonly say: "Bright, loud design can feel overwhelming to someone looking for help.";
818
+ }, {
819
+ readonly when: {
820
+ readonly motion: readonly ["snappy", "lively"];
821
+ };
822
+ readonly say: "Fast, bouncy motion works against the calm people come for.";
823
+ }, {
824
+ readonly check: "no-pattern";
825
+ readonly pattern: "proof.testimonial-carousel";
826
+ readonly say: "Client quotes can reveal who saw you; ask before showing any.";
827
+ }];
828
+ readonly words: readonly ["fix", "cure", "guaranteed"];
829
+ readonly structure: "practice";
830
+ readonly slice: false;
831
+ readonly stock: true;
832
+ readonly booking: "must";
833
+ }, {
834
+ readonly id: "clinic";
835
+ readonly label: "Clinic or practice";
836
+ readonly he: "מרפאה";
837
+ readonly group: "Health";
838
+ readonly uupm: "58 Medical Clinic";
839
+ readonly match: readonly ["clinic", "doctor", "physio", "physiotherapy", "medical", "מרפאה", "רופא", "פיזיותרפיה"];
840
+ readonly good: readonly [{
841
+ readonly preset: "clear-care";
842
+ readonly reason: "Clean and readable; trust first.";
843
+ }, {
844
+ readonly preset: "fresh-practice";
845
+ readonly reason: "Friendly, light and calm.";
846
+ }, {
847
+ readonly preset: "trusted-advisor";
848
+ readonly reason: "Firm and professional.";
849
+ }, {
850
+ readonly preset: "morning-glass";
851
+ readonly reason: "Modern and calm.";
852
+ }];
853
+ readonly colour: {
854
+ readonly mood: "medical blue and white";
855
+ readonly swatches: readonly ["#0E7490", "#0284C7", "#1E3A8A"];
856
+ };
857
+ readonly fonts: "professional, readable";
858
+ readonly tone: "Clear and plain; what you treat, how to book.";
859
+ readonly motion: "standard";
860
+ readonly moves: {
861
+ readonly scroll: "normal";
862
+ readonly animate: "subtle";
863
+ readonly between: "fade";
864
+ };
865
+ readonly imagery: "Your team and rooms; no stock doctors.";
866
+ readonly pages: readonly ["home", "treatments (services)", "team", "faq", "contact"];
867
+ readonly needs: readonly ["services", "team", "faq", "contact"];
868
+ readonly home: readonly ["hero.split", "feature.triad", "faq.accordion", "cta.banner"];
869
+ readonly avoid: readonly [{
870
+ readonly when: {
871
+ readonly moods: readonly ["playful"];
872
+ };
873
+ readonly say: "Playful design can make patients doubt the care.";
874
+ }, {
875
+ readonly check: "brand-hue";
876
+ readonly from: 270;
877
+ readonly to: 335;
878
+ readonly minChroma: 0.12;
879
+ readonly say: "A purple-pink brand is the colour of AI tools right now; on this kind of site it can read as generic.";
880
+ }, {
881
+ readonly check: "needs-fact";
882
+ readonly fact: "phone";
883
+ readonly say: "A phone number is the first thing people need here.";
884
+ }, {
885
+ readonly check: "needs-fact";
886
+ readonly fact: "hours";
887
+ readonly say: "People look for your opening hours first; a site without them sends them elsewhere.";
888
+ }];
889
+ readonly words: readonly ["cure", "guaranteed", "miracle", "best in town"];
890
+ readonly structure: "practice";
891
+ readonly slice: true;
892
+ readonly stock: true;
893
+ readonly booking: "must";
894
+ }, {
895
+ readonly id: "dental";
896
+ readonly label: "Dental practice";
897
+ readonly he: "מרפאת שיניים";
898
+ readonly group: "Health";
899
+ readonly uupm: "60 Dental Practice";
900
+ readonly match: readonly ["dental", "dentist", "orthodont", "שיניים", "רופא שיניים"];
901
+ readonly good: readonly [{
902
+ readonly preset: "fresh-practice";
903
+ readonly reason: "Fresh blue and soft shapes: a friendly smile.";
904
+ }, {
905
+ readonly preset: "clear-care";
906
+ readonly reason: "Clean and trustworthy.";
907
+ }, {
908
+ readonly preset: "morning-glass";
909
+ readonly reason: "Bright and modern.";
910
+ }];
911
+ readonly colour: {
912
+ readonly mood: "fresh blue, white, a touch of yellow";
913
+ readonly swatches: readonly ["#0284C7", "#0E7490", "#0E8A89"];
914
+ };
915
+ readonly fonts: "friendly, professional";
916
+ readonly tone: "Reassuring, plain.";
917
+ readonly motion: "standard";
918
+ readonly moves: {
919
+ readonly scroll: "normal";
920
+ readonly animate: "subtle";
921
+ readonly between: "fade";
922
+ };
923
+ readonly imagery: "Your clinic and team.";
924
+ readonly pages: readonly ["home", "treatments", "team", "faq", "contact"];
925
+ readonly needs: readonly ["services", "team", "faq", "contact"];
926
+ readonly home: readonly ["hero.split", "feature.triad", "proof.testimonial-carousel", "faq.accordion", "cta.banner"];
927
+ readonly avoid: readonly [{
928
+ readonly when: {
929
+ readonly mode: readonly ["dark"];
930
+ };
931
+ readonly say: "Dark pages feel heavy for a dental practice.";
932
+ }, {
933
+ readonly check: "needs-fact";
934
+ readonly fact: "phone";
935
+ readonly say: "A phone number is the first thing people need here.";
936
+ }, {
937
+ readonly check: "needs-fact";
938
+ readonly fact: "hours";
939
+ readonly say: "People look for your opening hours first; a site without them sends them elsewhere.";
940
+ }];
941
+ readonly words: readonly ["painless", "guaranteed", "perfect smile"];
942
+ readonly structure: "practice";
943
+ readonly slice: false;
944
+ readonly stock: true;
945
+ readonly booking: "must";
946
+ }, {
947
+ readonly id: "vet";
948
+ readonly label: "Vet or pet care";
949
+ readonly he: "וטרינר / טיפוח חיות";
950
+ readonly group: "Health";
951
+ readonly uupm: "61 Veterinary Clinic";
952
+ readonly match: readonly ["vet", "veterinary", "pet", "dog", "groom", "וטרינר", "כלבים", "חיות"];
953
+ readonly good: readonly [{
954
+ readonly preset: "little-ones";
955
+ readonly reason: "Round, warm and playful.";
956
+ }, {
957
+ readonly preset: "kind-community";
958
+ readonly reason: "Friendly and caring.";
959
+ }, {
960
+ readonly preset: "fresh-practice";
961
+ readonly reason: "Clean and reassuring for a clinic.";
962
+ }, {
963
+ readonly preset: "clear-care";
964
+ readonly reason: "Professional, for a medical practice.";
965
+ }];
966
+ readonly colour: {
967
+ readonly mood: "caring blue or teal, warm accents";
968
+ readonly swatches: readonly ["#006A6A", "#3B6939", "#0284C7"];
969
+ };
970
+ readonly fonts: "friendly, welcoming";
971
+ readonly tone: "Warm, practical.";
972
+ readonly motion: "standard";
973
+ readonly moves: {
974
+ readonly scroll: "normal";
975
+ readonly animate: "standard";
976
+ readonly between: "fade";
977
+ };
978
+ readonly imagery: "Real animals you treat (with permission).";
979
+ readonly pages: readonly ["home", "services", "team", "faq", "contact"];
980
+ readonly needs: readonly ["services", "team", "faq", "contact"];
981
+ readonly home: readonly ["hero.split", "feature.triad", "faq.accordion", "cta.banner"];
982
+ readonly avoid: readonly [{
983
+ readonly when: {
984
+ readonly mode: readonly ["dark"];
985
+ };
986
+ readonly say: "Dark pages feel unfriendly for pet owners.";
987
+ }, {
988
+ readonly check: "needs-fact";
989
+ readonly fact: "phone";
990
+ readonly say: "A phone number is the first thing people need here.";
991
+ }];
992
+ readonly words: readonly ["guaranteed", "cure"];
993
+ readonly structure: "practice";
994
+ readonly slice: false;
995
+ readonly stock: true;
996
+ readonly booking: "must";
997
+ }, {
998
+ readonly id: "restaurant";
999
+ readonly label: "Restaurant";
1000
+ readonly he: "מסעדה";
1001
+ readonly group: "Food and drink";
1002
+ readonly uupm: "34 Restaurant/Food Service";
1003
+ readonly match: readonly ["restaurant", "bistro", "kitchen", "chef", "מסעדה", "שף", "ביסטרו"];
1004
+ readonly good: readonly [{
1005
+ readonly preset: "warm-editorial";
1006
+ readonly reason: "Warm paper and serif, like a printed menu.";
1007
+ }, {
1008
+ readonly preset: "corner-cafe";
1009
+ readonly reason: "Friendly and casual.";
1010
+ }, {
1011
+ readonly preset: "after-dark";
1012
+ readonly reason: "Dark and lively for an evening place.";
1013
+ }, {
1014
+ readonly preset: "quiet-luxury";
1015
+ readonly reason: "For fine dining.";
1016
+ }];
1017
+ readonly colour: {
1018
+ readonly mood: "warm — orange, red, brown";
1019
+ readonly swatches: readonly ["#9A4F2B", "#9C4146", "#7A5B36"];
1020
+ };
1021
+ readonly fonts: "appetising, clear";
1022
+ readonly tone: "Inviting, sensory, short.";
1023
+ readonly motion: "standard";
1024
+ readonly moves: {
1025
+ readonly scroll: "smooth";
1026
+ readonly animate: "standard";
1027
+ readonly between: "fade";
1028
+ };
1029
+ readonly imagery: "Your own food and room photos.";
1030
+ readonly pages: readonly ["home", "menu", "about", "contact"];
1031
+ readonly needs: readonly ["menu", "about", "contact"];
1032
+ readonly home: readonly ["hero.full-bleed-media", "feature.triad", "proof.testimonial-carousel", "contact.split-map", "cta.banner"];
1033
+ readonly avoid: readonly [{
1034
+ readonly when: {
1035
+ readonly moods: readonly ["technical"];
1036
+ };
1037
+ readonly say: "A cold, technical look kills appetite.";
1038
+ }, {
1039
+ readonly check: "needs-fact";
1040
+ readonly fact: "hours";
1041
+ readonly say: "People look for your opening hours first; a site without them sends them elsewhere.";
1042
+ }, {
1043
+ readonly check: "needs-fact";
1044
+ readonly fact: "address";
1045
+ readonly say: "Visitors need the address to find you.";
1046
+ }, {
1047
+ readonly check: "image-hero";
1048
+ readonly say: "Lead with a picture: the first screen should show the place or the work, not only words.";
1049
+ }];
1050
+ readonly words: readonly ["best food in town", "world-class", "mouth-watering"];
1051
+ readonly structure: "place";
1052
+ readonly slice: false;
1053
+ readonly stock: true;
1054
+ readonly booking: "tables";
1055
+ }, {
1056
+ readonly id: "cafe-bakery";
1057
+ readonly label: "Café or bakery";
1058
+ readonly he: "בית קפה / מאפייה";
1059
+ readonly group: "Food and drink";
1060
+ readonly uupm: "63 Bakery/Cafe";
1061
+ readonly match: readonly ["cafe", "café", "coffee", "bakery", "patisserie", "בית קפה", "קפה", "מאפייה", "קונדיטוריה"];
1062
+ readonly good: readonly [{
1063
+ readonly preset: "corner-cafe";
1064
+ readonly reason: "Warm, round and cheerful.";
1065
+ }, {
1066
+ readonly preset: "warm-editorial";
1067
+ readonly reason: "Cream and brown, like a paper bag.";
1068
+ }, {
1069
+ readonly preset: "fresh-market";
1070
+ readonly reason: "Bright and fresh for a juice or brunch spot.";
1071
+ }, {
1072
+ readonly preset: "garden-party";
1073
+ readonly reason: "Soft and sweet for a patisserie.";
1074
+ }];
1075
+ readonly colour: {
1076
+ readonly mood: "warm brown, cream, appetising accents";
1077
+ readonly swatches: readonly ["#9C4146", "#9A4F2B", "#7D5260"];
1078
+ };
1079
+ readonly fonts: "warm, inviting";
1080
+ readonly tone: "Friendly, short, a little playful.";
1081
+ readonly motion: "standard";
1082
+ readonly moves: {
1083
+ readonly scroll: "smooth";
1084
+ readonly animate: "standard";
1085
+ readonly between: "slide";
1086
+ };
1087
+ readonly imagery: "Your bakes and drinks, close up.";
1088
+ readonly pages: readonly ["home", "menu", "about", "contact"];
1089
+ readonly needs: readonly ["menu", "about", "contact"];
1090
+ readonly home: readonly ["hero.split", "feature.triad", "collection.masonry-gallery", "cta.banner"];
1091
+ readonly avoid: readonly [{
1092
+ readonly when: {
1093
+ readonly mode: readonly ["dark"];
1094
+ };
1095
+ readonly say: "A café is a daytime place; dark pages feel closed.";
1096
+ }, {
1097
+ readonly check: "needs-fact";
1098
+ readonly fact: "hours";
1099
+ readonly say: "People look for your opening hours first; a site without them sends them elsewhere.";
1100
+ }, {
1101
+ readonly check: "needs-fact";
1102
+ readonly fact: "address";
1103
+ readonly say: "Visitors need the address to find you.";
1104
+ }];
1105
+ readonly words: readonly ["best coffee in town", "to die for"];
1106
+ readonly structure: "place";
1107
+ readonly slice: true;
1108
+ readonly stock: true;
1109
+ readonly booking: "none";
1110
+ }, {
1111
+ readonly id: "bar-winery";
1112
+ readonly label: "Bar, winery or brewery";
1113
+ readonly he: "בר / יקב / מבשלה";
1114
+ readonly group: "Food and drink";
1115
+ readonly uupm: "64 Brewery/Winery";
1116
+ readonly match: readonly ["bar", "wine", "winery", "brewery", "cocktail", "יקב", "בר", "יין", "בירה"];
1117
+ readonly good: readonly [{
1118
+ readonly preset: "quiet-luxury";
1119
+ readonly reason: "Bronze and serif, like a good label.";
1120
+ }, {
1121
+ readonly preset: "after-dark";
1122
+ readonly reason: "Dark and lively, open late.";
1123
+ }, {
1124
+ readonly preset: "warm-editorial";
1125
+ readonly reason: "Heritage and story.";
1126
+ }, {
1127
+ readonly preset: "ink-studio";
1128
+ readonly reason: "Craft-beer attitude.";
1129
+ }];
1130
+ readonly colour: {
1131
+ readonly mood: "deep amber, burgundy, gold";
1132
+ readonly swatches: readonly ["#7A5B36", "#9C4146", "#DB2777"];
1133
+ };
1134
+ readonly fonts: "artisanal, heritage";
1135
+ readonly tone: "Story-led: the place, the people, the craft.";
1136
+ readonly motion: "calm";
1137
+ readonly moves: {
1138
+ readonly scroll: "smooth";
1139
+ readonly animate: "subtle";
1140
+ readonly between: "cinematic";
1141
+ };
1142
+ readonly imagery: "The cellar, the bar, the bottle.";
1143
+ readonly pages: readonly ["home", "menu or wines", "our story", "visit", "contact"];
1144
+ readonly needs: readonly ["menu", "visit", "contact"];
1145
+ readonly home: readonly ["hero.full-bleed-media", "about.story", "collection.card-grid", "cta.banner"];
1146
+ readonly avoid: readonly [{
1147
+ readonly when: {
1148
+ readonly flavor: readonly ["bloom"];
1149
+ };
1150
+ readonly say: "Round, bouncy design reads as a kids' brand, not a cellar.";
1151
+ }, {
1152
+ readonly check: "needs-fact";
1153
+ readonly fact: "hours";
1154
+ readonly say: "People look for your opening hours first; a site without them sends them elsewhere.";
1155
+ }, {
1156
+ readonly check: "needs-fact";
1157
+ readonly fact: "address";
1158
+ readonly say: "Visitors need the address to find you.";
1159
+ }];
1160
+ readonly words: readonly ["best wine", "award-winning (unless you are)"];
1161
+ readonly structure: "place";
1162
+ readonly slice: false;
1163
+ readonly stock: true;
1164
+ readonly booking: "none";
1165
+ }, {
1166
+ readonly id: "boutique";
1167
+ readonly label: "Fashion or lifestyle shop";
1168
+ readonly he: "בוטיק";
1169
+ readonly group: "Shops";
1170
+ readonly uupm: "3 E-commerce · 4 E-commerce Luxury";
1171
+ readonly match: readonly ["boutique", "fashion", "clothing", "shop", "store", "בוטיק", "אופנה", "חנות"];
1172
+ readonly good: readonly [{
1173
+ readonly preset: "gallery-minimal";
1174
+ readonly reason: "Clean and chic; the products lead.";
1175
+ }, {
1176
+ readonly preset: "quiet-luxury";
1177
+ readonly reason: "Premium and calm.";
1178
+ }, {
1179
+ readonly preset: "bold-maker";
1180
+ readonly reason: "A brand with a loud voice.";
1181
+ }, {
1182
+ readonly preset: "zine";
1183
+ readonly reason: "Indie and edgy.";
1184
+ }];
1185
+ readonly colour: {
1186
+ readonly mood: "your brand colour on a quiet page";
1187
+ readonly swatches: readonly ["#3F4A5A", "#7A5B36", "#FF5C39"];
1188
+ };
1189
+ readonly fonts: "refined or bold";
1190
+ readonly tone: "Short and confident.";
1191
+ readonly motion: "standard";
1192
+ readonly moves: {
1193
+ readonly scroll: "smooth";
1194
+ readonly animate: "standard";
1195
+ readonly between: "slide";
1196
+ };
1197
+ readonly imagery: "Product photos on plain grounds; real people wearing them.";
1198
+ readonly pages: readonly ["home", "collection", "product (detail)", "about", "contact"];
1199
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
1200
+ readonly home: readonly ["hero.split", "collection.card-grid", "proof.logo-strip", "cta.banner"];
1201
+ readonly avoid: readonly [{
1202
+ readonly check: "copy-length";
1203
+ readonly max: "standard";
1204
+ readonly say: "Text-heavy pages slow down shoppers.";
1205
+ }, {
1206
+ readonly check: "needs-family";
1207
+ readonly family: "collection";
1208
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
1209
+ }];
1210
+ readonly words: readonly ["cheap", "must-have"];
1211
+ readonly structure: "studio";
1212
+ readonly slice: false;
1213
+ readonly stock: true;
1214
+ readonly booking: "none";
1215
+ }, {
1216
+ readonly id: "florist";
1217
+ readonly label: "Florist or plant shop";
1218
+ readonly he: "חנות פרחים";
1219
+ readonly group: "Shops";
1220
+ readonly uupm: "62 Florist/Plant Shop";
1221
+ readonly match: readonly ["florist", "flowers", "plants", "bouquet", "פרחים", "צמחים", "זרים"];
1222
+ readonly good: readonly [{
1223
+ readonly preset: "garden-party";
1224
+ readonly reason: "Soft, romantic and full of colour.";
1225
+ }, {
1226
+ readonly preset: "kind-community";
1227
+ readonly reason: "Leaf green and friendly.";
1228
+ }, {
1229
+ readonly preset: "fresh-market";
1230
+ readonly reason: "Bright, like a flower stall.";
1231
+ }, {
1232
+ readonly preset: "soft-spa";
1233
+ readonly reason: "Elegant for a design florist.";
1234
+ }];
1235
+ readonly colour: {
1236
+ readonly mood: "natural green with floral pinks";
1237
+ readonly swatches: readonly ["#3B6939", "#7D5260", "#00B86B"];
1238
+ };
1239
+ readonly fonts: "elegant, natural";
1240
+ readonly tone: "Seasonal, warm.";
1241
+ readonly motion: "standard";
1242
+ readonly moves: {
1243
+ readonly scroll: "smooth";
1244
+ readonly animate: "standard";
1245
+ readonly between: "fade";
1246
+ };
1247
+ readonly imagery: "Your own arrangements in daylight.";
1248
+ readonly pages: readonly ["home", "flowers (collection)", "weddings and events", "about", "contact"];
1249
+ readonly needs: readonly ["collection", "about", "contact"];
1250
+ readonly home: readonly ["hero.split", "collection.masonry-gallery", "feature.triad", "cta.banner"];
1251
+ readonly avoid: readonly [{
1252
+ readonly when: {
1253
+ readonly mode: readonly ["dark"];
1254
+ };
1255
+ readonly say: "Flowers lose their colour on a dark page.";
1256
+ }, {
1257
+ readonly check: "needs-family";
1258
+ readonly family: "collection";
1259
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
1260
+ }];
1261
+ readonly words: readonly ["cheap", "best prices"];
1262
+ readonly structure: "studio";
1263
+ readonly slice: false;
1264
+ readonly stock: true;
1265
+ readonly booking: "none";
1266
+ }, {
1267
+ readonly id: "home-goods";
1268
+ readonly label: "Furniture or home goods";
1269
+ readonly he: "רהיטים ועיצוב הבית";
1270
+ readonly group: "Shops";
1271
+ readonly uupm: "161 Home Decoration & Interior Design";
1272
+ readonly match: readonly ["furniture", "home goods", "homeware", "decor shop", "רהיטים", "כלי בית"];
1273
+ readonly good: readonly [{
1274
+ readonly preset: "warm-editorial";
1275
+ readonly reason: "Warm and tactile, like a catalogue.";
1276
+ }, {
1277
+ readonly preset: "gallery-minimal";
1278
+ readonly reason: "Clean and calm; each piece stands alone.";
1279
+ }, {
1280
+ readonly preset: "quiet-luxury";
1281
+ readonly reason: "Premium pieces deserve it.";
1282
+ }, {
1283
+ readonly preset: "frosted-portfolio";
1284
+ readonly reason: "Soft glass and space.";
1285
+ }];
1286
+ readonly colour: {
1287
+ readonly mood: "neutral interior palette, a material accent";
1288
+ readonly swatches: readonly ["#78716C", "#9A4F2B", "#7A5B36"];
1289
+ };
1290
+ readonly fonts: "professional, clean";
1291
+ readonly tone: "Clear and specific: size, material, care.";
1292
+ readonly motion: "calm";
1293
+ readonly moves: {
1294
+ readonly scroll: "smooth";
1295
+ readonly animate: "subtle";
1296
+ readonly between: "fade";
1297
+ };
1298
+ readonly imagery: "Pieces in real rooms and on plain grounds.";
1299
+ readonly pages: readonly ["home", "collection", "product (detail)", "about", "contact"];
1300
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
1301
+ readonly home: readonly ["hero.split", "collection.card-grid", "feature.alternating-rows", "cta.banner"];
1302
+ readonly avoid: readonly [{
1303
+ readonly when: {
1304
+ readonly moods: readonly ["playful"];
1305
+ };
1306
+ readonly say: "Excessive decoration distracts from the pieces.";
1307
+ }, {
1308
+ readonly check: "needs-family";
1309
+ readonly family: "collection";
1310
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
1311
+ }];
1312
+ readonly words: readonly ["luxury", "cheap"];
1313
+ readonly structure: "studio";
1314
+ readonly slice: false;
1315
+ readonly stock: true;
1316
+ readonly booking: "none";
1317
+ }, {
1318
+ readonly id: "consultant";
1319
+ readonly label: "Consultant";
1320
+ readonly he: "יועץ/ת";
1321
+ readonly group: "Professional services";
1322
+ readonly uupm: "5 B2B Service (consult keyword)";
1323
+ readonly match: readonly ["consult", "consultant", "advisor", "strategy", "יועץ", "ייעוץ"];
1324
+ readonly good: readonly [{
1325
+ readonly preset: "trusted-advisor";
1326
+ readonly reason: "Navy and plain type: serious and clear.";
1327
+ }, {
1328
+ readonly preset: "swiss-grid";
1329
+ readonly reason: "Sharp and modern.";
1330
+ }, {
1331
+ readonly preset: "tech-studio";
1332
+ readonly reason: "For tech and data consultants.";
1333
+ }, {
1334
+ readonly preset: "clear-care";
1335
+ readonly reason: "Light and approachable.";
1336
+ }];
1337
+ readonly colour: {
1338
+ readonly mood: "professional blue and neutral grey";
1339
+ readonly swatches: readonly ["#1E3A8A", "#111827", "#0E7490"];
1340
+ };
1341
+ readonly fonts: "formal, clear";
1342
+ readonly tone: "Plain and specific: problems you solve, results.";
1343
+ readonly motion: "standard";
1344
+ readonly moves: {
1345
+ readonly scroll: "normal";
1346
+ readonly animate: "subtle";
1347
+ readonly between: "fade";
1348
+ };
1349
+ readonly imagery: "Your portrait; diagrams over stock.";
1350
+ readonly pages: readonly ["home", "services", "case studies", "about", "contact"];
1351
+ readonly needs: readonly ["services", "about", "contact"];
1352
+ readonly home: readonly ["hero.split", "feature.triad", "proof.stat-row", "proof.testimonial-carousel", "cta.banner"];
1353
+ readonly avoid: readonly [{
1354
+ readonly when: {
1355
+ readonly moods: readonly ["playful"];
1356
+ };
1357
+ readonly say: "Playful reads as unserious to a client buying advice.";
1358
+ }, {
1359
+ readonly check: "brand-hue";
1360
+ readonly from: 270;
1361
+ readonly to: 335;
1362
+ readonly minChroma: 0.12;
1363
+ readonly say: "A purple-pink brand is the colour of AI tools right now; on this kind of site it can read as generic.";
1364
+ }];
1365
+ readonly words: readonly ["synergy", "guaranteed ROI", "world-class"];
1366
+ readonly structure: "practice";
1367
+ readonly slice: true;
1368
+ readonly stock: true;
1369
+ readonly booking: "sometimes";
1370
+ }, {
1371
+ readonly id: "coach";
1372
+ readonly label: "Life or business coach";
1373
+ readonly he: "מאמן/ת אישי/ת";
1374
+ readonly group: "Professional services";
1375
+ readonly uupm: "no row";
1376
+ readonly match: readonly ["life coach", "business coach", "mentor", "coaching", "מאמנת", "אימון אישי", "קואצ'ינג"];
1377
+ readonly good: readonly [{
1378
+ readonly preset: "morning-glass";
1379
+ readonly reason: "Fresh and hopeful.";
1380
+ }, {
1381
+ readonly preset: "trusted-advisor";
1382
+ readonly reason: "Credible for business coaching.";
1383
+ }, {
1384
+ readonly preset: "warm-editorial";
1385
+ readonly reason: "Warm and personal, story-led.";
1386
+ }, {
1387
+ readonly preset: "coral-studio";
1388
+ readonly reason: "Energetic and upbeat.";
1389
+ }];
1390
+ readonly colour: {
1391
+ readonly mood: "warm and hopeful";
1392
+ readonly swatches: readonly ["#0E8A89", "#E5484D", "#1E3A8A"];
1393
+ };
1394
+ readonly fonts: "warm, clear";
1395
+ readonly tone: "Personal, encouraging, first person.";
1396
+ readonly motion: "standard";
1397
+ readonly moves: {
1398
+ readonly scroll: "smooth";
1399
+ readonly animate: "standard";
1400
+ readonly between: "fade";
1401
+ };
1402
+ readonly imagery: "Your portrait, working with people.";
1403
+ readonly pages: readonly ["home", "how it works", "programmes", "about", "contact"];
1404
+ readonly needs: readonly ["collection", "about", "contact"];
1405
+ readonly home: readonly ["hero.split", "feature.triad", "pricing.tiers", "faq.accordion", "cta.banner"];
1406
+ readonly avoid: readonly [{
1407
+ readonly when: {
1408
+ readonly moods: readonly ["technical"];
1409
+ };
1410
+ readonly say: "A cold, technical look is the opposite of personal.";
1411
+ }];
1412
+ readonly words: readonly ["life-changing", "guaranteed"];
1413
+ readonly structure: "practice";
1414
+ readonly slice: false;
1415
+ readonly stock: true;
1416
+ readonly booking: "must";
1417
+ }, {
1418
+ readonly id: "law-accounting";
1419
+ readonly label: "Law or accounting firm";
1420
+ readonly he: "משרד עורכי דין / רואי חשבון";
1421
+ readonly group: "Professional services";
1422
+ readonly uupm: "40 Legal Services";
1423
+ readonly match: readonly ["law", "lawyer", "attorney", "legal", "accountant", "accounting", "עורך דין", "עורכת דין", "רואה חשבון", "משפט"];
1424
+ readonly good: readonly [{
1425
+ readonly preset: "trusted-advisor";
1426
+ readonly reason: "Navy and gold: authority without fuss.";
1427
+ }, {
1428
+ readonly preset: "swiss-grid";
1429
+ readonly reason: "Precise and modern.";
1430
+ }, {
1431
+ readonly preset: "clear-care";
1432
+ readonly reason: "Clear and approachable.";
1433
+ }, {
1434
+ readonly preset: "quiet-luxury";
1435
+ readonly reason: "For a boutique firm.";
1436
+ }];
1437
+ readonly colour: {
1438
+ readonly mood: "navy, gold, white";
1439
+ readonly swatches: readonly ["#1E3A8A", "#111827", "#7A5B36"];
1440
+ };
1441
+ readonly fonts: "professional, authoritative";
1442
+ readonly tone: "Formal, exact, no promises you cannot keep.";
1443
+ readonly motion: "calm";
1444
+ readonly moves: {
1445
+ readonly scroll: "normal";
1446
+ readonly animate: "still";
1447
+ readonly between: "none";
1448
+ };
1449
+ readonly imagery: "Your team; your office.";
1450
+ readonly pages: readonly ["home", "practice areas (services)", "team", "about", "contact"];
1451
+ readonly needs: readonly ["services", "team", "about", "contact"];
1452
+ readonly home: readonly ["hero.split", "feature.triad", "proof.stat-row", "cta.banner"];
1453
+ readonly avoid: readonly [{
1454
+ readonly when: {
1455
+ readonly flavor: readonly ["pop", "bloom"];
1456
+ };
1457
+ readonly say: "Playful design undermines the trust clients need.";
1458
+ }, {
1459
+ readonly when: {
1460
+ readonly motion: readonly ["lively"];
1461
+ };
1462
+ readonly say: "Bouncy motion feels out of place for legal or financial advice.";
1463
+ }, {
1464
+ readonly check: "brand-hue";
1465
+ readonly from: 270;
1466
+ readonly to: 335;
1467
+ readonly minChroma: 0.12;
1468
+ readonly say: "A purple-pink brand is the colour of AI tools right now; on this kind of site it can read as generic.";
1469
+ }];
1470
+ readonly words: readonly ["guarantee", "win your case", "best lawyer"];
1471
+ readonly structure: "practice";
1472
+ readonly slice: false;
1473
+ readonly stock: true;
1474
+ readonly booking: "sometimes";
1475
+ }, {
1476
+ readonly id: "real-estate";
1477
+ readonly label: "Real estate agent";
1478
+ readonly he: "נדל\"ן";
1479
+ readonly group: "Professional services";
1480
+ readonly uupm: "36 Real Estate/Property";
1481
+ readonly match: readonly ["real estate", "realtor", "property", "apartments", "נדל\"ן", "נדלן", "דירות"];
1482
+ readonly good: readonly [{
1483
+ readonly preset: "holiday-light";
1484
+ readonly reason: "Bright glass and big photos.";
1485
+ }, {
1486
+ readonly preset: "trusted-advisor";
1487
+ readonly reason: "Professional and trustworthy.";
1488
+ }, {
1489
+ readonly preset: "quiet-luxury";
1490
+ readonly reason: "For luxury property.";
1491
+ }, {
1492
+ readonly preset: "frosted-portfolio";
1493
+ readonly reason: "Clean and modern.";
1494
+ }];
1495
+ readonly colour: {
1496
+ readonly mood: "trust blue, gold, white";
1497
+ readonly swatches: readonly ["#0A66E8", "#1E3A8A", "#7A5B36"];
1498
+ };
1499
+ readonly fonts: "professional, confident";
1500
+ readonly tone: "Clear and factual.";
1501
+ readonly motion: "standard";
1502
+ readonly moves: {
1503
+ readonly scroll: "smooth";
1504
+ readonly animate: "standard";
1505
+ readonly between: "slide";
1506
+ };
1507
+ readonly imagery: "Your own property photos; never stock.";
1508
+ readonly pages: readonly ["home", "properties (collection)", "property (detail)", "about", "contact"];
1509
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
1510
+ readonly home: readonly ["hero.full-bleed-media", "collection.card-grid", "proof.testimonial-carousel", "contact.split-map"];
1511
+ readonly avoid: readonly [{
1512
+ readonly when: {
1513
+ readonly moods: readonly ["playful"];
1514
+ };
1515
+ readonly say: "Playful design doesn't fit a large purchase.";
1516
+ }, {
1517
+ readonly check: "image-hero";
1518
+ readonly say: "Lead with a picture: the first screen should show the place or the work, not only words.";
1519
+ }, {
1520
+ readonly check: "needs-fact";
1521
+ readonly fact: "phone";
1522
+ readonly say: "A phone number is the first thing people need here.";
1523
+ }];
1524
+ readonly words: readonly ["dream home", "guaranteed", "once in a lifetime"];
1525
+ readonly structure: "studio";
1526
+ readonly slice: false;
1527
+ readonly stock: false;
1528
+ readonly booking: "sometimes";
1529
+ }, {
1530
+ readonly id: "nonprofit";
1531
+ readonly label: "Nonprofit or community";
1532
+ readonly he: "עמותה";
1533
+ readonly group: "Community and places";
1534
+ readonly uupm: "44 Non-profit/Charity";
1535
+ readonly match: readonly ["nonprofit", "non-profit", "charity", "ngo", "volunteer", "community", "עמותה", "מתנדבים", "קהילה"];
1536
+ readonly good: readonly [{
1537
+ readonly preset: "kind-community";
1538
+ readonly reason: "Warm, open and welcoming.";
1539
+ }, {
1540
+ readonly preset: "clear-care";
1541
+ readonly reason: "Clear and credible.";
1542
+ }, {
1543
+ readonly preset: "warm-editorial";
1544
+ readonly reason: "For telling stories.";
1545
+ }, {
1546
+ readonly preset: "little-ones";
1547
+ readonly reason: "For children's causes.";
1548
+ }];
1549
+ readonly colour: {
1550
+ readonly mood: "cause colours, trust, warmth";
1551
+ readonly swatches: readonly ["#3B6939", "#0E7490", "#9A4F2B"];
1552
+ };
1553
+ readonly fonts: "heartfelt, readable";
1554
+ readonly tone: "Honest, specific about impact.";
1555
+ readonly motion: "standard";
1556
+ readonly moves: {
1557
+ readonly scroll: "normal";
1558
+ readonly animate: "standard";
1559
+ readonly between: "fade";
1560
+ };
1561
+ readonly imagery: "Real people you help (with permission).";
1562
+ readonly pages: readonly ["home", "what we do", "stories", "get involved", "contact"];
1563
+ readonly needs: readonly ["contact"];
1564
+ readonly home: readonly ["hero.split", "proof.stat-row", "story.long-form", "cta.banner"];
1565
+ readonly avoid: readonly [{
1566
+ readonly when: {
1567
+ readonly moods: readonly ["luxurious"];
1568
+ };
1569
+ readonly say: "Looking expensive makes donors ask where the money goes.";
1570
+ }];
1571
+ readonly words: readonly ["donate now!!", "save the world"];
1572
+ readonly structure: "practice";
1573
+ readonly slice: false;
1574
+ readonly stock: true;
1575
+ readonly booking: "none";
1576
+ }, {
1577
+ readonly id: "venue-events";
1578
+ readonly label: "Venue, weddings or events";
1579
+ readonly he: "אולם, חתונות ואירועים";
1580
+ readonly group: "Community and places";
1581
+ readonly uupm: "39 Wedding/Event Planning · 70 Event Management";
1582
+ readonly match: readonly ["venue", "wedding", "events", "event", "hall", "festival", "אולם", "חתונות", "אירועים", "גן אירועים"];
1583
+ readonly good: readonly [{
1584
+ readonly preset: "garden-party";
1585
+ readonly reason: "Romantic and warm for weddings.";
1586
+ }, {
1587
+ readonly preset: "quiet-luxury";
1588
+ readonly reason: "Elegant for a premium venue.";
1589
+ }, {
1590
+ readonly preset: "after-dark";
1591
+ readonly reason: "Dark and lively for parties.";
1592
+ }, {
1593
+ readonly preset: "festival";
1594
+ readonly reason: "Poster energy for festivals.";
1595
+ }];
1596
+ readonly colour: {
1597
+ readonly mood: "soft pink, gold, cream — or event colours";
1598
+ readonly swatches: readonly ["#7D5260", "#7A5B36", "#FF4FA3"];
1599
+ };
1600
+ readonly fonts: "elegant or bold";
1601
+ readonly tone: "Evocative; the day, the place, the people.";
1602
+ readonly motion: "standard";
1603
+ readonly moves: {
1604
+ readonly scroll: "extra";
1605
+ readonly animate: "standard";
1606
+ readonly between: "cinematic";
1607
+ };
1608
+ readonly imagery: "Real events at your venue.";
1609
+ readonly pages: readonly ["home", "spaces", "gallery", "faq", "contact"];
1610
+ readonly needs: readonly ["gallery", "faq", "contact"];
1611
+ readonly home: readonly ["hero.full-bleed-media", "collection.masonry-gallery", "faq.accordion", "cta.banner"];
1612
+ readonly avoid: readonly [{
1613
+ readonly when: {
1614
+ readonly moods: readonly ["technical"];
1615
+ };
1616
+ readonly say: "A technical look takes the romance out of the day.";
1617
+ }, {
1618
+ readonly check: "needs-family";
1619
+ readonly family: "collection";
1620
+ readonly say: "Show the work: a site like this needs a gallery or a grid of projects on the home page.";
1621
+ }, {
1622
+ readonly check: "image-hero";
1623
+ readonly say: "Lead with a picture: the first screen should show the place or the work, not only words.";
1624
+ }];
1625
+ readonly words: readonly ["fairy tale", "once in a lifetime"];
1626
+ readonly structure: "place";
1627
+ readonly slice: false;
1628
+ readonly stock: true;
1629
+ readonly booking: "tables";
1630
+ }, {
1631
+ readonly id: "hotel-bnb";
1632
+ readonly label: "Hotel, B&B or guesthouse";
1633
+ readonly he: "מלון / צימר";
1634
+ readonly group: "Community and places";
1635
+ readonly uupm: "38 Hotel/Hospitality";
1636
+ readonly match: readonly ["hotel", "b&b", "guesthouse", "cabin", "zimmer", "מלון", "צימר", "אירוח"];
1637
+ readonly good: readonly [{
1638
+ readonly preset: "holiday-light";
1639
+ readonly reason: "Sea-blue glass: makes people want to go.";
1640
+ }, {
1641
+ readonly preset: "quiet-luxury";
1642
+ readonly reason: "For a boutique hotel.";
1643
+ }, {
1644
+ readonly preset: "warm-editorial";
1645
+ readonly reason: "Warm and personal for a B&B.";
1646
+ }, {
1647
+ readonly preset: "morning-glass";
1648
+ readonly reason: "Fresh and calm.";
1649
+ }];
1650
+ readonly colour: {
1651
+ readonly mood: "warm neutrals, gold — or sea blue";
1652
+ readonly swatches: readonly ["#0A66E8", "#7A5B36", "#0E8A89"];
1653
+ };
1654
+ readonly fonts: "elegant, welcoming";
1655
+ readonly tone: "Welcoming, sensory.";
1656
+ readonly motion: "calm";
1657
+ readonly moves: {
1658
+ readonly scroll: "extra";
1659
+ readonly animate: "subtle";
1660
+ readonly between: "cinematic";
1661
+ };
1662
+ readonly imagery: "Rooms, views, breakfast; your own photos.";
1663
+ readonly pages: readonly ["home", "rooms (collection)", "room (detail)", "about", "contact"];
1664
+ readonly needs: readonly ["collection", "detail", "about", "contact"];
1665
+ readonly home: readonly ["hero.full-bleed-media", "collection.card-grid", "proof.testimonial-carousel", "faq.accordion", "cta.banner"];
1666
+ readonly avoid: readonly [{
1667
+ readonly when: {
1668
+ readonly moods: readonly ["technical"];
1669
+ };
1670
+ readonly say: "Cold and technical is the opposite of a welcome.";
1671
+ }, {
1672
+ readonly check: "image-hero";
1673
+ readonly say: "Lead with a picture: the first screen should show the place or the work, not only words.";
1674
+ }, {
1675
+ readonly check: "needs-fact";
1676
+ readonly fact: "address";
1677
+ readonly say: "Visitors need the address to find you.";
1678
+ }];
1679
+ readonly words: readonly ["paradise", "luxury (unless rated)"];
1680
+ readonly structure: "place";
1681
+ readonly slice: false;
1682
+ readonly stock: true;
1683
+ readonly booking: "tables";
1684
+ }, {
1685
+ readonly id: "classes";
1686
+ readonly label: "Teacher, tutor or classes";
1687
+ readonly he: "מורה, חוגים ושיעורים";
1688
+ readonly group: "Community and places";
1689
+ readonly uupm: "153 Music Instrument Learning · 56 Childcare/Daycare";
1690
+ readonly match: readonly ["tutor", "lessons", "teacher", "classes", "school", "music lessons", "kids", "מורה", "שיעורים", "חוג", "חוגים", "ילדים"];
1691
+ readonly good: readonly [{
1692
+ readonly preset: "little-ones";
1693
+ readonly reason: "Playful and safe for children.";
1694
+ }, {
1695
+ readonly preset: "kind-community";
1696
+ readonly reason: "Warm and open.";
1697
+ }, {
1698
+ readonly preset: "coral-studio";
1699
+ readonly reason: "Energetic for dance or music.";
1700
+ }, {
1701
+ readonly preset: "fresh-market";
1702
+ readonly reason: "Bright and lively.";
1703
+ }];
1704
+ readonly colour: {
1705
+ readonly mood: "warm, energetic";
1706
+ readonly swatches: readonly ["#006A6A", "#E5484D", "#3B6939"];
1707
+ };
1708
+ readonly fonts: "friendly, large";
1709
+ readonly tone: "Encouraging, clear for parents.";
1710
+ readonly motion: "standard";
1711
+ readonly moves: {
1712
+ readonly scroll: "normal";
1713
+ readonly animate: "lively";
1714
+ readonly between: "slide";
1715
+ };
1716
+ readonly imagery: "Real classes (with permission).";
1717
+ readonly pages: readonly ["home", "classes", "prices", "about", "contact"];
1718
+ readonly needs: readonly ["prices", "about", "contact"];
1719
+ readonly home: readonly ["hero.split", "feature.triad", "pricing.tiers", "faq.accordion", "cta.banner"];
1720
+ readonly avoid: readonly [{
1721
+ readonly when: {
1722
+ readonly moods: readonly ["luxurious"];
1723
+ };
1724
+ readonly say: "An expensive look puts off parents comparing classes.";
1725
+ }, {
1726
+ readonly when: {
1727
+ readonly motion: readonly ["off"];
1728
+ };
1729
+ readonly say: "A still site feels low-energy for a class.";
1730
+ }];
1731
+ readonly words: readonly ["guaranteed", "genius"];
1732
+ readonly structure: "practice";
1733
+ readonly slice: false;
1734
+ readonly stock: true;
1735
+ readonly booking: "must";
1736
+ }];
1737
+ declare const SPEC_ANALYSIS_SHAPE: {
1738
+ readonly analysis: {
1739
+ readonly businessType: "string — a harness.businessTypes id";
1740
+ readonly alternatives: "[string, string] — the two nearest business types";
1741
+ readonly business: "business";
1742
+ readonly needs: "need[] — what the site needs: the owner's (from: you) and the type's (from: type)";
1743
+ readonly facts: "{ [fact]: factRead } — site.facts keys, only what the prompt states; every quote is words of the prompt";
1744
+ readonly missingFacts: "string[] — site.facts keys the prompt does not state";
1745
+ readonly voice: "voice";
1746
+ readonly moods: "string[] — ≤ 3 moods";
1747
+ readonly avoid: "string[] — harness.userAvoids ids the owner asked for";
1748
+ readonly hero: "hero";
1749
+ readonly locale: "'he' | 'en'";
1750
+ };
1751
+ readonly business: {
1752
+ readonly name: "string — the business as the owner names it";
1753
+ readonly audience: "string — who it is for, one short line";
1754
+ };
1755
+ readonly need: {
1756
+ readonly id: "string — a harness.needs id";
1757
+ readonly from: "'you' | 'type'";
1758
+ readonly "name?": "string — the owner's own word for it";
1759
+ };
1760
+ readonly factRead: {
1761
+ readonly value: "string — the fact";
1762
+ readonly quote: "string — the words of the prompt it came from";
1763
+ };
1764
+ readonly voice: {
1765
+ readonly tone: "string — one line";
1766
+ readonly person: "'we' | 'I'";
1767
+ readonly formality: "'casual' | 'neutral' | 'formal'";
1768
+ readonly avoidWords: "string[]";
1769
+ };
1770
+ readonly hero: {
1771
+ readonly headline: "string — the hero headline";
1772
+ readonly lead: "string — the hero lead";
1773
+ };
1774
+ };
1775
+ declare const SPEC_HARNESS_EXAMPLES: readonly [{
1776
+ readonly id: "kadar";
1777
+ readonly locale: "he";
1778
+ readonly dir: "rtl";
1779
+ readonly prompt: "סטודיו קדר — כלי חרס בעבודת יד מסטודיו קטן ביפו. רוצה אתר שמציג את הכלים החדשים, מסביר על סדנאות יום שישי ומאפשר להשאיר פרטים להרשמה. בלי משהו קר או טכנולוגי.";
1780
+ readonly business: {
1781
+ readonly name: "סטודיו קדר";
1782
+ readonly latin: "Studio Kadar";
1783
+ readonly facts: {
1784
+ readonly email: "hello@studiokadar.co.il";
1785
+ };
1786
+ };
1787
+ readonly analysis: {
1788
+ readonly businessType: "makers";
1789
+ readonly alternatives: readonly ["artist", "classes"];
1790
+ readonly moods: readonly ["warm", "crafted", "calm"];
1791
+ readonly avoid: readonly ["too-corporate"];
1792
+ readonly copyLength: "standard";
1793
+ readonly sentences: readonly [readonly ["The business", "A small ceramics studio in Jaffa that makes stoneware by hand.", "כלי חרס בעבודת יד מסטודיו קטן ביפו"], readonly ["Who it is for", "People who buy hand-made tableware, and beginners who want to try the wheel.", "סדנאות יום שישי"], readonly ["What the site should do", "Show the new pieces and get people to sign up for a Friday workshop.", "ומאפשר להשאיר פרטים להרשמה"], readonly ["How it should feel", "Warm, hand-made and calm.", "בלי משהו קר או טכנולוגי"], readonly ["Put first", "New pieces from the kiln · Friday workshops · Made by hand in Jaffa", "הכלים החדשים"]];
1794
+ readonly hero: {
1795
+ readonly eyebrow: "כלי חרס · יפו";
1796
+ readonly headline: "סטודיו קדר";
1797
+ readonly lead: "כלי חרס בעבודת יד מסטודיו קטן ביפו.";
1798
+ };
1799
+ readonly missing: readonly ["phone", "city", "address", "hours"];
1800
+ readonly voice: {
1801
+ readonly tone: "Warm and plain, like the potter talking at the wheel. Short sentences.";
1802
+ readonly person: "we";
1803
+ readonly formality: "casual";
1804
+ readonly sample: "כל כלי יוצא מהתנור שלנו ביפו, ואין שניים זהים.";
1805
+ readonly avoid: readonly ["מושלם", "יוקרתי", "ייצור המוני"];
1806
+ };
1807
+ };
1808
+ readonly plan: {
1809
+ readonly homePatterns: readonly ["hero.split", "collection.card-grid", "feature.triad", "cta.banner"];
1810
+ readonly heroHasImage: true;
1811
+ readonly facts: {
1812
+ readonly email: "x";
1813
+ };
1814
+ };
1815
+ readonly said: readonly [{
1816
+ readonly id: "collection";
1817
+ readonly name: "New pieces";
1818
+ }, {
1819
+ readonly id: "services";
1820
+ readonly name: "Friday workshops";
1821
+ }, {
1822
+ readonly id: "sign-up-form";
1823
+ readonly name: "Workshop sign-up";
1824
+ }];
1825
+ readonly read: {
1826
+ readonly sources: readonly [{
1827
+ readonly kind: "site";
1828
+ readonly ref: "harastudio.example";
1829
+ }];
1830
+ readonly palette: readonly [{
1831
+ readonly hex: "#EFE5D6";
1832
+ readonly share: 0.46;
1833
+ }, {
1834
+ readonly hex: "#3B2F2A";
1835
+ readonly share: 0.22;
1836
+ }, {
1837
+ readonly hex: "#8E4A2C";
1838
+ readonly share: 0.18;
1839
+ }, {
1840
+ readonly hex: "#7A8B6F";
1841
+ readonly share: 0.08;
1842
+ }];
1843
+ readonly brand: "#8E4A2C";
1844
+ readonly ground: "light";
1845
+ readonly shape: "soft";
1846
+ readonly density: "airy";
1847
+ readonly motion: "some";
1848
+ readonly headings: "serif";
1849
+ readonly moods: readonly ["warm", "crafted", "calm"];
1850
+ };
1851
+ }, {
1852
+ readonly id: "spa";
1853
+ readonly locale: "en";
1854
+ readonly dir: "ltr";
1855
+ readonly prompt: "Tamar Spa is a small day spa in Haifa: massages, facials and a quiet garden. I want people to see the treatments and prices and book by phone. It should feel calm and natural, nothing flashy, and please no dark backgrounds.";
1856
+ readonly business: {
1857
+ readonly name: "Tamar Spa";
1858
+ readonly facts: {
1859
+ readonly city: "Haifa";
1860
+ };
1861
+ };
1862
+ readonly analysis: {
1863
+ readonly businessType: "spa";
1864
+ readonly alternatives: readonly ["salon", "yoga"];
1865
+ readonly moods: readonly ["calm", "natural", "elegant"];
1866
+ readonly avoid: readonly ["dark-pages", "loud-colour"];
1867
+ readonly copyLength: "standard";
1868
+ readonly sentences: readonly [readonly ["The business", "A small day spa in Haifa with massages, facials and a garden.", "a small day spa in Haifa"], readonly ["Who it is for", "Locals who want a quiet few hours; gift buyers.", "a quiet garden"], readonly ["What the site should do", "Show treatments and prices, and get people to call to book.", "book by phone"], readonly ["How it should feel", "Calm and natural; nothing flashy.", "calm and natural, nothing flashy"], readonly ["Put first", "Treatments · Prices · The garden · How to book", "treatments and prices"]];
1869
+ readonly hero: {
1870
+ readonly eyebrow: "Day spa · Haifa";
1871
+ readonly headline: "A quiet afternoon in Haifa";
1872
+ readonly lead: "Massages, facials and a garden to rest in.";
1873
+ };
1874
+ readonly missing: readonly ["phone", "address", "hours"];
1875
+ readonly voice: {
1876
+ readonly tone: "Soft and unhurried; speaks to the guest.";
1877
+ readonly person: "we";
1878
+ readonly formality: "neutral";
1879
+ readonly sample: "Leave the week at the gate. The garden is quiet until four.";
1880
+ readonly avoid: readonly ["deal", "hurry", "cheap"];
1881
+ };
1882
+ };
1883
+ readonly plan: {
1884
+ readonly homePatterns: readonly ["hero.split", "feature.triad", "pricing.tiers", "proof.testimonial-carousel", "cta.banner"];
1885
+ readonly heroHasImage: true;
1886
+ readonly facts: {
1887
+ readonly city: "Haifa";
1888
+ };
1889
+ };
1890
+ readonly said: readonly [{
1891
+ readonly id: "services";
1892
+ readonly name: "Treatments";
1893
+ }, {
1894
+ readonly id: "prices";
1895
+ readonly name: "Prices";
1896
+ }];
1897
+ readonly read: {
1898
+ readonly sources: readonly [{
1899
+ readonly kind: "image";
1900
+ readonly ref: "garden-terrace.jpg";
1901
+ }, {
1902
+ readonly kind: "image";
1903
+ readonly ref: "linen-towels.jpg";
1904
+ }];
1905
+ readonly palette: readonly [{
1906
+ readonly hex: "#E9DFD3";
1907
+ readonly share: 0.5;
1908
+ }, {
1909
+ readonly hex: "#A3B18A";
1910
+ readonly share: 0.2;
1911
+ }, {
1912
+ readonly hex: "#4F5E46";
1913
+ readonly share: 0.15;
1914
+ }, {
1915
+ readonly hex: "#C9A27E";
1916
+ readonly share: 0.1;
1917
+ }];
1918
+ readonly brand: "#4F5E46";
1919
+ readonly ground: "light";
1920
+ readonly shape: "round";
1921
+ readonly density: "airy";
1922
+ readonly motion: "some";
1923
+ readonly headings: "serif";
1924
+ readonly moods: readonly ["calm", "natural", "elegant"];
1925
+ };
1926
+ }, {
1927
+ readonly id: "physio";
1928
+ readonly locale: "en";
1929
+ readonly dir: "ltr";
1930
+ readonly prompt: "Levi Physio — sports and back physiotherapy in Tel Aviv, two therapists. I need a professional, modern site: what we treat, the team, and a way to book an appointment. Patients are mostly runners and office workers.";
1931
+ readonly business: {
1932
+ readonly name: "Levi Physio";
1933
+ readonly facts: {
1934
+ readonly email: "clinic@leviphysio.co.il";
1935
+ readonly city: "Tel Aviv";
1936
+ };
1937
+ };
1938
+ readonly analysis: {
1939
+ readonly businessType: "clinic";
1940
+ readonly alternatives: readonly ["fitness", "therapist"];
1941
+ readonly moods: readonly ["professional", "trustworthy", "calm"];
1942
+ readonly avoid: readonly [];
1943
+ readonly copyLength: "standard";
1944
+ readonly sentences: readonly [readonly ["The business", "A physiotherapy clinic in Tel Aviv for sports injuries and back pain, with two therapists.", "sports and back physiotherapy in Tel Aviv"], readonly ["Who it is for", "Runners and office workers with pain.", "mostly runners and office workers"], readonly ["What the site should do", "Explain what you treat, introduce the team, and get people to book.", "a way to book an appointment"], readonly ["How it should feel", "Professional and modern.", "professional, modern"], readonly ["Put first", "What we treat · The team · Book an appointment", "what we treat, the team"]];
1945
+ readonly hero: {
1946
+ readonly eyebrow: "Physiotherapy · Tel Aviv";
1947
+ readonly headline: "Back to running, sooner";
1948
+ readonly lead: "Sports and back physiotherapy in Tel Aviv.";
1949
+ };
1950
+ readonly missing: readonly ["phone", "address", "hours"];
1951
+ readonly voice: {
1952
+ readonly tone: "Clear and confident; plain words a patient understands.";
1953
+ readonly person: "we";
1954
+ readonly formality: "neutral";
1955
+ readonly sample: "We find what is causing the pain, then build a plan to get you moving.";
1956
+ readonly avoid: readonly ["cure", "guaranteed", "miracle"];
1957
+ };
1958
+ };
1959
+ readonly plan: {
1960
+ readonly homePatterns: readonly ["hero.split", "feature.triad", "faq.accordion", "cta.banner"];
1961
+ readonly heroHasImage: false;
1962
+ readonly facts: {
1963
+ readonly email: "x";
1964
+ readonly city: "x";
1965
+ };
1966
+ };
1967
+ readonly said: readonly [{
1968
+ readonly id: "services";
1969
+ readonly name: "What we treat";
1970
+ }, {
1971
+ readonly id: "team";
1972
+ readonly name: "The team";
1973
+ }, {
1974
+ readonly id: "booking-request";
1975
+ readonly name: "Book an appointment";
1976
+ }];
1977
+ readonly read: null;
1978
+ }];
1979
+
1980
+ /**
1981
+ * The design harness's knowledge (AI plan rev 3 §3f, H2): the 30 kinds of business IOX serves, each with the
1982
+ * styles that suit it (best first, with the reason), its look rules and content rules (one closed grammar,
1983
+ * read by the ranker and the lint), its voice, its motion, the pages it needs and its home sections.
1984
+ * Generated 1:1 from the contract (`harness`, gated in build-spec.mjs). Seeded from UI UX Pro Max — the
1985
+ * attribution travels with the data (`HARNESS_SOURCE.notice`).
1986
+ */
1987
+ declare const HARNESS_SOURCE: {
1988
+ readonly repo: "nextlevelbuilder/ui-ux-pro-max-skill";
1989
+ readonly sha: "d14efff8ed1faa4187f004f79926f428c8074ec7";
1990
+ readonly date: "2026-10-23";
1991
+ readonly licence: "MIT — Copyright (c) 2024 Next Level Builder";
1992
+ readonly notice: "Business-type rules adapted from UI UX Pro Max (MIT, Copyright (c) 2024 Next Level Builder).";
1993
+ };
1994
+ /** What a site may need — the closed list an analysis returns; each maps to the archetype a plan writes. */
1995
+ type NeedId = keyof typeof SPEC_NEEDS;
1996
+ declare const NEED_IDS: ReadonlyArray<NeedId>;
1997
+ interface NeedDef {
1998
+ readonly label: string;
1999
+ readonly archetype: string;
2000
+ }
2001
+ declare const NEEDS: Readonly<Record<NeedId, NeedDef>>;
2002
+ /** What an owner may ask to avoid ("no dark backgrounds") — each one look rule. */
2003
+ type UserAvoidId = keyof typeof SPEC_USER_AVOIDS;
2004
+ declare const USER_AVOID_IDS: ReadonlyArray<UserAvoidId>;
2005
+ /** The structures a site is built from (Studio · Practice · Place). */
2006
+ type StructureId = keyof typeof SPEC_STRUCTURES;
2007
+ declare const STRUCTURES: {
2008
+ readonly studio: {
2009
+ readonly label: "Studio";
2010
+ readonly blurb: "Your work, what you do, and a way to reach you.";
2011
+ readonly pages: readonly ["Home", "Work", "Project (one per project)", "About", "Contact"];
2012
+ readonly shipped: true;
2013
+ };
2014
+ readonly practice: {
2015
+ readonly label: "Practice";
2016
+ readonly blurb: "Services, prices and a clear way to book.";
2017
+ readonly pages: readonly ["Home", "Services", "Prices", "About", "Contact"];
2018
+ readonly shipped: false;
2019
+ };
2020
+ readonly place: {
2021
+ readonly label: "Place";
2022
+ readonly blurb: "A menu, opening hours and how to find you.";
2023
+ readonly pages: readonly ["Home", "Menu", "Visit (hours + map)", "About", "Contact"];
2024
+ readonly shipped: false;
2025
+ };
2026
+ };
2027
+ /** How much a kind of business needs "book a slot" — the next product bet (off this road). */
2028
+ declare enum BookingNeed {
2029
+ Must = "must",
2030
+ Tables = "tables",
2031
+ Sometimes = "sometimes",
2032
+ None = "none"
2033
+ }
2034
+ /** The content checks of the avoid grammar (a look rule is the other kind). */
2035
+ declare enum AvoidCheck {
2036
+ NeedsFamily = "needs-family",
2037
+ NeedsFact = "needs-fact",
2038
+ ImageHero = "image-hero",
2039
+ NoPattern = "no-pattern",
2040
+ BrandHue = "brand-hue",
2041
+ CopyLength = "copy-length"
2042
+ }
2043
+ /** How much text a site carries, shortest first. */
2044
+ declare enum CopyLength {
2045
+ Short = "short",
2046
+ Standard = "standard",
2047
+ Rich = "rich"
2048
+ }
2049
+ declare const COPY_LENGTH_ORDER: ReadonlyArray<`${CopyLength}`>;
2050
+ /** A look a business should not wear: each named axis lists the values that match (all named axes must). */
2051
+ interface LookCondition {
2052
+ readonly flavor?: ReadonlyArray<string>;
2053
+ readonly mode?: ReadonlyArray<string>;
2054
+ readonly motion?: ReadonlyArray<MotionId>;
2055
+ readonly moods?: ReadonlyArray<MoodId>;
2056
+ readonly tint?: ReadonlyArray<TintId>;
2057
+ readonly density?: ReadonlyArray<DensityId>;
2058
+ readonly scroll?: ReadonlyArray<string>;
2059
+ readonly animate?: ReadonlyArray<string>;
2060
+ readonly between?: ReadonlyArray<string>;
2061
+ }
2062
+ interface LookRule {
2063
+ readonly when: LookCondition;
2064
+ readonly say: string;
2065
+ }
2066
+ type CheckRule = {
2067
+ readonly check: `${AvoidCheck.NeedsFamily}`;
2068
+ readonly family: string;
2069
+ readonly say: string;
2070
+ } | {
2071
+ readonly check: `${AvoidCheck.NeedsFact}`;
2072
+ readonly fact: FactKey;
2073
+ readonly say: string;
2074
+ } | {
2075
+ readonly check: `${AvoidCheck.ImageHero}`;
2076
+ readonly say: string;
2077
+ } | {
2078
+ readonly check: `${AvoidCheck.NoPattern}`;
2079
+ readonly pattern: string;
2080
+ readonly say: string;
2081
+ } | {
2082
+ readonly check: `${AvoidCheck.BrandHue}`;
2083
+ readonly from: number;
2084
+ readonly to: number;
2085
+ readonly minChroma: number;
2086
+ readonly say: string;
2087
+ } | {
2088
+ readonly check: `${AvoidCheck.CopyLength}`;
2089
+ readonly max: `${CopyLength}`;
2090
+ readonly say: string;
2091
+ };
2092
+ type AvoidRule = LookRule | CheckRule;
2093
+ declare const isLookRule: (rule: AvoidRule) => rule is LookRule;
2094
+ interface GoodFit {
2095
+ readonly preset: string;
2096
+ readonly reason: string;
2097
+ }
2098
+ interface BusinessType {
2099
+ readonly id: string;
2100
+ readonly label: string;
2101
+ readonly he: string;
2102
+ readonly group: string;
2103
+ readonly uupm: string;
2104
+ /** Keywords (English + Hebrew): the eval's expected answer and the no-model fallback. */
2105
+ readonly match: ReadonlyArray<string>;
2106
+ /** The styles that suit it, best first, each with why. */
2107
+ readonly good: ReadonlyArray<GoodFit>;
2108
+ readonly colour: {
2109
+ readonly mood: string;
2110
+ readonly swatches: ReadonlyArray<string>;
2111
+ };
2112
+ readonly fonts: string;
2113
+ readonly tone: string;
2114
+ /** The motion TIMING it suits (the design axis — hover lift, durations). */
2115
+ readonly motion: MotionId;
2116
+ /** How its site usually scrolls, how animated it is and what plays between pages (rev 3.1). */
2117
+ readonly moves: Readonly<DesignMotion>;
2118
+ readonly imagery: string;
2119
+ readonly pages: ReadonlyArray<string>;
2120
+ /** The needs its page set implies, in page order (derived from `pages` at contract build). */
2121
+ readonly needs: ReadonlyArray<NeedId>;
2122
+ /** The home page's sections, library ids. */
2123
+ readonly home: ReadonlyArray<string>;
2124
+ readonly avoid: ReadonlyArray<AvoidRule>;
2125
+ /** Words its copy must not use. */
2126
+ readonly words: ReadonlyArray<string>;
2127
+ readonly structure: StructureId;
2128
+ /** In the M1-alpha slice. */
2129
+ readonly slice: boolean;
2130
+ /** Stock photos may fill its pictures (never the work itself). */
2131
+ readonly stock: boolean;
2132
+ readonly booking: `${BookingNeed}`;
2133
+ }
2134
+ /** The 30, in the board's order. Assignment here proves the generated data fits the type. */
2135
+ declare const BUSINESS_TYPES: ReadonlyArray<BusinessType>;
2136
+ declare function businessTypeById(id: string | null | undefined): BusinessType | undefined;
2137
+ declare const BUSINESS_TYPE_IDS: ReadonlyArray<string>;
2138
+ /** The user-avoid rule for an id, or undefined. */
2139
+ declare function userAvoidRule(id: string): LookRule | undefined;
2140
+
2141
+ /** The parts of a look a rule can name: the design's choices (motion included) in one colour mode. */
2142
+ type LookDesign = Pick<DesignChoices, 'flavorId' | 'motion' | 'density'> & Partial<Pick<DesignChoices, 'tint'>> & Partial<DesignMotion> & {
2143
+ mode: DesignMode;
2144
+ };
2145
+ /** True when `design` (worn with `moods`) is the look `when` describes — every axis it names must match. */
2146
+ declare function lookMatches(when: LookCondition, design: LookDesign, moods: ReadonlyArray<string>): boolean;
2147
+ /** A style preset as a rule sees it, in `mode` (default: the mode it opens in). */
2148
+ declare function presetLook(preset: StylePreset, mode?: DesignMode): LookDesign;
2149
+
2150
+ /**
2151
+ * Which styles suit a business, best first (AI plan rev 3 §3f, H3) — Design ▸ Look's order. Pure and
2152
+ * deterministic: the browser and the server give the same order, and the eval asserts it.
2153
+ */
2154
+ /** What the ranker reads of an analysis. */
2155
+ interface RankInput {
2156
+ businessType?: string | null;
2157
+ moods?: ReadonlyArray<string>;
2158
+ /** What the owner asked to avoid (`USER_AVOID_IDS`). */
2159
+ avoid?: ReadonlyArray<string>;
2160
+ }
2161
+ declare enum PresetFit {
2162
+ Good = "good",
2163
+ Ok = "ok",
2164
+ Poor = "poor"
2165
+ }
2166
+ /** Why a style sits where it does — the line Design ▸ Look shows. */
2167
+ declare enum RankReason {
2168
+ /** The business type names it as a good fit (`reason` = the type's line). */
2169
+ GoodFit = "good-fit",
2170
+ /** A type rule advises against its look (`reason` = the rule's line). */
2171
+ TypeAvoid = "type-avoid",
2172
+ /** The owner asked to avoid its look (`reason` = the rule's line). */
2173
+ UserAvoid = "user-avoid",
2174
+ /** It shares the analysis's moods (`sharedMoods`). */
2175
+ SharedMoods = "shared-moods",
2176
+ None = "none"
2177
+ }
2178
+ interface RankedPreset {
2179
+ id: string;
2180
+ fit: PresetFit;
2181
+ score: number;
2182
+ reasonKind: RankReason;
2183
+ /** In English, from the contract (the UI may localise `reasonKind` + `sharedMoods` instead). */
2184
+ reason: string;
2185
+ sharedMoods: MoodId[];
2186
+ /** Catalogue position — ties keep it. */
2187
+ order: number;
2188
+ /** With references (`rankWithReferences`): the boost the reading gave it, and whether it is the nearest. */
2189
+ refBoost?: number;
2190
+ nearest?: boolean;
2191
+ }
2192
+ /** The ranking's weights: the type's own order, then moods, then motion character, minus what is advised against. */
2193
+ declare const RANK_WEIGHTS: {
2194
+ readonly firstGoodFit: 100;
2195
+ readonly goodFitStep: 10;
2196
+ readonly sharedMood: 6;
2197
+ readonly sharedMove: 2;
2198
+ readonly typeAvoid: 60;
2199
+ readonly userAvoid: 80;
2200
+ };
2201
+ /**
2202
+ * Every preset, best first: score = the type's own order (a good fit 100, 90, 80…) + 6 per mood shared with
2203
+ * the analysis + 2 per motion choice shared with the type, − 60 for a look the type advises against, − 80 for
2204
+ * one the owner said to avoid. Ties keep catalogue order. With no matching type, moods alone order them.
2205
+ */
2206
+ declare function rankStylePresets(input: RankInput, presets?: ReadonlyArray<StylePreset>, types?: ReadonlyArray<BusinessType>): RankedPreset[];
2207
+ declare enum StyleReadSourceKind {
2208
+ Image = "image",
2209
+ Site = "site"
2210
+ }
2211
+ declare enum StyleReadGround {
2212
+ Light = "light",
2213
+ Dark = "dark",
2214
+ Mixed = "mixed"
2215
+ }
2216
+ declare enum StyleReadMotion {
2217
+ None = "none",
2218
+ Some = "some",
2219
+ Lots = "lots"
2220
+ }
2221
+ declare enum StyleReadHeadings {
2222
+ Serif = "serif",
2223
+ Sans = "sans",
2224
+ Display = "display",
2225
+ Mono = "mono"
2226
+ }
2227
+ /** What a reader measured (palette) and saw (moods, shape…) — never their CSS, text or pictures. */
2228
+ interface StyleRead {
2229
+ sources: ReadonlyArray<{
2230
+ kind: `${StyleReadSourceKind}`;
2231
+ ref: string;
2232
+ }>;
2233
+ /** ≤ 6, MEASURED, never asked of a model. */
2234
+ palette: ReadonlyArray<{
2235
+ hex: string;
2236
+ share: number;
2237
+ }>;
2238
+ /** The most frequent saturated colour — a CANDIDATE seed: the AA audit decides. */
2239
+ brand?: string;
2240
+ ground: `${StyleReadGround}`;
2241
+ shape?: ShapeId;
2242
+ density?: DensityId;
2243
+ motion?: `${StyleReadMotion}`;
2244
+ headings?: `${StyleReadHeadings}`;
2245
+ moods: ReadonlyArray<MoodId>;
2246
+ }
2247
+ /** The boosts a reading gives each preset, and the defaults it suggests. */
2248
+ interface StyleHints {
2249
+ boost: Record<string, number>;
2250
+ seed: string | null;
2251
+ tint: TintId;
2252
+ shape?: ShapeId;
2253
+ density?: DensityId;
2254
+ animate: AnimateId | null;
2255
+ }
2256
+ declare const READ_WEIGHTS: {
2257
+ readonly sharedMood: 8;
2258
+ readonly ground: 10;
2259
+ readonly shape: 6;
2260
+ readonly density: 4;
2261
+ readonly serifHeadings: 6;
2262
+ };
2263
+ /** How much motion a reading saw → How animated. */
2264
+ declare const READ_ANIMATE: Readonly<Record<`${StyleReadMotion}`, AnimateId>>;
2265
+ /** True when the preset's pairing sets headings in a serif (its display stack ends in the serif generic). */
2266
+ declare function presetHasSerifHeadings(preset: StylePreset): boolean;
2267
+ /** A reading → a score boost per preset and the defaults it suggests (pure, deterministic). */
2268
+ declare function mapStyleRead(read: StyleRead, presets?: ReadonlyArray<StylePreset>): StyleHints;
2269
+ /** `rankStylePresets` + the reading's boost; `nearest` = the best-boosted style that is not a poor fit. */
2270
+ declare function rankWithReferences(input: RankInput, read: StyleRead | null | undefined, presets?: ReadonlyArray<StylePreset>, types?: ReadonlyArray<BusinessType>): RankedPreset[];
2271
+
2272
+ /**
2273
+ * Where Design ▸ Motion starts (AI plan rev 3.1 §3p, MO-D3) — and what "Build with these" takes. Pure.
2274
+ * Scrolling and Between pages are the BUSINESS's (a spa scrolls softly whatever its look); How animated is the
2275
+ * CALMER of the business's (or what the references show) and the style's — so a quiet serif look never gets
2276
+ * bouncing cards. The owner's "little movement" caps all three. No matching type → the style's own.
2277
+ */
2278
+ interface MotionInput {
2279
+ businessType?: string | null;
2280
+ avoid?: ReadonlyArray<string>;
2281
+ }
2282
+ interface MotionStart extends DesignMotion {
2283
+ /** Why, in English — one line per step the start took. */
2284
+ why: string[];
2285
+ }
2286
+ /** The owner asked for little movement (`USER_AVOID_IDS`). */
2287
+ declare const LITTLE_MOVEMENT_AVOID = "lots-of-motion";
2288
+ /** What "little movement" caps each choice at. */
2289
+ declare const LITTLE_MOVEMENT_CAP: Readonly<DesignMotion>;
2290
+ type Axis = keyof DesignMotion;
2291
+ /** The stiller of two choices on one axis (the axes are ordered stillest first). */
2292
+ declare function calmerChoice<A extends Axis>(axis: A, a: DesignMotion[A], b: DesignMotion[A]): DesignMotion[A];
2293
+ declare function motionFor(input: MotionInput, presetId: string, read?: StyleRead | null, types?: ReadonlyArray<BusinessType>, presets?: ReadonlyArray<StylePreset>): MotionStart;
2294
+
2295
+ /** Who asked for a need: the owner named it, or the kind of business needs it ("we added"). */
2296
+ declare enum NeedSource {
2297
+ You = "you",
2298
+ Type = "type"
2299
+ }
2300
+ interface SiteNeed {
2301
+ id: NeedId;
2302
+ from: `${NeedSource}`;
2303
+ /** The owner's own word for it ("Friday workshops"). */
2304
+ name?: string;
2305
+ }
2306
+ /**
2307
+ * What the site needs (AI plan rev 3 §3d, H3): what the owner named, then what this kind of business needs and
2308
+ * they did not name — its page set, in order, and a booking request for a business that must take bookings —
2309
+ * each marked `from: 'type'` (the Analysis step's "we added"). Pure; an unknown type adds nothing.
2310
+ */
2311
+ declare function inferNeeds(typeId: string | null | undefined, said?: ReadonlyArray<Omit<SiteNeed, 'from'>>, types?: ReadonlyArray<BusinessType>): SiteNeed[];
2312
+
2313
+ /**
2314
+ * Design advice (AI plan rev 3 §3f, H5's core): the business type's avoid rules run against a built site's
2315
+ * look, home sections, facts and copy length. ADVICE only — Needs attention and the Publish dialog show it,
2316
+ * "Keep it" dismisses it, and nothing is ever refused on it (H-D9).
2317
+ */
2318
+ declare enum LintKind {
2319
+ Look = "look",
2320
+ Content = "content",
2321
+ Fact = "fact"
2322
+ }
2323
+ interface LintFinding {
2324
+ kind: LintKind;
2325
+ say: string;
2326
+ fact?: FactKey;
2327
+ }
2328
+ /** What the lint reads of a site. */
2329
+ interface LintSite {
2330
+ design: Pick<DesignChoices, 'flavorId' | 'seed' | 'motion' | 'density' | 'mode'> & Partial<Pick<DesignChoices, 'tint'>> & Partial<DesignMotion>;
2331
+ moods?: ReadonlyArray<string>;
2332
+ /** The home page's section patterns. */
2333
+ homePatterns?: ReadonlyArray<string>;
2334
+ /** Every page's section patterns (defaults to the home page's). */
2335
+ allPatterns?: ReadonlyArray<string>;
2336
+ facts?: Partial<Record<FactKey, string>>;
2337
+ copyLength?: `${CopyLength}`;
2338
+ heroHasImage?: boolean;
2339
+ }
2340
+ /** How far a site may move above what its kind of business usually wears before the lint says so. */
2341
+ declare const ANIMATE_ADVICE_STEPS = 2;
2342
+ /** A colour's OKLCH hue (degrees) and chroma, through design-core's one OKLab conversion. */
2343
+ declare function oklchHue(hex: string): {
2344
+ hue: number;
2345
+ chroma: number;
2346
+ } | null;
2347
+ declare function lintDesign(site: LintSite, typeId: string, types?: ReadonlyArray<BusinessType>): LintFinding[];
2348
+
2349
+ /**
2350
+ * What the reading of a prompt returns (AI plan rev 3 §3d): one of the 30 kinds of business (and the two
2351
+ * nearest), who it is for, what the site needs, the facts the prompt STATES (each with the words it came from)
2352
+ * and those it does not, the owner's voice, moods, what they asked to avoid, a hero line, the language. A model
2353
+ * writes it; `validateSiteAnalysis` is the gate — it refuses with a path and never repairs (a model gets the
2354
+ * issues back and rewrites; the caller decides what to drop).
2355
+ */
2356
+ declare enum AnalysisLocale {
2357
+ He = "he",
2358
+ En = "en"
2359
+ }
2360
+ declare enum VoicePerson {
2361
+ We = "we",
2362
+ I = "I"
2363
+ }
2364
+ declare enum VoiceFormality {
2365
+ Casual = "casual",
2366
+ Neutral = "neutral",
2367
+ Formal = "formal"
2368
+ }
2369
+ interface FactRead {
2370
+ value: string;
2371
+ /** The words of the prompt it came from — checked: every quote is in the prompt. */
2372
+ quote: string;
2373
+ }
2374
+ interface SiteAnalysis {
2375
+ businessType: string;
2376
+ alternatives: [string, string];
2377
+ business: {
2378
+ name: string;
2379
+ audience: string;
2380
+ };
2381
+ needs: SiteNeed[];
2382
+ facts: Partial<Record<FactKey, FactRead>>;
2383
+ missingFacts: FactKey[];
2384
+ voice: {
2385
+ tone: string;
2386
+ person: `${VoicePerson}`;
2387
+ formality: `${VoiceFormality}`;
2388
+ avoidWords: string[];
2389
+ };
2390
+ moods: MoodId[];
2391
+ avoid: UserAvoidId[];
2392
+ hero: {
2393
+ headline: string;
2394
+ lead: string;
2395
+ };
2396
+ locale: `${AnalysisLocale}`;
2397
+ }
2398
+ declare enum AnalysisIssueCode {
2399
+ Shape = "shape",
2400
+ UnknownKey = "unknown-key",
2401
+ Duplicate = "duplicate",
2402
+ UnknownBusinessType = "unknown-business-type",
2403
+ UnknownNeed = "unknown-need",
2404
+ UnknownFact = "unknown-fact",
2405
+ /** A fact's quote is not words of the prompt: it was not stated, so it may not be filled. */
2406
+ QuoteNotInPrompt = "quote-not-in-prompt",
2407
+ /** A fact reported both found and missing. */
2408
+ FactFoundAndMissing = "fact-found-and-missing",
2409
+ UnknownMood = "unknown-mood",
2410
+ TooManyMoods = "too-many-moods",
2411
+ UnknownAvoid = "unknown-avoid",
2412
+ InvalidValue = "invalid-value"
2413
+ }
2414
+ type AnalysisIssue = PathIssue<AnalysisIssueCode>;
2415
+ interface AnalysisValidation {
2416
+ valid: boolean;
2417
+ issues: AnalysisIssue[];
2418
+ }
2419
+ interface AnalysisContext {
2420
+ /** The owner's own words — every fact's quote must be found in them. */
2421
+ prompt: string;
2422
+ }
2423
+ /** At most this many moods (the closed list a preset carries too). */
2424
+ declare const MAX_ANALYSIS_MOODS = 3;
2425
+ declare function validateSiteAnalysis(value: unknown, ctx: AnalysisContext): AnalysisValidation;
2426
+
2427
+ /**
2428
+ * What the PLAN prompt is given (AI plan rev 3 §3f "Retrieval, not the whole knowledge base"): the one matched
2429
+ * business rule, the analysis the owner corrected, the style they picked, and the sections that rule's home
2430
+ * uses — never the 30 rules or the 24 presets. Design ▸ Look and the prompt read the same rule. Pure; the M1
2431
+ * caller serialises it.
2432
+ */
2433
+ interface PromptSection {
2434
+ id: string;
2435
+ family: string;
2436
+ /** The composed pattern's label; null while the library has not composed it yet (track L). */
2437
+ label: string | null;
2438
+ composed: boolean;
2439
+ }
2440
+ interface PromptContext {
2441
+ type: {
2442
+ id: string;
2443
+ label: string;
2444
+ tone: string;
2445
+ /** Words the copy must not use — the type's and the owner's. */
2446
+ avoidWords: string[];
2447
+ imagery: string;
2448
+ fonts: string;
2449
+ colourMood: string;
2450
+ structure: BusinessType['structure'];
2451
+ booking: BusinessType['booking'];
2452
+ /** What this kind of site should not look like — the look rules' lines. */
2453
+ lookAdvice: string[];
2454
+ } | null;
2455
+ business: SiteAnalysis['business'];
2456
+ voice: SiteAnalysis['voice'];
2457
+ needs: SiteNeed[];
2458
+ facts: Partial<Record<FactKey, string>>;
2459
+ /** The facts the prompt did not state — placeholders, never invented. */
2460
+ missingFacts: Array<{
2461
+ key: FactKey;
2462
+ label: string;
2463
+ }>;
2464
+ moods: SiteAnalysis['moods'];
2465
+ hero: SiteAnalysis['hero'];
2466
+ locale: SiteAnalysis['locale'];
2467
+ design: DesignChoices | null;
2468
+ sections: PromptSection[];
2469
+ }
2470
+ interface PromptContextOptions {
2471
+ /** The style the owner picked on Design ▸ Look. */
2472
+ presetId?: string | null;
2473
+ /** …or the exact choices (after Colour / Type / Shape / Motion edits) — wins over `presetId`. */
2474
+ design?: DesignChoices | null;
2475
+ }
2476
+ declare function analysisPromptContext(analysis: SiteAnalysis, opts?: PromptContextOptions): PromptContext;
2477
+
2478
+ interface BusinessTypeMatch {
2479
+ id: string;
2480
+ /** The keywords found, in the type's order. */
2481
+ keywords: string[];
2482
+ /** The letters matched — longer, more specific keywords weigh more ("barber" over "bar"). */
2483
+ score: number;
2484
+ }
2485
+ /** The kind of business the words name, best first; empty when none of the keywords appears. Ties keep the board's order. */
2486
+ declare function matchBusinessTypes(text: string, types?: ReadonlyArray<BusinessType>): BusinessTypeMatch[];
2487
+ /** The single best kind of business the words name, or null. */
2488
+ declare function matchBusinessType(text: string, types?: ReadonlyArray<BusinessType>): string | null;
2489
+ /** An address as a chip shows it: no scheme, no `www.`, no trailing punctuation or slash, lower-case host. */
2490
+ declare function normalizeAddress(raw: string): string;
2491
+ /** Every website address typed or pasted in the words (an http(s) address or a bare domain), once each, in
2492
+ * order. An email address is not a website. */
2493
+ declare function addressesIn(text: string): string[];
2494
+ /** The words without one address (removing its chip): every spelling of it, and the space it leaves. */
2495
+ declare function withoutAddress(text: string, address: string): string;
2496
+
2497
+ export { ANIMATE_ADVICE_STEPS, AnalysisIssueCode, AnalysisLocale, AvoidCheck, BUSINESS_TYPES, BUSINESS_TYPE_IDS, BookingNeed, COPY_LENGTH_ORDER, CopyLength, HARNESS_SOURCE, LITTLE_MOVEMENT_AVOID, LITTLE_MOVEMENT_CAP, LintKind, MAX_ANALYSIS_MOODS, NEEDS, NEED_IDS, NeedSource, PresetFit, RANK_WEIGHTS, READ_ANIMATE, READ_WEIGHTS, RankReason, SPEC_ANALYSIS_SHAPE, SPEC_BUSINESS_TYPES, SPEC_HARNESS_EXAMPLES, SPEC_HARNESS_SOURCE, SPEC_NEEDS, SPEC_STRUCTURES, SPEC_USER_AVOIDS, STRUCTURES, StyleReadGround, StyleReadHeadings, StyleReadMotion, StyleReadSourceKind, USER_AVOID_IDS, VoiceFormality, VoicePerson, addressesIn, analysisPromptContext, businessTypeById, calmerChoice, inferNeeds, isLookRule, lintDesign, lookMatches, mapStyleRead, matchBusinessType, matchBusinessTypes, motionFor, normalizeAddress, oklchHue, presetHasSerifHeadings, presetLook, rankStylePresets, rankWithReferences, userAvoidRule, validateSiteAnalysis, withoutAddress };
2498
+ export type { AnalysisContext, AnalysisIssue, AnalysisValidation, AvoidRule, BusinessType, BusinessTypeMatch, CheckRule, FactRead, GoodFit, LintFinding, LintSite, LookCondition, LookDesign, LookRule, MotionInput, MotionStart, NeedDef, NeedId, PromptContext, PromptContextOptions, PromptSection, RankInput, RankedPreset, SiteAnalysis, SiteNeed, StructureId, StyleHints, StyleRead, UserAvoidId };