@palate/cli 0.0.0-stage → 0.0.2

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 (1222) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +153 -2
  3. package/bin/palate.mjs +894 -0
  4. package/kb/anatomy/data-table.md +24 -0
  5. package/kb/anatomy/empty-state.md +16 -0
  6. package/kb/anatomy/filter-toolbar.md +19 -0
  7. package/kb/anatomy/meter.md +16 -0
  8. package/kb/anatomy/product-window.md +18 -0
  9. package/kb/anatomy/settings-page.md +18 -0
  10. package/kb/anatomy/status-indicator.md +17 -0
  11. package/kb/anatomy/toast-undo.md +16 -0
  12. package/kb/bench/briefs.json +618 -0
  13. package/kb/craft/SOURCES.md +48 -0
  14. package/kb/craft/creativity.md +55 -0
  15. package/kb/craft/details.md +75 -0
  16. package/kb/craft/landing-demos.md +46 -0
  17. package/kb/craft/mistakes.md +73 -0
  18. package/kb/craft/motion.md +53 -0
  19. package/kb/craft/principles.md +68 -0
  20. package/kb/index/discovery.json +1 -0
  21. package/kb/inspiration/index.json +79 -0
  22. package/kb/moves/animated-comparison-table.md +58 -0
  23. package/kb/moves/before-after-slider.md +58 -0
  24. package/kb/moves/bento-live-tiles.md +57 -0
  25. package/kb/moves/calm-motion-system.md +63 -0
  26. package/kb/moves/canvas-grain.md +58 -0
  27. package/kb/moves/changelog-as-magazine.md +56 -0
  28. package/kb/moves/code-drawn-diagram.md +56 -0
  29. package/kb/moves/colophon.md +54 -0
  30. package/kb/moves/command-palette-site-nav.md +58 -0
  31. package/kb/moves/confetti-free-celebration.md +58 -0
  32. package/kb/moves/console-easter-egg.md +57 -0
  33. package/kb/moves/copy-confirmation.md +57 -0
  34. package/kb/moves/cursor-reactive-light.md +57 -0
  35. package/kb/moves/dark-band-contrast-section.md +55 -0
  36. package/kb/moves/designed-dark-mode.md +58 -0
  37. package/kb/moves/duotone-photography.md +55 -0
  38. package/kb/moves/editorial-drop-cap.md +58 -0
  39. package/kb/moves/editorial-grid-pull-quotes.md +55 -0
  40. package/kb/moves/engraving-colour-lens.md +64 -0
  41. package/kb/moves/explorable-control.md +57 -0
  42. package/kb/moves/feature-films-on-painted-stages.md +58 -0
  43. package/kb/moves/first-win-onboarding.md +59 -0
  44. package/kb/moves/footer-live-status.md +56 -0
  45. package/kb/moves/footer-rewards-the-end.md +58 -0
  46. package/kb/moves/generative-brand-pattern.md +55 -0
  47. package/kb/moves/gentle-error-nudge.md +59 -0
  48. package/kb/moves/halftone-dot-imagery.md +55 -0
  49. package/kb/moves/hand-drawn-annotations.md +55 -0
  50. package/kb/moves/hero-paints-itself-in.md +65 -0
  51. package/kb/moves/honest-progress-narration.md +58 -0
  52. package/kb/moves/honest-testimonial-wall.md +57 -0
  53. package/kb/moves/inline-sparklines-in-copy.md +57 -0
  54. package/kb/moves/inspect-our-taste.md +58 -0
  55. package/kb/moves/interactive-pricing-calculator.md +59 -0
  56. package/kb/moves/isometric-illustration-system.md +56 -0
  57. package/kb/moves/kinetic-variable-type.md +57 -0
  58. package/kb/moves/konami-secret.md +59 -0
  59. package/kb/moves/layered-paper-depth.md +56 -0
  60. package/kb/moves/lightweight-3d-object-hero.md +59 -0
  61. package/kb/moves/line-engraving-from-image.md +63 -0
  62. package/kb/moves/link-preview-peek.md +57 -0
  63. package/kb/moves/live-data-ticker.md +61 -0
  64. package/kb/moves/made-with-proof.md +51 -0
  65. package/kb/moves/magnetic-buttons.md +55 -0
  66. package/kb/moves/marquee-done-right.md +58 -0
  67. package/kb/moves/moves.yaml +450 -0
  68. package/kb/moves/museum-painting-backdrop.md +59 -0
  69. package/kb/moves/one-colour-brand-world.md +56 -0
  70. package/kb/moves/playful-404.md +58 -0
  71. package/kb/moves/pointer-highlight-word.md +56 -0
  72. package/kb/moves/product-in-context.md +56 -0
  73. package/kb/moves/real-world-data.md +58 -0
  74. package/kb/moves/referral-reward-reveal.md +59 -0
  75. package/kb/moves/riso-print-texture.md +57 -0
  76. package/kb/moves/screenshot-detail-crops.md +56 -0
  77. package/kb/moves/scroll-progress-chapters.md +57 -0
  78. package/kb/moves/scroll-scrubbed-product-film.md +62 -0
  79. package/kb/moves/self-playing-product-demo.md +61 -0
  80. package/kb/moves/shape-continuity-morph.md +58 -0
  81. package/kb/moves/sliding-nav-indicator.md +58 -0
  82. package/kb/moves/sticky-scroll-story.md +56 -0
  83. package/kb/moves/story-led-long-scroll.md +56 -0
  84. package/kb/moves/tactile-button.md +63 -0
  85. package/kb/moves/technical-drawing-lines.md +57 -0
  86. package/kb/moves/time-of-day-theming.md +56 -0
  87. package/kb/moves/tiny-game-easter-egg.md +60 -0
  88. package/kb/moves/type-decode-reveal.md +57 -0
  89. package/kb/moves/typographic-numeral-hero.md +58 -0
  90. package/kb/moves/view-transitions-between-pages.md +57 -0
  91. package/kb/moves/waitlist-position-live.md +60 -0
  92. package/kb/patterns/app-team-members.md +27 -0
  93. package/kb/patterns/chat-agent-approvals.md +31 -0
  94. package/kb/patterns/commerce-product-page.md +34 -0
  95. package/kb/patterns/dashboard-entity-table.md +37 -0
  96. package/kb/patterns/dashboard-home-today.md +24 -0
  97. package/kb/patterns/docs-api-reference.md +31 -0
  98. package/kb/patterns/marketing-product-led-landing.md +30 -0
  99. package/kb/patterns/mobile-daily-checklist.md +26 -0
  100. package/kb/references/index.json +1 -0
  101. package/kb/references/thumbs/004c5e9072.jpg +0 -0
  102. package/kb/references/thumbs/008915eb21.jpg +0 -0
  103. package/kb/references/thumbs/0098cf66c2.jpg +0 -0
  104. package/kb/references/thumbs/012e61b31f.jpg +0 -0
  105. package/kb/references/thumbs/014d4e46fc.jpg +0 -0
  106. package/kb/references/thumbs/01e54f394a.jpg +0 -0
  107. package/kb/references/thumbs/01e99a579c.jpg +0 -0
  108. package/kb/references/thumbs/01fd014575.jpg +0 -0
  109. package/kb/references/thumbs/022778ca72.jpg +0 -0
  110. package/kb/references/thumbs/02717bf1e1.jpg +0 -0
  111. package/kb/references/thumbs/02a5cfdbe9.jpg +0 -0
  112. package/kb/references/thumbs/02c9823f8d.jpg +0 -0
  113. package/kb/references/thumbs/02f3974613.jpg +0 -0
  114. package/kb/references/thumbs/032427f1ce.jpg +0 -0
  115. package/kb/references/thumbs/03ba677d07.jpg +0 -0
  116. package/kb/references/thumbs/04f2476cfe.jpg +0 -0
  117. package/kb/references/thumbs/0563e7c52e.jpg +0 -0
  118. package/kb/references/thumbs/05fa6b8eef.jpg +0 -0
  119. package/kb/references/thumbs/065bce1517.jpg +0 -0
  120. package/kb/references/thumbs/06c017f113.jpg +0 -0
  121. package/kb/references/thumbs/0770e2d8d3.jpg +0 -0
  122. package/kb/references/thumbs/078a26c4cb.jpg +0 -0
  123. package/kb/references/thumbs/08679b6e84.jpg +0 -0
  124. package/kb/references/thumbs/088c45a34c.jpg +0 -0
  125. package/kb/references/thumbs/089e9fd4e4.jpg +0 -0
  126. package/kb/references/thumbs/08f773231e.jpg +0 -0
  127. package/kb/references/thumbs/093ca3e2e3.jpg +0 -0
  128. package/kb/references/thumbs/0963320f74.jpg +0 -0
  129. package/kb/references/thumbs/09fc1ded85.jpg +0 -0
  130. package/kb/references/thumbs/0a368f3963.jpg +0 -0
  131. package/kb/references/thumbs/0a9e0e5201.jpg +0 -0
  132. package/kb/references/thumbs/0aace67ee7.jpg +0 -0
  133. package/kb/references/thumbs/0b61ecf793.jpg +0 -0
  134. package/kb/references/thumbs/0bde18ae09.jpg +0 -0
  135. package/kb/references/thumbs/0bf7ee8143.jpg +0 -0
  136. package/kb/references/thumbs/0ca20a13e0.jpg +0 -0
  137. package/kb/references/thumbs/0cdc0198c4.jpg +0 -0
  138. package/kb/references/thumbs/0cf9790b28.jpg +0 -0
  139. package/kb/references/thumbs/0d0202904b.jpg +0 -0
  140. package/kb/references/thumbs/0d053aba18.jpg +0 -0
  141. package/kb/references/thumbs/0d0c2c13d2.jpg +0 -0
  142. package/kb/references/thumbs/0d30be99b0.jpg +0 -0
  143. package/kb/references/thumbs/0d503da1b7.jpg +0 -0
  144. package/kb/references/thumbs/0ddad7b740.jpg +0 -0
  145. package/kb/references/thumbs/0e0a148101.jpg +0 -0
  146. package/kb/references/thumbs/0e401b6b75.jpg +0 -0
  147. package/kb/references/thumbs/0e8f32ba0f.jpg +0 -0
  148. package/kb/references/thumbs/0ef1966a7d.jpg +0 -0
  149. package/kb/references/thumbs/0efd416d11.jpg +0 -0
  150. package/kb/references/thumbs/0f3af263ae.jpg +0 -0
  151. package/kb/references/thumbs/0f9644c3a5.jpg +0 -0
  152. package/kb/references/thumbs/1020552737.jpg +0 -0
  153. package/kb/references/thumbs/1037626587.jpg +0 -0
  154. package/kb/references/thumbs/10512b7e94.jpg +0 -0
  155. package/kb/references/thumbs/106dc4a7b5.jpg +0 -0
  156. package/kb/references/thumbs/108943f6f7.jpg +0 -0
  157. package/kb/references/thumbs/10a5551d51.jpg +0 -0
  158. package/kb/references/thumbs/10dd01076c.jpg +0 -0
  159. package/kb/references/thumbs/11b06e39da.jpg +0 -0
  160. package/kb/references/thumbs/11baa1ec83.jpg +0 -0
  161. package/kb/references/thumbs/11bbe12167.jpg +0 -0
  162. package/kb/references/thumbs/11ca37feb8.jpg +0 -0
  163. package/kb/references/thumbs/11f14d3f12.jpg +0 -0
  164. package/kb/references/thumbs/124530ceb5.jpg +0 -0
  165. package/kb/references/thumbs/1276402336.jpg +0 -0
  166. package/kb/references/thumbs/1280e5c9d6.jpg +0 -0
  167. package/kb/references/thumbs/12cac0d172.jpg +0 -0
  168. package/kb/references/thumbs/138be6623a.jpg +0 -0
  169. package/kb/references/thumbs/13a0c544d1.jpg +0 -0
  170. package/kb/references/thumbs/13a32cb94c.jpg +0 -0
  171. package/kb/references/thumbs/144035d641.jpg +0 -0
  172. package/kb/references/thumbs/1457e41924.jpg +0 -0
  173. package/kb/references/thumbs/14972e3a86.jpg +0 -0
  174. package/kb/references/thumbs/15a47f2e4c.jpg +0 -0
  175. package/kb/references/thumbs/15aa15d22e.jpg +0 -0
  176. package/kb/references/thumbs/160dcd24b7.jpg +0 -0
  177. package/kb/references/thumbs/1610978529.jpg +0 -0
  178. package/kb/references/thumbs/16db30ba37.jpg +0 -0
  179. package/kb/references/thumbs/16f19ae4f3.jpg +0 -0
  180. package/kb/references/thumbs/16f758b03f.jpg +0 -0
  181. package/kb/references/thumbs/1748e5b751.jpg +0 -0
  182. package/kb/references/thumbs/175d0b0e69.jpg +0 -0
  183. package/kb/references/thumbs/178f571a36.jpg +0 -0
  184. package/kb/references/thumbs/17c43dc025.jpg +0 -0
  185. package/kb/references/thumbs/17c7f05b50.jpg +0 -0
  186. package/kb/references/thumbs/17f97e61dd.jpg +0 -0
  187. package/kb/references/thumbs/1804e17365.jpg +0 -0
  188. package/kb/references/thumbs/195c162ed1.jpg +0 -0
  189. package/kb/references/thumbs/19e3699c29.jpg +0 -0
  190. package/kb/references/thumbs/1a48e0a4d5.jpg +0 -0
  191. package/kb/references/thumbs/1a6cda265e.jpg +0 -0
  192. package/kb/references/thumbs/1a7e012091.jpg +0 -0
  193. package/kb/references/thumbs/1a9173a172.jpg +0 -0
  194. package/kb/references/thumbs/1b34a6b4d2.jpg +0 -0
  195. package/kb/references/thumbs/1b5284f3b2.jpg +0 -0
  196. package/kb/references/thumbs/1b93fbd6d3.jpg +0 -0
  197. package/kb/references/thumbs/1c6728fef6.jpg +0 -0
  198. package/kb/references/thumbs/1c6f101618.jpg +0 -0
  199. package/kb/references/thumbs/1cf7011a94.jpg +0 -0
  200. package/kb/references/thumbs/1d1769e539.jpg +0 -0
  201. package/kb/references/thumbs/1d1fd23199.jpg +0 -0
  202. package/kb/references/thumbs/1d7b6602ac.jpg +0 -0
  203. package/kb/references/thumbs/1dbbc61b9e.jpg +0 -0
  204. package/kb/references/thumbs/1dbdd6d21d.jpg +0 -0
  205. package/kb/references/thumbs/1dd873744b.jpg +0 -0
  206. package/kb/references/thumbs/1df4dd7cf9.jpg +0 -0
  207. package/kb/references/thumbs/1ece8c35b8.jpg +0 -0
  208. package/kb/references/thumbs/1f0e5b9aa4.jpg +0 -0
  209. package/kb/references/thumbs/1f1419651b.jpg +0 -0
  210. package/kb/references/thumbs/1f2a6da92d.jpg +0 -0
  211. package/kb/references/thumbs/1f651f33c0.jpg +0 -0
  212. package/kb/references/thumbs/1f8b697d18.jpg +0 -0
  213. package/kb/references/thumbs/1fee3824cd.jpg +0 -0
  214. package/kb/references/thumbs/1ff7757853.jpg +0 -0
  215. package/kb/references/thumbs/2043182f01.jpg +0 -0
  216. package/kb/references/thumbs/2059dabcd5.jpg +0 -0
  217. package/kb/references/thumbs/209d9dbb95.jpg +0 -0
  218. package/kb/references/thumbs/20d8923554.jpg +0 -0
  219. package/kb/references/thumbs/210dd3b671.jpg +0 -0
  220. package/kb/references/thumbs/2120719116.jpg +0 -0
  221. package/kb/references/thumbs/21a7384429.jpg +0 -0
  222. package/kb/references/thumbs/225f187391.jpg +0 -0
  223. package/kb/references/thumbs/230caf7dd2.jpg +0 -0
  224. package/kb/references/thumbs/235afad355.jpg +0 -0
  225. package/kb/references/thumbs/2378066687.jpg +0 -0
  226. package/kb/references/thumbs/241faf68a1.jpg +0 -0
  227. package/kb/references/thumbs/24d9f1a9b9.jpg +0 -0
  228. package/kb/references/thumbs/2505c8b9a0.jpg +0 -0
  229. package/kb/references/thumbs/25593638ca.jpg +0 -0
  230. package/kb/references/thumbs/25dd454f18.jpg +0 -0
  231. package/kb/references/thumbs/2602e123e2.jpg +0 -0
  232. package/kb/references/thumbs/26095c0b11.jpg +0 -0
  233. package/kb/references/thumbs/26260d6238.jpg +0 -0
  234. package/kb/references/thumbs/26bba21836.jpg +0 -0
  235. package/kb/references/thumbs/26bde3520b.jpg +0 -0
  236. package/kb/references/thumbs/272e22067c.jpg +0 -0
  237. package/kb/references/thumbs/27421b3226.jpg +0 -0
  238. package/kb/references/thumbs/2769ebca41.jpg +0 -0
  239. package/kb/references/thumbs/27e2f6e8b0.jpg +0 -0
  240. package/kb/references/thumbs/28432ba373.jpg +0 -0
  241. package/kb/references/thumbs/2846626f19.jpg +0 -0
  242. package/kb/references/thumbs/28750e821e.jpg +0 -0
  243. package/kb/references/thumbs/289481230f.jpg +0 -0
  244. package/kb/references/thumbs/2897967408.jpg +0 -0
  245. package/kb/references/thumbs/28c0a5fa17.jpg +0 -0
  246. package/kb/references/thumbs/28c181fba5.jpg +0 -0
  247. package/kb/references/thumbs/29806f539f.jpg +0 -0
  248. package/kb/references/thumbs/2997f56ee7.jpg +0 -0
  249. package/kb/references/thumbs/29b34a10fb.jpg +0 -0
  250. package/kb/references/thumbs/29bd78cdb4.jpg +0 -0
  251. package/kb/references/thumbs/29c8c6c22a.jpg +0 -0
  252. package/kb/references/thumbs/2ac23f7fae.jpg +0 -0
  253. package/kb/references/thumbs/2b76e13f79.jpg +0 -0
  254. package/kb/references/thumbs/2b84226479.jpg +0 -0
  255. package/kb/references/thumbs/2bf2dbf737.jpg +0 -0
  256. package/kb/references/thumbs/2bf89abbf6.jpg +0 -0
  257. package/kb/references/thumbs/2c562cd534.jpg +0 -0
  258. package/kb/references/thumbs/2cfe9d48c4.jpg +0 -0
  259. package/kb/references/thumbs/2d49f19b27.jpg +0 -0
  260. package/kb/references/thumbs/2dc8670da7.jpg +0 -0
  261. package/kb/references/thumbs/2de947c469.jpg +0 -0
  262. package/kb/references/thumbs/2e075ca79f.jpg +0 -0
  263. package/kb/references/thumbs/2eb0820e6b.jpg +0 -0
  264. package/kb/references/thumbs/2ec56a9dc0.jpg +0 -0
  265. package/kb/references/thumbs/30bb4ad607.jpg +0 -0
  266. package/kb/references/thumbs/30d19b8444.jpg +0 -0
  267. package/kb/references/thumbs/3173c71d73.jpg +0 -0
  268. package/kb/references/thumbs/31e59e4518.jpg +0 -0
  269. package/kb/references/thumbs/322b8960e8.jpg +0 -0
  270. package/kb/references/thumbs/325c9be6f4.jpg +0 -0
  271. package/kb/references/thumbs/3273338982.jpg +0 -0
  272. package/kb/references/thumbs/32f8387f38.jpg +0 -0
  273. package/kb/references/thumbs/332f6b74c3.jpg +0 -0
  274. package/kb/references/thumbs/334b146b6a.jpg +0 -0
  275. package/kb/references/thumbs/339abd60e4.jpg +0 -0
  276. package/kb/references/thumbs/33e88ec295.jpg +0 -0
  277. package/kb/references/thumbs/340931b5d4.jpg +0 -0
  278. package/kb/references/thumbs/34165a93bd.jpg +0 -0
  279. package/kb/references/thumbs/34d0575dd7.jpg +0 -0
  280. package/kb/references/thumbs/3549e75f0a.jpg +0 -0
  281. package/kb/references/thumbs/35827f1561.jpg +0 -0
  282. package/kb/references/thumbs/37c50280ec.jpg +0 -0
  283. package/kb/references/thumbs/37e66ecf11.jpg +0 -0
  284. package/kb/references/thumbs/3841a04fdc.jpg +0 -0
  285. package/kb/references/thumbs/38490c088f.jpg +0 -0
  286. package/kb/references/thumbs/3850319e9f.jpg +0 -0
  287. package/kb/references/thumbs/3856a64166.jpg +0 -0
  288. package/kb/references/thumbs/3881f211c2.jpg +0 -0
  289. package/kb/references/thumbs/38c7dde2f3.jpg +0 -0
  290. package/kb/references/thumbs/38ce9e486c.jpg +0 -0
  291. package/kb/references/thumbs/390ea8e01b.jpg +0 -0
  292. package/kb/references/thumbs/391b7fc27c.jpg +0 -0
  293. package/kb/references/thumbs/395f7214dc.jpg +0 -0
  294. package/kb/references/thumbs/39e81a5db2.jpg +0 -0
  295. package/kb/references/thumbs/3a67c8d655.jpg +0 -0
  296. package/kb/references/thumbs/3a89c25e3b.jpg +0 -0
  297. package/kb/references/thumbs/3aa0837542.jpg +0 -0
  298. package/kb/references/thumbs/3aae18aa8a.jpg +0 -0
  299. package/kb/references/thumbs/3bdbe767db.jpg +0 -0
  300. package/kb/references/thumbs/3c0616fc7f.jpg +0 -0
  301. package/kb/references/thumbs/3c18e9db1d.jpg +0 -0
  302. package/kb/references/thumbs/3c5a14076c.jpg +0 -0
  303. package/kb/references/thumbs/3ca9ec15c6.jpg +0 -0
  304. package/kb/references/thumbs/3d7756fd35.jpg +0 -0
  305. package/kb/references/thumbs/3dd45bd33d.jpg +0 -0
  306. package/kb/references/thumbs/3de72d5414.jpg +0 -0
  307. package/kb/references/thumbs/3dede597af.jpg +0 -0
  308. package/kb/references/thumbs/3ea948619e.jpg +0 -0
  309. package/kb/references/thumbs/402c12054c.jpg +0 -0
  310. package/kb/references/thumbs/403ab4af90.jpg +0 -0
  311. package/kb/references/thumbs/40773a8c63.jpg +0 -0
  312. package/kb/references/thumbs/407d9583db.jpg +0 -0
  313. package/kb/references/thumbs/415dc1d84c.jpg +0 -0
  314. package/kb/references/thumbs/420b676a4f.jpg +0 -0
  315. package/kb/references/thumbs/42a1ee85eb.jpg +0 -0
  316. package/kb/references/thumbs/43059221aa.jpg +0 -0
  317. package/kb/references/thumbs/432fa0d22c.jpg +0 -0
  318. package/kb/references/thumbs/43826f20e3.jpg +0 -0
  319. package/kb/references/thumbs/43ac55c98a.jpg +0 -0
  320. package/kb/references/thumbs/43d098f3c3.jpg +0 -0
  321. package/kb/references/thumbs/4449d80c2c.jpg +0 -0
  322. package/kb/references/thumbs/44625727dc.jpg +0 -0
  323. package/kb/references/thumbs/4482bb87a1.jpg +0 -0
  324. package/kb/references/thumbs/44b078acdc.jpg +0 -0
  325. package/kb/references/thumbs/44d0305850.jpg +0 -0
  326. package/kb/references/thumbs/456bb6b59e.jpg +0 -0
  327. package/kb/references/thumbs/45df73ce48.jpg +0 -0
  328. package/kb/references/thumbs/45edb45d87.jpg +0 -0
  329. package/kb/references/thumbs/4671d57cd5.jpg +0 -0
  330. package/kb/references/thumbs/46cc108518.jpg +0 -0
  331. package/kb/references/thumbs/470022e614.jpg +0 -0
  332. package/kb/references/thumbs/4719a669ce.jpg +0 -0
  333. package/kb/references/thumbs/47404f5ad4.jpg +0 -0
  334. package/kb/references/thumbs/479d3eb977.jpg +0 -0
  335. package/kb/references/thumbs/479ed92ceb.jpg +0 -0
  336. package/kb/references/thumbs/47baed50c7.jpg +0 -0
  337. package/kb/references/thumbs/47fdcfd7b0.jpg +0 -0
  338. package/kb/references/thumbs/48fd5e94c5.jpg +0 -0
  339. package/kb/references/thumbs/493807917b.jpg +0 -0
  340. package/kb/references/thumbs/49a1c67293.jpg +0 -0
  341. package/kb/references/thumbs/49e2d7fafe.jpg +0 -0
  342. package/kb/references/thumbs/49f540fcb6.jpg +0 -0
  343. package/kb/references/thumbs/4a67ec4028.jpg +0 -0
  344. package/kb/references/thumbs/4a93275b04.jpg +0 -0
  345. package/kb/references/thumbs/4aae6f52da.jpg +0 -0
  346. package/kb/references/thumbs/4b1bae66bd.jpg +0 -0
  347. package/kb/references/thumbs/4b75da15a9.jpg +0 -0
  348. package/kb/references/thumbs/4b77789b88.jpg +0 -0
  349. package/kb/references/thumbs/4bc2f3f3a4.jpg +0 -0
  350. package/kb/references/thumbs/4c48f27b88.jpg +0 -0
  351. package/kb/references/thumbs/4c52bd8bfb.jpg +0 -0
  352. package/kb/references/thumbs/4c9b4acc60.jpg +0 -0
  353. package/kb/references/thumbs/4cbf0752d4.jpg +0 -0
  354. package/kb/references/thumbs/4cd2672517.jpg +0 -0
  355. package/kb/references/thumbs/4dd22a8181.jpg +0 -0
  356. package/kb/references/thumbs/4ee3447314.jpg +0 -0
  357. package/kb/references/thumbs/4ef29c8144.jpg +0 -0
  358. package/kb/references/thumbs/4f82fadfd6.jpg +0 -0
  359. package/kb/references/thumbs/4fc9b643d8.jpg +0 -0
  360. package/kb/references/thumbs/50549524b0.jpg +0 -0
  361. package/kb/references/thumbs/509a615883.jpg +0 -0
  362. package/kb/references/thumbs/50c03ef855.jpg +0 -0
  363. package/kb/references/thumbs/50cf9acad6.jpg +0 -0
  364. package/kb/references/thumbs/51131b025c.jpg +0 -0
  365. package/kb/references/thumbs/51da1124f0.jpg +0 -0
  366. package/kb/references/thumbs/524d5e7288.jpg +0 -0
  367. package/kb/references/thumbs/5251247c81.jpg +0 -0
  368. package/kb/references/thumbs/526b91b7ec.jpg +0 -0
  369. package/kb/references/thumbs/52f02f6c2e.jpg +0 -0
  370. package/kb/references/thumbs/530ab530dc.jpg +0 -0
  371. package/kb/references/thumbs/5335ee4404.jpg +0 -0
  372. package/kb/references/thumbs/5385b90939.jpg +0 -0
  373. package/kb/references/thumbs/53c54654cc.jpg +0 -0
  374. package/kb/references/thumbs/5420794c6c.jpg +0 -0
  375. package/kb/references/thumbs/542a9dce8b.jpg +0 -0
  376. package/kb/references/thumbs/5571530a5f.jpg +0 -0
  377. package/kb/references/thumbs/56cc68d804.jpg +0 -0
  378. package/kb/references/thumbs/577b7f7c44.jpg +0 -0
  379. package/kb/references/thumbs/57adf8f1bb.jpg +0 -0
  380. package/kb/references/thumbs/57c5f5e3a6.jpg +0 -0
  381. package/kb/references/thumbs/57ffe4e839.jpg +0 -0
  382. package/kb/references/thumbs/5817dfc7d6.jpg +0 -0
  383. package/kb/references/thumbs/581a182a7a.jpg +0 -0
  384. package/kb/references/thumbs/58807679c8.jpg +0 -0
  385. package/kb/references/thumbs/589a1d9111.jpg +0 -0
  386. package/kb/references/thumbs/59167391ab.jpg +0 -0
  387. package/kb/references/thumbs/5a70420166.jpg +0 -0
  388. package/kb/references/thumbs/5b10df1b8d.jpg +0 -0
  389. package/kb/references/thumbs/5b7a712fdb.jpg +0 -0
  390. package/kb/references/thumbs/5bc46b92ad.jpg +0 -0
  391. package/kb/references/thumbs/5c0546a120.jpg +0 -0
  392. package/kb/references/thumbs/5c2b6125a8.jpg +0 -0
  393. package/kb/references/thumbs/5c536b9e42.jpg +0 -0
  394. package/kb/references/thumbs/5c8e441d30.jpg +0 -0
  395. package/kb/references/thumbs/5cb6f1baa5.jpg +0 -0
  396. package/kb/references/thumbs/5ce6c1f21e.jpg +0 -0
  397. package/kb/references/thumbs/5cef052c0a.jpg +0 -0
  398. package/kb/references/thumbs/5d08438209.jpg +0 -0
  399. package/kb/references/thumbs/5d0f9af9b0.jpg +0 -0
  400. package/kb/references/thumbs/5d300ed332.jpg +0 -0
  401. package/kb/references/thumbs/5d708a4794.jpg +0 -0
  402. package/kb/references/thumbs/5de8826a98.jpg +0 -0
  403. package/kb/references/thumbs/5df7bff22c.jpg +0 -0
  404. package/kb/references/thumbs/5e087d0f00.jpg +0 -0
  405. package/kb/references/thumbs/5e44e70ca0.jpg +0 -0
  406. package/kb/references/thumbs/5eff5d80ce.jpg +0 -0
  407. package/kb/references/thumbs/5f015c96b1.jpg +0 -0
  408. package/kb/references/thumbs/5f3289b7c4.jpg +0 -0
  409. package/kb/references/thumbs/5f830c40eb.jpg +0 -0
  410. package/kb/references/thumbs/60c4c3527b.jpg +0 -0
  411. package/kb/references/thumbs/60e9e594dd.jpg +0 -0
  412. package/kb/references/thumbs/615421d7be.jpg +0 -0
  413. package/kb/references/thumbs/6176e4004f.jpg +0 -0
  414. package/kb/references/thumbs/61f0fe5e06.jpg +0 -0
  415. package/kb/references/thumbs/6213785db4.jpg +0 -0
  416. package/kb/references/thumbs/62a670ae09.jpg +0 -0
  417. package/kb/references/thumbs/63cc12981b.jpg +0 -0
  418. package/kb/references/thumbs/641f15cc71.jpg +0 -0
  419. package/kb/references/thumbs/642ab2081d.jpg +0 -0
  420. package/kb/references/thumbs/644a59bf6e.jpg +0 -0
  421. package/kb/references/thumbs/644da8a8e3.jpg +0 -0
  422. package/kb/references/thumbs/6458986897.jpg +0 -0
  423. package/kb/references/thumbs/64cfbd7b93.jpg +0 -0
  424. package/kb/references/thumbs/661a57686a.jpg +0 -0
  425. package/kb/references/thumbs/66355a813a.jpg +0 -0
  426. package/kb/references/thumbs/664396dd44.jpg +0 -0
  427. package/kb/references/thumbs/66d832d65f.jpg +0 -0
  428. package/kb/references/thumbs/66de9e9833.jpg +0 -0
  429. package/kb/references/thumbs/6750964fd9.jpg +0 -0
  430. package/kb/references/thumbs/67c7164832.jpg +0 -0
  431. package/kb/references/thumbs/681600b6cd.jpg +0 -0
  432. package/kb/references/thumbs/682e75afe4.jpg +0 -0
  433. package/kb/references/thumbs/69274bc952.jpg +0 -0
  434. package/kb/references/thumbs/696ec08c52.jpg +0 -0
  435. package/kb/references/thumbs/69760111cc.jpg +0 -0
  436. package/kb/references/thumbs/697e32664f.jpg +0 -0
  437. package/kb/references/thumbs/69df92544b.jpg +0 -0
  438. package/kb/references/thumbs/69e48c5229.jpg +0 -0
  439. package/kb/references/thumbs/6a5fb75de1.jpg +0 -0
  440. package/kb/references/thumbs/6a7389e472.jpg +0 -0
  441. package/kb/references/thumbs/6a9b041e02.jpg +0 -0
  442. package/kb/references/thumbs/6ab2fa93ee.jpg +0 -0
  443. package/kb/references/thumbs/6ae3400319.jpg +0 -0
  444. package/kb/references/thumbs/6b21344bf3.jpg +0 -0
  445. package/kb/references/thumbs/6bd1b67a8a.jpg +0 -0
  446. package/kb/references/thumbs/6c99156c4f.jpg +0 -0
  447. package/kb/references/thumbs/6cc9b65384.jpg +0 -0
  448. package/kb/references/thumbs/6d15830a73.jpg +0 -0
  449. package/kb/references/thumbs/6d4c33d180.jpg +0 -0
  450. package/kb/references/thumbs/6e36815799.jpg +0 -0
  451. package/kb/references/thumbs/6eddb9cbfc.jpg +0 -0
  452. package/kb/references/thumbs/6f97968a7c.jpg +0 -0
  453. package/kb/references/thumbs/6fa0716a7d.jpg +0 -0
  454. package/kb/references/thumbs/6facd57184.jpg +0 -0
  455. package/kb/references/thumbs/6fd57b785a.jpg +0 -0
  456. package/kb/references/thumbs/700b3cb185.jpg +0 -0
  457. package/kb/references/thumbs/71197443fa.jpg +0 -0
  458. package/kb/references/thumbs/72082bc9ee.jpg +0 -0
  459. package/kb/references/thumbs/72453db479.jpg +0 -0
  460. package/kb/references/thumbs/72cd64d500.jpg +0 -0
  461. package/kb/references/thumbs/72d1e75283.jpg +0 -0
  462. package/kb/references/thumbs/72e13f7f5b.jpg +0 -0
  463. package/kb/references/thumbs/7459f8e644.jpg +0 -0
  464. package/kb/references/thumbs/7470d55c79.jpg +0 -0
  465. package/kb/references/thumbs/74c468f02a.jpg +0 -0
  466. package/kb/references/thumbs/74fed6eb77.jpg +0 -0
  467. package/kb/references/thumbs/756e05080d.jpg +0 -0
  468. package/kb/references/thumbs/75df7e5f49.jpg +0 -0
  469. package/kb/references/thumbs/76226da6ef.jpg +0 -0
  470. package/kb/references/thumbs/76a34aa056.jpg +0 -0
  471. package/kb/references/thumbs/76c7076589.jpg +0 -0
  472. package/kb/references/thumbs/76cccc396c.jpg +0 -0
  473. package/kb/references/thumbs/774654789f.jpg +0 -0
  474. package/kb/references/thumbs/7746cc494d.jpg +0 -0
  475. package/kb/references/thumbs/7766e36aa3.jpg +0 -0
  476. package/kb/references/thumbs/78049331ef.jpg +0 -0
  477. package/kb/references/thumbs/78808a0ca5.jpg +0 -0
  478. package/kb/references/thumbs/7890b0a310.jpg +0 -0
  479. package/kb/references/thumbs/78911975e6.jpg +0 -0
  480. package/kb/references/thumbs/78d289d5a0.jpg +0 -0
  481. package/kb/references/thumbs/794126267e.jpg +0 -0
  482. package/kb/references/thumbs/7976eb9025.jpg +0 -0
  483. package/kb/references/thumbs/798519ec7c.jpg +0 -0
  484. package/kb/references/thumbs/7a6cc5eecc.jpg +0 -0
  485. package/kb/references/thumbs/7ac8a7cd4a.jpg +0 -0
  486. package/kb/references/thumbs/7b1341d61d.jpg +0 -0
  487. package/kb/references/thumbs/7b9c4031e3.jpg +0 -0
  488. package/kb/references/thumbs/7ba5ad3779.jpg +0 -0
  489. package/kb/references/thumbs/7be6eb2bd0.jpg +0 -0
  490. package/kb/references/thumbs/7c30864f5d.jpg +0 -0
  491. package/kb/references/thumbs/7c379b5e17.jpg +0 -0
  492. package/kb/references/thumbs/7c4050eb02.jpg +0 -0
  493. package/kb/references/thumbs/7ca47b3221.jpg +0 -0
  494. package/kb/references/thumbs/7d43516bd7.jpg +0 -0
  495. package/kb/references/thumbs/7da9dbb98a.jpg +0 -0
  496. package/kb/references/thumbs/7ddda8f57c.jpg +0 -0
  497. package/kb/references/thumbs/7ece6d215c.jpg +0 -0
  498. package/kb/references/thumbs/7eebf029de.jpg +0 -0
  499. package/kb/references/thumbs/7f45483c15.jpg +0 -0
  500. package/kb/references/thumbs/7fde06eaa5.jpg +0 -0
  501. package/kb/references/thumbs/80407b97e9.jpg +0 -0
  502. package/kb/references/thumbs/80f0a6cf4b.jpg +0 -0
  503. package/kb/references/thumbs/8118b451b8.jpg +0 -0
  504. package/kb/references/thumbs/816baed4a8.jpg +0 -0
  505. package/kb/references/thumbs/817d2d15d9.jpg +0 -0
  506. package/kb/references/thumbs/8260cb430d.jpg +0 -0
  507. package/kb/references/thumbs/827b562899.jpg +0 -0
  508. package/kb/references/thumbs/8293cf1e92.jpg +0 -0
  509. package/kb/references/thumbs/8294653169.jpg +0 -0
  510. package/kb/references/thumbs/83061f871f.jpg +0 -0
  511. package/kb/references/thumbs/833df778ca.jpg +0 -0
  512. package/kb/references/thumbs/83d3acaafc.jpg +0 -0
  513. package/kb/references/thumbs/844c6efeff.jpg +0 -0
  514. package/kb/references/thumbs/84563d482a.jpg +0 -0
  515. package/kb/references/thumbs/848082dd94.jpg +0 -0
  516. package/kb/references/thumbs/8494b1da94.jpg +0 -0
  517. package/kb/references/thumbs/84b71014be.jpg +0 -0
  518. package/kb/references/thumbs/84be4a5f3c.jpg +0 -0
  519. package/kb/references/thumbs/84fd0fd25a.jpg +0 -0
  520. package/kb/references/thumbs/853e488e22.jpg +0 -0
  521. package/kb/references/thumbs/858c91585d.jpg +0 -0
  522. package/kb/references/thumbs/85903e8fe9.jpg +0 -0
  523. package/kb/references/thumbs/86597d43fd.jpg +0 -0
  524. package/kb/references/thumbs/866eb99500.jpg +0 -0
  525. package/kb/references/thumbs/86ac050340.jpg +0 -0
  526. package/kb/references/thumbs/86afec7b64.jpg +0 -0
  527. package/kb/references/thumbs/87238127f5.jpg +0 -0
  528. package/kb/references/thumbs/87321df792.jpg +0 -0
  529. package/kb/references/thumbs/87460f70cd.jpg +0 -0
  530. package/kb/references/thumbs/8770dfeaec.jpg +0 -0
  531. package/kb/references/thumbs/8798451a8c.jpg +0 -0
  532. package/kb/references/thumbs/87da1f34a3.jpg +0 -0
  533. package/kb/references/thumbs/882cdf8c05.jpg +0 -0
  534. package/kb/references/thumbs/8839f4106f.jpg +0 -0
  535. package/kb/references/thumbs/8844455212.jpg +0 -0
  536. package/kb/references/thumbs/88abba0497.jpg +0 -0
  537. package/kb/references/thumbs/88b372435d.jpg +0 -0
  538. package/kb/references/thumbs/88bd4f35fa.jpg +0 -0
  539. package/kb/references/thumbs/88c71a075e.jpg +0 -0
  540. package/kb/references/thumbs/892e5f048e.jpg +0 -0
  541. package/kb/references/thumbs/893cc8e920.jpg +0 -0
  542. package/kb/references/thumbs/896c198814.jpg +0 -0
  543. package/kb/references/thumbs/8a8e22f756.jpg +0 -0
  544. package/kb/references/thumbs/8a9d8a35cb.jpg +0 -0
  545. package/kb/references/thumbs/8ab1d67fec.jpg +0 -0
  546. package/kb/references/thumbs/8ab201fe12.jpg +0 -0
  547. package/kb/references/thumbs/8ac372c102.jpg +0 -0
  548. package/kb/references/thumbs/8b15736d62.jpg +0 -0
  549. package/kb/references/thumbs/8b1d8d6a05.jpg +0 -0
  550. package/kb/references/thumbs/8bb6050e20.jpg +0 -0
  551. package/kb/references/thumbs/8c6c9d1577.jpg +0 -0
  552. package/kb/references/thumbs/8d337851e0.jpg +0 -0
  553. package/kb/references/thumbs/8d44b33cc5.jpg +0 -0
  554. package/kb/references/thumbs/8d4536ff3b.jpg +0 -0
  555. package/kb/references/thumbs/8d9b99454a.jpg +0 -0
  556. package/kb/references/thumbs/8dda2303ff.jpg +0 -0
  557. package/kb/references/thumbs/8dec722d62.jpg +0 -0
  558. package/kb/references/thumbs/8e0ea4ca74.jpg +0 -0
  559. package/kb/references/thumbs/8ebba84d69.jpg +0 -0
  560. package/kb/references/thumbs/8ef09140c0.jpg +0 -0
  561. package/kb/references/thumbs/8f2928a1b0.jpg +0 -0
  562. package/kb/references/thumbs/8f88f9ddba.jpg +0 -0
  563. package/kb/references/thumbs/8fa4451009.jpg +0 -0
  564. package/kb/references/thumbs/90109b0e02.jpg +0 -0
  565. package/kb/references/thumbs/90e854e5c9.jpg +0 -0
  566. package/kb/references/thumbs/914e79f893.jpg +0 -0
  567. package/kb/references/thumbs/9161369197.jpg +0 -0
  568. package/kb/references/thumbs/9165c87d6f.jpg +0 -0
  569. package/kb/references/thumbs/9193f6558a.jpg +0 -0
  570. package/kb/references/thumbs/91ac7df877.jpg +0 -0
  571. package/kb/references/thumbs/9216bd4931.jpg +0 -0
  572. package/kb/references/thumbs/922ae8a26a.jpg +0 -0
  573. package/kb/references/thumbs/92a70e6867.jpg +0 -0
  574. package/kb/references/thumbs/92c77ece22.jpg +0 -0
  575. package/kb/references/thumbs/92e5914fbf.jpg +0 -0
  576. package/kb/references/thumbs/92ee36419a.jpg +0 -0
  577. package/kb/references/thumbs/94153a60b0.jpg +0 -0
  578. package/kb/references/thumbs/9449666640.jpg +0 -0
  579. package/kb/references/thumbs/944be6a646.jpg +0 -0
  580. package/kb/references/thumbs/945831476e.jpg +0 -0
  581. package/kb/references/thumbs/94c1af82f4.jpg +0 -0
  582. package/kb/references/thumbs/9599d6d589.jpg +0 -0
  583. package/kb/references/thumbs/960710f4cf.jpg +0 -0
  584. package/kb/references/thumbs/9608f12d64.jpg +0 -0
  585. package/kb/references/thumbs/962dabfaa0.jpg +0 -0
  586. package/kb/references/thumbs/965a3a95c6.jpg +0 -0
  587. package/kb/references/thumbs/9672ed5ae4.jpg +0 -0
  588. package/kb/references/thumbs/96891ae9c1.jpg +0 -0
  589. package/kb/references/thumbs/96e1907c99.jpg +0 -0
  590. package/kb/references/thumbs/96f25b6578.jpg +0 -0
  591. package/kb/references/thumbs/97211df9ae.jpg +0 -0
  592. package/kb/references/thumbs/9769d763a5.jpg +0 -0
  593. package/kb/references/thumbs/9792bd6d05.jpg +0 -0
  594. package/kb/references/thumbs/97d2837e3e.jpg +0 -0
  595. package/kb/references/thumbs/97d90d1d85.jpg +0 -0
  596. package/kb/references/thumbs/97fcd5774a.jpg +0 -0
  597. package/kb/references/thumbs/980f68564e.jpg +0 -0
  598. package/kb/references/thumbs/98511fb393.jpg +0 -0
  599. package/kb/references/thumbs/98f8fa694d.jpg +0 -0
  600. package/kb/references/thumbs/9a42c6bb97.jpg +0 -0
  601. package/kb/references/thumbs/9ab3600a06.jpg +0 -0
  602. package/kb/references/thumbs/9ab48d9130.jpg +0 -0
  603. package/kb/references/thumbs/9ad519197d.jpg +0 -0
  604. package/kb/references/thumbs/9b1382c657.jpg +0 -0
  605. package/kb/references/thumbs/9b6cc1e077.jpg +0 -0
  606. package/kb/references/thumbs/9beede8480.jpg +0 -0
  607. package/kb/references/thumbs/9bf8976952.jpg +0 -0
  608. package/kb/references/thumbs/9cace7b75a.jpg +0 -0
  609. package/kb/references/thumbs/9cdcc5745e.jpg +0 -0
  610. package/kb/references/thumbs/9d0b269074.jpg +0 -0
  611. package/kb/references/thumbs/9d41788b48.jpg +0 -0
  612. package/kb/references/thumbs/9d475bd6af.jpg +0 -0
  613. package/kb/references/thumbs/9e6bc543d0.jpg +0 -0
  614. package/kb/references/thumbs/9ed0e0a206.jpg +0 -0
  615. package/kb/references/thumbs/9ef538de13.jpg +0 -0
  616. package/kb/references/thumbs/9efc373ab4.jpg +0 -0
  617. package/kb/references/thumbs/9f4a939fa5.jpg +0 -0
  618. package/kb/references/thumbs/9f8d12d7b9.jpg +0 -0
  619. package/kb/references/thumbs/9fd5e3efa7.jpg +0 -0
  620. package/kb/references/thumbs/a0a9b9c572.jpg +0 -0
  621. package/kb/references/thumbs/a29ca9b185.jpg +0 -0
  622. package/kb/references/thumbs/a2a42884af.jpg +0 -0
  623. package/kb/references/thumbs/a2f5064e34.jpg +0 -0
  624. package/kb/references/thumbs/a3112ce672.jpg +0 -0
  625. package/kb/references/thumbs/a3437736d1.jpg +0 -0
  626. package/kb/references/thumbs/a372667e76.jpg +0 -0
  627. package/kb/references/thumbs/a39bae94e9.jpg +0 -0
  628. package/kb/references/thumbs/a3fc75d94c.jpg +0 -0
  629. package/kb/references/thumbs/a440487631.jpg +0 -0
  630. package/kb/references/thumbs/a4993d5fb5.jpg +0 -0
  631. package/kb/references/thumbs/a500476a86.jpg +0 -0
  632. package/kb/references/thumbs/a55506bf46.jpg +0 -0
  633. package/kb/references/thumbs/a59a5f9843.jpg +0 -0
  634. package/kb/references/thumbs/a5bce0eede.jpg +0 -0
  635. package/kb/references/thumbs/a5d921e1f0.jpg +0 -0
  636. package/kb/references/thumbs/a5e19d4637.jpg +0 -0
  637. package/kb/references/thumbs/a5f92b97d5.jpg +0 -0
  638. package/kb/references/thumbs/a6562c210a.jpg +0 -0
  639. package/kb/references/thumbs/a6f61a8d09.jpg +0 -0
  640. package/kb/references/thumbs/a719fdf663.jpg +0 -0
  641. package/kb/references/thumbs/a724e5442f.jpg +0 -0
  642. package/kb/references/thumbs/a852b4319f.jpg +0 -0
  643. package/kb/references/thumbs/a896c08448.jpg +0 -0
  644. package/kb/references/thumbs/a8d190a4b8.jpg +0 -0
  645. package/kb/references/thumbs/a8dcdd57d7.jpg +0 -0
  646. package/kb/references/thumbs/a951347e18.jpg +0 -0
  647. package/kb/references/thumbs/a9a1a0bf7d.jpg +0 -0
  648. package/kb/references/thumbs/a9b72986a8.jpg +0 -0
  649. package/kb/references/thumbs/aa11555ba8.jpg +0 -0
  650. package/kb/references/thumbs/aa4aab9093.jpg +0 -0
  651. package/kb/references/thumbs/aa89b96658.jpg +0 -0
  652. package/kb/references/thumbs/aaeb3739b6.jpg +0 -0
  653. package/kb/references/thumbs/ab25a608ec.jpg +0 -0
  654. package/kb/references/thumbs/ab34b62268.jpg +0 -0
  655. package/kb/references/thumbs/ab3b0217bb.jpg +0 -0
  656. package/kb/references/thumbs/ac70c04afb.jpg +0 -0
  657. package/kb/references/thumbs/ace0879117.jpg +0 -0
  658. package/kb/references/thumbs/ad0515ae55.jpg +0 -0
  659. package/kb/references/thumbs/ad66b25b47.jpg +0 -0
  660. package/kb/references/thumbs/ad68229d2f.jpg +0 -0
  661. package/kb/references/thumbs/add6480693.jpg +0 -0
  662. package/kb/references/thumbs/ae5b8c3b8c.jpg +0 -0
  663. package/kb/references/thumbs/ae81247b47.jpg +0 -0
  664. package/kb/references/thumbs/af8aa54379.jpg +0 -0
  665. package/kb/references/thumbs/afa80dedd4.jpg +0 -0
  666. package/kb/references/thumbs/afe04d730f.jpg +0 -0
  667. package/kb/references/thumbs/b09a7dc315.jpg +0 -0
  668. package/kb/references/thumbs/b0c02629f6.jpg +0 -0
  669. package/kb/references/thumbs/b1cb4f91de.jpg +0 -0
  670. package/kb/references/thumbs/b1d4c13c92.jpg +0 -0
  671. package/kb/references/thumbs/b20eef86db.jpg +0 -0
  672. package/kb/references/thumbs/b3136ccdde.jpg +0 -0
  673. package/kb/references/thumbs/b3f5e8d7dd.jpg +0 -0
  674. package/kb/references/thumbs/b44adb81c9.jpg +0 -0
  675. package/kb/references/thumbs/b457a5894b.jpg +0 -0
  676. package/kb/references/thumbs/b461281e0f.jpg +0 -0
  677. package/kb/references/thumbs/b4942644f0.jpg +0 -0
  678. package/kb/references/thumbs/b49f8eccad.jpg +0 -0
  679. package/kb/references/thumbs/b56c69be23.jpg +0 -0
  680. package/kb/references/thumbs/b59786b33c.jpg +0 -0
  681. package/kb/references/thumbs/b5d368ce5a.jpg +0 -0
  682. package/kb/references/thumbs/b5eb442406.jpg +0 -0
  683. package/kb/references/thumbs/b7fdabf4ab.jpg +0 -0
  684. package/kb/references/thumbs/b88ee8d235.jpg +0 -0
  685. package/kb/references/thumbs/b8a4e5be8a.jpg +0 -0
  686. package/kb/references/thumbs/b8c85b661c.jpg +0 -0
  687. package/kb/references/thumbs/ba1b8e7435.jpg +0 -0
  688. package/kb/references/thumbs/ba9a593eed.jpg +0 -0
  689. package/kb/references/thumbs/baa7afc201.jpg +0 -0
  690. package/kb/references/thumbs/baf74398f7.jpg +0 -0
  691. package/kb/references/thumbs/bb3e947c10.jpg +0 -0
  692. package/kb/references/thumbs/bb4c1bb7c1.jpg +0 -0
  693. package/kb/references/thumbs/bbaa25cc8a.jpg +0 -0
  694. package/kb/references/thumbs/bc7e7f88cc.jpg +0 -0
  695. package/kb/references/thumbs/bc9d5b58f5.jpg +0 -0
  696. package/kb/references/thumbs/bcc99a51f7.jpg +0 -0
  697. package/kb/references/thumbs/bce13dd1c1.jpg +0 -0
  698. package/kb/references/thumbs/bd079a6130.jpg +0 -0
  699. package/kb/references/thumbs/bd2d70dda7.jpg +0 -0
  700. package/kb/references/thumbs/bd5895c5f2.jpg +0 -0
  701. package/kb/references/thumbs/bde8e31d62.jpg +0 -0
  702. package/kb/references/thumbs/be084e78f3.jpg +0 -0
  703. package/kb/references/thumbs/be94f170c8.jpg +0 -0
  704. package/kb/references/thumbs/bed33654f7.jpg +0 -0
  705. package/kb/references/thumbs/beeb9a0c18.jpg +0 -0
  706. package/kb/references/thumbs/bef42094dc.jpg +0 -0
  707. package/kb/references/thumbs/bf625496fa.jpg +0 -0
  708. package/kb/references/thumbs/bf771f1398.jpg +0 -0
  709. package/kb/references/thumbs/c0ddefa3d9.jpg +0 -0
  710. package/kb/references/thumbs/c0f01e536e.jpg +0 -0
  711. package/kb/references/thumbs/c1d592b678.jpg +0 -0
  712. package/kb/references/thumbs/c1e83e1b3e.jpg +0 -0
  713. package/kb/references/thumbs/c2168f8096.jpg +0 -0
  714. package/kb/references/thumbs/c249cd6b17.jpg +0 -0
  715. package/kb/references/thumbs/c2e3d4feed.jpg +0 -0
  716. package/kb/references/thumbs/c3cec01df1.jpg +0 -0
  717. package/kb/references/thumbs/c47bedb42d.jpg +0 -0
  718. package/kb/references/thumbs/c4b03b4680.jpg +0 -0
  719. package/kb/references/thumbs/c4e6d18ec3.jpg +0 -0
  720. package/kb/references/thumbs/c5477e2877.jpg +0 -0
  721. package/kb/references/thumbs/c566794674.jpg +0 -0
  722. package/kb/references/thumbs/c5b945afbb.jpg +0 -0
  723. package/kb/references/thumbs/c5e4659497.jpg +0 -0
  724. package/kb/references/thumbs/c622786702.jpg +0 -0
  725. package/kb/references/thumbs/c6250649ca.jpg +0 -0
  726. package/kb/references/thumbs/c6261a9526.jpg +0 -0
  727. package/kb/references/thumbs/c62e609076.jpg +0 -0
  728. package/kb/references/thumbs/c6602d3e85.jpg +0 -0
  729. package/kb/references/thumbs/c6c1a16e40.jpg +0 -0
  730. package/kb/references/thumbs/c77f932157.jpg +0 -0
  731. package/kb/references/thumbs/c79788f01e.jpg +0 -0
  732. package/kb/references/thumbs/c7a511ad1e.jpg +0 -0
  733. package/kb/references/thumbs/c7acfbc3c8.jpg +0 -0
  734. package/kb/references/thumbs/c7bb6d1bb8.jpg +0 -0
  735. package/kb/references/thumbs/c829eadcb9.jpg +0 -0
  736. package/kb/references/thumbs/c891fd9d85.jpg +0 -0
  737. package/kb/references/thumbs/c89f812ee3.jpg +0 -0
  738. package/kb/references/thumbs/c8a85b9f61.jpg +0 -0
  739. package/kb/references/thumbs/c8fdf85c9a.jpg +0 -0
  740. package/kb/references/thumbs/c961ac1031.jpg +0 -0
  741. package/kb/references/thumbs/c9fd3f88d8.jpg +0 -0
  742. package/kb/references/thumbs/ca0d6399c3.jpg +0 -0
  743. package/kb/references/thumbs/ca316c83e4.jpg +0 -0
  744. package/kb/references/thumbs/ca3b93aa0d.jpg +0 -0
  745. package/kb/references/thumbs/cb0596a85b.jpg +0 -0
  746. package/kb/references/thumbs/cb95a5c3ef.jpg +0 -0
  747. package/kb/references/thumbs/cbe238b656.jpg +0 -0
  748. package/kb/references/thumbs/cbf530e608.jpg +0 -0
  749. package/kb/references/thumbs/cc173494ec.jpg +0 -0
  750. package/kb/references/thumbs/ccb664bddf.jpg +0 -0
  751. package/kb/references/thumbs/ccf69d36cd.jpg +0 -0
  752. package/kb/references/thumbs/ccf759db42.jpg +0 -0
  753. package/kb/references/thumbs/cd2a285807.jpg +0 -0
  754. package/kb/references/thumbs/cd4a24a8ca.jpg +0 -0
  755. package/kb/references/thumbs/cdb3fe8938.jpg +0 -0
  756. package/kb/references/thumbs/cdce1b9bc6.jpg +0 -0
  757. package/kb/references/thumbs/cde3aa761a.jpg +0 -0
  758. package/kb/references/thumbs/ce9d5cd9c2.jpg +0 -0
  759. package/kb/references/thumbs/ceb01f8a34.jpg +0 -0
  760. package/kb/references/thumbs/cee15c98d0.jpg +0 -0
  761. package/kb/references/thumbs/cf6944ddae.jpg +0 -0
  762. package/kb/references/thumbs/d15dd21cd8.jpg +0 -0
  763. package/kb/references/thumbs/d1633bf2ed.jpg +0 -0
  764. package/kb/references/thumbs/d16a838000.jpg +0 -0
  765. package/kb/references/thumbs/d1cf87e9f0.jpg +0 -0
  766. package/kb/references/thumbs/d32511d913.jpg +0 -0
  767. package/kb/references/thumbs/d327e9dedd.jpg +0 -0
  768. package/kb/references/thumbs/d35bf6c85e.jpg +0 -0
  769. package/kb/references/thumbs/d37afc9d61.jpg +0 -0
  770. package/kb/references/thumbs/d3b66655c7.jpg +0 -0
  771. package/kb/references/thumbs/d40b4172b6.jpg +0 -0
  772. package/kb/references/thumbs/d4c40d1824.jpg +0 -0
  773. package/kb/references/thumbs/d4cb55a4b6.jpg +0 -0
  774. package/kb/references/thumbs/d4f0c30f7e.jpg +0 -0
  775. package/kb/references/thumbs/d51cce3ae5.jpg +0 -0
  776. package/kb/references/thumbs/d52948f9ba.jpg +0 -0
  777. package/kb/references/thumbs/d62bd3cba4.jpg +0 -0
  778. package/kb/references/thumbs/d668a21c92.jpg +0 -0
  779. package/kb/references/thumbs/d685072c52.jpg +0 -0
  780. package/kb/references/thumbs/d6d7b96093.jpg +0 -0
  781. package/kb/references/thumbs/d7cd874b21.jpg +0 -0
  782. package/kb/references/thumbs/d7e111736a.jpg +0 -0
  783. package/kb/references/thumbs/d88325f832.jpg +0 -0
  784. package/kb/references/thumbs/d9272ded76.jpg +0 -0
  785. package/kb/references/thumbs/d962e7c654.jpg +0 -0
  786. package/kb/references/thumbs/d97f000ee2.jpg +0 -0
  787. package/kb/references/thumbs/d9c1ae2543.jpg +0 -0
  788. package/kb/references/thumbs/d9ccb3cac8.jpg +0 -0
  789. package/kb/references/thumbs/da99019680.jpg +0 -0
  790. package/kb/references/thumbs/da9b8bc615.jpg +0 -0
  791. package/kb/references/thumbs/daafbee2c1.jpg +0 -0
  792. package/kb/references/thumbs/db0f11f143.jpg +0 -0
  793. package/kb/references/thumbs/db5dd367f5.jpg +0 -0
  794. package/kb/references/thumbs/db69677866.jpg +0 -0
  795. package/kb/references/thumbs/db87c1956e.jpg +0 -0
  796. package/kb/references/thumbs/dbb86d8bda.jpg +0 -0
  797. package/kb/references/thumbs/dbd3a8ff2a.jpg +0 -0
  798. package/kb/references/thumbs/dbdf4b2794.jpg +0 -0
  799. package/kb/references/thumbs/dd4c19b4b1.jpg +0 -0
  800. package/kb/references/thumbs/dd98d9f6fa.jpg +0 -0
  801. package/kb/references/thumbs/ddb00e3b6a.jpg +0 -0
  802. package/kb/references/thumbs/dde3541a5c.jpg +0 -0
  803. package/kb/references/thumbs/de2a4da502.jpg +0 -0
  804. package/kb/references/thumbs/de4c387a66.jpg +0 -0
  805. package/kb/references/thumbs/de5618fa82.jpg +0 -0
  806. package/kb/references/thumbs/de6bec2538.jpg +0 -0
  807. package/kb/references/thumbs/dea13cbb1f.jpg +0 -0
  808. package/kb/references/thumbs/deff9202aa.jpg +0 -0
  809. package/kb/references/thumbs/df12835f8d.jpg +0 -0
  810. package/kb/references/thumbs/df57acbb3d.jpg +0 -0
  811. package/kb/references/thumbs/df8265009e.jpg +0 -0
  812. package/kb/references/thumbs/dfc99a1e8e.jpg +0 -0
  813. package/kb/references/thumbs/dfc9fde460.jpg +0 -0
  814. package/kb/references/thumbs/e038348eee.jpg +0 -0
  815. package/kb/references/thumbs/e04c2ae1d5.jpg +0 -0
  816. package/kb/references/thumbs/e070345c43.jpg +0 -0
  817. package/kb/references/thumbs/e0a0c84d47.jpg +0 -0
  818. package/kb/references/thumbs/e0af1e6b9e.jpg +0 -0
  819. package/kb/references/thumbs/e1025942c4.jpg +0 -0
  820. package/kb/references/thumbs/e11b6f5b82.jpg +0 -0
  821. package/kb/references/thumbs/e1553de3fc.jpg +0 -0
  822. package/kb/references/thumbs/e162ebe7cd.jpg +0 -0
  823. package/kb/references/thumbs/e1f1e531d8.jpg +0 -0
  824. package/kb/references/thumbs/e20842e5c9.jpg +0 -0
  825. package/kb/references/thumbs/e24e7d949b.jpg +0 -0
  826. package/kb/references/thumbs/e2a3e5d10a.jpg +0 -0
  827. package/kb/references/thumbs/e2de02615a.jpg +0 -0
  828. package/kb/references/thumbs/e305dad7dd.jpg +0 -0
  829. package/kb/references/thumbs/e52e3ef97f.jpg +0 -0
  830. package/kb/references/thumbs/e570e92d06.jpg +0 -0
  831. package/kb/references/thumbs/e583932fb9.jpg +0 -0
  832. package/kb/references/thumbs/e5da3c038f.jpg +0 -0
  833. package/kb/references/thumbs/e657634af3.jpg +0 -0
  834. package/kb/references/thumbs/e67946e3e1.jpg +0 -0
  835. package/kb/references/thumbs/e69e0f3639.jpg +0 -0
  836. package/kb/references/thumbs/e6ebe66031.jpg +0 -0
  837. package/kb/references/thumbs/e7db9563c9.jpg +0 -0
  838. package/kb/references/thumbs/e84a4c3b7b.jpg +0 -0
  839. package/kb/references/thumbs/e84cf52c27.jpg +0 -0
  840. package/kb/references/thumbs/e8707cf6e8.jpg +0 -0
  841. package/kb/references/thumbs/e888890b40.jpg +0 -0
  842. package/kb/references/thumbs/e8a502b418.jpg +0 -0
  843. package/kb/references/thumbs/e8ba68371d.jpg +0 -0
  844. package/kb/references/thumbs/e9098f54cc.jpg +0 -0
  845. package/kb/references/thumbs/e9144deae9.jpg +0 -0
  846. package/kb/references/thumbs/e93e98d757.jpg +0 -0
  847. package/kb/references/thumbs/e9762dd435.jpg +0 -0
  848. package/kb/references/thumbs/e9db4544c8.jpg +0 -0
  849. package/kb/references/thumbs/e9ddffeacd.jpg +0 -0
  850. package/kb/references/thumbs/e9e2cf1d7e.jpg +0 -0
  851. package/kb/references/thumbs/ea1e23e623.jpg +0 -0
  852. package/kb/references/thumbs/ea41200f5e.jpg +0 -0
  853. package/kb/references/thumbs/eaf4916e1a.jpg +0 -0
  854. package/kb/references/thumbs/eb2c505fc8.jpg +0 -0
  855. package/kb/references/thumbs/eb47943693.jpg +0 -0
  856. package/kb/references/thumbs/eb4ffd6625.jpg +0 -0
  857. package/kb/references/thumbs/eb82ac0a4d.jpg +0 -0
  858. package/kb/references/thumbs/ebeb345ade.jpg +0 -0
  859. package/kb/references/thumbs/ec4e2aba0a.jpg +0 -0
  860. package/kb/references/thumbs/ed683bc9f7.jpg +0 -0
  861. package/kb/references/thumbs/ed9e236a84.jpg +0 -0
  862. package/kb/references/thumbs/ee45e1caea.jpg +0 -0
  863. package/kb/references/thumbs/ee50bbf2e7.jpg +0 -0
  864. package/kb/references/thumbs/eed6ad3b7b.jpg +0 -0
  865. package/kb/references/thumbs/eee247fd70.jpg +0 -0
  866. package/kb/references/thumbs/ef87b6cb99.jpg +0 -0
  867. package/kb/references/thumbs/ef87dccf04.jpg +0 -0
  868. package/kb/references/thumbs/ef941bba1e.jpg +0 -0
  869. package/kb/references/thumbs/effc14fb2c.jpg +0 -0
  870. package/kb/references/thumbs/f04aa5a191.jpg +0 -0
  871. package/kb/references/thumbs/f13f12485f.jpg +0 -0
  872. package/kb/references/thumbs/f16a5c0fd4.jpg +0 -0
  873. package/kb/references/thumbs/f1ba7a7a8f.jpg +0 -0
  874. package/kb/references/thumbs/f1bc4c9c19.jpg +0 -0
  875. package/kb/references/thumbs/f1ee827878.jpg +0 -0
  876. package/kb/references/thumbs/f21736aeff.jpg +0 -0
  877. package/kb/references/thumbs/f22bc41213.jpg +0 -0
  878. package/kb/references/thumbs/f266aaffcc.jpg +0 -0
  879. package/kb/references/thumbs/f2c0ed0d65.jpg +0 -0
  880. package/kb/references/thumbs/f32ac710fd.jpg +0 -0
  881. package/kb/references/thumbs/f32b697ff6.jpg +0 -0
  882. package/kb/references/thumbs/f39c883904.jpg +0 -0
  883. package/kb/references/thumbs/f3b9d55e6e.jpg +0 -0
  884. package/kb/references/thumbs/f3c1763e14.jpg +0 -0
  885. package/kb/references/thumbs/f40853fd43.jpg +0 -0
  886. package/kb/references/thumbs/f4fd07dc4d.jpg +0 -0
  887. package/kb/references/thumbs/f50b756ee5.jpg +0 -0
  888. package/kb/references/thumbs/f51272e9b3.jpg +0 -0
  889. package/kb/references/thumbs/f538895eee.jpg +0 -0
  890. package/kb/references/thumbs/f5d28081b5.jpg +0 -0
  891. package/kb/references/thumbs/f6046c9501.jpg +0 -0
  892. package/kb/references/thumbs/f62e4af316.jpg +0 -0
  893. package/kb/references/thumbs/f6f6bffeb8.jpg +0 -0
  894. package/kb/references/thumbs/f736e00af6.jpg +0 -0
  895. package/kb/references/thumbs/f7932da47d.jpg +0 -0
  896. package/kb/references/thumbs/f879e118ca.jpg +0 -0
  897. package/kb/references/thumbs/f88257215d.jpg +0 -0
  898. package/kb/references/thumbs/f88c45a6d7.jpg +0 -0
  899. package/kb/references/thumbs/f89a7b646e.jpg +0 -0
  900. package/kb/references/thumbs/f8a1e7a274.jpg +0 -0
  901. package/kb/references/thumbs/f9183cf2b6.jpg +0 -0
  902. package/kb/references/thumbs/f995de5ce9.jpg +0 -0
  903. package/kb/references/thumbs/f9ada2c3e1.jpg +0 -0
  904. package/kb/references/thumbs/f9d4616f89.jpg +0 -0
  905. package/kb/references/thumbs/f9f4307bb0.jpg +0 -0
  906. package/kb/references/thumbs/fa070122c7.jpg +0 -0
  907. package/kb/references/thumbs/fa29cc1369.jpg +0 -0
  908. package/kb/references/thumbs/fa791a4dab.jpg +0 -0
  909. package/kb/references/thumbs/fa8060509e.jpg +0 -0
  910. package/kb/references/thumbs/fafeed4003.jpg +0 -0
  911. package/kb/references/thumbs/fb1c024f38.jpg +0 -0
  912. package/kb/references/thumbs/fb77aa28b3.jpg +0 -0
  913. package/kb/references/thumbs/fb9f7f1966.jpg +0 -0
  914. package/kb/references/thumbs/fba8a8c2da.jpg +0 -0
  915. package/kb/references/thumbs/fce2754c36.jpg +0 -0
  916. package/kb/references/thumbs/fce2fb83df.jpg +0 -0
  917. package/kb/references/thumbs/fd4c51bb47.jpg +0 -0
  918. package/kb/references/thumbs/fd8c269817.jpg +0 -0
  919. package/kb/references/thumbs/fdb7b250ca.jpg +0 -0
  920. package/kb/references/thumbs/fe18088de8.jpg +0 -0
  921. package/kb/references/thumbs/fe4f742ba7.jpg +0 -0
  922. package/kb/references/thumbs/fe64742ce7.jpg +0 -0
  923. package/kb/references/thumbs/feb5d62161.jpg +0 -0
  924. package/kb/references/thumbs/fed21b3e98.jpg +0 -0
  925. package/kb/references/thumbs/fed2205951.jpg +0 -0
  926. package/kb/references/thumbs/ffdacf1715.jpg +0 -0
  927. package/kb/sections/_buttons.md +93 -0
  928. package/kb/sections/_finish.md +325 -0
  929. package/kb/sections/about-founder-note.md +85 -0
  930. package/kb/sections/about-team-roster.md +86 -0
  931. package/kb/sections/alternating-rows-live-tiles.md +110 -0
  932. package/kb/sections/annotated-product-shot.md +105 -0
  933. package/kb/sections/asymmetric-bento-dominant.md +114 -0
  934. package/kb/sections/before-after-features.md +104 -0
  935. package/kb/sections/before-after-repair.md +107 -0
  936. package/kb/sections/bento-lead-tile.md +112 -0
  937. package/kb/sections/book-a-slot-honest.md +116 -0
  938. package/kb/sections/capability-prompt-ledger.md +68 -0
  939. package/kb/sections/case-study-band.md +113 -0
  940. package/kb/sections/centred-stack-hero.md +107 -0
  941. package/kb/sections/closing-demo-final-state.md +81 -0
  942. package/kb/sections/closing-full-bleed-line-and-form.md +86 -0
  943. package/kb/sections/closing-result-previewed.md +88 -0
  944. package/kb/sections/closing-three-real-steps.md +87 -0
  945. package/kb/sections/command-reference-table.md +70 -0
  946. package/kb/sections/comparison-old-way-bars.md +88 -0
  947. package/kb/sections/comparison-same-task-two-ways.md +88 -0
  948. package/kb/sections/day-of-the-place.md +102 -0
  949. package/kb/sections/docs-reading-rail.md +88 -0
  950. package/kb/sections/editorial-columns-hero.md +107 -0
  951. package/kb/sections/editorial-essay-pull-quote.md +112 -0
  952. package/kb/sections/events-calendar-list.md +107 -0
  953. package/kb/sections/explorable-control-demo.md +102 -0
  954. package/kb/sections/faq-open-answers-editorial.md +85 -0
  955. package/kb/sections/faq-ruled-accordion-aside.md +87 -0
  956. package/kb/sections/footer-closing-scene.md +84 -0
  957. package/kb/sections/footer-editorial-sitemap.md +85 -0
  958. package/kb/sections/footer-minimal-credits.md +80 -0
  959. package/kb/sections/full-bleed-image-band.md +103 -0
  960. package/kb/sections/full-bleed-image-hero.md +105 -0
  961. package/kb/sections/gallery-first-hero.md +109 -0
  962. package/kb/sections/horizontal-scroll-strip.md +101 -0
  963. package/kb/sections/how-i-work-own-voice.md +111 -0
  964. package/kb/sections/how-it-works-in-place.md +109 -0
  965. package/kb/sections/impact-numbers-sourced.md +109 -0
  966. package/kb/sections/install-steps-per-agent.md +77 -0
  967. package/kb/sections/masonry-real-work.md +109 -0
  968. package/kb/sections/numbered-editorial-columns.md +105 -0
  969. package/kb/sections/object-first-hero.md +106 -0
  970. package/kb/sections/object-timeline.md +105 -0
  971. package/kb/sections/one-huge-number.md +100 -0
  972. package/kb/sections/one-person-story.md +103 -0
  973. package/kb/sections/order-ahead-ticket.md +119 -0
  974. package/kb/sections/press-strip-quoted.md +106 -0
  975. package/kb/sections/pricing-comparison-table-sticky.md +94 -0
  976. package/kb/sections/pricing-free-pro-upgrade-moment.md +85 -0
  977. package/kb/sections/pricing-plan-beside-product.md +88 -0
  978. package/kb/sections/pricing-plans-ledger.md +94 -0
  979. package/kb/sections/pricing-usage-calculator.md +93 -0
  980. package/kb/sections/printed-menu-card.md +110 -0
  981. package/kb/sections/process-happening.md +102 -0
  982. package/kb/sections/project-index-ruled.md +106 -0
  983. package/kb/sections/proof-logo-cloud-with-reasons.md +82 -0
  984. package/kb/sections/proof-measured-numbers.md +88 -0
  985. package/kb/sections/proof-output-wall.md +84 -0
  986. package/kb/sections/proof-single-honest-quote.md +81 -0
  987. package/kb/sections/resources-searchable-list.md +110 -0
  988. package/kb/sections/rooms-and-rates.md +107 -0
  989. package/kb/sections/ruled-facts-table.md +108 -0
  990. package/kb/sections/ruled-list-pinned-visual.md +107 -0
  991. package/kb/sections/scroll-scrubbed-product-demo.md +103 -0
  992. package/kb/sections/self-playing-run-demo.md +104 -0
  993. package/kb/sections/services-price-ledger.md +106 -0
  994. package/kb/sections/signup-form-with-next-steps.md +86 -0
  995. package/kb/sections/signup-waitlist-place-in-line.md +90 -0
  996. package/kb/sections/spec-sheet-features.md +108 -0
  997. package/kb/sections/split-hero-live-object.md +108 -0
  998. package/kb/sections/sticky-feature-narrative.md +104 -0
  999. package/kb/sections/todays-board-hero.md +112 -0
  1000. package/kb/sections/touchable-tool-hero.md +111 -0
  1001. package/kb/sections/typographic-statement-hero.md +99 -0
  1002. package/kb/sections/visit-hours-map.md +110 -0
  1003. package/kb/sections/ways-to-help-honest.md +115 -0
  1004. package/kb/sources/design-reference.md +991 -0
  1005. package/kb/sources/product-and-docs.md +37 -0
  1006. package/kb/systems/1win/DESIGN.md +463 -0
  1007. package/kb/systems/LICENSE-awesome-design-md +21 -0
  1008. package/kb/systems/README.md +7 -0
  1009. package/kb/systems/airbnb/DESIGN.md +545 -0
  1010. package/kb/systems/airtable/DESIGN.md +554 -0
  1011. package/kb/systems/aljazeera/DESIGN.md +594 -0
  1012. package/kb/systems/apple/DESIGN.md +562 -0
  1013. package/kb/systems/binance/DESIGN.md +634 -0
  1014. package/kb/systems/bmw/DESIGN.md +544 -0
  1015. package/kb/systems/bmw-m/DESIGN.md +503 -0
  1016. package/kb/systems/bugatti/DESIGN.md +454 -0
  1017. package/kb/systems/cal/DESIGN.md +542 -0
  1018. package/kb/systems/categories.json +87 -0
  1019. package/kb/systems/claude/DESIGN.md +589 -0
  1020. package/kb/systems/clay/DESIGN.md +541 -0
  1021. package/kb/systems/clickhouse/DESIGN.md +544 -0
  1022. package/kb/systems/cohere/DESIGN.md +451 -0
  1023. package/kb/systems/coinbase/DESIGN.md +570 -0
  1024. package/kb/systems/composio/DESIGN.md +506 -0
  1025. package/kb/systems/cursor/DESIGN.md +537 -0
  1026. package/kb/systems/dell-1996/DESIGN.md +632 -0
  1027. package/kb/systems/dji/DESIGN.md +882 -0
  1028. package/kb/systems/elevenlabs/DESIGN.md +504 -0
  1029. package/kb/systems/expo/DESIGN.md +526 -0
  1030. package/kb/systems/ferrari/DESIGN.md +531 -0
  1031. package/kb/systems/figma/DESIGN.md +578 -0
  1032. package/kb/systems/framer/DESIGN.md +544 -0
  1033. package/kb/systems/hashicorp/DESIGN.md +575 -0
  1034. package/kb/systems/hp/DESIGN.md +670 -0
  1035. package/kb/systems/ibm/DESIGN.md +550 -0
  1036. package/kb/systems/intercom/DESIGN.md +546 -0
  1037. package/kb/systems/jobright/DESIGN.md +525 -0
  1038. package/kb/systems/kraken/DESIGN.md +125 -0
  1039. package/kb/systems/lamborghini/DESIGN.md +288 -0
  1040. package/kb/systems/linear.app/DESIGN.md +548 -0
  1041. package/kb/systems/lovable/DESIGN.md +298 -0
  1042. package/kb/systems/mastercard/DESIGN.md +365 -0
  1043. package/kb/systems/mercury/DESIGN.md +568 -0
  1044. package/kb/systems/meta/DESIGN.md +683 -0
  1045. package/kb/systems/minimax/DESIGN.md +746 -0
  1046. package/kb/systems/mintlify/DESIGN.md +852 -0
  1047. package/kb/systems/miro/DESIGN.md +825 -0
  1048. package/kb/systems/mistral.ai/DESIGN.md +773 -0
  1049. package/kb/systems/mongodb/DESIGN.md +767 -0
  1050. package/kb/systems/mydealz/DESIGN.md +551 -0
  1051. package/kb/systems/nerdwallet/DESIGN.md +722 -0
  1052. package/kb/systems/nike/DESIGN.md +575 -0
  1053. package/kb/systems/nintendo-2001/DESIGN.md +649 -0
  1054. package/kb/systems/notion/DESIGN.md +821 -0
  1055. package/kb/systems/nvidia/DESIGN.md +640 -0
  1056. package/kb/systems/ollama/DESIGN.md +539 -0
  1057. package/kb/systems/opencode.ai/DESIGN.md +521 -0
  1058. package/kb/systems/oracle/DESIGN.md +778 -0
  1059. package/kb/systems/oura/DESIGN.md +616 -0
  1060. package/kb/systems/pinterest/DESIGN.md +597 -0
  1061. package/kb/systems/playstation/DESIGN.md +661 -0
  1062. package/kb/systems/posthog/DESIGN.md +690 -0
  1063. package/kb/systems/raycast/DESIGN.md +669 -0
  1064. package/kb/systems/renault/DESIGN.md +589 -0
  1065. package/kb/systems/replicate/DESIGN.md +616 -0
  1066. package/kb/systems/resend/DESIGN.md +585 -0
  1067. package/kb/systems/revolut/DESIGN.md +636 -0
  1068. package/kb/systems/runwayml/DESIGN.md +244 -0
  1069. package/kb/systems/sanity/DESIGN.md +357 -0
  1070. package/kb/systems/sap/DESIGN.md +639 -0
  1071. package/kb/systems/sentry/DESIGN.md +551 -0
  1072. package/kb/systems/shopify/DESIGN.md +516 -0
  1073. package/kb/systems/slack/DESIGN.md +482 -0
  1074. package/kb/systems/spacex/DESIGN.md +363 -0
  1075. package/kb/systems/spotify/DESIGN.md +246 -0
  1076. package/kb/systems/starbucks/DESIGN.md +580 -0
  1077. package/kb/systems/stripe/DESIGN.md +487 -0
  1078. package/kb/systems/supabase/DESIGN.md +462 -0
  1079. package/kb/systems/superhuman/DESIGN.md +448 -0
  1080. package/kb/systems/tesla/DESIGN.md +286 -0
  1081. package/kb/systems/theverge/DESIGN.md +339 -0
  1082. package/kb/systems/together.ai/DESIGN.md +633 -0
  1083. package/kb/systems/uber/DESIGN.md +636 -0
  1084. package/kb/systems/vercel/DESIGN.md +736 -0
  1085. package/kb/systems/vodafone/DESIGN.md +538 -0
  1086. package/kb/systems/voltagent/DESIGN.md +521 -0
  1087. package/kb/systems/warp/DESIGN.md +526 -0
  1088. package/kb/systems/webflow/DESIGN.md +588 -0
  1089. package/kb/systems/wired/DESIGN.md +497 -0
  1090. package/kb/systems/wise/DESIGN.md +544 -0
  1091. package/kb/systems/x.ai/DESIGN.md +465 -0
  1092. package/kb/systems/zapier/DESIGN.md +537 -0
  1093. package/kb/taste/garvit-by-job.md +46 -0
  1094. package/kb/taste/garvit-portfolio.md +94 -0
  1095. package/kb/universal/color-roles.md +26 -0
  1096. package/kb/universal/copy.md +16 -0
  1097. package/kb/universal/details.md +31 -0
  1098. package/kb/universal/first-screen.md +30 -0
  1099. package/kb/universal/fit-the-codebase.md +29 -0
  1100. package/kb/universal/layout-width.md +28 -0
  1101. package/kb/universal/motion-feedback.md +23 -0
  1102. package/kb/universal/signature.md +29 -0
  1103. package/kb/universal/states.md +17 -0
  1104. package/kb/universal/type-app.md +33 -0
  1105. package/kb/universal/type-marketing.md +28 -0
  1106. package/package.json +37 -4
  1107. package/scripts/pack-assets.mjs +58 -0
  1108. package/skill/palate/SKILL.md +261 -0
  1109. package/src/auth-recheck.mjs +4 -0
  1110. package/src/auth.mjs +416 -0
  1111. package/src/capture.mjs +182 -0
  1112. package/src/catalog/classify.mjs +96 -0
  1113. package/src/catalog/curated.mjs +128 -0
  1114. package/src/catalog/index-build.mjs +67 -0
  1115. package/src/catalog/literal.mjs +146 -0
  1116. package/src/catalog/store.mjs +40 -0
  1117. package/src/catalog/vibrant.mjs +126 -0
  1118. package/src/check.mjs +93 -0
  1119. package/src/concept.mjs +157 -0
  1120. package/src/context.mjs +226 -0
  1121. package/src/copy.mjs +188 -0
  1122. package/src/devserver.mjs +135 -0
  1123. package/src/fontgenre.mjs +44 -0
  1124. package/src/guard-agents.mjs +213 -0
  1125. package/src/guard.mjs +377 -0
  1126. package/src/kb.mjs +91 -0
  1127. package/src/look.mjs +312 -0
  1128. package/src/loop/ambition.mjs +620 -0
  1129. package/src/loop/animate.mjs +70 -0
  1130. package/src/loop/artdirection.mjs +264 -0
  1131. package/src/loop/bench.mjs +184 -0
  1132. package/src/loop/benchpick.mjs +155 -0
  1133. package/src/loop/blueprint.mjs +620 -0
  1134. package/src/loop/board.html +180 -0
  1135. package/src/loop/build.mjs +393 -0
  1136. package/src/loop/buttons.mjs +413 -0
  1137. package/src/loop/common.mjs +206 -0
  1138. package/src/loop/cost.mjs +63 -0
  1139. package/src/loop/craft.mjs +152 -0
  1140. package/src/loop/craftchecks.mjs +148 -0
  1141. package/src/loop/critique.mjs +393 -0
  1142. package/src/loop/details.mjs +225 -0
  1143. package/src/loop/direction.html +168 -0
  1144. package/src/loop/direction.mjs +256 -0
  1145. package/src/loop/directions.json +8 -0
  1146. package/src/loop/explore.mjs +219 -0
  1147. package/src/loop/fail.mjs +110 -0
  1148. package/src/loop/fix.mjs +194 -0
  1149. package/src/loop/floor.mjs +677 -0
  1150. package/src/loop/forget.mjs +52 -0
  1151. package/src/loop/gate.mjs +1053 -0
  1152. package/src/loop/grid.html +123 -0
  1153. package/src/loop/growth.mjs +118 -0
  1154. package/src/loop/icons.mjs +109 -0
  1155. package/src/loop/imagery.mjs +1280 -0
  1156. package/src/loop/judge-api.mjs +245 -0
  1157. package/src/loop/judge.mjs +167 -0
  1158. package/src/loop/layouts.mjs +492 -0
  1159. package/src/loop/library.mjs +82 -0
  1160. package/src/loop/lookplan.mjs +182 -0
  1161. package/src/loop/lookvec.mjs +645 -0
  1162. package/src/loop/match.mjs +923 -0
  1163. package/src/loop/matched.mjs +26 -0
  1164. package/src/loop/myrefs.mjs +151 -0
  1165. package/src/loop/pick.mjs +213 -0
  1166. package/src/loop/picker.html +118 -0
  1167. package/src/loop/plan.mjs +289 -0
  1168. package/src/loop/polish.mjs +39 -0
  1169. package/src/loop/research-learn.mjs +41 -0
  1170. package/src/loop/research.mjs +1130 -0
  1171. package/src/loop/rulereview.mjs +146 -0
  1172. package/src/loop/rules-board.html +199 -0
  1173. package/src/loop/rules.mjs +939 -0
  1174. package/src/loop/similar.mjs +276 -0
  1175. package/src/loop/states-source.mjs +258 -0
  1176. package/src/loop/states.mjs +1547 -0
  1177. package/src/loop/stats.mjs +78 -0
  1178. package/src/loop/taste.mjs +81 -0
  1179. package/src/loop/timeline.mjs +149 -0
  1180. package/src/loop/variants.mjs +228 -0
  1181. package/src/loop/vary.mjs +249 -0
  1182. package/src/mcp/server.mjs +1246 -0
  1183. package/src/motion.mjs +207 -0
  1184. package/src/moves.mjs +242 -0
  1185. package/src/novelty.mjs +116 -0
  1186. package/src/page-ambition.js +181 -0
  1187. package/src/page-craft.js +724 -0
  1188. package/src/page-details.js +415 -0
  1189. package/src/page-devices.js +365 -0
  1190. package/src/page-fingerprint.js +281 -0
  1191. package/src/page-gate.js +1307 -0
  1192. package/src/page-look.js +698 -0
  1193. package/src/page-metrics.js +78 -0
  1194. package/src/page-principles.js +1167 -0
  1195. package/src/page-rules.js +308 -0
  1196. package/src/page-sections.js +211 -0
  1197. package/src/page-states.js +703 -0
  1198. package/src/paths.mjs +13 -0
  1199. package/src/png.mjs +107 -0
  1200. package/src/point/auto.mjs +224 -0
  1201. package/src/point/locate.mjs +114 -0
  1202. package/src/point/overlay.js +1516 -0
  1203. package/src/point/server.mjs +1122 -0
  1204. package/src/point/trail.mjs +219 -0
  1205. package/src/pool.mjs +80 -0
  1206. package/src/principles.mjs +279 -0
  1207. package/src/refs.mjs +299 -0
  1208. package/src/robots.mjs +145 -0
  1209. package/src/sections.mjs +210 -0
  1210. package/src/shoot.mjs +235 -0
  1211. package/src/systems/apply.mjs +355 -0
  1212. package/src/systems/load.mjs +251 -0
  1213. package/src/systems/pick.mjs +213 -0
  1214. package/templates/vite-react-tw/index.html +12 -0
  1215. package/templates/vite-react-tw/package.json +25 -0
  1216. package/templates/vite-react-tw/src/App.tsx +3 -0
  1217. package/templates/vite-react-tw/src/index.css +1 -0
  1218. package/templates/vite-react-tw/src/main.tsx +10 -0
  1219. package/templates/vite-react-tw/tsconfig.app.json +26 -0
  1220. package/templates/vite-react-tw/tsconfig.json +7 -0
  1221. package/templates/vite-react-tw/tsconfig.node.json +23 -0
  1222. package/templates/vite-react-tw/vite.config.ts +8 -0
