@tryvitris/website-harness 0.1.0-beta.6 → 0.1.0-beta.7

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 (458) hide show
  1. package/README.md +4 -4
  2. package/agent/graph.yaml +0 -2
  3. package/agent/refs/components.md +5 -41
  4. package/agent/refs/compose.md +1 -1
  5. package/agent/refs/implement.md +2 -2
  6. package/agent/refs/jev.md +1 -1
  7. package/agent/refs/layout.md +1 -1
  8. package/agent/refs/storyboard.md +1 -1
  9. package/agent/refs/template-adaptation.md +1 -1
  10. package/bin/api/agent/evaluate.js +10 -15
  11. package/bin/api/agent/grade.js +10 -15
  12. package/bin/api/cli/api.js +18 -23
  13. package/bin/api/cli.js +20 -25
  14. package/bin/api/engine.js +11 -16
  15. package/bin/api/hosting.js +12 -17
  16. package/bin/api/index.js +2 -3
  17. package/bin/api/references.js +1 -2
  18. package/bin/api/render.js +2 -4
  19. package/bin/chunks/{chunk-4GZCAWWK.js → chunk-4MFPATAB.js} +2 -4
  20. package/bin/chunks/{chunk-5OOPJNGN.js → chunk-5JTBC6UK.js} +1 -4
  21. package/bin/chunks/{chunk-Z2UNY47A.js → chunk-5YSPWKFF.js} +1 -1
  22. package/bin/chunks/{chunk-FYN4T4SV.js → chunk-7V3OKLKH.js} +15 -26
  23. package/bin/chunks/{chunk-3CTBXY5K.js → chunk-FRABKM65.js} +1936 -1899
  24. package/bin/chunks/{chunk-4DM5TTLG.js → chunk-H7Y72HXC.js} +5 -5
  25. package/bin/chunks/{chunk-R7YELY3C.js → chunk-HL6JVA4A.js} +100 -81
  26. package/bin/chunks/{chunk-54JC5L35.js → chunk-O55LAQ2C.js} +3 -5
  27. package/bin/chunks/{chunk-VH7PM7KJ.js → chunk-P56ZDMX7.js} +4 -6
  28. package/bin/chunks/{chunk-7VLBEAFW.js → chunk-PGFFKPK6.js} +2 -2
  29. package/bin/chunks/{chunk-YQYHROLZ.js → chunk-QRWGFLUU.js} +2 -2
  30. package/bin/chunks/{chunk-CBEJZO4L.js → chunk-TTAUU3AZ.js} +2 -2
  31. package/bin/chunks/{chunk-E5Y46VBX.js → chunk-VTI32UGJ.js} +200 -103
  32. package/bin/chunks/{chunk-DRJQ4OOU.js → chunk-WOORR67N.js} +0 -45
  33. package/bin/chunks/{chunk-B5I45LFD.js → chunk-YZWEXHT4.js} +11 -13
  34. package/bin/chunks/{chunk-YCVGD2CG.js → chunk-ZIROO2U4.js} +1204 -1176
  35. package/bin/chunks/{chunk-42IXFXUD.js → chunk-ZWFG4GPG.js} +11 -15
  36. package/bin/chunks/{design-context-store-IAT2P2OC.js → design-context-store-DCZOAK56.js} +10 -15
  37. package/bin/chunks/{packets-VBMY4SQJ.js → packets-QOLWPRNV.js} +10 -15
  38. package/bin/chunks/{policy-2I37JUU3.js → policy-MP2JZXI3.js} +1 -1
  39. package/bin/chunks/{preparation-S4MG3RPL.js → preparation-T2IOD5SJ.js} +10 -15
  40. package/bin/chunks/{questions-HKELBDFL.js → questions-XK545GCX.js} +1 -11
  41. package/bin/types/src/agent/composition-authoring.d.ts +2 -2
  42. package/bin/types/src/agent/jev/calibration.d.ts +2 -2
  43. package/bin/types/src/agent/jev/config.d.ts +1 -1
  44. package/bin/types/src/agent/jev/questions.d.ts +0 -10
  45. package/bin/types/src/agent/jev/types.d.ts +0 -2
  46. package/bin/types/src/agent/site-inputs.d.ts +9 -1
  47. package/bin/types/src/agent/template-catalog.d.ts +20 -0
  48. package/bin/types/src/agent/theme-selection.d.ts +4 -2
  49. package/bin/types/src/build/archives.d.ts +2 -0
  50. package/bin/vitris-art.js +10 -15
  51. package/bin/vitris-build.js +3 -5
  52. package/bin/vitris-create-site.js +12 -17
  53. package/bin/vitris-cursor-hook.js +10 -15
  54. package/bin/vitris-eval.js +12 -17
  55. package/bin/vitris-go.js +14 -19
  56. package/bin/vitris-harvest.js +11 -16
  57. package/bin/vitris-knowledge.js +11 -16
  58. package/bin/vitris-launch-preflight.js +11 -17
  59. package/bin/vitris-motion-view.js +13 -19
  60. package/bin/vitris-references.js +4 -7
  61. package/bin/vitris-refresh.js +11 -16
  62. package/bin/vitris-stock.js +1 -1
  63. package/bin/vitris-themes.js +10 -15
  64. package/bin/vitris-upgrade.js +11 -16
  65. package/bin/vitris-verify-browser.js +43 -8
  66. package/bin/vitris-verify-performance.js +3 -5
  67. package/bin/vitris.js +20 -25
  68. package/design-system/MASTER.md +2 -2
  69. package/docs/CLI.md +2 -1
  70. package/docs/DISTRIBUTION.md +1 -1
  71. package/package.json +2 -7
  72. package/templates/site/README.md +2 -0
  73. package/templates/site/gitignore +1 -0
  74. package/bin/chunks/chunk-6H3T46F5.js +0 -25
  75. package/bin/chunks/chunk-ANMJRJQ5.js +0 -31
  76. package/bin/chunks/chunk-FOXUQXTV.js +0 -278
  77. package/bin/chunks/chunk-HNORQ74T.js +0 -40
  78. package/bin/chunks/chunk-T7DGRVTP.js +0 -458
  79. package/bin/types/src/agent/jev/block-catalog.d.ts +0 -95
  80. package/bin/types/src/agent/jev/component-select.d.ts +0 -102
  81. package/bin/types/src/blocks/library-profile.d.ts +0 -9
  82. package/bin/types/src/blocks/metadata.d.ts +0 -65
  83. package/bin/vitris-blocks.js +0 -238
  84. package/blocks/CONVENTIONS.md +0 -121
  85. package/blocks/INDEX.md +0 -130
  86. package/blocks/about/about-awards/README.md +0 -36
  87. package/blocks/about/about-awards/styles.css +0 -13
  88. package/blocks/about/about-awards/template.html +0 -1
  89. package/blocks/about/about-credentials/README.md +0 -33
  90. package/blocks/about/about-credentials/block.meta.json +0 -85
  91. package/blocks/about/about-credentials/styles.css +0 -4
  92. package/blocks/about/about-credentials/template.html +0 -1
  93. package/blocks/about/about-founder/README.md +0 -35
  94. package/blocks/about/about-founder/styles.css +0 -9
  95. package/blocks/about/about-founder/template.html +0 -1
  96. package/blocks/about/about-mission/README.md +0 -31
  97. package/blocks/about/about-mission/styles.css +0 -5
  98. package/blocks/about/about-mission/template.html +0 -1
  99. package/blocks/about/about-statement/README.md +0 -28
  100. package/blocks/about/about-statement/styles.css +0 -7
  101. package/blocks/about/about-statement/template.html +0 -1
  102. package/blocks/about/about-story/README.md +0 -35
  103. package/blocks/about/about-story/styles.css +0 -5
  104. package/blocks/about/about-story/template.html +0 -1
  105. package/blocks/about/about-timeline/README.md +0 -33
  106. package/blocks/about/about-timeline/styles.css +0 -8
  107. package/blocks/about/about-timeline/template.html +0 -1
  108. package/blocks/about/about-values/README.md +0 -31
  109. package/blocks/about/about-values/styles.css +0 -3
  110. package/blocks/about/about-values/template.html +0 -1
  111. package/blocks/blog/blog-featured/README.md +0 -39
  112. package/blocks/blog/blog-featured/styles.css +0 -12
  113. package/blocks/blog/blog-featured/template.html +0 -1
  114. package/blocks/blog/blog-index/README.md +0 -34
  115. package/blocks/blog/blog-index/styles.css +0 -6
  116. package/blocks/blog/blog-index/template.html +0 -1
  117. package/blocks/blog/blog-post-header/README.md +0 -31
  118. package/blocks/blog/blog-post-header/styles.css +0 -8
  119. package/blocks/blog/blog-post-header/template.html +0 -1
  120. package/blocks/contact/contact-cards/README.md +0 -32
  121. package/blocks/contact/contact-cards/styles.css +0 -7
  122. package/blocks/contact/contact-cards/template.html +0 -1
  123. package/blocks/contact/contact-chips/README.md +0 -41
  124. package/blocks/contact/contact-chips/styles.css +0 -13
  125. package/blocks/contact/contact-chips/template.html +0 -1
  126. package/blocks/contact/contact-hours/README.md +0 -41
  127. package/blocks/contact/contact-hours/block.meta.json +0 -87
  128. package/blocks/contact/contact-hours/styles.css +0 -8
  129. package/blocks/contact/contact-hours/template.html +0 -1
  130. package/blocks/contact/contact-map/README.md +0 -39
  131. package/blocks/contact/contact-map/styles.css +0 -10
  132. package/blocks/contact/contact-map/template.html +0 -1
  133. package/blocks/contact/contact-offices/README.md +0 -32
  134. package/blocks/contact/contact-offices/styles.css +0 -8
  135. package/blocks/contact/contact-offices/template.html +0 -1
  136. package/blocks/contact/contact-phone-first/README.md +0 -33
  137. package/blocks/contact/contact-phone-first/block.meta.json +0 -86
  138. package/blocks/contact/contact-phone-first/styles.css +0 -11
  139. package/blocks/contact/contact-phone-first/template.html +0 -1
  140. package/blocks/contact/contact-split/README.md +0 -43
  141. package/blocks/contact/contact-split/styles.css +0 -12
  142. package/blocks/contact/contact-split/template.html +0 -1
  143. package/blocks/contact/contact-visit/README.md +0 -36
  144. package/blocks/contact/contact-visit/block.meta.json +0 -88
  145. package/blocks/contact/contact-visit/styles.css +0 -13
  146. package/blocks/contact/contact-visit/template.html +0 -1
  147. package/blocks/contact/service-areas/README.md +0 -32
  148. package/blocks/contact/service-areas/styles.css +0 -9
  149. package/blocks/contact/service-areas/template.html +0 -1
  150. package/blocks/content/glossary/README.md +0 -35
  151. package/blocks/content/glossary/styles.css +0 -6
  152. package/blocks/content/glossary/template.html +0 -1
  153. package/blocks/content/list-split/README.md +0 -33
  154. package/blocks/content/list-split/styles.css +0 -13
  155. package/blocks/content/list-split/template.html +0 -1
  156. package/blocks/content/prose-split/README.md +0 -32
  157. package/blocks/content/prose-split/styles.css +0 -12
  158. package/blocks/content/prose-split/template.html +0 -1
  159. package/blocks/content/specification-ledger/README.md +0 -32
  160. package/blocks/content/specification-ledger/block.meta.json +0 -85
  161. package/blocks/content/specification-ledger/styles.css +0 -10
  162. package/blocks/content/specification-ledger/template.html +0 -1
  163. package/blocks/cta/cta-band/README.md +0 -33
  164. package/blocks/cta/cta-band/styles.css +0 -11
  165. package/blocks/cta/cta-band/template.html +0 -1
  166. package/blocks/cta/cta-card/README.md +0 -35
  167. package/blocks/cta/cta-card/styles.css +0 -8
  168. package/blocks/cta/cta-card/template.html +0 -1
  169. package/blocks/cta/cta-floating-bar/README.md +0 -28
  170. package/blocks/cta/cta-floating-bar/styles.css +0 -8
  171. package/blocks/cta/cta-floating-bar/template.html +0 -1
  172. package/blocks/cta/cta-inline/README.md +0 -30
  173. package/blocks/cta/cta-inline/styles.css +0 -9
  174. package/blocks/cta/cta-inline/template.html +0 -1
  175. package/blocks/cta/cta-newsletter/README.md +0 -34
  176. package/blocks/cta/cta-newsletter/styles.css +0 -8
  177. package/blocks/cta/cta-newsletter/template.html +0 -1
  178. package/blocks/cta/cta-photo-fan/README.md +0 -36
  179. package/blocks/cta/cta-photo-fan/styles.css +0 -14
  180. package/blocks/cta/cta-photo-fan/template.html +0 -1
  181. package/blocks/cta/cta-split/README.md +0 -38
  182. package/blocks/cta/cta-split/styles.css +0 -10
  183. package/blocks/cta/cta-split/template.html +0 -1
  184. package/blocks/faq/faq-accordion/README.md +0 -36
  185. package/blocks/faq/faq-accordion/styles.css +0 -6
  186. package/blocks/faq/faq-accordion/template.html +0 -1
  187. package/blocks/faq/faq-grouped/README.md +0 -40
  188. package/blocks/faq/faq-grouped/styles.css +0 -20
  189. package/blocks/faq/faq-grouped/template.html +0 -1
  190. package/blocks/faq/faq-split/README.md +0 -37
  191. package/blocks/faq/faq-split/styles.css +0 -5
  192. package/blocks/faq/faq-split/template.html +0 -1
  193. package/blocks/faq/faq-tabs/README.md +0 -36
  194. package/blocks/faq/faq-tabs/styles.css +0 -3
  195. package/blocks/faq/faq-tabs/template.html +0 -1
  196. package/blocks/feature/feature-bento/README.md +0 -33
  197. package/blocks/feature/feature-bento/styles.css +0 -7
  198. package/blocks/feature/feature-bento/template.html +0 -1
  199. package/blocks/feature/feature-compare-table/README.md +0 -44
  200. package/blocks/feature/feature-compare-table/styles.css +0 -15
  201. package/blocks/feature/feature-compare-table/template.html +0 -1
  202. package/blocks/feature/feature-comparison/README.md +0 -34
  203. package/blocks/feature/feature-comparison/styles.css +0 -6
  204. package/blocks/feature/feature-comparison/template.html +0 -1
  205. package/blocks/feature/feature-grid-3/README.md +0 -34
  206. package/blocks/feature/feature-grid-3/styles.css +0 -8
  207. package/blocks/feature/feature-grid-3/template.html +0 -1
  208. package/blocks/feature/feature-icon-list/README.md +0 -39
  209. package/blocks/feature/feature-icon-list/styles.css +0 -9
  210. package/blocks/feature/feature-icon-list/template.html +0 -1
  211. package/blocks/feature/feature-spotlight/README.md +0 -39
  212. package/blocks/feature/feature-spotlight/styles.css +0 -5
  213. package/blocks/feature/feature-spotlight/template.html +0 -1
  214. package/blocks/feature/feature-stats-band/README.md +0 -33
  215. package/blocks/feature/feature-stats-band/styles.css +0 -8
  216. package/blocks/feature/feature-stats-band/template.html +0 -1
  217. package/blocks/feature/feature-tabs/README.md +0 -38
  218. package/blocks/feature/feature-tabs/styles.css +0 -7
  219. package/blocks/feature/feature-tabs/template.html +0 -1
  220. package/blocks/feature/feature-thumb-list/README.md +0 -38
  221. package/blocks/feature/feature-thumb-list/styles.css +0 -13
  222. package/blocks/feature/feature-thumb-list/template.html +0 -1
  223. package/blocks/feature/feature-zigzag/README.md +0 -31
  224. package/blocks/feature/feature-zigzag/styles.css +0 -6
  225. package/blocks/feature/feature-zigzag/template.html +0 -1
  226. package/blocks/footer/footer-columns/README.md +0 -39
  227. package/blocks/footer/footer-columns/styles.css +0 -16
  228. package/blocks/footer/footer-columns/template.html +0 -1
  229. package/blocks/footer/footer-compact/README.md +0 -33
  230. package/blocks/footer/footer-compact/styles.css +0 -12
  231. package/blocks/footer/footer-compact/template.html +0 -1
  232. package/blocks/footer/footer-cta/README.md +0 -37
  233. package/blocks/footer/footer-cta/styles.css +0 -18
  234. package/blocks/footer/footer-cta/template.html +0 -1
  235. package/blocks/footer/footer-social/README.md +0 -37
  236. package/blocks/footer/footer-social/styles.css +0 -17
  237. package/blocks/footer/footer-social/template.html +0 -1
  238. package/blocks/footer/footer-wordmark/README.md +0 -40
  239. package/blocks/footer/footer-wordmark/styles.css +0 -19
  240. package/blocks/footer/footer-wordmark/template.html +0 -1
  241. package/blocks/gallery/gallery-before-after/README.md +0 -31
  242. package/blocks/gallery/gallery-before-after/styles.css +0 -6
  243. package/blocks/gallery/gallery-before-after/template.html +0 -1
  244. package/blocks/gallery/gallery-carousel/README.md +0 -32
  245. package/blocks/gallery/gallery-carousel/styles.css +0 -7
  246. package/blocks/gallery/gallery-carousel/template.html +0 -1
  247. package/blocks/gallery/gallery-grid/README.md +0 -39
  248. package/blocks/gallery/gallery-grid/styles.css +0 -13
  249. package/blocks/gallery/gallery-grid/template.html +0 -1
  250. package/blocks/gallery/gallery-masonry/README.md +0 -33
  251. package/blocks/gallery/gallery-masonry/styles.css +0 -4
  252. package/blocks/gallery/gallery-masonry/template.html +0 -1
  253. package/blocks/gallery/gallery-mosaic-split/README.md +0 -40
  254. package/blocks/gallery/gallery-mosaic-split/styles.css +0 -15
  255. package/blocks/gallery/gallery-mosaic-split/template.html +0 -1
  256. package/blocks/hero/hero-asymmetric/README.md +0 -34
  257. package/blocks/hero/hero-asymmetric/styles.css +0 -13
  258. package/blocks/hero/hero-asymmetric/template.html +0 -10
  259. package/blocks/hero/hero-before-after/README.md +0 -38
  260. package/blocks/hero/hero-before-after/styles.css +0 -8
  261. package/blocks/hero/hero-before-after/template.html +0 -19
  262. package/blocks/hero/hero-editorial/README.md +0 -34
  263. package/blocks/hero/hero-editorial/block.meta.json +0 -85
  264. package/blocks/hero/hero-editorial/styles.css +0 -6
  265. package/blocks/hero/hero-editorial/template.html +0 -10
  266. package/blocks/hero/hero-evidence/README.md +0 -32
  267. package/blocks/hero/hero-evidence/block.meta.json +0 -85
  268. package/blocks/hero/hero-evidence/styles.css +0 -13
  269. package/blocks/hero/hero-evidence/template.html +0 -1
  270. package/blocks/hero/hero-form/README.md +0 -46
  271. package/blocks/hero/hero-form/styles.css +0 -11
  272. package/blocks/hero/hero-form/template.html +0 -15
  273. package/blocks/hero/hero-menu/README.md +0 -36
  274. package/blocks/hero/hero-menu/styles.css +0 -7
  275. package/blocks/hero/hero-menu/template.html +0 -10
  276. package/blocks/hero/hero-overlay/README.md +0 -35
  277. package/blocks/hero/hero-overlay/styles.css +0 -14
  278. package/blocks/hero/hero-overlay/template.html +0 -10
  279. package/blocks/hero/hero-page/README.md +0 -35
  280. package/blocks/hero/hero-page/styles.css +0 -19
  281. package/blocks/hero/hero-page/template.html +0 -1
  282. package/blocks/hero/hero-product/README.md +0 -41
  283. package/blocks/hero/hero-product/styles.css +0 -11
  284. package/blocks/hero/hero-product/template.html +0 -14
  285. package/blocks/hero/hero-service/README.md +0 -37
  286. package/blocks/hero/hero-service/block.meta.json +0 -85
  287. package/blocks/hero/hero-service/styles.css +0 -17
  288. package/blocks/hero/hero-service/template.html +0 -1
  289. package/blocks/hero/hero-split/README.md +0 -36
  290. package/blocks/hero/hero-split/styles.css +0 -7
  291. package/blocks/hero/hero-split/template.html +0 -11
  292. package/blocks/hero/hero-statement/README.md +0 -33
  293. package/blocks/hero/hero-statement/styles.css +0 -8
  294. package/blocks/hero/hero-statement/template.html +0 -1
  295. package/blocks/hero/hero-stats/README.md +0 -37
  296. package/blocks/hero/hero-stats/styles.css +0 -10
  297. package/blocks/hero/hero-stats/template.html +0 -10
  298. package/blocks/hero/hero-video-still/README.md +0 -36
  299. package/blocks/hero/hero-video-still/styles.css +0 -9
  300. package/blocks/hero/hero-video-still/template.html +0 -13
  301. package/blocks/icons.md +0 -44
  302. package/blocks/incentives/incentive-banner/README.md +0 -28
  303. package/blocks/incentives/incentive-banner/styles.css +0 -7
  304. package/blocks/incentives/incentive-banner/template.html +0 -1
  305. package/blocks/incentives/incentive-cards/README.md +0 -31
  306. package/blocks/incentives/incentive-cards/styles.css +0 -4
  307. package/blocks/incentives/incentive-cards/template.html +0 -1
  308. package/blocks/navbar/nav-announcement/README.md +0 -35
  309. package/blocks/navbar/nav-announcement/styles.css +0 -10
  310. package/blocks/navbar/nav-announcement/template.html +0 -14
  311. package/blocks/navbar/nav-centered/README.md +0 -35
  312. package/blocks/navbar/nav-centered/styles.css +0 -11
  313. package/blocks/navbar/nav-centered/template.html +0 -12
  314. package/blocks/navbar/nav-minimal/README.md +0 -29
  315. package/blocks/navbar/nav-minimal/styles.css +0 -5
  316. package/blocks/navbar/nav-minimal/template.html +0 -6
  317. package/blocks/navbar/nav-split/README.md +0 -34
  318. package/blocks/navbar/nav-split/styles.css +0 -11
  319. package/blocks/navbar/nav-split/template.html +0 -11
  320. package/blocks/navbar/nav-utility/README.md +0 -37
  321. package/blocks/navbar/nav-utility/styles.css +0 -17
  322. package/blocks/navbar/nav-utility/template.html +0 -12
  323. package/blocks/pricing/menu-featured/README.md +0 -34
  324. package/blocks/pricing/menu-featured/styles.css +0 -4
  325. package/blocks/pricing/menu-featured/template.html +0 -1
  326. package/blocks/pricing/menu-sections/README.md +0 -33
  327. package/blocks/pricing/menu-sections/styles.css +0 -9
  328. package/blocks/pricing/menu-sections/template.html +0 -1
  329. package/blocks/pricing/pricing-table/README.md +0 -40
  330. package/blocks/pricing/pricing-table/styles.css +0 -9
  331. package/blocks/pricing/pricing-table/template.html +0 -1
  332. package/blocks/pricing/pricing-tiers/README.md +0 -34
  333. package/blocks/pricing/pricing-tiers/styles.css +0 -7
  334. package/blocks/pricing/pricing-tiers/template.html +0 -1
  335. package/blocks/pricing/pricing-toggle/README.md +0 -34
  336. package/blocks/pricing/pricing-toggle/styles.css +0 -10
  337. package/blocks/pricing/pricing-toggle/template.html +0 -1
  338. package/blocks/process/process-carousel/README.md +0 -33
  339. package/blocks/process/process-carousel/styles.css +0 -5
  340. package/blocks/process/process-carousel/template.html +0 -1
  341. package/blocks/process/process-split/README.md +0 -35
  342. package/blocks/process/process-split/styles.css +0 -6
  343. package/blocks/process/process-split/template.html +0 -1
  344. package/blocks/process/process-stepper/README.md +0 -40
  345. package/blocks/process/process-stepper/styles.css +0 -11
  346. package/blocks/process/process-stepper/template.html +0 -1
  347. package/blocks/process/process-steps/README.md +0 -35
  348. package/blocks/process/process-steps/styles.css +0 -6
  349. package/blocks/process/process-steps/template.html +0 -1
  350. package/blocks/process/process-sticky/README.md +0 -38
  351. package/blocks/process/process-sticky/styles.css +0 -12
  352. package/blocks/process/process-sticky/template.html +0 -1
  353. package/blocks/process/process-timeline/README.md +0 -35
  354. package/blocks/process/process-timeline/styles.css +0 -10
  355. package/blocks/process/process-timeline/template.html +0 -1
  356. package/blocks/services/services-cards/README.md +0 -34
  357. package/blocks/services/services-cards/styles.css +0 -3
  358. package/blocks/services/services-cards/template.html +0 -1
  359. package/blocks/services/services-carousel/README.md +0 -34
  360. package/blocks/services/services-carousel/styles.css +0 -6
  361. package/blocks/services/services-carousel/template.html +0 -1
  362. package/blocks/services/services-list/README.md +0 -32
  363. package/blocks/services/services-list/block.meta.json +0 -85
  364. package/blocks/services/services-list/styles.css +0 -10
  365. package/blocks/services/services-list/template.html +0 -1
  366. package/blocks/services/services-menu/README.md +0 -39
  367. package/blocks/services/services-menu/styles.css +0 -6
  368. package/blocks/services/services-menu/template.html +0 -1
  369. package/blocks/services/services-packages/README.md +0 -34
  370. package/blocks/services/services-packages/styles.css +0 -6
  371. package/blocks/services/services-packages/template.html +0 -1
  372. package/blocks/services/services-panels/README.md +0 -36
  373. package/blocks/services/services-panels/styles.css +0 -15
  374. package/blocks/services/services-panels/template.html +0 -1
  375. package/blocks/services/services-photo-grid/README.md +0 -39
  376. package/blocks/services/services-photo-grid/styles.css +0 -10
  377. package/blocks/services/services-photo-grid/template.html +0 -1
  378. package/blocks/services/services-priority/README.md +0 -33
  379. package/blocks/services/services-priority/block.meta.json +0 -86
  380. package/blocks/services/services-priority/styles.css +0 -16
  381. package/blocks/services/services-priority/template.html +0 -1
  382. package/blocks/stats/stats-cards/README.md +0 -31
  383. package/blocks/stats/stats-cards/styles.css +0 -4
  384. package/blocks/stats/stats-cards/template.html +0 -1
  385. package/blocks/stats/stats-mosaic/README.md +0 -27
  386. package/blocks/stats/stats-mosaic/styles.css +0 -9
  387. package/blocks/stats/stats-mosaic/template.html +0 -1
  388. package/blocks/stats/stats-row/README.md +0 -29
  389. package/blocks/stats/stats-row/styles.css +0 -8
  390. package/blocks/stats/stats-row/template.html +0 -1
  391. package/blocks/stats/stats-split/README.md +0 -35
  392. package/blocks/stats/stats-split/styles.css +0 -3
  393. package/blocks/stats/stats-split/template.html +0 -1
  394. package/blocks/team/team-featured/README.md +0 -42
  395. package/blocks/team/team-featured/styles.css +0 -9
  396. package/blocks/team/team-featured/template.html +0 -1
  397. package/blocks/team/team-grid/README.md +0 -35
  398. package/blocks/team/team-grid/styles.css +0 -8
  399. package/blocks/team/team-grid/template.html +0 -1
  400. package/blocks/team/team-list/README.md +0 -32
  401. package/blocks/team/team-list/styles.css +0 -7
  402. package/blocks/team/team-list/template.html +0 -1
  403. package/blocks/testimonial/testimonial-carousel/README.md +0 -32
  404. package/blocks/testimonial/testimonial-carousel/styles.css +0 -7
  405. package/blocks/testimonial/testimonial-carousel/template.html +0 -1
  406. package/blocks/testimonial/testimonial-grid/README.md +0 -32
  407. package/blocks/testimonial/testimonial-grid/styles.css +0 -5
  408. package/blocks/testimonial/testimonial-grid/template.html +0 -1
  409. package/blocks/testimonial/testimonial-mosaic/README.md +0 -38
  410. package/blocks/testimonial/testimonial-mosaic/styles.css +0 -14
  411. package/blocks/testimonial/testimonial-mosaic/template.html +0 -1
  412. package/blocks/testimonial/testimonial-platform/README.md +0 -34
  413. package/blocks/testimonial/testimonial-platform/styles.css +0 -17
  414. package/blocks/testimonial/testimonial-platform/template.html +0 -1
  415. package/blocks/testimonial/testimonial-rating/README.md +0 -28
  416. package/blocks/testimonial/testimonial-rating/styles.css +0 -6
  417. package/blocks/testimonial/testimonial-rating/template.html +0 -1
  418. package/blocks/testimonial/testimonial-spotlight/README.md +0 -31
  419. package/blocks/testimonial/testimonial-spotlight/styles.css +0 -9
  420. package/blocks/testimonial/testimonial-spotlight/template.html +0 -1
  421. package/blocks/testimonial/testimonial-switcher/README.md +0 -39
  422. package/blocks/testimonial/testimonial-switcher/styles.css +0 -23
  423. package/blocks/testimonial/testimonial-switcher/template.html +0 -1
  424. package/blocks/testimonial/testimonial-wall/README.md +0 -34
  425. package/blocks/testimonial/testimonial-wall/styles.css +0 -7
  426. package/blocks/testimonial/testimonial-wall/template.html +0 -1
  427. package/blocks/trust-strip/trust-badges/README.md +0 -30
  428. package/blocks/trust-strip/trust-badges/styles.css +0 -5
  429. package/blocks/trust-strip/trust-badges/template.html +0 -1
  430. package/blocks/trust-strip/trust-certs/README.md +0 -31
  431. package/blocks/trust-strip/trust-certs/styles.css +0 -12
  432. package/blocks/trust-strip/trust-certs/template.html +0 -1
  433. package/blocks/trust-strip/trust-logos/README.md +0 -32
  434. package/blocks/trust-strip/trust-logos/styles.css +0 -5
  435. package/blocks/trust-strip/trust-logos/template.html +0 -1
  436. package/blocks/trust-strip/trust-quote/README.md +0 -29
  437. package/blocks/trust-strip/trust-quote/styles.css +0 -5
  438. package/blocks/trust-strip/trust-quote/template.html +0 -1
  439. package/blocks/trust-strip/trust-reviews/README.md +0 -35
  440. package/blocks/trust-strip/trust-reviews/styles.css +0 -9
  441. package/blocks/trust-strip/trust-reviews/template.html +0 -1
  442. package/blocks/work/case-alternating/README.md +0 -34
  443. package/blocks/work/case-alternating/block.meta.json +0 -86
  444. package/blocks/work/case-alternating/styles.css +0 -7
  445. package/blocks/work/case-alternating/template.html +0 -1
  446. package/blocks/work/case-carousel/README.md +0 -26
  447. package/blocks/work/case-carousel/styles.css +0 -7
  448. package/blocks/work/case-carousel/template.html +0 -1
  449. package/blocks/work/case-header/README.md +0 -38
  450. package/blocks/work/case-header/styles.css +0 -18
  451. package/blocks/work/case-header/template.html +0 -1
  452. package/blocks/work/project-evidence/README.md +0 -35
  453. package/blocks/work/project-evidence/block.meta.json +0 -87
  454. package/blocks/work/project-evidence/styles.css +0 -12
  455. package/blocks/work/project-evidence/template.html +0 -1
  456. package/blocks/work/project-grid/README.md +0 -38
  457. package/blocks/work/project-grid/styles.css +0 -9
  458. package/blocks/work/project-grid/template.html +0 -1
@@ -6,6 +6,34 @@ import {
6
6
  escapeHtml
7
7
  } from "./chunk-7FS67SRF.js";
8
8
 
9
+ // src/compile/frontmatter.ts
10
+ function parseFrontmatter(raw) {
11
+ const text = raw.replace(/^\uFEFF/, "");
12
+ if (!text.startsWith("---")) {
13
+ return { meta: {}, body: text.trim() };
14
+ }
15
+ const end = text.indexOf("\n---", 3);
16
+ if (end === -1) {
17
+ return { meta: {}, body: text.trim() };
18
+ }
19
+ const block = text.slice(3, end).trim();
20
+ const body = text.slice(end + 4).replace(/^\r?\n/, "");
21
+ const meta = {};
22
+ for (const line of block.split(/\r?\n/)) {
23
+ const trimmed = line.trim();
24
+ if (!trimmed || trimmed.startsWith("#")) continue;
25
+ const colon = trimmed.indexOf(":");
26
+ if (colon === -1) continue;
27
+ const key = trimmed.slice(0, colon).trim();
28
+ let value = trimmed.slice(colon + 1).trim();
29
+ if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
30
+ value = value.slice(1, -1);
31
+ }
32
+ if (key) meta[key] = value;
33
+ }
34
+ return { meta, body: body.trim() };
35
+ }
36
+
9
37
  // src/compile/paths.ts
10
38
  function fileToPath(relFile) {
11
39
  const normalized = relFile.replace(/\\/g, "/").replace(/^\.\//, "");
@@ -802,1241 +830,1241 @@ function instrumentSections(html, site) {
802
830
  });
803
831
  }
804
832
 