@@ -0,0 +1,393 @@
1
+ // `palate critique <route>`: a designer's review, section by section, as specific findings (not a score).
2
+ // palate renders the route at 1440 and 390, crops each section, measures the whole page (repeated devices,
3
+ // how the product is shown, logo rows, what moves) and writes a critique sheet: crops, facts, the user's
4
+ // taste for this kind of screen, what they disagreed with before, library references per section, and a
5
+ // rubric assembled from kb/craft. The agent (it has vision) writes findings; `palate critique --findings f`
6
+ // opens a review board where the user agrees or disagrees with each one, and disagreements teach taste.
7
+ import fs from "node:fs";
8
+ import http from "node:http";
9
+ import path from "node:path";
10
+ import { fileURLToPath } from "node:url";
11
+ import { contactSheet, cropSections, findSections, MOTION_INIT, openPage, shootFull, slugOf, stamp, withBrowser } from "../look.mjs";
12
+ import { freePort, normalizeRoute, shoot } from "../shoot.mjs";
13
+ import { measurePrinciples, principlesReport } from "../principles.mjs";
14
+ import { readJson, TASTE_DIR } from "./common.mjs";
15
+ import { craftRubric, LIB_DIR, screenWords, sectionKind, slash, tasteFor } from "./craft.mjs";
16
+ import { openBrowser } from "./pick.mjs";
17
+ import { latestStates } from "./states.mjs";
18
+
19
+ const here = path.dirname(fileURLToPath(import.meta.url));
20
+ const devicesScript = fs.readFileSync(path.join(here, "..", "page-devices.js"), "utf8").trim().replace(/;\s*$/, "");
21
+ export const CRITIQUES = path.join(TASTE_DIR, "critiques.jsonl");
22
+ export const SEVERITIES = ["high", "medium", "low", "idea"];
23
+
24
+ const root = (dir, route) => path.join(dir, ".palate", "critique", slugOf(route));
25
+
26
+ // The newest critique session for a route (or for any route), or null; withFindings: only sessions with findings.
27
+ export function latestCritique(dir, route, { withFindings = false } = {}) {
28
+ const base = path.join(dir, ".palate", "critique");
29
+ const slugs = route ? [slugOf(route)] : fs.existsSync(base) ? fs.readdirSync(base) : [];
30
+ const all = slugs.flatMap((s) => (fs.existsSync(path.join(base, s)) ? fs.readdirSync(path.join(base, s)).map((t) => path.join(base, s, t)) : []));
31
+ const done = all.filter((d) => fs.existsSync(path.join(d, withFindings ? "findings.json" : "sections.json"))).sort((a, b) => path.basename(a).localeCompare(path.basename(b)));
32
+ return done.at(-1) ?? null;
33
+ }
34
+
35
+ // The states sheet, when `palate states` has run on this route: every part in every state, with findings.
36
+ function statesLine(dir, route) {
37
+ const s = latestStates(dir, route);
38
+ if (!s) return `- States: not rendered yet. \`palate states ${route}\` shows every part empty, loading, failing, with long text and many items, at 320 wide; the critique covers the page as it is.`;
39
+ const rec = readJson(path.join(s, "findings.json"), { findings: [] });
40
+ const high = rec.findings.filter((f) => f.severity === "high").length;
41
+ return `- States (palate states ${path.basename(s)}): ${rec.sheet ? slash(rec.sheet) : slash(path.join(s, "sheet.png"))}, one row per part, one column per state. ${rec.findings.length} missing state(s)${high ? `, ${high} high` : ""}, in ${slash(path.join(s, "states.md"))}; don't repeat them as findings, palate fix includes them.`;
42
+ }
43
+
44
+ // One sheet line, at most ~230 characters (long selectors are in the files next to the sheet).
45
+ const clip = (l) => (l.length > 230 ? `${l.slice(0, 227).replace(/\s+\S*$/, "")}…` : l);
46
+
47
+ const REVIEW_GUIDE = `# How to review
48
+
49
+ ## 1. The whole page first (full-page screenshots and the facts in the sheet)
50
+ - [page.1] Job: what is this page for, and does the first screen say it in one look?
51
+ - [page.2] Repetition: which devices appear in more than one section (kicker labels, section numbers, frames, backdrops, rules, two-column heads, dark bands)? A device used everywhere stops meaning anything. Keep one at most, and say which.
52
+ - [page.3] Showing the product: is it shown working (live UI, interaction, motion, real data) or only as pictures of it? Static screenshots in frames are the weakest proof; say which picture should become live and how.
53
+ - [page.4] Motion: does anything move on load, on scroll or on interaction beyond hover colour? A page that never moves feels static. Say where motion would explain something (a state change, the product doing its job), never decoration.
54
+ - [page.5] Rhythm: section lengths, density changes, where attention drops, where two sections say the same thing.
55
+ - [page.6] Memorability: what will someone remember tomorrow? If nothing, which section should carry the signature idea?
56
+
57
+ ## 2. Then each section (both widths)
58
+ - [section.1] Job: what must this section make the reader believe or do? Does it show and sell, or explain like documentation (process rows, step lists, inventories of features)?
59
+ - [section.2] Hierarchy: one focal point; the order the eye takes.
60
+ - [section.3] Type: sizes, weights, measure, wrapping, orphans.
61
+ - [section.4] Spacing and alignment: shared edges, consistent rhythm, crowding.
62
+ - [section.5] Legibility at a glance: anything too small, faint or low-contrast to read at 100% (logo rows, captions, labels, marks)?
63
+ - [section.6] Details: icons, brand marks, avatars, inputs, numbers, empty and loading states, hover/focus/pressed.
64
+ - [section.7] Phone (390): what breaks, crowds, gets too long or loses its point.
65
+ - [section.8] Ideas: if the section is generic or forgettable, one structural idea that would make it memorable (cite a reference number if one fits).
66
+ `;
67
+
68
+ const pastDisagreements = (n = 15) => {
69
+ if (!fs.existsSync(CRITIQUES)) return [];
70
+ return fs
71
+ .readFileSync(CRITIQUES, "utf8")
72
+ .split("\n")
73
+ .filter(Boolean)
74
+ .map((l) => JSON.parse(l))
75
+ .filter((r) => r.verdict === "disagree")
76
+ .slice(-n);
77
+ };
78
+
79
+ // Measured whole-page facts (from page-devices.js), as lines for the sheet.
80
+ export function deviceLines(d) {
81
+ const out = [];
82
+ out.push(d.repeated.length ? `- Repeated devices (3+ sections): ${d.repeated.map((r) => `${r.device} in sections ${r.sections.join(", ")}`).join("; ")}.` : "- No device repeats in 3+ sections.");
83
+ const kick = [...new Map(d.kickers.map((k) => [`${k.text}|${k.section}`, k])).values()];
84
+ if (kick.length) out.push(`- Kicker labels above headings (${d.kickers.length}, in ${new Set(d.kickers.map((k) => k.section)).size} sections): ${kick.slice(0, 10).map((k) => `"${k.text}" (section ${k.section})`).join(", ")}.`);
85
+ const pics = d.media.filter((m) => m.kind === "static picture");
86
+ const live = d.media.filter((m) => m.kind.startsWith("live"));
87
+ out.push(`- How the product is shown: ${pics.length} large static picture(s)${pics.filter((p) => p.framed).length ? ` (${pics.filter((p) => p.framed).length} in frames or backdrops)` : ""}, ${live.length} live (video, canvas, iframe).${pics.length ? ` ${pics.map((p) => `Section ${p.section}: ${p.size}${p.alt ? ` "${p.alt.slice(0, 60)}"` : ""}`).join(" · ")}` : ""}`);
88
+ for (const r of d.logoRows) out.push(`- Logo row in section ${r.section} (${r.selector}): ${r.count} marks at ${r.markPx}px with ${r.textPx}px names${r.monochrome ? `, all one colour${r.paintedByMask ? " (painted through a CSS mask)" : ""}` : ""}${r.contrast ? `, mark contrast ${r.contrast}:1 against the background` : ""}${r.markPx < 20 ? "; marks under 20px read as texture, not as logos" : ""}: ${r.names.join(", ")}.`);
89
+ const m = d.motion;
90
+ // Entrances: CSS animations, opacity/transform transitions and scripted fades outside sticky or fixed chrome.
91
+ const entrances = (m.entrances ?? 0) + (m.scriptedAnimations ?? 0) + m.cssAnimations + (m.styled > 1 ? m.styled : 0);
92
+ out.push(`- Motion, during load and one scroll through the page: ${m.entrances ?? "?"} entrance-like animation(s) or opacity/transform transition(s), ${m.scriptedAnimations ?? "?"} Web Animations, ${m.styled ?? "?"} element(s) moved or faded by script; ${m.started ?? "?"} transition(s) ran in all (${(m.startedProps ?? []).join(", ") || "none"}). Transitions are declared on ${m.transitions} element(s) (${m.transitionProps.join(", ") || "none"}) for hover and state changes.${entrances ? "" : " Nothing enters or reveals on load or scroll: the page is static apart from hover and state changes."}`);
93
+ return out;
94
+ }
95
+
96
+ export async function critique(dir, rawRoute, { url } = {}) {
97
+ const route = normalizeRoute(rawRoute);
98
+ const session = path.join(root(dir, route), stamp());
99
+ fs.mkdirSync(path.join(session, "sections"), { recursive: true });
100
+ fs.writeFileSync(path.join(dir, ".palate", ".gitignore"), "*\n");
101
+
102
+ const { shot, widths, devices, title, refRows, principles } = await withBrowser(dir, { url }, async ({ base, browser }) => {
103
+ // Its principles pass is replaced by the section-aware one below.
104
+ const shot = await shoot(dir, route, { url: base, principles: false });
105
+ const widths = {};
106
+ const principles = {};
107
+ let devices = null;
108
+ let title = "";
109
+ for (const w of [1440, 390]) {
110
+ const { page, ctx } = await openPage(browser, base, route, { width: w, init: MOTION_INIT });
111
+ const sections = await findSections(page);
112
+ widths[w] = await cropSections(page, sections, path.join(session, "sections"), `w${w}`);
113
+ principles[w] = await measurePrinciples(page, { sections }).catch(() => null);
114
+ if (w === 1440) {
115
+ await shootFull(page, path.join(session, "full-1440.png"));
116
+ devices = await page.evaluate(`(${devicesScript})(${JSON.stringify(sections)})`);
117
+ title = await page.title();
118
+ }
119
+ await ctx.close();
120
+ }
121
+ // References from the library for each section's kind, and for logo rows found inside sections.
122
+ const { searchLibrary } = await import("./library.mjs");
123
+ const used = new Set();
124
+ const refRows = [];
125
+ const kinds = widths[1440].map((s, i) => ({ label: `Section ${s.index} · ${s.name.slice(0, 40)}`, kind: sectionKind(s, { first: i === (widths[1440][0]?.tag === "header" ? 1 : 0), media: devices.media.some((m) => m.section === s.index) }) }));
126
+ for (const r of devices.logoRows) kinds.push({ label: `Logo row in section ${r.section}`, kind: "logo cloud" });
127
+ for (const k of kinds) {
128
+ const refs = searchLibrary(k.kind, { n: 6, preferWhole: true }).filter((r) => !used.has(r.id) && fs.existsSync(path.join(LIB_DIR, "thumbs", `${r.id}.jpg`))).slice(0, 3);
129
+ refs.forEach((r) => used.add(r.id));
130
+ if (refs.length) refRows.push({ ...k, refs });
131
+ }
132
+ // All sections at 1440 in one image, for agents that take images inline.
133
+ await contactSheet(browser, widths[1440].map((s) => ({ label: `Section ${s.index} · ${s.name.slice(0, 70)}`, cells: [{ file: s.file }] })), path.join(session, "sections.png"), { cell: 960, maxCell: 900 });
134
+ if (refRows.length) {
135
+ let n = 0;
136
+ for (const row of refRows) for (const r of row.refs) r.n = `R${++n}`;
137
+ await contactSheet(browser, refRows.map((row) => ({ label: `${row.label}: ${row.kind}`, cells: row.refs.map((r) => ({ caption: `${r.n} · ${r.source}`, file: path.join(LIB_DIR, "thumbs", `${r.id}.jpg`) })) })), path.join(session, "references.png"), { cell: 360, maxCell: 240 });
138
+ }
139
+ return { shot, widths, devices, title, refRows, principles };
140
+ });
141
+
142
+ const sections = widths[1440].map((s) => ({ ...s, crops: Object.fromEntries(Object.entries(widths).map(([w, list]) => [w, list.find((x) => x.index === s.index)?.file ?? list.find((x) => x.name === s.name)?.file ?? null])) }));
143
+ const kind = screenWords(route, sections.map((s) => s.name), title);
144
+ fs.writeFileSync(path.join(session, "sections.json"), JSON.stringify({ route, title, kind, sections, at390: widths[390], devices, references: refRows.map((r) => ({ label: r.label, kind: r.kind, refs: r.refs.map((x) => ({ n: x.n, id: x.id, source: x.source, url: x.url, license: x.license, thumb: slash(path.join(LIB_DIR, "thumbs", `${x.id}.jpg`)) })) })) }, null, 1));
145
+ fs.writeFileSync(path.join(session, "shoot.md"), shot.report);
146
+ fs.writeFileSync(path.join(session, "principles.json"), JSON.stringify(principles, null, 1));
147
+ // shoot's own principles block is replaced by the section-aware one in the sheet.
148
+ // From shoot, only what it found wrong (its facts repeat the principles' facts) and the originality notes.
149
+ const shootLines = shot.report
150
+ .replace(/### Principles[\s\S]*?(?=\n## |$)/g, "")
151
+ .split(/\n(?=## )/)
152
+ .flatMap((block) => {
153
+ const head = block.match(/^## (.+)/)?.[1] ?? "";
154
+ const lines = block.split("\n").filter((l) => (/originality/i.test(head) ? /^- / : /^- ⚠/).test(l));
155
+ return lines.length ? [`${/^\d+px$/.test(head) ? `At ${head}:` : `${head}:`}`, ...lines.map(clip)] : [];
156
+ });
157
+ const factLine = /^- (Hierarchy|Alignment|Spacing|Type|Surfaces|Colour|Density)/;
158
+
159
+ // The sheet is a summary (about 12KB): the crops, the facts, the top principle findings and the taste.
160
+ // The rubric (titles and detections, and the full entries with fixes), every principle finding, the
161
+ // review guide and shoot's report go in files next to it, opened when needed.
162
+ const rubric = craftRubric(null, { compact: true });
163
+ const full = craftRubric();
164
+ if (full.text) fs.writeFileSync(path.join(session, "rubric.md"), full.text);
165
+ if (rubric.text) fs.writeFileSync(path.join(session, "rubric-compact.md"), `# Rubric (kb/craft): each item's title and how to detect it\nFlag an item only when its detection is met, and quote the element. Fixes: rubric.md.\n\n${rubric.text}`);
166
+ const rubricIndex = rubric.files.map((f) => {
167
+ const src = fs.readFileSync(f, "utf8");
168
+ const t = src.match(/^title:\s*(.+)$/m)?.[1].replace(/^["']|["']$/g, "") ?? src.match(/^#\s+(.+)$/m)?.[1] ?? path.basename(f, ".md");
169
+ return `${t} (${path.basename(f, ".md")})`;
170
+ });
171
+ fs.writeFileSync(path.join(session, "principles.md"), [principles[1440] && principlesReport(principles[1440], { max: 99 }).join("\n"), principles[390] && principlesReport(principles[390], { max: 99 }).join("\n")].filter(Boolean).join("\n\n"));
172
+ fs.writeFileSync(path.join(session, "review-guide.md"), REVIEW_GUIDE);
173
+ const taste = tasteFor(kind, { sections: 1, lean: true, project: path.basename(path.resolve(dir)) });
174
+ const past = pastDisagreements(8);
175
+ const findings = path.join(session, "findings.json");
176
+ const cropDir = path.join(session, "sections");
177
+ // A finding already listed at 1440 (same check, same section) isn't repeated at 390.
178
+ const key = (l) => {
179
+ const id = l.match(/\[(P\d+)\]/)?.[1];
180
+ return id ? `${id}|${l.match(/section (\d+)/)?.[1] ?? ""}` : null;
181
+ };
182
+ const at1440 = new Set((principles[1440] ? principlesReport(principles[1440], { max: 5 }) : []).map(key).filter(Boolean));
183
+ const seen1440 = (l) => at1440.has(key(l));
184
+ const sheet = [
185
+ `# Critique: ${route}${title ? ` (${title})` : ""}`,
186
+ "",
187
+ "You are a senior product designer reviewing this page for the person who owns it. Write specific findings, not a score: name the element, what is wrong, why it matters, and the exact fix (values, tokens, components, copy). Include ideas, not only defects: where a section is generic or forgettable, say what would make it memorable.",
188
+ "",
189
+ "## Look at it",
190
+ `- Full page: ${slash(path.join(session, "full-1440.png"))} (1440) and ${shot.files.filter((f) => /w390-full\.png$/.test(f)).map(slash).join("") || "the 390 shot from palate shoot"} (390)`,
191
+ `- All sections at 1440 in one image: ${slash(path.join(session, "sections.png"))}`,
192
+ `- Sections (open every crop, 1440 first, then 390; all in ${slash(cropDir)}/):`,
193
+ ...sections.map((s) => ` ${s.index}. **${s.name}** \`${s.selector}\`${s.sticky ? " (sticky)" : ""}: ${Object.entries(s.crops).filter(([, f]) => f).map(([, f]) => path.basename(f)).join(" · ")}`),
194
+ statesLine(dir, route),
195
+ refRows.length ? `- References from palate's library for each kind of section: ${slash(path.join(session, "references.png"))} (numbers R1…; sources in sections.json). Point to one when an idea would borrow from it.` : "",
196
+ "",
197
+ "## Whole page (measured at 1440)",
198
+ ...deviceLines(devices),
199
+ "",
200
+ "## Principles (the top findings, measured; confirm on the crops before reporting)",
201
+ ...(principles[1440] ? principlesReport(principles[1440], { max: 5 }).slice(1).map(clip) : ["- Not measured at 1440."]),
202
+ ...(principles[390] ? ["At 390 (only what 1440 didn't already show):", ...principlesReport(principles[390], { max: 2 }).slice(1).filter((l) => !factLine.test(l) && !/^- …and/.test(l) && !seen1440(l)).map(clip)] : []),
203
+ `Every finding at both widths, with selectors: ${slash(path.join(session, "principles.md"))}`,
204
+ "",
205
+ "## Measured by palate shoot (problems only; the full report: shoot.md next to this sheet)",
206
+ shootLines.join("\n") || "- No measurable problems.",
207
+ "",
208
+ "## The user's taste for this kind of screen",
209
+ taste || "No taste profile yet: judge clarity first, with one crafted touch at most.",
210
+ past.length ? `\n## The user disagreed with these before (do not raise them again)\n${past.map((p) => `- ${p.what}${p.note ? ` (their note: ${p.note})` : ""}`).join("\n")}` : "",
211
+ "",
212
+ "## How to review",
213
+ `The whole page first, then each section at both widths. The questions, in full: ${slash(path.join(session, "review-guide.md"))}.`,
214
+ "- Page: [page.1] job, [page.2] repeated devices, [page.3] the product shown working or only pictured, [page.4] motion, [page.5] rhythm, [page.6] memorability.",
215
+ "- Each section: [section.1] job (sells or documents?), [section.2] hierarchy, [section.3] type, [section.4] spacing and alignment, [section.5] legibility at a glance, [section.6] details and states, [section.7] phone, [section.8] one idea if it's generic.",
216
+ "",
217
+ "## Rubric (kb/craft)",
218
+ rubric.text ? `Open ${slash(path.join(session, "rubric-compact.md"))} (each item's title and detection) and check the page against it; fixes are in ${slash(path.join(session, "rubric.md"))}. Flag an item only when its detection is met, and quote the element. It covers: ${rubricIndex.join(", ")}.` : "No craft checklists installed (kb/craft is empty). Use the review questions above.",
219
+ "",
220
+ "## Write the findings",
221
+ `Write JSON to ${slash(findings)}:`,
222
+ "```json",
223
+ JSON.stringify(
224
+ {
225
+ route,
226
+ findings: [
227
+ { id: "F1", section: "2", severity: "high", what: "What is wrong, naming the element", why: "Why it matters to this page's job or reader", fix: "The concrete change: values, components, copy", rubric: "page.2" },
228
+ { id: "F2", section: "page", severity: "idea", what: "Where the page is generic or forgettable", why: "…", fix: "The idea, concretely, and the reference it borrows from (e.g. R3)", rubric: "page.6", width: 1440 },
229
+ ],
230
+ },
231
+ ).replace(/\{"id"/g, '\n {"id"'),
232
+ "```",
233
+ "- section: the section number above, or \"page\" for a whole-page finding.",
234
+ "- severity: high (hurts the page's job, or a visible bug) · medium (a designer would notice) · low (polish) · idea (not wrong, could be memorable).",
235
+ "- rubric: the item it comes from, e.g. page.2, section.5, or a kb/craft id (M16, D01, …). width: 1440 or 390 when it only shows at one width.",
236
+ "- Aim for 8–20 findings, most important first. Whole-page findings when devices repeat. At least one idea for every section that is generic. Skip anything the taste profile says the user likes, and anything they disagreed with before.",
237
+ "",
238
+ `Then run: palate critique --findings ${slash(findings)}`,
239
+ "It opens a review board in the user's browser; they agree or disagree with each finding. Then: palate fix " + route,
240
+ ]
241
+ .filter((l) => l !== "")
242
+ .join("\n")
243
+ .replace(/\n(#{2,3} )/g, "\n\n$1");
244
+ fs.writeFileSync(path.join(session, "sheet.md"), sheet);
245
+ return { sheet: `${sheet}\n\n(Sheet saved to ${slash(path.join(session, "sheet.md"))})`, session, sections, findings, images: [path.join(session, "sections.png"), ...(refRows.length ? [path.join(session, "references.png")] : [])] };
246
+ }
247
+
248
+ // Reads and normalises a findings file. Accepts a few common aliases so a slightly-off file still loads.
249
+ export function loadFindings(file) {
250
+ const raw = readJson(file, null);
251
+ if (!raw) throw new Error(`Could not read findings JSON from ${file}`);
252
+ const list = Array.isArray(raw) ? raw : raw.findings;
253
+ if (!list?.length) throw new Error(`No findings in ${file}. Expected {"route": "/", "findings": [{ id, section, severity, what, why, fix, rubric }]}`);
254
+ const sev = (s) => {
255
+ const v = String(s ?? "").toLowerCase();
256
+ return SEVERITIES.includes(v) ? v : /crit|block|major/.test(v) ? "high" : /minor|polish|nit/.test(v) ? "low" : /idea|sugg|opportun/.test(v) ? "idea" : "medium";
257
+ };
258
+ const findings = list.map((f, i) => {
259
+ const what = f.what ?? f.issue ?? f.problem ?? f.title;
260
+ const fix = f.fix ?? f.suggestion ?? f.change;
261
+ if (!what || !fix) throw new Error(`Finding ${f.id ?? i + 1} needs "what" and "fix".`);
262
+ return { id: String(f.id ?? `F${i + 1}`), section: String(f.section ?? "page"), severity: sev(f.severity), what, why: f.why ?? f.reason ?? "", fix, rubric: f.rubric ?? "", width: f.width ? Number(f.width) : null };
263
+ });
264
+ return { route: raw.route ? normalizeRoute(raw.route) : null, findings };
265
+ }
266
+
267
+ // Which session a findings file belongs to: its own folder if it is a session, else the latest for its route.
268
+ function sessionFor(dir, file, route) {
269
+ const own = path.dirname(path.resolve(file));
270
+ if (fs.existsSync(path.join(own, "sections.json"))) return own;
271
+ const s = latestCritique(dir, route);
272
+ if (!s) throw new Error(`No critique session found${route ? ` for ${route}` : ""}. Run: palate critique <route>`);
273
+ return s;
274
+ }
275
+
276
+ // The review board: a local page where the user agrees or disagrees with each finding. Saves as they go.
277
+ export async function startBoard(dir, file, { open = true } = {}) {
278
+ const { route: given, findings } = loadFindings(file);
279
+ const session = sessionFor(dir, file, given);
280
+ const meta = readJson(path.join(session, "sections.json"), {});
281
+ const route = given ?? meta.route;
282
+ const target = path.join(session, "findings.json");
283
+ if (path.resolve(file) !== path.resolve(target)) fs.copyFileSync(file, target);
284
+ const reviewFile = path.join(session, "review.json");
285
+ const review = readJson(reviewFile, { verdicts: {} });
286
+ const save = () => fs.writeFileSync(reviewFile, JSON.stringify(review, null, 1));
287
+
288
+ const sections = meta.sections ?? [];
289
+ const sectionOf = (f) => {
290
+ const n = Number(String(f.section).match(/^\s*#?(\d+)/)?.[1]);
291
+ if (n) return sections.find((s) => s.index === n) ?? null;
292
+ const q = f.section.toLowerCase();
293
+ return q === "page" ? null : sections.find((s) => s.name.toLowerCase() === q) ?? sections.find((s) => s.name.toLowerCase().includes(q) || q.includes(s.name.toLowerCase())) ?? null;
294
+ };
295
+ const items = findings.map((f) => {
296
+ const s = sectionOf(f);
297
+ return { ...f, sectionIndex: s?.index ?? 0, sectionName: s?.name ?? "The whole page" };
298
+ });
299
+ const crops = {};
300
+ for (const s of sections) for (const [w, f] of Object.entries(s.crops ?? {})) if (f) crops[`${w}-${s.index}`] = f;
301
+ if (fs.existsSync(path.join(session, "full-1440.png"))) crops["1440-0"] = path.join(session, "full-1440.png");
302
+
303
+ let finish;
304
+ const done = new Promise((r) => (finish = r));
305
+ let finished = false;
306
+ const body = (req) => new Promise((r) => {
307
+ let b = "";
308
+ req.on("data", (c) => (b += c));
309
+ req.on("end", () => r(b ? JSON.parse(b) : {}));
310
+ });
311
+ const server = http.createServer(async (req, res) => {
312
+ const u = new URL(req.url, "http://x");
313
+ try {
314
+ if (u.pathname === "/") {
315
+ res.writeHead(200, { "content-type": "text/html; charset=utf-8" });
316
+ return res.end(fs.readFileSync(path.join(here, "board.html")));
317
+ }
318
+ if (u.pathname === "/api/state") {
319
+ res.writeHead(200, { "content-type": "application/json" });
320
+ return res.end(JSON.stringify({ route, title: meta.title ?? "", project: path.basename(dir), findings: items, crops: Object.keys(crops), verdicts: review.verdicts, finished }));
321
+ }
322
+ if (u.pathname === "/api/verdict" && req.method === "POST") {
323
+ const { id, verdict, note } = await body(req);
324
+ if (!items.some((f) => f.id === id)) throw new Error(`No finding ${id}`);
325
+ const v = (review.verdicts[id] ??= {});
326
+ if (verdict !== undefined) v.verdict = ["agree", "disagree"].includes(verdict) ? verdict : null;
327
+ if (note !== undefined) v.note = String(note).slice(0, 2000);
328
+ v.at = new Date().toISOString();
329
+ save();
330
+ res.writeHead(204);
331
+ return res.end();
332
+ }
333
+ if (u.pathname === "/api/done" && req.method === "POST") {
334
+ res.writeHead(204);
335
+ res.end();
336
+ if (!finished) {
337
+ finished = true;
338
+ setTimeout(finish, 200);
339
+ }
340
+ return;
341
+ }
342
+ const m = /^\/img\/(\d+)-(\d+)\.png$/.exec(u.pathname);
343
+ if (m && crops[`${m[1]}-${m[2]}`]) {
344
+ res.writeHead(200, { "content-type": "image/png" });
345
+ return fs.createReadStream(crops[`${m[1]}-${m[2]}`]).pipe(res);
346
+ }
347
+ res.writeHead(404);
348
+ res.end();
349
+ } catch (e) {
350
+ res.writeHead(400, { "content-type": "text/plain" });
351
+ res.end(String(e.message));
352
+ }
353
+ });
354
+ const port = await freePort();
355
+ await new Promise((r) => server.listen(port, "127.0.0.1", r));
356
+ const link = `http://localhost:${port}`;
357
+ if (open) openBrowser(link);
358
+ const result = done.then(() => {
359
+ server.close();
360
+ return report();
361
+ });
362
+ return { link, session, count: items.length, done: result };
363
+
364
+ function report() {
365
+ review.finishedAt = new Date().toISOString();
366
+ save();
367
+ fs.mkdirSync(TASTE_DIR, { recursive: true });
368
+ const lines = items.map((f) => ({ project: path.basename(dir), route, kind: meta.kind, id: f.id, section: f.sectionName, severity: f.severity, what: f.what, why: f.why, fix: f.fix, rubric: f.rubric, verdict: review.verdicts[f.id]?.verdict ?? null, note: review.verdicts[f.id]?.note ?? "", at: review.finishedAt }));
369
+ fs.appendFileSync(CRITIQUES, lines.map((l) => JSON.stringify(l)).join("\n") + "\n");
370
+ const by = (v) => items.filter((f) => (review.verdicts[f.id]?.verdict ?? null) === v);
371
+ const fmt = (f) => `- ${f.id} [${f.severity}] ${f.sectionName}: ${f.what}${review.verdicts[f.id]?.note ? `\n the user's note: ${review.verdicts[f.id].note}` : ""}`;
372
+ return [
373
+ `# Critique of ${route}: the user's verdicts`,
374
+ "",
375
+ `Agreed: ${by("agree").length} · Disagreed: ${by("disagree").length} · Not marked: ${by(null).length}`,
376
+ by("agree").length ? `\n## Agreed\n${by("agree").map(fmt).join("\n")}` : "",
377
+ by("disagree").length ? `\n## Disagreed (the user does not consider these problems; leave them alone)\n${by("disagree").map(fmt).join("\n")}` : "",
378
+ by(null).length ? `\n## Not marked\n${by(null).map(fmt).join("\n")}` : "",
379
+ "",
380
+ `Saved to ${slash(reviewFile)} and the user's taste log (${slash(CRITIQUES)}).`,
381
+ `Next: palate fix ${route} (a brief from the agreed findings, most severe first), then palate taste learn.`,
382
+ ]
383
+ .filter((l) => l !== "")
384
+ .join("\n");
385
+ }
386
+ }
387
+
388
+ // CLI: open the board, wait for the user, return their verdicts.
389
+ export async function reviewFindings(dir, file, opts = {}) {
390
+ const b = await startBoard(dir, file, opts);
391
+ console.log(`Review board ready: ${b.link} (${b.count} findings). Waiting for the user…`);
392
+ return b.done;
393
+ }
@@ -0,0 +1,225 @@
1
+ // `palate details <route>`: a micro-component upgrade pass. Finds the generic small parts from the DOM
2
+ // (page-details.js) and by interacting with the page (hover, keyboard focus, :active rules), crops each
3
+ // one, and writes a brief that lists every part with its upgrade. Real content only.
4
+ import fs from "node:fs";
5
+ import path from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+ import { contactSheet, openPage, slugOf, stamp, withBrowser } from "../look.mjs";
8
+ import { normalizeRoute } from "../shoot.mjs";
9
+ import { craftRubric, LIB_DIR, slash } from "./craft.mjs";
10
+
11
+ const here = path.dirname(fileURLToPath(import.meta.url));
12
+ const detailsScript = fs.readFileSync(path.join(here, "..", "page-details.js"), "utf8").trim().replace(/;\s*$/, "");
13
+
14
+ // What each kind of part should become.
15
+ export const UPGRADES = {
16
+ avatar: "Use the real person's photo when the project has one (look in public/, content and data files). Otherwise a license-clean generated avatar seeded by the name, so each person always gets the same one: a soft two-stop gradient or a boring-avatars style shape (`boring-avatars` package, or a 20-line SVG), with initials only as a fallback. Never stock faces presented as customers, users or team.",
17
+ "brand-marks": "Use each brand's official mark in its own colours (Simple Icons ships official SVGs with brand hex colours, CC0; follow each brand's guidelines), 20–28px tall next to 14–15px names, or full-colour wordmarks without names. If the row stays one colour by choice, make it legible: marks at least 20px, colour at 4.5:1 or better against the background, not a pale grey. See the logo-cloud references below.",
18
+ inputs: "Style every control with the project's tokens: `appearance: none`, the project's radius and border, inherited font, a custom checkbox / radio / select arrow (or the project's component library's), a visible label (not a placeholder), and a clear :focus-visible ring.",
19
+ "empty-state": "Say what is empty and why, and offer the next action as a button (\"No invoices yet. Create your first invoice\"). Never show raw null, undefined or NaN: fix the data path.",
20
+ numbers: "Format with Intl.NumberFormat (thousands separators, currency, compact like 12.4k where precision doesn't matter), dates with Intl.DateTimeFormat or relative time, and `tabular-nums` on number columns only.",
21
+ emoji: "Replace with an icon from the project's own icon set (see palate context), or drop it. No emoji in UI copy.",
22
+ icons: "One icon family, one stroke width (e.g. Lucide at 1.5 or 2), consistent sizes (16 inline, 20 in buttons), aligned optically with the text.",
23
+ placeholder: "Replace with real content from the project. If none exists, leave the slot out or ask the user; never invent names, quotes or numbers.",
24
+ badges: "Keep the one or two badges that change a decision; turn the rest into plain metadata text, or group them behind one count.",
25
+ hover: "Add a hover state: a colour, background or underline shift, 150ms ease-out, inside `@media (hover: hover)` so touch screens don't get stuck states.",
26
+ focus: "Add a visible keyboard focus state: `:focus-visible` ring 2px, offset 2px, in the project's focus colour; never remove outlines without a replacement.",
27
+ pressed: "Add pressed feedback on buttons: `:active { scale: 0.97 }` (or a darker fill) over 100ms, disabled under reduced motion.",
28
+ meta: "Favicon: an icon file (Next: app/icon.svg or icon.png; elsewhere link rel=icon). apple-touch-icon 180×180. A social image 1200×630 made from the page's own headline and product (Next: app/opengraph-image.tsx with ImageResponse), og:title, meta description, twitter:card summary_large_image.",
29
+ };
30
+
31
+ // Hover, keyboard focus and :active rules on the page's interactive elements. A state counts when any
32
+ // computed style that paints the element changes: colour, fills (including gradients and filter), borders,
33
+ // shadows, text decoration, opacity, transforms, outline, on the element, its first children, or ::before/::after.
34
+ export async function stateChecks(page) {
35
+ const count = await page.evaluate(() => {
36
+ const els = [...document.querySelectorAll("a[href], button, [role=button], input:not([type=hidden]), select, textarea, summary")].filter((e) => {
37
+ const r = e.getBoundingClientRect();
38
+ const cs = getComputedStyle(e);
39
+ return r.width > 4 && r.height > 4 && cs.visibility !== "hidden" && parseFloat(cs.opacity) > 0.05 && !e.closest(".sr-only");
40
+ });
41
+ els.slice(0, 28).forEach((e, i) => e.setAttribute("data-palate-i", String(i)));
42
+ return Math.min(els.length, 28);
43
+ });
44
+ const snap = (i) =>
45
+ page.evaluate((i) => {
46
+ const e = document.querySelector(`[data-palate-i="${i}"]`);
47
+ if (!e) return null;
48
+ const props = (c) => [c.color, c.backgroundColor, c.backgroundImage, c.backgroundSize, c.backgroundPosition, c.borderTopColor, c.borderRightColor, c.borderBottomColor, c.borderLeftColor, c.boxShadow, c.textShadow, c.textDecorationLine, c.textDecorationColor, c.textDecorationThickness, c.textUnderlineOffset, c.opacity, c.filter, c.backdropFilter, c.transform, c.scale, c.translate, c.rotate, c.outlineStyle, c.outlineWidth, c.outlineColor, c.outlineOffset, c.fill, c.stroke].join("|");
49
+ const pick = (el) => {
50
+ const pseudo = ["::before", "::after"].map((p) => getComputedStyle(el, p)).filter((c) => c.content && c.content !== "none" && c.content !== "normal").map((c) => `${props(c)}|${c.width}|${c.height}`);
51
+ return [props(getComputedStyle(el)), ...pseudo].join("~");
52
+ };
53
+ // A native control drawn by its label or a sibling (a transparent radio over a styled span) shows its
54
+ // states there.
55
+ const own = [e, ...e.querySelectorAll("*")].slice(0, 6);
56
+ const near = e.matches("input, select") ? [...(e.labels ?? []), e.closest("label"), e.nextElementSibling, e.previousElementSibling].filter((x) => x && !own.includes(x)) : [];
57
+ return [...own, ...near].map(pick).join("#");
58
+ }, i);
59
+ const describe = (i) =>
60
+ page.evaluate((i) => {
61
+ const e = document.querySelector(`[data-palate-i="${i}"]`);
62
+ // A live page can re-render and drop the element between steps.
63
+ if (!e) return null;
64
+ const r = e.getBoundingClientRect();
65
+ return { tag: e.tagName.toLowerCase(), text: (e.getAttribute("aria-label") || e.textContent || e.getAttribute("placeholder") || "").replace(/\s+/g, " ").trim().slice(0, 40), box: { x: Math.round(r.left + scrollX), y: Math.round(r.top + scrollY), width: Math.round(r.width), height: Math.round(r.height) }, button: e.matches("button, [role=button], input[type=submit]") || (getComputedStyle(e).backgroundColor !== "rgba(0, 0, 0, 0)" && e.matches("a")) };
66
+ }, i);
67
+ const base = [];
68
+ for (let i = 0; i < count; i++) base[i] = await snap(i);
69
+ // Disabled controls (disabled, aria-disabled, or in a disabled fieldset) have no hover or pressed state on purpose.
70
+ const off = await page.evaluate((count) => {
71
+ const out = [];
72
+ for (let i = 0; i < count; i++) {
73
+ const e = document.querySelector(`[data-palate-i="${i}"]`);
74
+ if (e && (e.matches(":disabled") || e.closest("[aria-disabled=true]"))) out.push(i);
75
+ }
76
+ return out;
77
+ }, count);
78
+ const noHover = [];
79
+ for (let i = 0; i < count; i++) {
80
+ if (off.includes(i)) continue;
81
+ const ok = await page.hover(`[data-palate-i="${i}"]`, { timeout: 1500 }).then(() => true).catch(() => false);
82
+ if (!ok) continue;
83
+ await page.waitForTimeout(260);
84
+ if ((await snap(i)) === base[i]) noHover.push(i);
85
+ await page.mouse.move(0, 0);
86
+ await page.waitForTimeout(60);
87
+ }
88
+ await page.evaluate(() => window.scrollTo({ top: 0, behavior: "instant" }));
89
+ const focused = new Map();
90
+ for (let k = 0; k < 45; k++) {
91
+ await page.keyboard.press("Tab");
92
+ await page.waitForTimeout(90);
93
+ const i = await page.evaluate(() => document.activeElement?.getAttribute("data-palate-i"));
94
+ if (i == null || focused.has(Number(i))) continue;
95
+ focused.set(Number(i), (await snap(Number(i))) !== base[Number(i)]);
96
+ }
97
+ const noFocus = [...focused].filter(([, changed]) => !changed).map(([i]) => i);
98
+ // Pressed: a CSS :active rule (nested rules included) that matches the button. Script-driven press feedback isn't seen.
99
+ const noPress = await page.evaluate((count) => {
100
+ const actives = [];
101
+ const walk = (rules, parent) => {
102
+ for (const r of rules) {
103
+ if (r.selectorText !== undefined) {
104
+ const full = r.selectorText.split(",").map((s) => (parent ? (s.includes("&") ? s.replace(/&/g, parent) : `${parent} ${s}`) : s)).join(",");
105
+ if (full.includes(":active")) actives.push(...full.split(",").filter((s) => s.includes(":active")).map((s) => s.replace(/:active/g, "").trim()));
106
+ if (r.cssRules?.length) walk(r.cssRules, full.split(",")[0]);
107
+ } else if (r.cssRules) walk(r.cssRules, parent);
108
+ }
109
+ };
110
+ for (const sh of document.styleSheets) {
111
+ try {
112
+ walk(sh.cssRules, null);
113
+ } catch {}
114
+ }
115
+ const out = [];
116
+ for (let i = 0; i < count; i++) {
117
+ const e = document.querySelector(`[data-palate-i="${i}"]`);
118
+ if (!e || !e.matches("button, [role=button], input[type=submit]") || e.matches(":disabled") || e.closest("[aria-disabled=true]")) continue;
119
+ if (!actives.some((s) => { try { return e.matches(s || "*") || [...e.querySelectorAll("*")].some((c) => c.matches(s)); } catch { return false; } })) out.push(i);
120
+ }
121
+ return out;
122
+ }, count);
123
+ const items = [];
124
+ for (const [kind, list] of [["hover", noHover], ["focus", noFocus], ["pressed", noPress]]) {
125
+ if (!list.length) continue;
126
+ const ds = (await Promise.all(list.map(describe))).filter(Boolean);
127
+ if (!ds.length) continue;
128
+ items.push({ kind, detail: `${list.length} ${kind === "pressed" ? "button(s) with no :active style" : kind === "hover" ? "element(s) that don't change on hover" : "element(s) with no visible keyboard focus"}: ${ds.slice(0, 6).map((d) => `<${d.tag}> "${d.text}"`).join(", ")}`, box: ds[0].box, selector: null, text: ds[0].text });
129
+ }
130
+ return { items, checked: count, tabbed: focused.size };
131
+ }
132
+
133
+ export async function details(dir, rawRoute, { url } = {}) {
134
+ const route = normalizeRoute(rawRoute);
135
+ const session = path.join(dir, ".palate", "details", slugOf(route), stamp());
136
+ fs.mkdirSync(path.join(session, "crops"), { recursive: true });
137
+ fs.writeFileSync(path.join(dir, ".palate", ".gitignore"), "*\n");
138
+
139
+ const { items, states, phone, logoSheet } = await withBrowser(dir, { url }, async ({ base, browser }) => {
140
+ const { page, ctx } = await openPage(browser, base, route, { width: 1440 });
141
+ const found = await page.evaluate(`(${detailsScript})()`);
142
+ // Crop each part with some room around it.
143
+ const pageW = await page.evaluate(() => document.documentElement.clientWidth);
144
+ const pageH = await page.evaluate(() => document.documentElement.scrollHeight);
145
+ const crop = async (it, n) => {
146
+ if (!it.box || it.box.width < 2) return null;
147
+ const pad = 24;
148
+ const clip = { x: Math.max(0, it.box.x - pad), y: Math.max(0, it.box.y - pad), width: Math.min(pageW, it.box.width + pad * 2), height: Math.min(420, it.box.height + pad * 2, pageH - Math.max(0, it.box.y - pad)) };
149
+ clip.width = Math.min(clip.width, pageW - clip.x);
150
+ if (clip.width < 8 || clip.height < 8) return null;
151
+ const file = path.join(session, "crops", `${n}-${it.kind}.png`);
152
+ await page.screenshot({ path: file, fullPage: true, clip }).catch(() => null);
153
+ return fs.existsSync(file) ? file : null;
154
+ };
155
+ const items = found.map((it, i) => ({ ...it, n: `D${i + 1}` }));
156
+ for (const it of items) it.crop = await crop(it, it.n);
157
+ const states = await stateChecks(page);
158
+ for (const it of states.items) {
159
+ it.n = `D${items.length + 1}`;
160
+ it.crop = await crop(it, it.n);
161
+ items.push(it);
162
+ }
163
+ await ctx.close();
164
+ // The phone width only for what changes there: brand marks and inputs.
165
+ const m = await openPage(browser, base, route, { width: 390 });
166
+ const phone = (await m.page.evaluate(`(${detailsScript})()`)).filter((x) => ["brand-marks", "inputs"].includes(x.kind) && !items.some((y) => y.kind === x.kind && y.detail === x.detail));
167
+ await m.ctx.close();
168
+ if (items.length) await contactSheet(browser, [{ label: "", cells: items.filter((i) => i.crop).map((i) => ({ caption: `${i.n} · ${i.kind}`, file: i.crop })) }].map((r) => ({ ...r, cells: r.cells })), path.join(session, "details.png"), { cell: 320, maxCell: 260 });
169
+ // Logo clouds from the library, when brand marks need work.
170
+ let logoSheet = null;
171
+ if (items.some((i) => i.kind === "brand-marks")) {
172
+ const { searchLibrary } = await import("./library.mjs");
173
+ const refs = searchLibrary("logo cloud", { n: 6, preferWhole: true }).filter((r) => fs.existsSync(path.join(LIB_DIR, "thumbs", `${r.id}.jpg`))).slice(0, 4);
174
+ if (refs.length) {
175
+ logoSheet = path.join(session, "logo-cloud-refs.png");
176
+ await contactSheet(browser, [{ label: "Logo clouds from palate's library", cells: refs.map((r, i) => ({ caption: `L${i + 1} · ${r.source}`, file: path.join(LIB_DIR, "thumbs", `${r.id}.jpg`) })) }], logoSheet, { cell: 360, maxCell: 240 });
177
+ }
178
+ }
179
+ return { items, states, phone, logoSheet };
180
+ });
181
+
182
+ fs.writeFileSync(path.join(session, "details.json"), JSON.stringify({ route, items, phone, states: { checked: states.checked, tabbed: states.tabbed } }, null, 1));
183
+ const rubric = craftRubric(/detail|micro|component|finish/i);
184
+ const byKind = {};
185
+ for (const it of [...items, ...phone.map((p) => ({ ...p, n: "phone", detail: `${p.detail} (at 390px)` }))]) (byKind[it.kind] ??= []).push(it);
186
+ const order = ["placeholder", "empty-state", "brand-marks", "avatar", "inputs", "focus", "pressed", "hover", "numbers", "emoji", "icons", "badges", "meta"];
187
+ const kinds = Object.keys(byKind).sort((a, b) => order.indexOf(a) - order.indexOf(b));
188
+ const brief = [
189
+ `# Details: ${route}`,
190
+ "",
191
+ "A micro-component pass: upgrade the small parts that make a screen look generated. Keep the layout and the idea; change only the parts listed. Open the contact sheet first, then each crop.",
192
+ "",
193
+ items.length ? `Contact sheet: ${slash(path.join(session, "details.png"))} (numbers D1…; one crop per part in ${slash(path.join(session, "crops"))}).` : "",
194
+ "",
195
+ kinds.length ? "## What palate found, and the upgrade" : "## palate found no generic small parts. Look at the page yourself with the checklist below.",
196
+ ...kinds.flatMap((k) => [
197
+ "",
198
+ `### ${k}`,
199
+ ...byKind[k].map((it) => `- ${it.n}: ${it.detail}${it.selector ? ` \`${it.selector}\`` : ""}${it.text && !it.detail.includes(it.text) ? ` ("${it.text}")` : ""}${it.names ? ` · ${it.names.join(", ")}` : ""}${it.crop ? ` · crop ${slash(it.crop)}` : ""}`),
200
+ `Upgrade: ${UPGRADES[k] ?? "Bring it up to the project's standard."}`,
201
+ ...(k === "brand-marks" && logoSheet ? [`References: ${slash(logoSheet)} (logo clouds from palate's library: look at mark size, colour and spacing).`] : []),
202
+ ]),
203
+ "",
204
+ `Checked ${states.checked} interactive elements for hover and pressed states, and ${states.tabbed} reached by Tab for focus. Script-driven press feedback (e.g. Motion's whileTap) isn't seen by the pressed check; skip those.`,
205
+ "",
206
+ "## Also look for (not measurable)",
207
+ "- Icons that don't match the text weight or sit off the baseline; arrows that don't move on hover where the label says \"go\".",
208
+ "- Truncation without a tooltip, numbers without units, timestamps without a timezone or relative form.",
209
+ "- Loading and error states for every async part (skeletons shaped like the content, errors that say how to recover).",
210
+ "- Selection colour, scrollbar styling in scroll areas, caret colour in inputs, placeholder contrast.",
211
+ rubric.text ? `\n## Details checklist (kb/craft)\n${rubric.text}` : "",
212
+ "",
213
+ "## Rules",
214
+ "- Real content only. Avatars are real people the project has, or a generated, license-clean option seeded by the name; never stock faces presented as customers or team. Brand marks are the brands' official marks, used for the brands the project really works with.",
215
+ "- Use the project's tokens, icon set and components (palate context). Don't install packages without asking the user; a 20-line SVG often does the job.",
216
+ "- Keep changes scoped to the parts listed; no layout changes.",
217
+ "",
218
+ "## Verify",
219
+ `Run \`palate details ${route}\` again: each part you fixed should be gone from the list. Then \`palate shoot ${route}\` and look at the crops of what you changed.`,
220
+ ]
221
+ .filter((l, i, a) => !(l === "" && a[i - 1] === ""))
222
+ .join("\n");
223
+ fs.writeFileSync(path.join(session, "brief.md"), brief);
224
+ return `${brief}\n\n(Brief saved to ${slash(path.join(session, "brief.md"))})`;
225
+ }