805
- // src/compile/primitives.ts
806
- var primitivesCss = `
807
- /* \u2014\u2014 Layout \u2014\u2014 */
808
- .section {
809
- padding-block: var(--section-y);
810
- }
811
- .section--tight { padding-block: var(--space-6); }
812
- .section--roomy { padding-block: calc(var(--section-y) + var(--space-5)); }
813
- .section--surface { background: var(--color-surface); }
814
- .section--muted { background: var(--color-surface-2); }
815
- .section--dark,
816
- [data-scheme="dark"] {
817
- --color-bg: #141210;
818
- --color-text: #F7F4EF;
819
- --color-muted: #B8B0A4;
820
- --color-surface: #1E1B18;
821
- --color-surface-2: #2A2622;
822
- --color-border: #3A342E;
823
- background: var(--color-bg);
824
- color: var(--color-text);
825
- }
826
- .section__head {
827
- display: grid;
828
- gap: var(--space-3);
829
- margin-bottom: var(--space-7);
830
- max-width: 42rem;
831
- }
832
- .section__head--center {
833
- margin-inline: auto;
834
- text-align: center;
835
- justify-items: center;
836
- }
837
- .section__head--row {
838
- max-width: none;
839
- grid-template-columns: minmax(0, 42rem);
840
- align-items: end;
841
- justify-content: space-between;
842
- }
843
- @media (min-width: 720px) {
844
- .section__head--row { grid-template-columns: minmax(0, 42rem) auto; }
845
- }
846
- .section__head--row > .btn-group { justify-self: end; }
847
- /* Editorial split head: short label column, heading + lede column. */
848
- .section__head--split { max-width: none; }
849
- @media (min-width: 720px) {
850
- .section__head--split {
851
- grid-template-columns: minmax(0, 14rem) minmax(0, 42rem);
852
- gap: var(--space-5) var(--space-7);
853
- align-items: start;
833
+ // src/runtime/before-after.ts
834
+ var beforeAfterJs = `(() => {
835
+ const roots = [...document.querySelectorAll("[data-island=\\"before-after\\"]")];
836
+ for (const root of roots) {
837
+ if (!(root instanceof HTMLElement)) continue;
838
+ const after = root.querySelector(".before-after__after");
839
+ const handle = root.querySelector(".before-after__handle");
840
+ if (!(after instanceof HTMLElement) || !(handle instanceof HTMLElement)) continue;
841
+
842
+ let dragging = false;
843
+ const setPos = (clientX) => {
844
+ const rect = root.getBoundingClientRect();
845
+ const pct = Math.min(100, Math.max(0, ((clientX - rect.left) / rect.width) * 100));
846
+ after.style.clipPath = \`inset(0 0 0 \${pct}%)\`;
847
+ handle.style.left = \`\${pct}%\`;
848
+ root.setAttribute("aria-valuenow", String(Math.round(pct)));
849
+ };
850
+
851
+ const onMove = (e) => {
852
+ if (!dragging) return;
853
+ const x = "touches" in e ? e.touches[0].clientX : e.clientX;
854
+ setPos(x);
855
+ };
856
+ const stop = () => { dragging = false; };
857
+
858
+ root.addEventListener("pointerdown", (e) => {
859
+ dragging = true;
860
+ root.setPointerCapture?.(e.pointerId);
861
+ setPos(e.clientX);
862
+ });
863
+ root.addEventListener("pointermove", onMove);
864
+ root.addEventListener("pointerup", stop);
865
+ root.addEventListener("pointercancel", stop);
866
+ root.addEventListener("keydown", (e) => {
867
+ if (!(e instanceof KeyboardEvent)) return;
868
+ const now = Number(root.getAttribute("aria-valuenow") || "50");
869
+ if (e.key === "ArrowLeft") setPos(root.getBoundingClientRect().left + ((now - 5) / 100) * root.clientWidth);
870
+ if (e.key === "ArrowRight") setPos(root.getBoundingClientRect().left + ((now + 5) / 100) * root.clientWidth);
871
+ });
872
+ root.setAttribute("role", "slider");
873
+ root.setAttribute("aria-valuemin", "0");
874
+ root.setAttribute("aria-valuemax", "100");
875
+ root.setAttribute("aria-valuenow", "50");
876
+ root.tabIndex = 0;
854
877
  }
855
- .section__head--split > .eyebrow { padding-top: 0.45em; }
856
- .section__head--split > :not(.eyebrow) { grid-column: 2; }
857
- }
858
- .sticky-col { align-self: start; }
859
- @media (min-width: 1080px) {
860
- .sticky-col { position: sticky; top: calc(var(--header-h, 4rem) + var(--space-5)); }
861
- }
862
- .section__head .lede,
863
- .lede {
864
- margin: 0;
865
- color: var(--color-muted);
866
- font-size: var(--step-1);
867
- line-height: 1.55;
868
- max-width: 38rem;
869
- }
870
- .lede--lg { font-size: var(--step-2); line-height: 1.45; }
871
- .eyebrow {
872
- margin: 0;
873
- font-size: var(--step-0);
874
- font-weight: 600;
875
- letter-spacing: 0.08em;
876
- text-transform: uppercase;
877
- color: var(--color-muted);
878
- }
879
- .eyebrow--accent { color: var(--color-accent); }
880
- .grid {
881
- display: grid;
882
- gap: var(--gap, var(--space-5));
883
- }
884
- .grid--2 { grid-template-columns: 1fr; }
885
- .grid--3 { grid-template-columns: 1fr; }
886
- .grid--4 { grid-template-columns: 1fr; }
887
- @media (min-width: 720px) {
888
- .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
889
- .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
890
- .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
891
- }
892
- @media (min-width: 1080px) {
893
- .grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
894
- }
895
- .split {
896
- display: grid;
897
- gap: var(--space-6);
898
- align-items: center;
899
- }
900
- .split--top { align-items: start; }
901
- @media (min-width: 720px) {
902
- .split { grid-template-columns: 1fr 1fr; gap: var(--space-7); }
903
- .split--reverse > :first-child { order: 2; }
904
- }
905
- @media (min-width: 1080px) {
906
- .split { gap: var(--space-8); }
907
- }
908
- .bento {
909
- display: grid;
910
- gap: var(--space-3);
911
- grid-template-columns: repeat(2, minmax(0, 1fr));
912
- }
913
- .bento__wide, .bento__full { grid-column: span 2; }
914
- @media (min-width: 720px) {
915
- .bento {
916
- gap: var(--space-4);
917
- grid-template-columns: repeat(6, minmax(0, 1fr));
918
- grid-auto-rows: minmax(9rem, auto);
919
- grid-auto-flow: dense;
878
+ })();
879
+ `;
880
+
881
+ // src/runtime/carousel.ts
882
+ var carouselJs = `(() => {
883
+ const roots = [...document.querySelectorAll("[data-island=\\"carousel\\"]")];
884
+ for (const root of roots) {
885
+ const track = root.querySelector(".carousel__track");
886
+ const prev = root.querySelector("[data-carousel-prev]");
887
+ const next = root.querySelector("[data-carousel-next]");
888
+ if (!(track instanceof HTMLElement)) continue;
889
+ const step = () => Math.max(track.clientWidth * 0.85, 240);
890
+ prev?.addEventListener("click", () => track.scrollBy({ left: -step(), behavior: "smooth" }));
891
+ next?.addEventListener("click", () => track.scrollBy({ left: step(), behavior: "smooth" }));
892
+ root.addEventListener("keydown", (e) => {
893
+ if (!(e instanceof KeyboardEvent)) return;
894
+ if (e.key === "ArrowLeft") track.scrollBy({ left: -step(), behavior: "smooth" });
895
+ if (e.key === "ArrowRight") track.scrollBy({ left: step(), behavior: "smooth" });
896
+ });
920
897
  }
921
- .bento > * { grid-column: span 3; }
922
- .bento__wide { grid-column: span 4; }
923
- .bento__tall { grid-row: span 2; }
924
- .bento__full { grid-column: span 6; }
925
- .bento__narrow { grid-column: span 2; }
926
- }
927
- .stack { display: grid; gap: var(--space-4); }
928
- .stack--tight { gap: var(--space-2); }
929
- .stack--loose { gap: var(--space-6); }
930
- .row {
931
- display: flex;
932
- flex-wrap: wrap;
933
- align-items: center;
934
- gap: var(--space-3);
935
- }
936
- .row--between { justify-content: space-between; }
898
+ })();
899
+ `;
937
900
 
938
- /* \u2014\u2014 Surfaces \u2014\u2014 */
939
- .card {
940
- position: relative;
941
- display: flex;
942
- flex-direction: column;
943
- background: var(--color-surface);
944
- border: 1px solid var(--color-border);
945
- border-radius: var(--radius-lg);
946
- overflow: hidden;
947
- }
948
- .card--bordered { box-shadow: none; }
949
- .card--elevated { box-shadow: var(--shadow-2); border-color: transparent; }
950
- .card--flat {
951
- box-shadow: none;
952
- border-color: transparent;
953
- background: var(--color-surface-2);
954
- }
955
- .card--accent { border-color: var(--color-accent); box-shadow: 0 0 0 1px var(--color-accent); }
956
- .card--interactive {
957
- transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
958
- }
959
- .card--interactive:hover {
960
- transform: translateY(-2px);
961
- box-shadow: var(--shadow-2);
962
- }
963
- .card__media {
964
- position: relative;
965
- overflow: hidden;
966
- background: var(--color-surface-2);
967
- border-radius: 0;
968
- }
969
- .card__media img,
970
- .card__media video {
971
- width: 100%;
972
- height: 100%;
973
- object-fit: cover;
974
- transition: transform 400ms ease;
975
- }
976
- .card--interactive:hover .card__media img { transform: scale(1.03); }
977
- .card__body {
978
- display: grid;
979
- gap: var(--space-2);
980
- padding: var(--space-5);
981
- flex: 1;
982
- align-content: start;
983
- }
984
- .card__body > h3,
985
- .card__body > h4 {
986
- font-size: var(--step-2);
987
- line-height: 1.25;
988
- }
989
- .card__body > p { margin: 0; color: var(--color-muted); font-size: var(--step-1); }
990
- .card__body > .btn-group,
991
- .card__body > .btn,
992
- .card__body > .btn-outline,
993
- .card__body > .btn-arrow {
994
- margin-top: var(--space-2);
995
- justify-self: start;
996
- }
997
- .card__body > .btn-arrow { align-self: end; margin-top: auto; padding-top: var(--space-3); }
998
- /* Photo tile with a bottom scrim and light text (services tiles, project grids, step panels). */
999
- .photo-card {
1000
- position: relative;
1001
- isolation: isolate;
1002
- display: flex;
1003
- flex-direction: column;
1004
- justify-content: flex-end;
1005
- overflow: hidden;
1006
- border-radius: var(--radius-lg);
1007
- background: var(--color-surface-2);
1008
- color: #fff;
1009
- text-decoration: none;
1010
- }
1011
- .photo-card > img {
1012
- position: absolute;
1013
- inset: 0;
1014
- z-index: -2;
1015
- width: 100%;
1016
- height: 100%;
1017
- object-fit: cover;
1018
- transition: transform 500ms ease;
1019
- }
1020
- .photo-card::before {
1021
- content: "";
1022
- position: absolute;
1023
- inset: 0;
1024
- z-index: -1;
1025
- background: linear-gradient(180deg, rgba(0, 0, 0, 0.05) 30%, rgba(0, 0, 0, 0.72) 100%);
1026
- }
1027
- .photo-card__body {
1028
- display: grid;
1029
- gap: var(--space-1);
1030
- padding: var(--space-5);
1031
- }
1032
- .photo-card__body h2,
1033
- .photo-card__body h3,
1034
- .photo-card__body strong { color: #fff; }
1035
- .photo-card__body p { margin: 0; color: rgba(255, 255, 255, 0.82); }
1036
- .photo-card__body .eyebrow { color: rgba(255, 255, 255, 0.72); }
1037
- a.photo-card:hover > img,
1038
- a.photo-card:focus-visible > img { transform: scale(1.04); }
1039
- a.photo-card:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
1040
- .card__footer {
1041
- margin-top: auto;
1042
- padding: var(--space-4) var(--space-5);
1043
- border-top: 1px solid var(--color-border);
1044
- display: flex;
1045
- align-items: center;
1046
- justify-content: space-between;
1047
- gap: var(--space-3);
1048
- }
1049
- .hairline {
1050
- border: 0;
1051
- border-top: 1px solid var(--color-border);
1052
- margin: var(--space-6) 0;
1053
- }
1054
- .frame {
1055
- overflow: hidden;
1056
- border-radius: var(--radius-lg);
1057
- background: var(--color-surface-2);
1058
- box-shadow: var(--shadow-2);
1059
- }
1060
- .frame > img,
1061
- .frame > video { width: 100%; height: 100%; object-fit: cover; }
1062
- .ratio-16x9,
1063
- .ratio-4x3,
1064
- .ratio-3x2,
1065
- .ratio-1x1,
1066
- .ratio-3x4,
1067
- .ratio-21x9 {
1068
- position: relative;
1069
- overflow: hidden;
1070
- border-radius: var(--radius-lg);
1071
- background: var(--color-surface-2);
1072
- }
1073
- .ratio-16x9 { aspect-ratio: 16 / 9; }
1074
- .ratio-4x3 { aspect-ratio: 4 / 3; }
1075
- .ratio-3x2 { aspect-ratio: 3 / 2; }
1076
- .ratio-1x1 { aspect-ratio: 1 / 1; }
1077
- .ratio-3x4 { aspect-ratio: 3 / 4; }
1078
- .ratio-21x9 { aspect-ratio: 21 / 9; }
1079
- .card__media[class*="ratio-"] { border-radius: 0; }
1080
- .ratio-16x9 > img,
1081
- .ratio-4x3 > img,
1082
- .ratio-3x2 > img,
1083
- .ratio-1x1 > img,
1084
- .ratio-3x4 > img,
1085
- .ratio-21x9 > img {
1086
- position: absolute;
1087
- inset: 0;
1088
- width: 100%;
1089
- height: 100%;
1090
- object-fit: cover;
1091
- }
1092
- .icon-tile {
1093
- display: inline-flex;
1094
- align-items: center;
1095
- justify-content: center;
1096
- width: 2.75rem;
1097
- height: 2.75rem;
1098
- border-radius: var(--radius);
1099
- background: color-mix(in srgb, var(--color-accent) 12%, transparent);
1100
- color: var(--color-accent);
1101
- flex-shrink: 0;
1102
- }
1103
- .icon-tile .icon { width: 1.35rem; height: 1.35rem; }
1104
- .icon-tile--round { border-radius: var(--radius-pill); }
1105
- .icon-tile--muted { background: var(--color-surface-2); color: var(--color-text); }
901
+ // src/runtime/header.ts
902
+ var headerJs = `(() => {
903
+ const headers = [...document.querySelectorAll("[data-island=\\"header\\"]")];
904
+ if (!headers.length) return;
1106
905
 
1107
- /* \u2014\u2014 Marks \u2014\u2014 */
1108
- .badge {
1109
- display: inline-flex;
1110
- align-items: center;
1111
- gap: 0.4rem;
1112
- min-height: 1.85rem;
1113
- padding: 0.25rem 0.75rem;
1114
- border-radius: var(--radius-pill);
1115
- font-size: var(--step-0);
1116
- font-weight: 600;
1117
- line-height: 1.2;
1118
- background: var(--color-surface-2);
1119
- color: var(--color-text);
1120
- border: 1px solid transparent;
1121
- white-space: nowrap;
1122
- }
1123
- .badge .icon { width: 1rem; height: 1rem; }
1124
- .badge--accent {
1125
- background: color-mix(in srgb, var(--color-accent) 14%, transparent);
1126
- color: var(--color-accent);
1127
- }
1128
- .badge--muted { color: var(--color-muted); }
1129
- .badge--outline {
1130
- background: transparent;
1131
- border-color: var(--color-border);
1132
- }
1133
- .stat { display: grid; gap: var(--space-1); align-content: start; }
1134
- .stat__value {
1135
- margin: 0;
1136
- font-family: var(--font-display);
1137
- font-size: var(--step-4);
1138
- font-weight: 600;
1139
- letter-spacing: -0.03em;
1140
- font-variant-numeric: tabular-nums;
1141
- line-height: 1.05;
1142
- }
1143
- .stat__label {
1144
- margin: 0;
1145
- color: var(--color-muted);
1146
- font-size: var(--step-0);
1147
- }
1148
- .stat--sm .stat__value { font-size: var(--step-3); }
1149
- .rating {
1150
- display: inline-flex;
1151
- align-items: center;
1152
- gap: 0.15rem;
1153
- color: var(--color-accent);
1154
- letter-spacing: 0.05em;
1155
- line-height: 1;
1156
- }
1157
- .rating .icon { width: 1.05rem; height: 1.05rem; fill: currentColor; stroke: none; }
1158
- .price {
1159
- display: flex;
1160
- align-items: baseline;
1161
- gap: 0.3rem;
1162
- margin: 0;
1163
- }
1164
- .price__amount {
1165
- font-family: var(--font-display);
1166
- font-size: var(--step-4);
1167
- font-weight: 600;
1168
- letter-spacing: -0.03em;
1169
- line-height: 1;
1170
- font-variant-numeric: tabular-nums;
1171
- }
1172
- .price__period { color: var(--color-muted); font-size: var(--step-0); }
1173
- .prose {
1174
- max-width: 65ch;
1175
- }
1176
- .prose > * + * { margin-top: var(--space-4); }
1177
- .list-check,
1178
- .list-plain {
1179
- list-style: none;
1180
- margin: 0;
1181
- padding: 0;
1182
- display: grid;
1183
- gap: var(--space-3);
1184
- }
1185
- .list-check li {
1186
- display: flex;
1187
- align-items: flex-start;
1188
- gap: 0.65rem;
1189
- line-height: 1.5;
1190
- }
1191
- .list-check li > .icon {
1192
- margin-top: 0.2em;
1193
- color: var(--color-accent);
1194
- }
1195
- .table-wrap { overflow-x: auto; }
1196
- .table {
1197
- width: 100%;
1198
- border-collapse: collapse;
1199
- font-variant-numeric: tabular-nums;
1200
- }
1201
- .table th,
1202
- .table td {
1203
- padding: var(--space-3) var(--space-4);
1204
- text-align: left;
1205
- border-bottom: 1px solid var(--color-border);
1206
- vertical-align: top;
1207
- }
1208
- .table th {
1209
- font-size: var(--step-0);
1210
- font-weight: 600;
1211
- letter-spacing: 0.06em;
1212
- text-transform: uppercase;
1213
- color: var(--color-muted);
1214
- }
1215
- .table td:not(:first-child),
1216
- .table th:not(:first-child) { text-align: right; }
1217
- .table--plain th,
1218
- .table--plain td { padding-inline: 0; }
906
+ const onScroll = () => {
907
+ const scrolled = window.scrollY > 8;
908
+ for (const el of headers) el.classList.toggle("is-scrolled", scrolled);
909
+ };
910
+ onScroll();
911
+ window.addEventListener("scroll", onScroll, { passive: true });
1219
912
 
1220
- /* \u2014\u2014 People / proof \u2014\u2014 */
1221
- .avatar {
1222
- width: 2.75rem;
1223
- height: 2.75rem;
1224
- border-radius: var(--radius-pill);
1225
- object-fit: cover;
1226
- background: var(--color-surface-2);
1227
- border: 2px solid var(--color-surface);
1228
- flex-shrink: 0;
1229
- }
1230
- .avatar--sm { width: 2rem; height: 2rem; }
1231
- .avatar--lg { width: 4rem; height: 4rem; }
1232
- .avatar-group {
1233
- display: inline-flex;
1234
- align-items: center;
1235
- }
1236
- .avatar-group .avatar { margin-inline-start: -0.55rem; box-shadow: 0 0 0 2px var(--color-bg); }
1237
- .avatar-group .avatar:first-child { margin-inline-start: 0; }
1238
- /* \u2014\u2014 Chips (radio / checkbox pills) \u2014\u2014 */
1239
- .chips {
1240
- display: flex;
1241
- flex-wrap: wrap;
1242
- gap: var(--space-2);
1243
- margin: 0;
1244
- padding: 0;
1245
- border: 0;
1246
- }
1247
- .chips > legend,
1248
- .chips__label {
1249
- display: block;
1250
- width: 100%;
1251
- margin-bottom: var(--space-2);
1252
- font-size: var(--step-0);
1253
- font-weight: 600;
1254
- color: var(--color-text);
1255
- }
1256
- .chips label { position: relative; display: inline-flex; }
1257
- .chips input {
1258
- position: absolute;
1259
- inset: 0;
1260
- margin: 0;
1261
- opacity: 0;
1262
- cursor: pointer;
1263
- }
1264
- .chips span {
1265
- display: inline-flex;
1266
- align-items: center;
1267
- min-height: 2.25rem;
1268
- padding: 0.35rem 0.9rem;
1269
- border: 1px solid var(--color-border);
1270
- border-radius: var(--radius-pill);
1271
- font-size: var(--step-0);
1272
- font-weight: 500;
1273
- color: var(--color-text);
1274
- background: var(--color-surface);
1275
- transition: background 0.15s ease, border-color 0.15s ease;
1276
- }
1277
- .chips label:hover span { border-color: var(--color-text); }
1278
- .chips input:checked + span {
1279
- background: var(--color-text);
1280
- border-color: var(--color-text);
1281
- color: var(--color-bg);
1282
- }
1283
- .chips input:focus-visible + span { outline: 2px solid var(--color-focus); outline-offset: 2px; }
1284
- .byline {
1285
- display: flex;
1286
- align-items: center;
1287
- gap: var(--space-3);
1288
- font-size: var(--step-0);
1289
- }
1290
- .byline strong { display: block; font-weight: 600; color: var(--color-text); }
1291
- .byline span { color: var(--color-muted); }
1292
- .logo-row {
1293
- display: flex;
1294
- flex-wrap: wrap;
1295
- align-items: center;
1296
- justify-content: center;
1297
- gap: var(--space-5) var(--space-7);
1298
- opacity: 0.65;
1299
- }
1300
- .logo-row img {
1301
- max-height: 1.75rem;
1302
- width: auto;
1303
- filter: grayscale(1);
1304
- }
1305
- .quote {
1306
- margin: 0;
1307
- font-family: var(--font-display);
1308
- font-size: var(--step-2);
1309
- line-height: 1.4;
1310
- letter-spacing: -0.015em;
1311
- text-wrap: pretty;
1312
- }
1313
- .quote--lg { font-size: var(--step-3); line-height: 1.3; letter-spacing: -0.02em; }
1314
- .quote cite,
1315
- .quote footer {
1316
- display: block;
1317
- margin-top: var(--space-4);
1318
- font-style: normal;
1319
- font-family: var(--font-body);
1320
- font-size: var(--step-0);
1321
- letter-spacing: 0;
1322
- color: var(--color-muted);
1323
- }
1324
- .quote--card {
1325
- font-family: var(--font-body);
1326
- font-size: var(--step-1);
1327
- line-height: 1.6;
1328
- letter-spacing: 0;
1329
- }
913
+ for (const root of headers) {
914
+ const toggle = root.querySelector("[data-nav-toggle]");
915
+ const drawer = root.querySelector(".nav-drawer");
916
+ const panel = root.querySelector(".nav-drawer__panel");
917
+ if (!toggle || !drawer || !panel) continue;
1330
918
 
1331
- /* \u2014\u2014 Controls \u2014\u2014 */
1332
- .btn-lg { padding: 0.9rem 1.75rem; min-height: 3rem; font-size: var(--step-1); }
1333
- .btn-sm { padding: 0.45rem 1rem; min-height: 2.25rem; font-size: var(--step-0); }
1334
- .btn-icon {
1335
- width: var(--tap-min);
1336
- height: var(--tap-min);
1337
- padding: 0;
1338
- border-radius: var(--radius-pill);
1339
- }
1340
- .btn-group {
1341
- display: flex;
1342
- flex-wrap: wrap;
1343
- gap: var(--space-3);
1344
- align-items: center;
1345
- }
1346
- .field {
1347
- display: grid;
1348
- gap: var(--space-2);
1349
- }
1350
- .field label {
1351
- font-weight: 600;
1352
- font-size: var(--step-0);
1353
- }
1354
- .field + .field { margin-top: var(--space-4); }
1355
- .form-grid {
1356
- display: grid;
1357
- gap: var(--space-4);
1358
- }
1359
- .form-grid .field + .field { margin-top: 0; }
1360
- @media (min-width: 720px) {
1361
- .form-grid--2 { grid-template-columns: 1fr 1fr; }
1362
- .form-grid .field--full { grid-column: 1 / -1; }
1363
- }
1364
- .input,
1365
- .textarea,
1366
- .select {
1367
- width: 100%;
1368
- min-height: var(--tap-min);
1369
- padding: 0.65rem 0.9rem;
1370
- border: 1px solid var(--color-border);
1371
- border-radius: var(--radius);
1372
- background: var(--color-surface);
1373
- color: var(--color-text);
1374
- font: inherit;
1375
- line-height: 1.4;
1376
- }
1377
- .textarea { min-height: 7rem; resize: vertical; }
1378
- .input:focus-visible,
1379
- .textarea:focus-visible,
1380
- .select:focus-visible {
1381
- outline: none;
1382
- box-shadow: var(--ring);
1383
- border-color: var(--color-focus);
1384
- }
1385
- .input-row {
1386
- display: flex;
1387
- flex-wrap: wrap;
1388
- gap: var(--space-2);
1389
- }
1390
- .input-row .input { flex: 1 1 14rem; }
1391
- .checkbox {
1392
- width: 1.15rem;
1393
- height: 1.15rem;
1394
- accent-color: var(--color-accent);
1395
- }
1396
- .accordion {
1397
- border-top: 1px solid var(--color-border);
1398
- }
1399
- .accordion details {
1400
- border-bottom: 1px solid var(--color-border);
1401
- }
1402
- .accordion summary {
1403
- list-style: none;
1404
- cursor: pointer;
1405
- min-height: var(--tap-min);
1406
- display: flex;
1407
- align-items: center;
1408
- justify-content: space-between;
1409
- gap: var(--space-4);
1410
- padding: var(--space-4) 0;
1411
- font-weight: 600;
1412
- font-size: var(--step-1);
1413
- }
1414
- .accordion summary::-webkit-details-marker { display: none; }
1415
- .accordion summary::after {
1416
- content: "+";
1417
- flex-shrink: 0;
1418
- width: 1.75rem;
1419
- height: 1.75rem;
1420
- display: inline-grid;
1421
- place-items: center;
1422
- border-radius: var(--radius-pill);
1423
- background: var(--color-surface-2);
1424
- font-weight: 500;
1425
- color: var(--color-muted);
1426
- transition: transform 180ms ease;
1427
- }
1428
- .accordion details[open] summary::after { content: "\u2013"; }
1429
- .accordion details > *:not(summary) {
1430
- margin: 0;
1431
- padding-bottom: var(--space-4);
1432
- max-width: 60ch;
1433
- color: var(--color-muted);
1434
- }
1435
- .tabs {
1436
- display: grid;
1437
- gap: var(--space-5);
1438
- }
1439
- .tabs__list {
1440
- display: flex;
1441
- flex-wrap: wrap;
1442
- gap: var(--space-2);
1443
- border-bottom: 1px solid var(--color-border);
1444
- }
1445
- .tabs__list--pill {
1446
- border-bottom: 0;
1447
- gap: var(--space-1);
1448
- padding: var(--space-1);
1449
- background: var(--color-surface-2);
1450
- border-radius: var(--radius-pill);
1451
- width: fit-content;
919
+ const close = () => {
920
+ drawer.classList.remove("is-open");
921
+ toggle.setAttribute("aria-expanded", "false");
922
+ document.body.style.overflow = "";
923
+ };
924
+ const open = () => {
925
+ drawer.classList.add("is-open");
926
+ toggle.setAttribute("aria-expanded", "true");
927
+ document.body.style.overflow = "hidden";
928
+ const focusable = panel.querySelector("a,button,[tabindex]:not([tabindex='-1'])");
929
+ if (focusable instanceof HTMLElement) focusable.focus();
930
+ };
931
+
932
+ toggle.addEventListener("click", () => {
933
+ if (drawer.classList.contains("is-open")) close();
934
+ else open();
935
+ });
936
+ drawer.addEventListener("click", (e) => {
937
+ if (e.target === drawer) close();
938
+ });
939
+ document.addEventListener("keydown", (e) => {
940
+ if (e.key === "Escape") close();
941
+ });
942
+ panel.querySelectorAll("a").forEach((a) => a.addEventListener("click", close));
943
+ }
944
+ })();
945
+ `;
946
+
947
+ // src/runtime/experience.ts
948
+ function experienceArrivalBootstrap(pauseKey = "vitris-experience-paused") {
949
+ return `(()=>{try{if(matchMedia('(prefers-reduced-motion:reduce)').matches||document.documentElement.dataset.motionPolicy==='off'||localStorage.getItem(${JSON.stringify(pauseKey)})==='true')return;const key='vitris-experience-handoff',raw=sessionStorage.getItem(key);sessionStorage.removeItem(key);const handoff=raw?JSON.parse(raw):null;const route=handoff&&handoff.path===location.pathname&&Date.now()-handoff.at<15000;const initial=!sessionStorage.getItem('vitris-experience-arrived');if(!route&&!initial)return;document.documentElement.dataset.experienceArrival=route?'route':'initial';window.VitrisExperienceArrival={mode:route?'route':'initial',title:route?handoff.title:null,timer:setTimeout(()=>{delete document.documentElement.dataset.experienceArrival;delete window.VitrisExperienceArrival;},3500)};}catch{}})();`;
1452
950
  }
1453
- .tabs__tab {
1454
- appearance: none;
1455
- background: transparent;
1456
- border: 0;
1457
- border-bottom: 2px solid transparent;
1458
- margin-bottom: -1px;
1459
- padding: var(--space-3) var(--space-4);
1460
- min-height: var(--tap-min);
1461
- font: inherit;
1462
- font-weight: 600;
1463
- color: var(--color-muted);
1464
- cursor: pointer;
1465
- transition: color 160ms ease;
951
+ var experienceJs = String.raw`(()=>{
952
+ if(window.VitrisExperience)return;
953
+ let cleanup=()=>{};
954
+ const reduce=matchMedia('(prefers-reduced-motion:reduce)'),fine=matchMedia('(hover:hover) and (pointer:fine)');
955
+ const allowed=()=>!reduce.matches&&document.documentElement.dataset.motionPolicy!=='off'&&!document.hidden;
956
+ const clamp=(n,min,max)=>Math.max(min,Math.min(max,n));
957
+ function init(){
958
+ cleanup();const abort=new AbortController(),cancels=[];let raf=0;
959
+ const on=(el,event,fn,options={})=>el?.addEventListener(event,fn,{...options,signal:abort.signal});
960
+ const preview=document.querySelector('[data-experience-preview]'),cursor=document.querySelector('[data-experience-cursor]');
961
+ let active=null,mode='',last=0,target={x:0,y:0},position={x:0,y:0},cursorPosition={x:0,y:0};
962
+ const stop=()=>{active=null;cancelAnimationFrame(raf);raf=0;preview?.setAttribute('data-visible','false');cursor?.setAttribute('data-visible','false');};
963
+ function bounds(x,y){const w=preview?.offsetWidth||310,h=preview?.offsetHeight||230;return {x:clamp(x,w/2+12,innerWidth-w/2-12),y:clamp(y,h/2+12,innerHeight-h/2-12)};}
964
+ function paint(){if(preview)preview.style.transform='translate3d('+(position.x-(preview.offsetWidth/2))+'px,'+(position.y-(preview.offsetHeight/2))+'px,0)';if(cursor)cursor.style.transform='translate3d('+(cursorPosition.x-(cursor.offsetWidth/2))+'px,'+(cursorPosition.y-(cursor.offsetHeight/2))+'px,0)';}
965
+ function follow(t){if(!active||!allowed()){stop();return;}const dt=Math.min(48,t-last||16);last=t;const approach=(v,to,ms)=>v+(to-v)*(1-Math.exp(-dt/ms));position={x:approach(position.x,target.x,190),y:approach(position.y,target.y,190)};cursorPosition={x:approach(cursorPosition.x,target.x,110),y:approach(cursorPosition.y,target.y,110)};paint();if(Math.abs(position.x-target.x)+Math.abs(position.y-target.y)>.15){raf=requestAnimationFrame(follow);}else raf=0;}
966
+ const focusPosition=el=>{const r=el.getBoundingClientRect();return bounds(innerWidth*.72,r.top+r.height/2);};
967
+ function show(el,x,y,input){if(!preview||!fine.matches||!allowed()||innerWidth<=Number(preview.dataset.experienceMinWidth||1024)||el.closest('[data-view="grid"]'))return;active=el;mode=input;target=position=cursorPosition=bounds(x,y);last=0;const image=preview.querySelector('img');if(image){image.src=el.dataset.experienceImage;image.alt='';}const label=cursor?.querySelector('[data-experience-label]')||preview.querySelector('[data-experience-label]');if(label)label.textContent='View '+(el.dataset.experienceName||el.textContent.trim());paint();preview.dataset.visible='true';if(cursor)cursor.dataset.visible='true';}
968
+ document.querySelectorAll('[data-experience-image]').forEach(el=>{
969
+ on(el,'pointerenter',e=>show(el,e.clientX,e.clientY,'pointer'));
970
+ on(el,'pointermove',e=>{if(active!==el)return;target=bounds(e.clientX,e.clientY);if(!raf)raf=requestAnimationFrame(follow);});
971
+ on(el,'pointerleave',()=>{if(document.activeElement!==el)stop();});
972
+ on(el,'focus',()=>{const p=focusPosition(el);show(el,p.x,p.y,'keyboard');});on(el,'blur',stop);on(el,'click',stop);
973
+ });
974
+ on(window,'scroll',()=>{if(active&&mode==='keyboard'){target=position=cursorPosition=focusPosition(active);paint();}else stop();},{passive:true});on(window,'resize',stop);on(document,'visibilitychange',stop);on(reduce,'change',stop);on(fine,'change',stop);
975
+ const magnets=[...document.querySelectorAll('[data-experience-magnetic]')];
976
+ magnets.forEach(el=>{let x=0,y=0;const reset=()=>{x=y=0;el.style.transition=allowed()?'transform 1.2s cubic-bezier(.2,1.5,.5,1)':'none';el.style.transform='';};on(el,'pointermove',e=>{if(!allowed()||!fine.matches)return;const r=el.getBoundingClientRect();x=clamp((e.clientX-r.left-r.width/2+x)*.1,-8,8);y=clamp((e.clientY-r.top-r.height/2+y)*.1,-8,8);el.style.transition='transform .4s';el.style.transform='translate3d('+x+'px,'+y+'px,0)';});on(el,'pointerleave',reset);cancels.push(reset);});
977
+ const drifts=[...document.querySelectorAll('[data-experience-drift]')],tracks=[...document.querySelectorAll('[data-experience-marquee-speed]')];let previousY=scrollY,scrollRaf=0;
978
+ const settleDrift=()=>drifts.forEach(el=>{const trigger=document.getElementById(el.dataset.experienceTrigger)||el.parentElement;const r=trigger.getBoundingClientRect(),factor=Number(el.dataset.experienceDrift||.13),max=Number(el.dataset.experienceDriftMax||40);const value=allowed()&&r.bottom>0&&r.top<innerHeight?(el.dataset.experienceDriftMode==='center'?clamp((r.top-innerHeight*.5)*factor,-max,0):clamp(-r.top*factor,0,max)):0;el.style.transform=value?'translate3d(0,'+value+'px,0)':'';});
979
+ function sizeTracks(){tracks.forEach(el=>{const copy=el.firstElementChild;if(copy)el.style.animationDuration=(copy.getBoundingClientRect().width/Number(el.dataset.experienceMarqueeSpeed||73))+'s';});}
980
+ function scroll(){settleDrift();const delta=scrollY-previousY;if(Math.abs(delta)>2&&allowed())tracks.forEach(el=>{const animation=el.getAnimations()[0];if(!animation)return;const duration=Number(animation.effect.getTiming().duration);if(Number(animation.currentTime)<duration*2)animation.currentTime=Number(animation.currentTime)+duration*100;animation.updatePlaybackRate(delta>=0?1:-1);});previousY=scrollY;scrollRaf=0;}
981
+ on(window,'scroll',()=>{if(!scrollRaf)scrollRaf=requestAnimationFrame(scroll);},{passive:true});on(window,'resize',()=>{sizeTracks();settleDrift();});sizeTracks();document.fonts?.ready.then(()=>{if(!abort.signal.aborted)sizeTracks();});settleDrift();
982
+ const observer=new IntersectionObserver(entries=>entries.forEach(e=>{if(e.isIntersecting){e.target.classList.add('experience-seen');if(e.target.hasAttribute('data-experience-intro')&&allowed())e.target.querySelectorAll('[data-experience-line]').forEach((el,i)=>{const animation=el.animate([{transform:'translateY(24px)',opacity:.75},{transform:'none',opacity:1}],{duration:650,delay:Math.min(i*90,270),easing:'cubic-bezier(.2,1,.3,1)'});cancels.push(()=>animation.cancel());});observer.unobserve(e.target);}}),{threshold:.15});document.querySelectorAll('[data-experience-seam],[data-experience-intro]').forEach(el=>observer.observe(el));
983
+ const curtain=document.querySelector('[data-experience-transition]');let navigating=false;
984
+ const opening=()=>{if(allowed())document.querySelectorAll('[data-experience-opening]').forEach((el,i)=>{const a=el.animate([{transform:'translateY(32px)'},{transform:'translateY(0)'}],{duration:1000,delay:Math.min(i*60,180),easing:'cubic-bezier(.15,1,.2,1)',fill:'backwards'});cancels.push(()=>a.cancel());});};
985
+ const arrival=window.VitrisExperienceArrival;
986
+ if(arrival&&curtain){clearTimeout(arrival.timer);delete window.VitrisExperienceArrival;try{sessionStorage.setItem('vitris-experience-arrived','seen');}catch{}
987
+ if(allowed()){
988
+ const title=document.createElement('span');title.textContent=arrival.title||curtain.dataset.experienceArrival||document.title;curtain.replaceChildren(title);curtain.dataset.state='arrival-hold';curtain.style.visibility='visible';curtain.style.transform='translateY(0)';curtain.style.borderRadius='0';curtain.style.pointerEvents='auto';
989
+ const reveal=()=>{if(abort.signal.aborted)return;if(!allowed()){delete document.documentElement.dataset.experienceArrival;curtain.style.visibility='';curtain.style.transform='';curtain.style.borderRadius='';curtain.style.pointerEvents='';return;}opening();curtain.dataset.state='revealing';const a=curtain.animate([{transform:'translateY(0)',borderRadius:'0'},{transform:'translateY(-115%)',borderRadius:'0 0 50% 50% / 0 0 12% 12%'}],{duration:800,easing:'cubic-bezier(.65,0,.2,1)',fill:'forwards'});cancels.push(()=>a.cancel());a.finished.catch(()=>{}).finally(()=>{delete document.documentElement.dataset.experienceArrival;curtain.style.visibility='';curtain.style.transform='';curtain.style.borderRadius='';curtain.style.pointerEvents='';curtain.dataset.state='idle';a.cancel();});};
990
+ const timer=setTimeout(reveal,arrival.mode==='initial'?420:0);cancels.push(()=>clearTimeout(timer));
991
+ }else delete document.documentElement.dataset.experienceArrival;
992
+ }else opening();
993
+ const arrivalSettled=()=>new Promise(resolve=>{if(!document.documentElement.dataset.experienceArrival){resolve();return;}let timer;const done=()=>{observer.disconnect();clearTimeout(timer);abort.signal.removeEventListener('abort',done);resolve();};const observer=new MutationObserver(()=>{if(!document.documentElement.dataset.experienceArrival)done();});observer.observe(document.documentElement,{attributes:true,attributeFilter:['data-experience-arrival']});timer=setTimeout(done,3500);abort.signal.addEventListener('abort',done,{once:true});});
994
+ on(document,'click',async e=>{const a=e.target.closest('a[href]');if(!curtain||!a||e.defaultPrevented||e.button!==0||e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||a.hasAttribute('download')||a.target&&a.target!=='_self'||!allowed())return;const url=new URL(a.href,location.href);if(url.origin!==location.origin||url.pathname===location.pathname||url.hash||!/^https?:$/.test(url.protocol))return;e.preventDefault();if(navigating)return;navigating=true;await arrivalSettled();if(abort.signal.aborted)return;if(!allowed()){location.assign(url.href);return;}document.dispatchEvent(new Event('vitris:before-navigate'));const label=document.createElement('span');label.textContent=a.dataset.experienceTitle||a.dataset.chapterName||a.textContent.trim().split('\n')[0];label.style.opacity='0';curtain.replaceChildren(label);curtain.dataset.state='covering';curtain.style.visibility='visible';curtain.style.pointerEvents='auto';try{const cover=curtain.animate([{transform:'translateY(115%)',borderRadius:'50% 50% 0 0 / 12% 12% 0 0'},{transform:'translateY(0)',borderRadius:'0'}],{duration:500,easing:'cubic-bezier(.7,0,.9,.4)',fill:'forwards'});cancels.push(()=>cover.cancel());await cover.finished;const title=label.animate([{opacity:0,transform:'translateY(20px)'},{opacity:1,transform:'none'}],{duration:650,fill:'forwards'});cancels.push(()=>title.cancel());await new Promise(resolve=>setTimeout(resolve,430));if(curtain.hasAttribute('data-experience-arrival')&&allowed())try{sessionStorage.setItem('vitris-experience-handoff',JSON.stringify({path:url.pathname,title:label.textContent,at:Date.now()}));}catch{}}catch{}finally{location.assign(url.href);}});
995
+ const settlePolicy=()=>{if(!allowed()){stop();magnets.forEach(el=>{el.style.transition='none';el.style.transform='';});document.querySelectorAll('[data-experience-opening],[data-experience-line]').forEach(el=>el.getAnimations().forEach(a=>a.cancel()));if(curtain){curtain.getAnimations().forEach(a=>a.cancel());delete document.documentElement.dataset.experienceArrival;curtain.style.visibility='';curtain.style.transform='';curtain.style.borderRadius='';curtain.style.pointerEvents='';}}settleDrift();};
996
+ const policy=new MutationObserver(settlePolicy);policy.observe(document.documentElement,{attributes:true,attributeFilter:['data-motion-policy']});on(reduce,'change',settlePolicy);on(fine,'change',()=>{magnets.forEach(el=>{el.style.transition='none';el.style.transform='';});});on(document,'visibilitychange',settlePolicy);
997
+ cleanup=()=>{stop();cancelAnimationFrame(scrollRaf);abort.abort();observer.disconnect();policy.disconnect();cancels.forEach(fn=>fn());drifts.forEach(el=>el.style.transform='');delete document.documentElement.dataset.experienceArrival;if(curtain){curtain.style.visibility='';curtain.style.pointerEvents='';curtain.style.transform='';curtain.style.borderRadius='';}};
998
+ }
999
+ window.VitrisExperience={init,dispose:()=>cleanup()};init();
1000
+ addEventListener('pagehide',()=>cleanup());addEventListener('pageshow',e=>{if(e.persisted)init();});
1001
+ })();`;
1002
+
1003
+ // src/runtime/leads.ts
1004
+ var leadsJs = `(() => {
1005
+ let challengeScript;
1006
+ const loadChallenge = () => {
1007
+ if (window.turnstile) return Promise.resolve(window.turnstile);
1008
+ if (!challengeScript) challengeScript = new Promise((resolve, reject) => {
1009
+ const script = document.createElement('script');
1010
+ script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
1011
+ script.onload = () => window.turnstile ? resolve(window.turnstile) : reject(new Error('challenge_unavailable'));
1012
+ script.onerror = () => { script.remove(); challengeScript = null; reject(new Error('challenge_unavailable')); };
1013
+ document.head.append(script);
1014
+ });
1015
+ return challengeScript;
1016
+ };
1017
+ document.querySelectorAll('form[data-lead-form][data-vitris-enhanced]').forEach(form => {
1018
+ // Named controls can shadow native form properties and methods.
1019
+ const data = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'dataset').get.call(form);
1020
+ const setAttribute = Element.prototype.setAttribute.bind(form);
1021
+ const removeAttribute = Element.prototype.removeAttribute.bind(form);
1022
+ const querySelectorAll = Element.prototype.querySelectorAll.bind(form);
1023
+ if (data.vitrisInitialized) return;
1024
+ data.vitrisInitialized = '1';
1025
+ let submitting = false, key, signature, widget, token = '', challengeResolve, challengeReject, completedSignature;
1026
+ const note = document.createElement('p'); note.className = 'c-lead-status';
1027
+ note.setAttribute('role', 'status'); note.setAttribute('aria-live', 'polite'); note.tabIndex = -1;
1028
+ note.style.display = 'none'; Element.prototype.after.call(form, note);
1029
+ const say = (message, error = false) => {
1030
+ note.style.display = ''; note.setAttribute('role', error ? 'alert' : 'status'); note.textContent = message;
1031
+ if (error) note.focus();
1032
+ };
1033
+ let challengeBox;
1034
+ const challenge = async () => {
1035
+ const api = await loadChallenge();
1036
+ if (challengeBox) challengeBox.style.display = '';
1037
+ if (token) return token;
1038
+ if (!challengeBox) { challengeBox = document.createElement('div'); challengeBox.className = 'vitris-challenge'; challengeBox.setAttribute('aria-label', 'Security verification'); Element.prototype.append.call(form, challengeBox); }
1039
+ return new Promise((resolve, reject) => {
1040
+ challengeResolve = resolve; challengeReject = reject;
1041
+ if (widget !== undefined) api.reset(widget);
1042
+ else widget = api.render(challengeBox, {
1043
+ sitekey: data.vitrisSitekey, action: data.vitrisAction,
1044
+ callback: value => { token = value; challengeResolve?.(value); },
1045
+ 'expired-callback': () => { token = ''; if (submitting) say('Security check expired. Please submit again.', true); challengeReject?.(new Error('challenge_expired')); },
1046
+ 'timeout-callback': () => { token = ''; challengeReject?.(new Error('challenge_expired')); },
1047
+ 'error-callback': () => { token = ''; challengeReject?.(new Error('challenge_unavailable')); }
1048
+ });
1049
+ });
1050
+ };
1051
+ EventTarget.prototype.addEventListener.call(form, 'submit', async event => {
1052
+ if (event.defaultPrevented) return;
1053
+ event.preventDefault(); if (submitting) return;
1054
+ if (!HTMLFormElement.prototype.reportValidity.call(form)) return;
1055
+ const values = new URLSearchParams(new FormData(form));
1056
+ values.delete('cf-turnstile-response'); values.delete('idempotency_key');
1057
+ const current = values.toString();
1058
+ if (current === completedSignature) { say('Your message was already accepted.'); return; }
1059
+ if (!data.vitrisForm || !data.vitrisSitekey) { say('This preview does not send messages. Please use the listed contact details.', true); return; }
1060
+ if (current !== signature) { key = crypto.randomUUID(); signature = current; }
1061
+ submitting = true;
1062
+ const controls = [...querySelectorAll('button[type="submit"], button:not([type]), input[type="submit"], [data-vitrisid="emailSendButton"]')];
1063
+ const prior = controls.map(c => c.disabled);
1064
+ controls.forEach(c => { c.disabled = true; c.setAttribute('aria-disabled', 'true'); }); setAttribute('aria-busy', 'true');
1065
+ let timeout;
1066
+ try {
1067
+ say('Please complete the security check.');
1068
+ const challengeTimeout = new Promise((_, reject) => { timeout = setTimeout(() => reject(new Error('challenge_unavailable')), 120000); });
1069
+ const verified = await Promise.race([challenge(), challengeTimeout]);
1070
+ clearTimeout(timeout);
1071
+ values.set('cf-turnstile-response', verified); values.set('idempotency_key', key);
1072
+ say('Sending your inquiry\u2026');
1073
+ const controller = new AbortController();
1074
+ timeout = setTimeout(() => controller.abort(), Math.max(100, Math.min(30000, Number(data.leadTimeoutMs) || 10000)));
1075
+ const response = await fetch(Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'action').get.call(form), { method:'POST', body:values, headers:{accept:'application/json'}, signal:controller.signal, credentials:'omit' });
1076
+ const result = response.headers.get('content-type')?.includes('application/json') ? await response.json() : null;
1077
+ if (!response.ok || result?.ok !== true) throw new Error(result?.error || 'backend_unavailable');
1078
+ say(result.mode === 'test' ? 'Test message accepted. No customer email will be sent.' : 'Message accepted. Your inquiry has been saved.');
1079
+ completedSignature = current;
1080
+ if (challengeBox) challengeBox.style.display = 'none';
1081
+ } catch (error) {
1082
+ const messages = {
1083
+ challenge_required:'Please complete the security check and try again.',
1084
+ challenge_invalid:'Security check expired or was invalid. Please try again.',
1085
+ challenge_replayed:'Security check was already used. Please try again.',
1086
+ challenge_expired:'Security check expired. Please try again.',
1087
+ challenge_unavailable:'Security check is unavailable. Please try again or use the listed contact details.',
1088
+ rate_limited:'Too many attempts. Please wait ten minutes and try again.',
1089
+ validation_error:'Please check your form fields and try again.',
1090
+ form_disabled:'This form is currently unavailable. Please use the listed contact details.',
1091
+ configuration_unavailable:'This form is currently unavailable. Please use the listed contact details.',
1092
+ idempotency_conflict:'This request changed during a retry. Please edit your message and try again.'
1093
+ };
1094
+ say(error?.name === 'AbortError' ? 'The request timed out. Your message is still here; please try again.' : (messages[error?.message] || 'Acceptance could not be confirmed. Your details are still here; please try again or use the listed contact options.'), true);
1095
+ if (challengeBox) challengeBox.style.display = '';
1096
+ } finally {
1097
+ clearTimeout(timeout); token = ''; challengeResolve = null; challengeReject = null;
1098
+ if (window.turnstile && widget !== undefined) window.turnstile.reset(widget);
1099
+ controls.forEach((c, i) => { c.disabled = prior[i]; c.removeAttribute('aria-disabled'); });
1100
+ removeAttribute('aria-busy'); submitting = false;
1101
+ }
1102
+ });
1103
+ });
1104
+ })();`;
1105
+
1106
+ // src/runtime/lightbox.ts
1107
+ var lightboxJs = `(() => {
1108
+ const roots = [...document.querySelectorAll("[data-island=\\"lightbox\\"]")];
1109
+ for (const root of roots) {
1110
+ const dialog = root.querySelector("dialog");
1111
+ const img = dialog?.querySelector("img");
1112
+ if (!(dialog instanceof HTMLDialogElement) || !(img instanceof HTMLImageElement)) continue;
1113
+
1114
+ root.querySelectorAll("[data-lightbox-src]").forEach((btn) => {
1115
+ btn.addEventListener("click", () => {
1116
+ const src = btn.getAttribute("data-lightbox-src");
1117
+ const alt = btn.getAttribute("data-lightbox-alt") || "";
1118
+ if (!src) return;
1119
+ img.src = src;
1120
+ img.alt = alt;
1121
+ dialog.showModal();
1122
+ });
1123
+ });
1124
+ dialog.addEventListener("click", (e) => {
1125
+ if (e.target === dialog) dialog.close();
1126
+ });
1127
+ dialog.querySelector("[data-lightbox-close]")?.addEventListener("click", () => dialog.close());
1128
+ }
1129
+ })();
1130
+ `;
1131
+
1132
+ // src/runtime/tabs.ts
1133
+ var tabsJs = `(() => {
1134
+ const roots = [...document.querySelectorAll("[data-island=\\"tabs\\"]")];
1135
+ for (const root of roots) {
1136
+ const tabs = [...root.querySelectorAll("[role=\\"tab\\"]")];
1137
+ const panels = [...root.querySelectorAll("[role=\\"tabpanel\\"]")];
1138
+ if (!tabs.length) continue;
1139
+
1140
+ const select = (tab) => {
1141
+ for (const t of tabs) {
1142
+ const on = t === tab;
1143
+ t.setAttribute("aria-selected", on ? "true" : "false");
1144
+ t.tabIndex = on ? 0 : -1;
1145
+ }
1146
+ const id = tab.getAttribute("aria-controls");
1147
+ for (const p of panels) {
1148
+ p.hidden = p.id !== id;
1149
+ }
1150
+ };
1151
+
1152
+ tabs.forEach((tab, i) => {
1153
+ tab.addEventListener("click", () => select(tab));
1154
+ tab.addEventListener("keydown", (e) => {
1155
+ if (!(e instanceof KeyboardEvent)) return;
1156
+ let next = i;
1157
+ if (e.key === "ArrowRight") next = (i + 1) % tabs.length;
1158
+ if (e.key === "ArrowLeft") next = (i - 1 + tabs.length) % tabs.length;
1159
+ if (next !== i) {
1160
+ e.preventDefault();
1161
+ tabs[next].focus();
1162
+ select(tabs[next]);
1163
+ }
1164
+ });
1165
+ });
1166
+ const initial = tabs.find((t) => t.getAttribute("aria-selected") === "true") || tabs[0];
1167
+ select(initial);
1168
+ }
1169
+ })();
1170
+ `;
1171
+
1172
+ // src/compile/primitives.ts
1173
+ var primitivesCss = `
1174
+ /* \u2014\u2014 Layout \u2014\u2014 */
1175
+ .section {
1176
+ padding-block: var(--section-y);
1466
1177
  }
1467
- .tabs__tab:hover { color: var(--color-text); }
1468
- .tabs__tab[aria-selected="true"] {
1178
+ .section--tight { padding-block: var(--space-6); }
1179
+ .section--roomy { padding-block: calc(var(--section-y) + var(--space-5)); }
1180
+ .section--surface { background: var(--color-surface); }
1181
+ .section--muted { background: var(--color-surface-2); }
1182
+ .section--dark,
1183
+ [data-scheme="dark"] {
1184
+ --color-bg: #141210;
1185
+ --color-text: #F7F4EF;
1186
+ --color-muted: #B8B0A4;
1187
+ --color-surface: #1E1B18;
1188
+ --color-surface-2: #2A2622;
1189
+ --color-border: #3A342E;
1190
+ background: var(--color-bg);
1469
1191
  color: var(--color-text);
1470
- border-bottom-color: var(--color-accent);
1471
1192
  }
1472
- .tabs__list--pill .tabs__tab {
1473
- border: 0;
1474
- margin: 0;
1475
- min-height: 2.5rem;
1476
- padding: var(--space-2) var(--space-4);
1477
- border-radius: var(--radius-pill);
1193
+ .section__head {
1194
+ display: grid;
1195
+ gap: var(--space-3);
1196
+ margin-bottom: var(--space-7);
1197
+ max-width: 42rem;
1478
1198
  }
1479
- .tabs__list--pill .tabs__tab[aria-selected="true"] {
1480
- background: var(--color-surface);
1481
- box-shadow: var(--shadow-1);
1482
- }
1483
- .tabs__panel[hidden] { display: none; }
1484
- .announcement {
1485
- display: flex;
1486
- flex-wrap: wrap;
1487
- align-items: center;
1488
- justify-content: center;
1489
- gap: var(--space-2) var(--space-4);
1490
- padding: var(--space-3) var(--space-4);
1491
- background: var(--color-surface-2);
1492
- border-bottom: 1px solid var(--color-border);
1493
- font-size: var(--step-0);
1199
+ .section__head--center {
1200
+ margin-inline: auto;
1494
1201
  text-align: center;
1202
+ justify-items: center;
1495
1203
  }
1496
- .announcement a { font-weight: 600; color: inherit; }
1497
-
1498
- /* \u2014\u2014 Chrome \u2014\u2014 */
1499
- .header--sticky {
1500
- position: sticky;
1501
- top: 0;
1502
- z-index: 50;
1503
- background: color-mix(in srgb, var(--color-bg) 86%, transparent);
1504
- backdrop-filter: blur(var(--blur-header));
1505
- -webkit-backdrop-filter: blur(var(--blur-header));
1506
- border-bottom: 1px solid transparent;
1507
- transition: border-color 180ms ease, background-color 180ms ease;
1204
+ .section__head--row {
1205
+ max-width: none;
1206
+ grid-template-columns: minmax(0, 42rem);
1207
+ align-items: end;
1208
+ justify-content: space-between;
1508
1209
  }
1509
- .header--sticky.is-scrolled {
1510
- border-bottom-color: var(--color-border);
1511
- background: color-mix(in srgb, var(--color-bg) 92%, transparent);
1210
+ @media (min-width: 720px) {
1211
+ .section__head--row { grid-template-columns: minmax(0, 42rem) auto; }
1512
1212
  }
1513
- .nav-links {
1514
- display: flex;
1515
- align-items: center;
1516
- gap: var(--space-1);
1213
+ .section__head--row > .btn-group { justify-self: end; }
1214
+ /* Editorial split head: short label column, heading + lede column. */
1215
+ .section__head--split { max-width: none; }
1216
+ @media (min-width: 720px) {
1217
+ .section__head--split {
1218
+ grid-template-columns: minmax(0, 14rem) minmax(0, 42rem);
1219
+ gap: var(--space-5) var(--space-7);
1220
+ align-items: start;
1221
+ }
1222
+ .section__head--split > .eyebrow { padding-top: 0.45em; }
1223
+ .section__head--split > :not(.eyebrow) { grid-column: 2; }
1517
1224
  }
1518
- .nav-links a {
1519
- display: inline-flex;
1520
- align-items: center;
1521
- min-height: 2.5rem;
1522
- padding: 0 var(--space-3);
1523
- border-radius: var(--radius-pill);
1225
+ .sticky-col { align-self: start; }
1226
+ @media (min-width: 1080px) {
1227
+ .sticky-col { position: sticky; top: calc(var(--header-h, 4rem) + var(--space-5)); }
1228
+ }
1229
+ .section__head .lede,
1230
+ .lede {
1231
+ margin: 0;
1232
+ color: var(--color-muted);
1233
+ font-size: var(--step-1);
1234
+ line-height: 1.55;
1235
+ max-width: 38rem;
1236
+ }
1237
+ .lede--lg { font-size: var(--step-2); line-height: 1.45; }
1238
+ .eyebrow {
1239
+ margin: 0;
1524
1240
  font-size: var(--step-0);
1525
- font-weight: 500;
1241
+ font-weight: 600;
1242
+ letter-spacing: 0.08em;
1243
+ text-transform: uppercase;
1526
1244
  color: var(--color-muted);
1527
- text-decoration: none;
1528
- transition: color 160ms ease, background-color 160ms ease;
1529
1245
  }
1530
- .nav-links a:hover,
1531
- .nav-links a[aria-current="page"] {
1532
- color: var(--color-text);
1533
- background: color-mix(in srgb, var(--color-text) 5%, transparent);
1246
+ .eyebrow--accent { color: var(--color-accent); }
1247
+ .grid {
1248
+ display: grid;
1249
+ gap: var(--gap, var(--space-5));
1534
1250
  }
1535
- .brand {
1536
- display: inline-flex;
1251
+ .grid--2 { grid-template-columns: 1fr; }
1252
+ .grid--3 { grid-template-columns: 1fr; }
1253
+ .grid--4 { grid-template-columns: 1fr; }
1254
+ @media (min-width: 720px) {
1255
+ .grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1256
+ .grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
1257
+ .grid--4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
1258
+ }
1259
+ @media (min-width: 1080px) {
1260
+ .grid--4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
1261
+ }
1262
+ .split {
1263
+ display: grid;
1264
+ gap: var(--space-6);
1537
1265
  align-items: center;
1538
- gap: var(--space-2);
1539
- font-family: var(--font-display);
1540
- font-weight: 700;
1541
- font-size: var(--step-2);
1542
- letter-spacing: -0.02em;
1543
- color: var(--color-text);
1544
- text-decoration: none;
1545
- white-space: nowrap;
1546
1266
  }
1547
- .brand img { height: 2rem; width: auto; }
1548
- .nav-drawer {
1549
- position: fixed;
1550
- inset: 0;
1551
- z-index: 60;
1552
- background: color-mix(in srgb, var(--color-text) 40%, transparent);
1553
- opacity: 0;
1554
- visibility: hidden;
1555
- pointer-events: none;
1556
- transition: opacity 180ms ease, visibility 180ms ease;
1267
+ .split--top { align-items: start; }
1268
+ @media (min-width: 720px) {
1269
+ .split { grid-template-columns: 1fr 1fr; gap: var(--space-7); }
1270
+ .split--reverse > :first-child { order: 2; }
1557
1271
  }
1558
- .nav-drawer.is-open {
1559
- opacity: 1;
1560
- visibility: visible;
1561
- pointer-events: auto;
1272
+ @media (min-width: 1080px) {
1273
+ .split { gap: var(--space-8); }
1562
1274
  }
1563
- .nav-drawer__panel {
1564
- position: absolute;
1565
- inset-block: 0;
1566
- inset-inline-end: 0;
1567
- width: min(20rem, 88vw);
1568
- background: var(--color-surface);
1569
- color: var(--color-text);
1570
- padding: calc(var(--header-h) + var(--space-2)) var(--space-5) var(--space-5);
1571
- box-shadow: var(--shadow-3);
1572
- transform: translateX(100%);
1573
- transition: transform 200ms ease;
1275
+ .bento {
1574
1276
  display: grid;
1575
- align-content: start;
1576
- gap: var(--space-5);
1277
+ gap: var(--space-3);
1278
+ grid-template-columns: repeat(2, minmax(0, 1fr));
1577
1279
  }
1578
- .nav-drawer.is-open .nav-drawer__panel { transform: none; }
1579
- .nav-drawer__panel nav {
1580
- display: grid;
1280
+ .bento__wide, .bento__full { grid-column: span 2; }
1281
+ @media (min-width: 720px) {
1282
+ .bento {
1283
+ gap: var(--space-4);
1284
+ grid-template-columns: repeat(6, minmax(0, 1fr));
1285
+ grid-auto-rows: minmax(9rem, auto);
1286
+ grid-auto-flow: dense;
1287
+ }
1288
+ .bento > * { grid-column: span 3; }
1289
+ .bento__wide { grid-column: span 4; }
1290
+ .bento__tall { grid-row: span 2; }
1291
+ .bento__full { grid-column: span 6; }
1292
+ .bento__narrow { grid-column: span 2; }
1581
1293
  }
1582
- .nav-drawer__panel nav a {
1583
- display: block;
1584
- padding: var(--space-3) 0;
1585
- border-bottom: 1px solid var(--color-border);
1586
- font-weight: 600;
1587
- text-decoration: none;
1588
- color: var(--color-text);
1294
+ .stack { display: grid; gap: var(--space-4); }
1295
+ .stack--tight { gap: var(--space-2); }
1296
+ .stack--loose { gap: var(--space-6); }
1297
+ .row {
1298
+ display: flex;
1299
+ flex-wrap: wrap;
1300
+ align-items: center;
1301
+ gap: var(--space-3);
1589
1302
  }
1590
- .nav-drawer__panel .btn-group > * { flex: 1; }
1303
+ .row--between { justify-content: space-between; }
1591
1304
 
1592
- /* \u2014\u2014 Island widgets \u2014\u2014 */
1593
- .carousel {
1594
- display: grid;
1595
- gap: var(--space-5);
1596
- }
1597
- .carousel__track {
1305
+ /* \u2014\u2014 Surfaces \u2014\u2014 */
1306
+ .card {
1307
+ position: relative;
1598
1308
  display: flex;
1599
- gap: var(--space-4);
1600
- overflow-x: auto;
1601
- scroll-snap-type: x mandatory;
1602
- scroll-behavior: smooth;
1603
- padding-bottom: var(--space-2);
1604
- scrollbar-width: none;
1309
+ flex-direction: column;
1310
+ background: var(--color-surface);
1311
+ border: 1px solid var(--color-border);
1312
+ border-radius: var(--radius-lg);
1313
+ overflow: hidden;
1605
1314
  }
1606
- .carousel__track::-webkit-scrollbar { display: none; }
1607
- .carousel__track > * {
1608
- flex: 0 0 min(100%, 22rem);
1609
- scroll-snap-align: start;
1315
+ .card--bordered { box-shadow: none; }
1316
+ .card--elevated { box-shadow: var(--shadow-2); border-color: transparent; }
1317
+ .card--flat {
1318
+ box-shadow: none;
1319
+ border-color: transparent;
1320
+ background: var(--color-surface-2);
1610
1321
  }
1611
- .carousel__nav {
1612
- display: flex;
1613
- gap: var(--space-2);
1322
+ .card--accent { border-color: var(--color-accent); box-shadow: 0 0 0 1px var(--color-accent); }
1323
+ .card--interactive {
1324
+ transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
1614
1325
  }
1615
- .carousel__nav > button {
1616
- display: inline-grid;
1617
- place-items: center;
1618
- width: 2.75rem;
1619
- height: 2.75rem;
1620
- min-height: 0;
1621
- padding: 0;
1622
- border-radius: var(--radius-pill);
1623
- border: 1px solid var(--color-border);
1624
- background: var(--color-surface);
1625
- color: var(--color-text);
1626
- font: inherit;
1627
- font-size: 1.1rem;
1628
- line-height: 1;
1629
- cursor: pointer;
1630
- transition: border-color 160ms ease, background-color 160ms ease;
1326
+ .card--interactive:hover {
1327
+ transform: translateY(-2px);
1328
+ box-shadow: var(--shadow-2);
1631
1329
  }
1632
- .carousel__nav > button:hover { border-color: var(--color-text); }
1633
- .carousel__nav > button:disabled { opacity: 0.4; cursor: default; }
1634
- .before-after {
1330
+ .card__media {
1635
1331
  position: relative;
1636
1332
  overflow: hidden;
1637
- border-radius: var(--radius-lg);
1638
1333
  background: var(--color-surface-2);
1639
- user-select: none;
1640
- touch-action: none;
1334
+ border-radius: 0;
1641
1335
  }
1642
- .before-after__before,
1643
- .before-after__after {
1644
- display: block;
1336
+ .card__media img,
1337
+ .card__media video {
1645
1338
  width: 100%;
1646
- aspect-ratio: 16 / 10;
1339
+ height: 100%;
1647
1340
  object-fit: cover;
1341
+ transition: transform 400ms ease;
1648
1342
  }
1649
- .before-after__after {
1650
- position: absolute;
1651
- inset: 0;
1652
- clip-path: inset(0 0 0 50%);
1343
+ .card--interactive:hover .card__media img { transform: scale(1.03); }
1344
+ .card__body {
1345
+ display: grid;
1346
+ gap: var(--space-2);
1347
+ padding: var(--space-5);
1348
+ flex: 1;
1349
+ align-content: start;
1653
1350
  }
1654
- .before-after__handle {
1351
+ .card__body > h3,
1352
+ .card__body > h4 {
1353
+ font-size: var(--step-2);
1354
+ line-height: 1.25;
1355
+ }
1356
+ .card__body > p { margin: 0; color: var(--color-muted); font-size: var(--step-1); }
1357
+ .card__body > .btn-group,
1358
+ .card__body > .btn,
1359
+ .card__body > .btn-outline,
1360
+ .card__body > .btn-arrow {
1361
+ margin-top: var(--space-2);
1362
+ justify-self: start;
1363
+ }
1364
+ .card__body > .btn-arrow { align-self: end; margin-top: auto; padding-top: var(--space-3); }
1365
+ /* Photo tile with a bottom scrim and light text (services tiles, project grids, step panels). */
1366
+ .photo-card {
1367
+ position: relative;
1368
+ isolation: isolate;
1369
+ display: flex;
1370
+ flex-direction: column;
1371
+ justify-content: flex-end;
1372
+ overflow: hidden;
1373
+ border-radius: var(--radius-lg);
1374
+ background: var(--color-surface-2);
1375
+ color: #fff;
1376
+ text-decoration: none;
1377
+ }
1378
+ .photo-card > img {
1655
1379
  position: absolute;
1656
- inset-block: 0;
1657
- left: 50%;
1658
- width: 2px;
1659
- background: var(--color-surface);
1660
- transform: translateX(-50%);
1661
- cursor: ew-resize;
1380
+ inset: 0;
1381
+ z-index: -2;
1382
+ width: 100%;
1383
+ height: 100%;
1384
+ object-fit: cover;
1385
+ transition: transform 500ms ease;
1662
1386
  }
1663
- .before-after__handle::after {
1387
+ .photo-card::before {
1664
1388
  content: "";
1665
1389
  position: absolute;
1666
- top: 50%;
1667
- left: 50%;
1668
- width: 2.5rem;
1669
- height: 2.5rem;
1670
- border-radius: var(--radius-pill);
1671
- border: 2px solid var(--color-surface);
1672
- background: color-mix(in srgb, var(--color-text) 70%, transparent);
1390
+ inset: 0;
1391
+ z-index: -1;
1392
+ background: linear-gradient(180deg, rgba(0, 0, 0, 0.05) 30%, rgba(0, 0, 0, 0.72) 100%);
1393
+ }
1394
+ .photo-card__body {
1395
+ display: grid;
1396
+ gap: var(--space-1);
1397
+ padding: var(--space-5);
1398
+ }
1399
+ .photo-card__body h2,
1400
+ .photo-card__body h3,
1401
+ .photo-card__body strong { color: #fff; }
1402
+ .photo-card__body p { margin: 0; color: rgba(255, 255, 255, 0.82); }
1403
+ .photo-card__body .eyebrow { color: rgba(255, 255, 255, 0.72); }
1404
+ a.photo-card:hover > img,
1405
+ a.photo-card:focus-visible > img { transform: scale(1.04); }
1406
+ a.photo-card:focus-visible { outline: 2px solid var(--color-focus); outline-offset: 2px; }
1407
+ .card__footer {
1408
+ margin-top: auto;
1409
+ padding: var(--space-4) var(--space-5);
1410
+ border-top: 1px solid var(--color-border);
1411
+ display: flex;
1412
+ align-items: center;
1413
+ justify-content: space-between;
1414
+ gap: var(--space-3);
1415
+ }
1416
+ .hairline {
1417
+ border: 0;
1418
+ border-top: 1px solid var(--color-border);
1419
+ margin: var(--space-6) 0;
1420
+ }
1421
+ .frame {
1422
+ overflow: hidden;
1423
+ border-radius: var(--radius-lg);
1424
+ background: var(--color-surface-2);
1673
1425
  box-shadow: var(--shadow-2);
1674
- transform: translate(-50%, -50%);
1675
1426
  }
1676
- .before-after__label {
1427
+ .frame > img,
1428
+ .frame > video { width: 100%; height: 100%; object-fit: cover; }
1429
+ .ratio-16x9,
1430
+ .ratio-4x3,
1431
+ .ratio-3x2,
1432
+ .ratio-1x1,
1433
+ .ratio-3x4,
1434
+ .ratio-21x9 {
1435
+ position: relative;
1436
+ overflow: hidden;
1437
+ border-radius: var(--radius-lg);
1438
+ background: var(--color-surface-2);
1439
+ }
1440
+ .ratio-16x9 { aspect-ratio: 16 / 9; }
1441
+ .ratio-4x3 { aspect-ratio: 4 / 3; }
1442
+ .ratio-3x2 { aspect-ratio: 3 / 2; }
1443
+ .ratio-1x1 { aspect-ratio: 1 / 1; }
1444
+ .ratio-3x4 { aspect-ratio: 3 / 4; }
1445
+ .ratio-21x9 { aspect-ratio: 21 / 9; }
1446
+ .card__media[class*="ratio-"] { border-radius: 0; }
1447
+ .ratio-16x9 > img,
1448
+ .ratio-4x3 > img,
1449
+ .ratio-3x2 > img,
1450
+ .ratio-1x1 > img,
1451
+ .ratio-3x4 > img,
1452
+ .ratio-21x9 > img {
1677
1453
  position: absolute;
1678
- top: var(--space-3);
1679
- padding: 0.2rem 0.6rem;
1454
+ inset: 0;
1455
+ width: 100%;
1456
+ height: 100%;
1457
+ object-fit: cover;
1458
+ }
1459
+ .icon-tile {
1460
+ display: inline-flex;
1461
+ align-items: center;
1462
+ justify-content: center;
1463
+ width: 2.75rem;
1464
+ height: 2.75rem;
1465
+ border-radius: var(--radius);
1466
+ background: color-mix(in srgb, var(--color-accent) 12%, transparent);
1467
+ color: var(--color-accent);
1468
+ flex-shrink: 0;
1469
+ }
1470
+ .icon-tile .icon { width: 1.35rem; height: 1.35rem; }
1471
+ .icon-tile--round { border-radius: var(--radius-pill); }
1472
+ .icon-tile--muted { background: var(--color-surface-2); color: var(--color-text); }
1473
+
1474
+ /* \u2014\u2014 Marks \u2014\u2014 */
1475
+ .badge {
1476
+ display: inline-flex;
1477
+ align-items: center;
1478
+ gap: 0.4rem;
1479
+ min-height: 1.85rem;
1480
+ padding: 0.25rem 0.75rem;
1680
1481
  border-radius: var(--radius-pill);
1681
1482
  font-size: var(--step-0);
1682
1483
  font-weight: 600;
1683
- background: color-mix(in srgb, var(--color-bg) 80%, transparent);
1484
+ line-height: 1.2;
1485
+ background: var(--color-surface-2);
1684
1486
  color: var(--color-text);
1685
- pointer-events: none;
1487
+ border: 1px solid transparent;
1488
+ white-space: nowrap;
1686
1489
  }
1687
- .before-after__label--before { left: var(--space-3); }
1688
- .before-after__label--after { right: var(--space-3); }
1689
- .icon {
1690
- width: 1.25rem;
1691
- height: 1.25rem;
1692
- stroke: currentColor;
1693
- fill: none;
1694
- stroke-width: 1.75;
1695
- stroke-linecap: round;
1696
- stroke-linejoin: round;
1697
- flex-shrink: 0;
1490
+ .badge .icon { width: 1rem; height: 1rem; }
1491
+ .badge--accent {
1492
+ background: color-mix(in srgb, var(--color-accent) 14%, transparent);
1493
+ color: var(--color-accent);
1698
1494
  }
1699
- .icon--lg { width: 1.75rem; height: 1.75rem; }
1700
- .icon--sm { width: 1rem; height: 1rem; }
1701
- `;
1702
-
1703
- // src/runtime/before-after.ts
1704
- var beforeAfterJs = `(() => {
1705
- const roots = [...document.querySelectorAll("[data-island=\\"before-after\\"]")];
1706
- for (const root of roots) {
1707
- if (!(root instanceof HTMLElement)) continue;
1708
- const after = root.querySelector(".before-after__after");
1709
- const handle = root.querySelector(".before-after__handle");
1710
- if (!(after instanceof HTMLElement) || !(handle instanceof HTMLElement)) continue;
1711
-
1712
- let dragging = false;
1713
- const setPos = (clientX) => {
1714
- const rect = root.getBoundingClientRect();
1715
- const pct = Math.min(100, Math.max(0, ((clientX - rect.left) / rect.width) * 100));
1716
- after.style.clipPath = \`inset(0 0 0 \${pct}%)\`;
1717
- handle.style.left = \`\${pct}%\`;
1718
- root.setAttribute("aria-valuenow", String(Math.round(pct)));
1719
- };
1720
-
1721
- const onMove = (e) => {
1722
- if (!dragging) return;
1723
- const x = "touches" in e ? e.touches[0].clientX : e.clientX;
1724
- setPos(x);
1725
- };
1726
- const stop = () => { dragging = false; };
1727
-
1728
- root.addEventListener("pointerdown", (e) => {
1729
- dragging = true;
1730
- root.setPointerCapture?.(e.pointerId);
1731
- setPos(e.clientX);
1732
- });
1733
- root.addEventListener("pointermove", onMove);
1734
- root.addEventListener("pointerup", stop);
1735
- root.addEventListener("pointercancel", stop);
1736
- root.addEventListener("keydown", (e) => {
1737
- if (!(e instanceof KeyboardEvent)) return;
1738
- const now = Number(root.getAttribute("aria-valuenow") || "50");
1739
- if (e.key === "ArrowLeft") setPos(root.getBoundingClientRect().left + ((now - 5) / 100) * root.clientWidth);
1740
- if (e.key === "ArrowRight") setPos(root.getBoundingClientRect().left + ((now + 5) / 100) * root.clientWidth);
1741
- });
1742
- root.setAttribute("role", "slider");
1743
- root.setAttribute("aria-valuemin", "0");
1744
- root.setAttribute("aria-valuemax", "100");
1745
- root.setAttribute("aria-valuenow", "50");
1746
- root.tabIndex = 0;
1747
- }
1748
- })();
1749
- `;
1750
-
1751
- // src/runtime/carousel.ts
1752
- var carouselJs = `(() => {
1753
- const roots = [...document.querySelectorAll("[data-island=\\"carousel\\"]")];
1754
- for (const root of roots) {
1755
- const track = root.querySelector(".carousel__track");
1756
- const prev = root.querySelector("[data-carousel-prev]");
1757
- const next = root.querySelector("[data-carousel-next]");
1758
- if (!(track instanceof HTMLElement)) continue;
1759
- const step = () => Math.max(track.clientWidth * 0.85, 240);
1760
- prev?.addEventListener("click", () => track.scrollBy({ left: -step(), behavior: "smooth" }));
1761
- next?.addEventListener("click", () => track.scrollBy({ left: step(), behavior: "smooth" }));
1762
- root.addEventListener("keydown", (e) => {
1763
- if (!(e instanceof KeyboardEvent)) return;
1764
- if (e.key === "ArrowLeft") track.scrollBy({ left: -step(), behavior: "smooth" });
1765
- if (e.key === "ArrowRight") track.scrollBy({ left: step(), behavior: "smooth" });
1766
- });
1767
- }
1768
- })();
1769
- `;
1770
-
1771
- // src/runtime/header.ts
1772
- var headerJs = `(() => {
1773
- const headers = [...document.querySelectorAll("[data-island=\\"header\\"]")];
1774
- if (!headers.length) return;
1775
-
1776
- const onScroll = () => {
1777
- const scrolled = window.scrollY > 8;
1778
- for (const el of headers) el.classList.toggle("is-scrolled", scrolled);
1779
- };
1780
- onScroll();
1781
- window.addEventListener("scroll", onScroll, { passive: true });
1782
-
1783
- for (const root of headers) {
1784
- const toggle = root.querySelector("[data-nav-toggle]");
1785
- const drawer = root.querySelector(".nav-drawer");
1786
- const panel = root.querySelector(".nav-drawer__panel");
1787
- if (!toggle || !drawer || !panel) continue;
1788
-
1789
- const close = () => {
1790
- drawer.classList.remove("is-open");
1791
- toggle.setAttribute("aria-expanded", "false");
1792
- document.body.style.overflow = "";
1793
- };
1794
- const open = () => {
1795
- drawer.classList.add("is-open");
1796
- toggle.setAttribute("aria-expanded", "true");
1797
- document.body.style.overflow = "hidden";
1798
- const focusable = panel.querySelector("a,button,[tabindex]:not([tabindex='-1'])");
1799
- if (focusable instanceof HTMLElement) focusable.focus();
1800
- };
1495
+ .badge--muted { color: var(--color-muted); }
1496
+ .badge--outline {
1497
+ background: transparent;
1498
+ border-color: var(--color-border);
1499
+ }
1500
+ .stat { display: grid; gap: var(--space-1); align-content: start; }
1501
+ .stat__value {
1502
+ margin: 0;
1503
+ font-family: var(--font-display);
1504
+ font-size: var(--step-4);
1505
+ font-weight: 600;
1506
+ letter-spacing: -0.03em;
1507
+ font-variant-numeric: tabular-nums;
1508
+ line-height: 1.05;
1509
+ }
1510
+ .stat__label {
1511
+ margin: 0;
1512
+ color: var(--color-muted);
1513
+ font-size: var(--step-0);
1514
+ }
1515
+ .stat--sm .stat__value { font-size: var(--step-3); }
1516
+ .rating {
1517
+ display: inline-flex;
1518
+ align-items: center;
1519
+ gap: 0.15rem;
1520
+ color: var(--color-accent);
1521
+ letter-spacing: 0.05em;
1522
+ line-height: 1;
1523
+ }
1524
+ .rating .icon { width: 1.05rem; height: 1.05rem; fill: currentColor; stroke: none; }
1525
+ .price {
1526
+ display: flex;
1527
+ align-items: baseline;
1528
+ gap: 0.3rem;
1529
+ margin: 0;
1530
+ }
1531
+ .price__amount {
1532
+ font-family: var(--font-display);
1533
+ font-size: var(--step-4);
1534
+ font-weight: 600;
1535
+ letter-spacing: -0.03em;
1536
+ line-height: 1;
1537
+ font-variant-numeric: tabular-nums;
1538
+ }
1539
+ .price__period { color: var(--color-muted); font-size: var(--step-0); }
1540
+ .prose {
1541
+ max-width: 65ch;
1542
+ }
1543
+ .prose > * + * { margin-top: var(--space-4); }
1544
+ .list-check,
1545
+ .list-plain {
1546
+ list-style: none;
1547
+ margin: 0;
1548
+ padding: 0;
1549
+ display: grid;
1550
+ gap: var(--space-3);
1551
+ }
1552
+ .list-check li {
1553
+ display: flex;
1554
+ align-items: flex-start;
1555
+ gap: 0.65rem;
1556
+ line-height: 1.5;
1557
+ }
1558
+ .list-check li > .icon {
1559
+ margin-top: 0.2em;
1560
+ color: var(--color-accent);
1561
+ }
1562
+ .table-wrap { overflow-x: auto; }
1563
+ .table {
1564
+ width: 100%;
1565
+ border-collapse: collapse;
1566
+ font-variant-numeric: tabular-nums;
1567
+ }
1568
+ .table th,
1569
+ .table td {
1570
+ padding: var(--space-3) var(--space-4);
1571
+ text-align: left;
1572
+ border-bottom: 1px solid var(--color-border);
1573
+ vertical-align: top;
1574
+ }
1575
+ .table th {
1576
+ font-size: var(--step-0);
1577
+ font-weight: 600;
1578
+ letter-spacing: 0.06em;
1579
+ text-transform: uppercase;
1580
+ color: var(--color-muted);
1581
+ }
1582
+ .table td:not(:first-child),
1583
+ .table th:not(:first-child) { text-align: right; }
1584
+ .table--plain th,
1585
+ .table--plain td { padding-inline: 0; }
1801
1586
 
1802
- toggle.addEventListener("click", () => {
1803
- if (drawer.classList.contains("is-open")) close();
1804
- else open();
1805
- });
1806
- drawer.addEventListener("click", (e) => {
1807
- if (e.target === drawer) close();
1808
- });
1809
- document.addEventListener("keydown", (e) => {
1810
- if (e.key === "Escape") close();
1811
- });
1812
- panel.querySelectorAll("a").forEach((a) => a.addEventListener("click", close));
1813
- }
1814
- })();
1815
- `;
1587
+ /* \u2014\u2014 People / proof \u2014\u2014 */
1588
+ .avatar {
1589
+ width: 2.75rem;
1590
+ height: 2.75rem;
1591
+ border-radius: var(--radius-pill);
1592
+ object-fit: cover;
1593
+ background: var(--color-surface-2);
1594
+ border: 2px solid var(--color-surface);
1595
+ flex-shrink: 0;
1596
+ }
1597
+ .avatar--sm { width: 2rem; height: 2rem; }
1598
+ .avatar--lg { width: 4rem; height: 4rem; }
1599
+ .avatar-group {
1600
+ display: inline-flex;
1601
+ align-items: center;
1602
+ }
1603
+ .avatar-group .avatar { margin-inline-start: -0.55rem; box-shadow: 0 0 0 2px var(--color-bg); }
1604
+ .avatar-group .avatar:first-child { margin-inline-start: 0; }
1605
+ /* \u2014\u2014 Chips (radio / checkbox pills) \u2014\u2014 */
1606
+ .chips {
1607
+ display: flex;
1608
+ flex-wrap: wrap;
1609
+ gap: var(--space-2);
1610
+ margin: 0;
1611
+ padding: 0;
1612
+ border: 0;
1613
+ }
1614
+ .chips > legend,
1615
+ .chips__label {
1616
+ display: block;
1617
+ width: 100%;
1618
+ margin-bottom: var(--space-2);
1619
+ font-size: var(--step-0);
1620
+ font-weight: 600;
1621
+ color: var(--color-text);
1622
+ }
1623
+ .chips label { position: relative; display: inline-flex; }
1624
+ .chips input {
1625
+ position: absolute;
1626
+ inset: 0;
1627
+ margin: 0;
1628
+ opacity: 0;
1629
+ cursor: pointer;
1630
+ }
1631
+ .chips span {
1632
+ display: inline-flex;
1633
+ align-items: center;
1634
+ min-height: 2.25rem;
1635
+ padding: 0.35rem 0.9rem;
1636
+ border: 1px solid var(--color-border);
1637
+ border-radius: var(--radius-pill);
1638
+ font-size: var(--step-0);
1639
+ font-weight: 500;
1640
+ color: var(--color-text);
1641
+ background: var(--color-surface);
1642
+ transition: background 0.15s ease, border-color 0.15s ease;
1643
+ }
1644
+ .chips label:hover span { border-color: var(--color-text); }
1645
+ .chips input:checked + span {
1646
+ background: var(--color-text);
1647
+ border-color: var(--color-text);
1648
+ color: var(--color-bg);
1649
+ }
1650
+ .chips input:focus-visible + span { outline: 2px solid var(--color-focus); outline-offset: 2px; }
1651
+ .byline {
1652
+ display: flex;
1653
+ align-items: center;
1654
+ gap: var(--space-3);
1655
+ font-size: var(--step-0);
1656
+ }
1657
+ .byline strong { display: block; font-weight: 600; color: var(--color-text); }
1658
+ .byline span { color: var(--color-muted); }
1659
+ .logo-row {
1660
+ display: flex;
1661
+ flex-wrap: wrap;
1662
+ align-items: center;
1663
+ justify-content: center;
1664
+ gap: var(--space-5) var(--space-7);
1665
+ opacity: 0.65;
1666
+ }
1667
+ .logo-row img {
1668
+ max-height: 1.75rem;
1669
+ width: auto;
1670
+ filter: grayscale(1);
1671
+ }
1672
+ .quote {
1673
+ margin: 0;
1674
+ font-family: var(--font-display);
1675
+ font-size: var(--step-2);
1676
+ line-height: 1.4;
1677
+ letter-spacing: -0.015em;
1678
+ text-wrap: pretty;
1679
+ }
1680
+ .quote--lg { font-size: var(--step-3); line-height: 1.3; letter-spacing: -0.02em; }
1681
+ .quote cite,
1682
+ .quote footer {
1683
+ display: block;
1684
+ margin-top: var(--space-4);
1685
+ font-style: normal;
1686
+ font-family: var(--font-body);
1687
+ font-size: var(--step-0);
1688
+ letter-spacing: 0;
1689
+ color: var(--color-muted);
1690
+ }
1691
+ .quote--card {
1692
+ font-family: var(--font-body);
1693
+ font-size: var(--step-1);
1694
+ line-height: 1.6;
1695
+ letter-spacing: 0;
1696
+ }
1816
1697
 
1817
- // src/runtime/experience.ts
1818
- function experienceArrivalBootstrap(pauseKey = "vitris-experience-paused") {
1819
- return `(()=>{try{if(matchMedia('(prefers-reduced-motion:reduce)').matches||document.documentElement.dataset.motionPolicy==='off'||localStorage.getItem(${JSON.stringify(pauseKey)})==='true')return;const key='vitris-experience-handoff',raw=sessionStorage.getItem(key);sessionStorage.removeItem(key);const handoff=raw?JSON.parse(raw):null;const route=handoff&&handoff.path===location.pathname&&Date.now()-handoff.at<15000;const initial=!sessionStorage.getItem('vitris-experience-arrived');if(!route&&!initial)return;document.documentElement.dataset.experienceArrival=route?'route':'initial';window.VitrisExperienceArrival={mode:route?'route':'initial',title:route?handoff.title:null,timer:setTimeout(()=>{delete document.documentElement.dataset.experienceArrival;delete window.VitrisExperienceArrival;},3500)};}catch{}})();`;
1698
+ /* \u2014\u2014 Controls \u2014\u2014 */
1699
+ .btn-lg { padding: 0.9rem 1.75rem; min-height: 3rem; font-size: var(--step-1); }
1700
+ .btn-sm { padding: 0.45rem 1rem; min-height: 2.25rem; font-size: var(--step-0); }
1701
+ .btn-icon {
1702
+ width: var(--tap-min);
1703
+ height: var(--tap-min);
1704
+ padding: 0;
1705
+ border-radius: var(--radius-pill);
1820
1706
  }
1821
- var experienceJs = String.raw`(()=>{
1822
- if(window.VitrisExperience)return;
1823
- let cleanup=()=>{};
1824
- const reduce=matchMedia('(prefers-reduced-motion:reduce)'),fine=matchMedia('(hover:hover) and (pointer:fine)');
1825
- const allowed=()=>!reduce.matches&&document.documentElement.dataset.motionPolicy!=='off'&&!document.hidden;
1826
- const clamp=(n,min,max)=>Math.max(min,Math.min(max,n));
1827
- function init(){
1828
- cleanup();const abort=new AbortController(),cancels=[];let raf=0;
1829
- const on=(el,event,fn,options={})=>el?.addEventListener(event,fn,{...options,signal:abort.signal});
1830
- const preview=document.querySelector('[data-experience-preview]'),cursor=document.querySelector('[data-experience-cursor]');
1831
- let active=null,mode='',last=0,target={x:0,y:0},position={x:0,y:0},cursorPosition={x:0,y:0};
1832
- const stop=()=>{active=null;cancelAnimationFrame(raf);raf=0;preview?.setAttribute('data-visible','false');cursor?.setAttribute('data-visible','false');};
1833
- function bounds(x,y){const w=preview?.offsetWidth||310,h=preview?.offsetHeight||230;return {x:clamp(x,w/2+12,innerWidth-w/2-12),y:clamp(y,h/2+12,innerHeight-h/2-12)};}
1834
- function paint(){if(preview)preview.style.transform='translate3d('+(position.x-(preview.offsetWidth/2))+'px,'+(position.y-(preview.offsetHeight/2))+'px,0)';if(cursor)cursor.style.transform='translate3d('+(cursorPosition.x-(cursor.offsetWidth/2))+'px,'+(cursorPosition.y-(cursor.offsetHeight/2))+'px,0)';}
1835
- function follow(t){if(!active||!allowed()){stop();return;}const dt=Math.min(48,t-last||16);last=t;const approach=(v,to,ms)=>v+(to-v)*(1-Math.exp(-dt/ms));position={x:approach(position.x,target.x,190),y:approach(position.y,target.y,190)};cursorPosition={x:approach(cursorPosition.x,target.x,110),y:approach(cursorPosition.y,target.y,110)};paint();if(Math.abs(position.x-target.x)+Math.abs(position.y-target.y)>.15){raf=requestAnimationFrame(follow);}else raf=0;}
1836
- const focusPosition=el=>{const r=el.getBoundingClientRect();return bounds(innerWidth*.72,r.top+r.height/2);};
1837
- function show(el,x,y,input){if(!preview||!fine.matches||!allowed()||innerWidth<=Number(preview.dataset.experienceMinWidth||1024)||el.closest('[data-view="grid"]'))return;active=el;mode=input;target=position=cursorPosition=bounds(x,y);last=0;const image=preview.querySelector('img');if(image){image.src=el.dataset.experienceImage;image.alt='';}const label=cursor?.querySelector('[data-experience-label]')||preview.querySelector('[data-experience-label]');if(label)label.textContent='View '+(el.dataset.experienceName||el.textContent.trim());paint();preview.dataset.visible='true';if(cursor)cursor.dataset.visible='true';}
1838
- document.querySelectorAll('[data-experience-image]').forEach(el=>{
1839
- on(el,'pointerenter',e=>show(el,e.clientX,e.clientY,'pointer'));
1840
- on(el,'pointermove',e=>{if(active!==el)return;target=bounds(e.clientX,e.clientY);if(!raf)raf=requestAnimationFrame(follow);});
1841
- on(el,'pointerleave',()=>{if(document.activeElement!==el)stop();});
1842
- on(el,'focus',()=>{const p=focusPosition(el);show(el,p.x,p.y,'keyboard');});on(el,'blur',stop);on(el,'click',stop);
1843
- });
1844
- on(window,'scroll',()=>{if(active&&mode==='keyboard'){target=position=cursorPosition=focusPosition(active);paint();}else stop();},{passive:true});on(window,'resize',stop);on(document,'visibilitychange',stop);on(reduce,'change',stop);on(fine,'change',stop);
1845
- const magnets=[...document.querySelectorAll('[data-experience-magnetic]')];
1846
- magnets.forEach(el=>{let x=0,y=0;const reset=()=>{x=y=0;el.style.transition=allowed()?'transform 1.2s cubic-bezier(.2,1.5,.5,1)':'none';el.style.transform='';};on(el,'pointermove',e=>{if(!allowed()||!fine.matches)return;const r=el.getBoundingClientRect();x=clamp((e.clientX-r.left-r.width/2+x)*.1,-8,8);y=clamp((e.clientY-r.top-r.height/2+y)*.1,-8,8);el.style.transition='transform .4s';el.style.transform='translate3d('+x+'px,'+y+'px,0)';});on(el,'pointerleave',reset);cancels.push(reset);});
1847
- const drifts=[...document.querySelectorAll('[data-experience-drift]')],tracks=[...document.querySelectorAll('[data-experience-marquee-speed]')];let previousY=scrollY,scrollRaf=0;
1848
- const settleDrift=()=>drifts.forEach(el=>{const trigger=document.getElementById(el.dataset.experienceTrigger)||el.parentElement;const r=trigger.getBoundingClientRect(),factor=Number(el.dataset.experienceDrift||.13),max=Number(el.dataset.experienceDriftMax||40);const value=allowed()&&r.bottom>0&&r.top<innerHeight?(el.dataset.experienceDriftMode==='center'?clamp((r.top-innerHeight*.5)*factor,-max,0):clamp(-r.top*factor,0,max)):0;el.style.transform=value?'translate3d(0,'+value+'px,0)':'';});
1849
- function sizeTracks(){tracks.forEach(el=>{const copy=el.firstElementChild;if(copy)el.style.animationDuration=(copy.getBoundingClientRect().width/Number(el.dataset.experienceMarqueeSpeed||73))+'s';});}
1850
- function scroll(){settleDrift();const delta=scrollY-previousY;if(Math.abs(delta)>2&&allowed())tracks.forEach(el=>{const animation=el.getAnimations()[0];if(!animation)return;const duration=Number(animation.effect.getTiming().duration);if(Number(animation.currentTime)<duration*2)animation.currentTime=Number(animation.currentTime)+duration*100;animation.updatePlaybackRate(delta>=0?1:-1);});previousY=scrollY;scrollRaf=0;}
1851
- on(window,'scroll',()=>{if(!scrollRaf)scrollRaf=requestAnimationFrame(scroll);},{passive:true});on(window,'resize',()=>{sizeTracks();settleDrift();});sizeTracks();document.fonts?.ready.then(()=>{if(!abort.signal.aborted)sizeTracks();});settleDrift();
1852
- const observer=new IntersectionObserver(entries=>entries.forEach(e=>{if(e.isIntersecting){e.target.classList.add('experience-seen');if(e.target.hasAttribute('data-experience-intro')&&allowed())e.target.querySelectorAll('[data-experience-line]').forEach((el,i)=>{const animation=el.animate([{transform:'translateY(24px)',opacity:.75},{transform:'none',opacity:1}],{duration:650,delay:Math.min(i*90,270),easing:'cubic-bezier(.2,1,.3,1)'});cancels.push(()=>animation.cancel());});observer.unobserve(e.target);}}),{threshold:.15});document.querySelectorAll('[data-experience-seam],[data-experience-intro]').forEach(el=>observer.observe(el));
1853
- const curtain=document.querySelector('[data-experience-transition]');let navigating=false;
1854
- const opening=()=>{if(allowed())document.querySelectorAll('[data-experience-opening]').forEach((el,i)=>{const a=el.animate([{transform:'translateY(32px)'},{transform:'translateY(0)'}],{duration:1000,delay:Math.min(i*60,180),easing:'cubic-bezier(.15,1,.2,1)',fill:'backwards'});cancels.push(()=>a.cancel());});};
1855
- const arrival=window.VitrisExperienceArrival;
1856
- if(arrival&&curtain){clearTimeout(arrival.timer);delete window.VitrisExperienceArrival;try{sessionStorage.setItem('vitris-experience-arrived','seen');}catch{}
1857
- if(allowed()){
1858
- const title=document.createElement('span');title.textContent=arrival.title||curtain.dataset.experienceArrival||document.title;curtain.replaceChildren(title);curtain.dataset.state='arrival-hold';curtain.style.visibility='visible';curtain.style.transform='translateY(0)';curtain.style.borderRadius='0';curtain.style.pointerEvents='auto';
1859
- const reveal=()=>{if(abort.signal.aborted)return;if(!allowed()){delete document.documentElement.dataset.experienceArrival;curtain.style.visibility='';curtain.style.transform='';curtain.style.borderRadius='';curtain.style.pointerEvents='';return;}opening();curtain.dataset.state='revealing';const a=curtain.animate([{transform:'translateY(0)',borderRadius:'0'},{transform:'translateY(-115%)',borderRadius:'0 0 50% 50% / 0 0 12% 12%'}],{duration:800,easing:'cubic-bezier(.65,0,.2,1)',fill:'forwards'});cancels.push(()=>a.cancel());a.finished.catch(()=>{}).finally(()=>{delete document.documentElement.dataset.experienceArrival;curtain.style.visibility='';curtain.style.transform='';curtain.style.borderRadius='';curtain.style.pointerEvents='';curtain.dataset.state='idle';a.cancel();});};
1860
- const timer=setTimeout(reveal,arrival.mode==='initial'?420:0);cancels.push(()=>clearTimeout(timer));
1861
- }else delete document.documentElement.dataset.experienceArrival;
1862
- }else opening();
1863
- const arrivalSettled=()=>new Promise(resolve=>{if(!document.documentElement.dataset.experienceArrival){resolve();return;}let timer;const done=()=>{observer.disconnect();clearTimeout(timer);abort.signal.removeEventListener('abort',done);resolve();};const observer=new MutationObserver(()=>{if(!document.documentElement.dataset.experienceArrival)done();});observer.observe(document.documentElement,{attributes:true,attributeFilter:['data-experience-arrival']});timer=setTimeout(done,3500);abort.signal.addEventListener('abort',done,{once:true});});
1864
- on(document,'click',async e=>{const a=e.target.closest('a[href]');if(!curtain||!a||e.defaultPrevented||e.button!==0||e.ctrlKey||e.metaKey||e.shiftKey||e.altKey||a.hasAttribute('download')||a.target&&a.target!=='_self'||!allowed())return;const url=new URL(a.href,location.href);if(url.origin!==location.origin||url.pathname===location.pathname||url.hash||!/^https?:$/.test(url.protocol))return;e.preventDefault();if(navigating)return;navigating=true;await arrivalSettled();if(abort.signal.aborted)return;if(!allowed()){location.assign(url.href);return;}document.dispatchEvent(new Event('vitris:before-navigate'));const label=document.createElement('span');label.textContent=a.dataset.experienceTitle||a.dataset.chapterName||a.textContent.trim().split('\n')[0];label.style.opacity='0';curtain.replaceChildren(label);curtain.dataset.state='covering';curtain.style.visibility='visible';curtain.style.pointerEvents='auto';try{const cover=curtain.animate([{transform:'translateY(115%)',borderRadius:'50% 50% 0 0 / 12% 12% 0 0'},{transform:'translateY(0)',borderRadius:'0'}],{duration:500,easing:'cubic-bezier(.7,0,.9,.4)',fill:'forwards'});cancels.push(()=>cover.cancel());await cover.finished;const title=label.animate([{opacity:0,transform:'translateY(20px)'},{opacity:1,transform:'none'}],{duration:650,fill:'forwards'});cancels.push(()=>title.cancel());await new Promise(resolve=>setTimeout(resolve,430));if(curtain.hasAttribute('data-experience-arrival')&&allowed())try{sessionStorage.setItem('vitris-experience-handoff',JSON.stringify({path:url.pathname,title:label.textContent,at:Date.now()}));}catch{}}catch{}finally{location.assign(url.href);}});
1865
- const settlePolicy=()=>{if(!allowed()){stop();magnets.forEach(el=>{el.style.transition='none';el.style.transform='';});document.querySelectorAll('[data-experience-opening],[data-experience-line]').forEach(el=>el.getAnimations().forEach(a=>a.cancel()));if(curtain){curtain.getAnimations().forEach(a=>a.cancel());delete document.documentElement.dataset.experienceArrival;curtain.style.visibility='';curtain.style.transform='';curtain.style.borderRadius='';curtain.style.pointerEvents='';}}settleDrift();};
1866
- const policy=new MutationObserver(settlePolicy);policy.observe(document.documentElement,{attributes:true,attributeFilter:['data-motion-policy']});on(reduce,'change',settlePolicy);on(fine,'change',()=>{magnets.forEach(el=>{el.style.transition='none';el.style.transform='';});});on(document,'visibilitychange',settlePolicy);
1867
- cleanup=()=>{stop();cancelAnimationFrame(scrollRaf);abort.abort();observer.disconnect();policy.disconnect();cancels.forEach(fn=>fn());drifts.forEach(el=>el.style.transform='');delete document.documentElement.dataset.experienceArrival;if(curtain){curtain.style.visibility='';curtain.style.pointerEvents='';curtain.style.transform='';curtain.style.borderRadius='';}};
1868
- }
1869
- window.VitrisExperience={init,dispose:()=>cleanup()};init();
1870
- addEventListener('pagehide',()=>cleanup());addEventListener('pageshow',e=>{if(e.persisted)init();});
1871
- })();`;
1872
-
1873
- // src/runtime/leads.ts
1874
- var leadsJs = `(() => {
1875
- let challengeScript;
1876
- const loadChallenge = () => {
1877
- if (window.turnstile) return Promise.resolve(window.turnstile);
1878
- if (!challengeScript) challengeScript = new Promise((resolve, reject) => {
1879
- const script = document.createElement('script');
1880
- script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
1881
- script.onload = () => window.turnstile ? resolve(window.turnstile) : reject(new Error('challenge_unavailable'));
1882
- script.onerror = () => { script.remove(); challengeScript = null; reject(new Error('challenge_unavailable')); };
1883
- document.head.append(script);
1884
- });
1885
- return challengeScript;
1886
- };
1887
- document.querySelectorAll('form[data-lead-form][data-vitris-enhanced]').forEach(form => {
1888
- // Named controls can shadow native form properties and methods.
1889
- const data = Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'dataset').get.call(form);
1890
- const setAttribute = Element.prototype.setAttribute.bind(form);
1891
- const removeAttribute = Element.prototype.removeAttribute.bind(form);
1892
- const querySelectorAll = Element.prototype.querySelectorAll.bind(form);
1893
- if (data.vitrisInitialized) return;
1894
- data.vitrisInitialized = '1';
1895
- let submitting = false, key, signature, widget, token = '', challengeResolve, challengeReject, completedSignature;
1896
- const note = document.createElement('p'); note.className = 'c-lead-status';
1897
- note.setAttribute('role', 'status'); note.setAttribute('aria-live', 'polite'); note.tabIndex = -1;
1898
- note.style.display = 'none'; Element.prototype.after.call(form, note);
1899
- const say = (message, error = false) => {
1900
- note.style.display = ''; note.setAttribute('role', error ? 'alert' : 'status'); note.textContent = message;
1901
- if (error) note.focus();
1902
- };
1903
- let challengeBox;
1904
- const challenge = async () => {
1905
- const api = await loadChallenge();
1906
- if (challengeBox) challengeBox.style.display = '';
1907
- if (token) return token;
1908
- if (!challengeBox) { challengeBox = document.createElement('div'); challengeBox.className = 'vitris-challenge'; challengeBox.setAttribute('aria-label', 'Security verification'); Element.prototype.append.call(form, challengeBox); }
1909
- return new Promise((resolve, reject) => {
1910
- challengeResolve = resolve; challengeReject = reject;
1911
- if (widget !== undefined) api.reset(widget);
1912
- else widget = api.render(challengeBox, {
1913
- sitekey: data.vitrisSitekey, action: data.vitrisAction,
1914
- callback: value => { token = value; challengeResolve?.(value); },
1915
- 'expired-callback': () => { token = ''; if (submitting) say('Security check expired. Please submit again.', true); challengeReject?.(new Error('challenge_expired')); },
1916
- 'timeout-callback': () => { token = ''; challengeReject?.(new Error('challenge_expired')); },
1917
- 'error-callback': () => { token = ''; challengeReject?.(new Error('challenge_unavailable')); }
1918
- });
1919
- });
1920
- };
1921
- EventTarget.prototype.addEventListener.call(form, 'submit', async event => {
1922
- if (event.defaultPrevented) return;
1923
- event.preventDefault(); if (submitting) return;
1924
- if (!HTMLFormElement.prototype.reportValidity.call(form)) return;
1925
- const values = new URLSearchParams(new FormData(form));
1926
- values.delete('cf-turnstile-response'); values.delete('idempotency_key');
1927
- const current = values.toString();
1928
- if (current === completedSignature) { say('Your message was already accepted.'); return; }
1929
- if (!data.vitrisForm || !data.vitrisSitekey) { say('This preview does not send messages. Please use the listed contact details.', true); return; }
1930
- if (current !== signature) { key = crypto.randomUUID(); signature = current; }
1931
- submitting = true;
1932
- const controls = [...querySelectorAll('button[type="submit"], button:not([type]), input[type="submit"], [data-vitrisid="emailSendButton"]')];
1933
- const prior = controls.map(c => c.disabled);
1934
- controls.forEach(c => { c.disabled = true; c.setAttribute('aria-disabled', 'true'); }); setAttribute('aria-busy', 'true');
1935
- let timeout;
1936
- try {
1937
- say('Please complete the security check.');
1938
- const challengeTimeout = new Promise((_, reject) => { timeout = setTimeout(() => reject(new Error('challenge_unavailable')), 120000); });
1939
- const verified = await Promise.race([challenge(), challengeTimeout]);
1940
- clearTimeout(timeout);
1941
- values.set('cf-turnstile-response', verified); values.set('idempotency_key', key);
1942
- say('Sending your inquiry\u2026');
1943
- const controller = new AbortController();
1944
- timeout = setTimeout(() => controller.abort(), Math.max(100, Math.min(30000, Number(data.leadTimeoutMs) || 10000)));
1945
- const response = await fetch(Object.getOwnPropertyDescriptor(HTMLFormElement.prototype, 'action').get.call(form), { method:'POST', body:values, headers:{accept:'application/json'}, signal:controller.signal, credentials:'omit' });
1946
- const result = response.headers.get('content-type')?.includes('application/json') ? await response.json() : null;
1947
- if (!response.ok || result?.ok !== true) throw new Error(result?.error || 'backend_unavailable');
1948
- say(result.mode === 'test' ? 'Test message accepted. No customer email will be sent.' : 'Message accepted. Your inquiry has been saved.');
1949
- completedSignature = current;
1950
- if (challengeBox) challengeBox.style.display = 'none';
1951
- } catch (error) {
1952
- const messages = {
1953
- challenge_required:'Please complete the security check and try again.',
1954
- challenge_invalid:'Security check expired or was invalid. Please try again.',
1955
- challenge_replayed:'Security check was already used. Please try again.',
1956
- challenge_expired:'Security check expired. Please try again.',
1957
- challenge_unavailable:'Security check is unavailable. Please try again or use the listed contact details.',
1958
- rate_limited:'Too many attempts. Please wait ten minutes and try again.',
1959
- validation_error:'Please check your form fields and try again.',
1960
- form_disabled:'This form is currently unavailable. Please use the listed contact details.',
1961
- configuration_unavailable:'This form is currently unavailable. Please use the listed contact details.',
1962
- idempotency_conflict:'This request changed during a retry. Please edit your message and try again.'
1963
- };
1964
- say(error?.name === 'AbortError' ? 'The request timed out. Your message is still here; please try again.' : (messages[error?.message] || 'Acceptance could not be confirmed. Your details are still here; please try again or use the listed contact options.'), true);
1965
- if (challengeBox) challengeBox.style.display = '';
1966
- } finally {
1967
- clearTimeout(timeout); token = ''; challengeResolve = null; challengeReject = null;
1968
- if (window.turnstile && widget !== undefined) window.turnstile.reset(widget);
1969
- controls.forEach((c, i) => { c.disabled = prior[i]; c.removeAttribute('aria-disabled'); });
1970
- removeAttribute('aria-busy'); submitting = false;
1971
- }
1972
- });
1973
- });
1974
- })();`;
1975
-
1976
- // src/runtime/lightbox.ts
1977
- var lightboxJs = `(() => {
1978
- const roots = [...document.querySelectorAll("[data-island=\\"lightbox\\"]")];
1979
- for (const root of roots) {
1980
- const dialog = root.querySelector("dialog");
1981
- const img = dialog?.querySelector("img");
1982
- if (!(dialog instanceof HTMLDialogElement) || !(img instanceof HTMLImageElement)) continue;
1983
-
1984
- root.querySelectorAll("[data-lightbox-src]").forEach((btn) => {
1985
- btn.addEventListener("click", () => {
1986
- const src = btn.getAttribute("data-lightbox-src");
1987
- const alt = btn.getAttribute("data-lightbox-alt") || "";
1988
- if (!src) return;
1989
- img.src = src;
1990
- img.alt = alt;
1991
- dialog.showModal();
1992
- });
1993
- });
1994
- dialog.addEventListener("click", (e) => {
1995
- if (e.target === dialog) dialog.close();
1996
- });
1997
- dialog.querySelector("[data-lightbox-close]")?.addEventListener("click", () => dialog.close());
1998
- }
1999
- })();
2000
- `;
2001
-
2002
- // src/runtime/tabs.ts
2003
- var tabsJs = `(() => {
2004
- const roots = [...document.querySelectorAll("[data-island=\\"tabs\\"]")];
2005
- for (const root of roots) {
2006
- const tabs = [...root.querySelectorAll("[role=\\"tab\\"]")];
2007
- const panels = [...root.querySelectorAll("[role=\\"tabpanel\\"]")];
2008
- if (!tabs.length) continue;
1707
+ .btn-group {
1708
+ display: flex;
1709
+ flex-wrap: wrap;
1710
+ gap: var(--space-3);
1711
+ align-items: center;
1712
+ }
1713
+ .field {
1714
+ display: grid;
1715
+ gap: var(--space-2);
1716
+ }
1717
+ .field label {
1718
+ font-weight: 600;
1719
+ font-size: var(--step-0);
1720
+ }
1721
+ .field + .field { margin-top: var(--space-4); }
1722
+ .form-grid {
1723
+ display: grid;
1724
+ gap: var(--space-4);
1725
+ }
1726
+ .form-grid .field + .field { margin-top: 0; }
1727
+ @media (min-width: 720px) {
1728
+ .form-grid--2 { grid-template-columns: 1fr 1fr; }
1729
+ .form-grid .field--full { grid-column: 1 / -1; }
1730
+ }
1731
+ .input,
1732
+ .textarea,
1733
+ .select {
1734
+ width: 100%;
1735
+ min-height: var(--tap-min);
1736
+ padding: 0.65rem 0.9rem;
1737
+ border: 1px solid var(--color-border);
1738
+ border-radius: var(--radius);
1739
+ background: var(--color-surface);
1740
+ color: var(--color-text);
1741
+ font: inherit;
1742
+ line-height: 1.4;
1743
+ }
1744
+ .textarea { min-height: 7rem; resize: vertical; }
1745
+ .input:focus-visible,
1746
+ .textarea:focus-visible,
1747
+ .select:focus-visible {
1748
+ outline: none;
1749
+ box-shadow: var(--ring);
1750
+ border-color: var(--color-focus);
1751
+ }
1752
+ .input-row {
1753
+ display: flex;
1754
+ flex-wrap: wrap;
1755
+ gap: var(--space-2);
1756
+ }
1757
+ .input-row .input { flex: 1 1 14rem; }
1758
+ .checkbox {
1759
+ width: 1.15rem;
1760
+ height: 1.15rem;
1761
+ accent-color: var(--color-accent);
1762
+ }
1763
+ .accordion {
1764
+ border-top: 1px solid var(--color-border);
1765
+ }
1766
+ .accordion details {
1767
+ border-bottom: 1px solid var(--color-border);
1768
+ }
1769
+ .accordion summary {
1770
+ list-style: none;
1771
+ cursor: pointer;
1772
+ min-height: var(--tap-min);
1773
+ display: flex;
1774
+ align-items: center;
1775
+ justify-content: space-between;
1776
+ gap: var(--space-4);
1777
+ padding: var(--space-4) 0;
1778
+ font-weight: 600;
1779
+ font-size: var(--step-1);
1780
+ }
1781
+ .accordion summary::-webkit-details-marker { display: none; }
1782
+ .accordion summary::after {
1783
+ content: "+";
1784
+ flex-shrink: 0;
1785
+ width: 1.75rem;
1786
+ height: 1.75rem;
1787
+ display: inline-grid;
1788
+ place-items: center;
1789
+ border-radius: var(--radius-pill);
1790
+ background: var(--color-surface-2);
1791
+ font-weight: 500;
1792
+ color: var(--color-muted);
1793
+ transition: transform 180ms ease;
1794
+ }
1795
+ .accordion details[open] summary::after { content: "\u2013"; }
1796
+ .accordion details > *:not(summary) {
1797
+ margin: 0;
1798
+ padding-bottom: var(--space-4);
1799
+ max-width: 60ch;
1800
+ color: var(--color-muted);
1801
+ }
1802
+ .tabs {
1803
+ display: grid;
1804
+ gap: var(--space-5);
1805
+ }
1806
+ .tabs__list {
1807
+ display: flex;
1808
+ flex-wrap: wrap;
1809
+ gap: var(--space-2);
1810
+ border-bottom: 1px solid var(--color-border);
1811
+ }
1812
+ .tabs__list--pill {
1813
+ border-bottom: 0;
1814
+ gap: var(--space-1);
1815
+ padding: var(--space-1);
1816
+ background: var(--color-surface-2);
1817
+ border-radius: var(--radius-pill);
1818
+ width: fit-content;
1819
+ }
1820
+ .tabs__tab {
1821
+ appearance: none;
1822
+ background: transparent;
1823
+ border: 0;
1824
+ border-bottom: 2px solid transparent;
1825
+ margin-bottom: -1px;
1826
+ padding: var(--space-3) var(--space-4);
1827
+ min-height: var(--tap-min);
1828
+ font: inherit;
1829
+ font-weight: 600;
1830
+ color: var(--color-muted);
1831
+ cursor: pointer;
1832
+ transition: color 160ms ease;
1833
+ }
1834
+ .tabs__tab:hover { color: var(--color-text); }
1835
+ .tabs__tab[aria-selected="true"] {
1836
+ color: var(--color-text);
1837
+ border-bottom-color: var(--color-accent);
1838
+ }
1839
+ .tabs__list--pill .tabs__tab {
1840
+ border: 0;
1841
+ margin: 0;
1842
+ min-height: 2.5rem;
1843
+ padding: var(--space-2) var(--space-4);
1844
+ border-radius: var(--radius-pill);
1845
+ }
1846
+ .tabs__list--pill .tabs__tab[aria-selected="true"] {
1847
+ background: var(--color-surface);
1848
+ box-shadow: var(--shadow-1);
1849
+ }
1850
+ .tabs__panel[hidden] { display: none; }
1851
+ .announcement {
1852
+ display: flex;
1853
+ flex-wrap: wrap;
1854
+ align-items: center;
1855
+ justify-content: center;
1856
+ gap: var(--space-2) var(--space-4);
1857
+ padding: var(--space-3) var(--space-4);
1858
+ background: var(--color-surface-2);
1859
+ border-bottom: 1px solid var(--color-border);
1860
+ font-size: var(--step-0);
1861
+ text-align: center;
1862
+ }
1863
+ .announcement a { font-weight: 600; color: inherit; }
2009
1864
 
2010
- const select = (tab) => {
2011
- for (const t of tabs) {
2012
- const on = t === tab;
2013
- t.setAttribute("aria-selected", on ? "true" : "false");
2014
- t.tabIndex = on ? 0 : -1;
2015
- }
2016
- const id = tab.getAttribute("aria-controls");
2017
- for (const p of panels) {
2018
- p.hidden = p.id !== id;
2019
- }
2020
- };
1865
+ /* \u2014\u2014 Chrome \u2014\u2014 */
1866
+ .header--sticky {
1867
+ position: sticky;
1868
+ top: 0;
1869
+ z-index: 50;
1870
+ background: color-mix(in srgb, var(--color-bg) 86%, transparent);
1871
+ backdrop-filter: blur(var(--blur-header));
1872
+ -webkit-backdrop-filter: blur(var(--blur-header));
1873
+ border-bottom: 1px solid transparent;
1874
+ transition: border-color 180ms ease, background-color 180ms ease;
1875
+ }
1876
+ .header--sticky.is-scrolled {
1877
+ border-bottom-color: var(--color-border);
1878
+ background: color-mix(in srgb, var(--color-bg) 92%, transparent);
1879
+ }
1880
+ .nav-links {
1881
+ display: flex;
1882
+ align-items: center;
1883
+ gap: var(--space-1);
1884
+ }
1885
+ .nav-links a {
1886
+ display: inline-flex;
1887
+ align-items: center;
1888
+ min-height: 2.5rem;
1889
+ padding: 0 var(--space-3);
1890
+ border-radius: var(--radius-pill);
1891
+ font-size: var(--step-0);
1892
+ font-weight: 500;
1893
+ color: var(--color-muted);
1894
+ text-decoration: none;
1895
+ transition: color 160ms ease, background-color 160ms ease;
1896
+ }
1897
+ .nav-links a:hover,
1898
+ .nav-links a[aria-current="page"] {
1899
+ color: var(--color-text);
1900
+ background: color-mix(in srgb, var(--color-text) 5%, transparent);
1901
+ }
1902
+ .brand {
1903
+ display: inline-flex;
1904
+ align-items: center;
1905
+ gap: var(--space-2);
1906
+ font-family: var(--font-display);
1907
+ font-weight: 700;
1908
+ font-size: var(--step-2);
1909
+ letter-spacing: -0.02em;
1910
+ color: var(--color-text);
1911
+ text-decoration: none;
1912
+ white-space: nowrap;
1913
+ }
1914
+ .brand img { height: 2rem; width: auto; }
1915
+ .nav-drawer {
1916
+ position: fixed;
1917
+ inset: 0;
1918
+ z-index: 60;
1919
+ background: color-mix(in srgb, var(--color-text) 40%, transparent);
1920
+ opacity: 0;
1921
+ visibility: hidden;
1922
+ pointer-events: none;
1923
+ transition: opacity 180ms ease, visibility 180ms ease;
1924
+ }
1925
+ .nav-drawer.is-open {
1926
+ opacity: 1;
1927
+ visibility: visible;
1928
+ pointer-events: auto;
1929
+ }
1930
+ .nav-drawer__panel {
1931
+ position: absolute;
1932
+ inset-block: 0;
1933
+ inset-inline-end: 0;
1934
+ width: min(20rem, 88vw);
1935
+ background: var(--color-surface);
1936
+ color: var(--color-text);
1937
+ padding: calc(var(--header-h) + var(--space-2)) var(--space-5) var(--space-5);
1938
+ box-shadow: var(--shadow-3);
1939
+ transform: translateX(100%);
1940
+ transition: transform 200ms ease;
1941
+ display: grid;
1942
+ align-content: start;
1943
+ gap: var(--space-5);
1944
+ }
1945
+ .nav-drawer.is-open .nav-drawer__panel { transform: none; }
1946
+ .nav-drawer__panel nav {
1947
+ display: grid;
1948
+ }
1949
+ .nav-drawer__panel nav a {
1950
+ display: block;
1951
+ padding: var(--space-3) 0;
1952
+ border-bottom: 1px solid var(--color-border);
1953
+ font-weight: 600;
1954
+ text-decoration: none;
1955
+ color: var(--color-text);
1956
+ }
1957
+ .nav-drawer__panel .btn-group > * { flex: 1; }
2021
1958
 
2022
- tabs.forEach((tab, i) => {
2023
- tab.addEventListener("click", () => select(tab));
2024
- tab.addEventListener("keydown", (e) => {
2025
- if (!(e instanceof KeyboardEvent)) return;
2026
- let next = i;
2027
- if (e.key === "ArrowRight") next = (i + 1) % tabs.length;
2028
- if (e.key === "ArrowLeft") next = (i - 1 + tabs.length) % tabs.length;
2029
- if (next !== i) {
2030
- e.preventDefault();
2031
- tabs[next].focus();
2032
- select(tabs[next]);
2033
- }
2034
- });
2035
- });
2036
- const initial = tabs.find((t) => t.getAttribute("aria-selected") === "true") || tabs[0];
2037
- select(initial);
2038
- }
2039
- })();
1959
+ /* \u2014\u2014 Island widgets \u2014\u2014 */
1960
+ .carousel {
1961
+ display: grid;
1962
+ gap: var(--space-5);
1963
+ }
1964
+ .carousel__track {
1965
+ display: flex;
1966
+ gap: var(--space-4);
1967
+ overflow-x: auto;
1968
+ scroll-snap-type: x mandatory;
1969
+ scroll-behavior: smooth;
1970
+ padding-bottom: var(--space-2);
1971
+ scrollbar-width: none;
1972
+ }
1973
+ .carousel__track::-webkit-scrollbar { display: none; }
1974
+ .carousel__track > * {
1975
+ flex: 0 0 min(100%, 22rem);
1976
+ scroll-snap-align: start;
1977
+ }
1978
+ .carousel__nav {
1979
+ display: flex;
1980
+ gap: var(--space-2);
1981
+ }
1982
+ .carousel__nav > button {
1983
+ display: inline-grid;
1984
+ place-items: center;
1985
+ width: 2.75rem;
1986
+ height: 2.75rem;
1987
+ min-height: 0;
1988
+ padding: 0;
1989
+ border-radius: var(--radius-pill);
1990
+ border: 1px solid var(--color-border);
1991
+ background: var(--color-surface);
1992
+ color: var(--color-text);
1993
+ font: inherit;
1994
+ font-size: 1.1rem;
1995
+ line-height: 1;
1996
+ cursor: pointer;
1997
+ transition: border-color 160ms ease, background-color 160ms ease;
1998
+ }
1999
+ .carousel__nav > button:hover { border-color: var(--color-text); }
2000
+ .carousel__nav > button:disabled { opacity: 0.4; cursor: default; }
2001
+ .before-after {
2002
+ position: relative;
2003
+ overflow: hidden;
2004
+ border-radius: var(--radius-lg);
2005
+ background: var(--color-surface-2);
2006
+ user-select: none;
2007
+ touch-action: none;
2008
+ }
2009
+ .before-after__before,
2010
+ .before-after__after {
2011
+ display: block;
2012
+ width: 100%;
2013
+ aspect-ratio: 16 / 10;
2014
+ object-fit: cover;
2015
+ }
2016
+ .before-after__after {
2017
+ position: absolute;
2018
+ inset: 0;
2019
+ clip-path: inset(0 0 0 50%);
2020
+ }
2021
+ .before-after__handle {
2022
+ position: absolute;
2023
+ inset-block: 0;
2024
+ left: 50%;
2025
+ width: 2px;
2026
+ background: var(--color-surface);
2027
+ transform: translateX(-50%);
2028
+ cursor: ew-resize;
2029
+ }
2030
+ .before-after__handle::after {
2031
+ content: "";
2032
+ position: absolute;
2033
+ top: 50%;
2034
+ left: 50%;
2035
+ width: 2.5rem;
2036
+ height: 2.5rem;
2037
+ border-radius: var(--radius-pill);
2038
+ border: 2px solid var(--color-surface);
2039
+ background: color-mix(in srgb, var(--color-text) 70%, transparent);
2040
+ box-shadow: var(--shadow-2);
2041
+ transform: translate(-50%, -50%);
2042
+ }
2043
+ .before-after__label {
2044
+ position: absolute;
2045
+ top: var(--space-3);
2046
+ padding: 0.2rem 0.6rem;
2047
+ border-radius: var(--radius-pill);
2048
+ font-size: var(--step-0);
2049
+ font-weight: 600;
2050
+ background: color-mix(in srgb, var(--color-bg) 80%, transparent);
2051
+ color: var(--color-text);
2052
+ pointer-events: none;
2053
+ }
2054
+ .before-after__label--before { left: var(--space-3); }
2055
+ .before-after__label--after { right: var(--space-3); }
2056
+ .icon {
2057
+ width: 1.25rem;
2058
+ height: 1.25rem;
2059
+ stroke: currentColor;
2060
+ fill: none;
2061
+ stroke-width: 1.75;
2062
+ stroke-linecap: round;
2063
+ stroke-linejoin: round;
2064
+ flex-shrink: 0;
2065
+ }
2066
+ .icon--lg { width: 1.75rem; height: 1.75rem; }
2067
+ .icon--sm { width: 1rem; height: 1rem; }
2040
2068
  `;
2041
2069
 
2042
2070
  // src/compile/scroll-motion.ts
@@ -2724,6 +2752,7 @@ function compileAllPages(site, pages, catalog, kernelOrigin) {
2724
2752
  }
2725
2753
 
2726
2754
  export {
2755
+ parseFrontmatter,
2727
2756
  fileToPath,
2728
2757
  defaultTitleFromPath,
2729
2758
  beaconJs,
@@ -2736,7 +2765,6 @@ export {
2736
2765
  flattenBody,
2737
2766
  wrapMain,
2738
2767
  rewriteLeadForms,
2739
- primitivesCss,
2740
2768
  MOTION_EFFECTS,
2741
2769
  baseCss,
2742
2770
  compilePage,