@tokenoftrust/storefront-runner 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (337) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +40 -0
  3. package/apps/storefront/.dev.vars.example +41 -0
  4. package/apps/storefront/.env.example +24 -0
  5. package/apps/storefront/astro.config.mjs +245 -0
  6. package/apps/storefront/env.d.ts +155 -0
  7. package/apps/storefront/lib/ensure-preview-reconcile-secret.sh +31 -0
  8. package/apps/storefront/lib/resolve-cf-token.sh +48 -0
  9. package/apps/storefront/lib/resolve-tot-credentials.sh +69 -0
  10. package/apps/storefront/migrations/0000_baseline.sql +54 -0
  11. package/apps/storefront/migrations/0001_products_fts.sql +9 -0
  12. package/apps/storefront/migrations/README.md +54 -0
  13. package/apps/storefront/migrations/meta/0000_snapshot.json +347 -0
  14. package/apps/storefront/migrations/meta/0001_snapshot.json +347 -0
  15. package/apps/storefront/migrations/meta/_journal.json +20 -0
  16. package/apps/storefront/package.json +41 -0
  17. package/apps/storefront/public/brand/northwind-logo-dark.svg +4 -0
  18. package/apps/storefront/public/brand/northwind-logo-light.svg +4 -0
  19. package/apps/storefront/public/brand/northwind-og.svg +13 -0
  20. package/apps/storefront/public/favicon.svg +5 -0
  21. package/apps/storefront/public/js/dashboard-team.js +147 -0
  22. package/apps/storefront/public/js/dashboard-vendor-search.js +115 -0
  23. package/apps/storefront/src/components/Badge.astro +34 -0
  24. package/apps/storefront/src/components/Breadcrumbs.astro +45 -0
  25. package/apps/storefront/src/components/CollectionCard.astro +56 -0
  26. package/apps/storefront/src/components/EmptyState.astro +35 -0
  27. package/apps/storefront/src/components/Img.astro +68 -0
  28. package/apps/storefront/src/components/ProductCard.astro +228 -0
  29. package/apps/storefront/src/components/Section.astro +39 -0
  30. package/apps/storefront/src/components/Seo.astro +70 -0
  31. package/apps/storefront/src/components/WidgetFrame.astro +34 -0
  32. package/apps/storefront/src/components/auth/AuthBadge.astro +44 -0
  33. package/apps/storefront/src/components/chrome/AnnouncementBar.astro +108 -0
  34. package/apps/storefront/src/components/chrome/MegaMenu.astro +26 -0
  35. package/apps/storefront/src/components/chrome/NavDropdown.astro +116 -0
  36. package/apps/storefront/src/components/chrome/SiteFooter.astro +181 -0
  37. package/apps/storefront/src/components/chrome/SiteHeader.astro +181 -0
  38. package/apps/storefront/src/components/chrome/UtilityNav.astro +79 -0
  39. package/apps/storefront/src/components/commerce/FoxyLoader.astro +23 -0
  40. package/apps/storefront/src/components/commerce/PriceDisplay.astro +91 -0
  41. package/apps/storefront/src/components/commerce/ProductCarousel.astro +197 -0
  42. package/apps/storefront/src/components/commerce/ProductGrid.astro +75 -0
  43. package/apps/storefront/src/components/commerce/RatingStars.astro +58 -0
  44. package/apps/storefront/src/components/compliance/NicotineWarning.astro +33 -0
  45. package/apps/storefront/src/components/home/Hero.astro +164 -0
  46. package/apps/storefront/src/components/islands/AgeGate.tsx +105 -0
  47. package/apps/storefront/src/components/islands/ImageGallery.tsx +237 -0
  48. package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +73 -0
  49. package/apps/storefront/src/components/islands/MobileNav.tsx +239 -0
  50. package/apps/storefront/src/components/islands/QuickView.tsx +138 -0
  51. package/apps/storefront/src/components/islands/RecentlyViewed.tsx +122 -0
  52. package/apps/storefront/src/components/islands/SavedList.tsx +99 -0
  53. package/apps/storefront/src/components/islands/SearchTypeahead.tsx +248 -0
  54. package/apps/storefront/src/components/islands/VariantSelector.tsx +378 -0
  55. package/apps/storefront/src/components/marketing/CardGrid.astro +72 -0
  56. package/apps/storefront/src/components/marketing/CodeSample.astro +20 -0
  57. package/apps/storefront/src/components/marketing/CtaBand.astro +24 -0
  58. package/apps/storefront/src/components/marketing/Faq.astro +37 -0
  59. package/apps/storefront/src/components/marketing/Integrations.astro +63 -0
  60. package/apps/storefront/src/components/marketing/MarketingBlocks.astro +53 -0
  61. package/apps/storefront/src/components/marketing/MarketingCtas.astro +48 -0
  62. package/apps/storefront/src/components/marketing/MarketingHero.astro +72 -0
  63. package/apps/storefront/src/components/marketing/ProofStrip.astro +37 -0
  64. package/apps/storefront/src/components/marketing/SplitCompare.astro +53 -0
  65. package/apps/storefront/src/components/marketing/Steps.astro +36 -0
  66. package/apps/storefront/src/components/marketing/Testimonials.astro +38 -0
  67. package/apps/storefront/src/components/marketing/TrustBar.astro +22 -0
  68. package/apps/storefront/src/components/nav/Footer.astro +148 -0
  69. package/apps/storefront/src/components/nav/Header.astro +190 -0
  70. package/apps/storefront/src/components/plp/ActiveFilters.astro +79 -0
  71. package/apps/storefront/src/components/plp/FacetSidebar.astro +146 -0
  72. package/apps/storefront/src/components/plp/Pagination.astro +99 -0
  73. package/apps/storefront/src/components/plp/SortSelect.astro +64 -0
  74. package/apps/storefront/src/config/devTenants.ts +16 -0
  75. package/apps/storefront/src/config/kvTenantResolver.ts +87 -0
  76. package/apps/storefront/src/config/resolver.ts +46 -0
  77. package/apps/storefront/src/config/tenants.ts +193 -0
  78. package/apps/storefront/src/layouts/Layout.astro +303 -0
  79. package/apps/storefront/src/lib/analytics/index.ts +47 -0
  80. package/apps/storefront/src/lib/auth/brokerAssertion.ts +136 -0
  81. package/apps/storefront/src/lib/auth/devAuth.ts +90 -0
  82. package/apps/storefront/src/lib/auth/gatePage.ts +81 -0
  83. package/apps/storefront/src/lib/auth/identityToken.ts +341 -0
  84. package/apps/storefront/src/lib/auth/loginGate.ts +107 -0
  85. package/apps/storefront/src/lib/auth/route.ts +146 -0
  86. package/apps/storefront/src/lib/auth/session.ts +203 -0
  87. package/apps/storefront/src/lib/auth/totAccessClient.ts +503 -0
  88. package/apps/storefront/src/lib/basePath.ts +41 -0
  89. package/apps/storefront/src/lib/cfImage.ts +55 -0
  90. package/apps/storefront/src/lib/chrome/model.ts +65 -0
  91. package/apps/storefront/src/lib/colors.ts +97 -0
  92. package/apps/storefront/src/lib/content-edit/client.ts +230 -0
  93. package/apps/storefront/src/lib/content-edit/index.ts +14 -0
  94. package/apps/storefront/src/lib/content-edit/route.ts +25 -0
  95. package/apps/storefront/src/lib/content-edit/types.ts +19 -0
  96. package/apps/storefront/src/lib/cspStaticHashes.ts +24 -0
  97. package/apps/storefront/src/lib/d1/catalog.ts +289 -0
  98. package/apps/storefront/src/lib/dashboard/staffAdmission.ts +43 -0
  99. package/apps/storefront/src/lib/dashboard/staffVendorAccess.ts +449 -0
  100. package/apps/storefront/src/lib/dashboard/tenantSelection.ts +136 -0
  101. package/apps/storefront/src/lib/dashboard/vendorQuery.ts +61 -0
  102. package/apps/storefront/src/lib/demoGate.ts +113 -0
  103. package/apps/storefront/src/lib/dev/ai-widget-client.js +127 -0
  104. package/apps/storefront/src/lib/dev/cliSignInCode.ts +132 -0
  105. package/apps/storefront/src/lib/diag/redact.ts +20 -0
  106. package/apps/storefront/src/lib/edgeCache.ts +128 -0
  107. package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +62 -0
  108. package/apps/storefront/src/lib/env.ts +60 -0
  109. package/apps/storefront/src/lib/fixtures/sampleProducts.ts +130 -0
  110. package/apps/storefront/src/lib/format.ts +29 -0
  111. package/apps/storefront/src/lib/foxyCommerce.ts +49 -0
  112. package/apps/storefront/src/lib/imageAttrs.ts +55 -0
  113. package/apps/storefront/src/lib/jsonld.ts +136 -0
  114. package/apps/storefront/src/lib/maintenance.ts +71 -0
  115. package/apps/storefront/src/lib/memoryKv.ts +32 -0
  116. package/apps/storefront/src/lib/messaging/messagesClient.ts +143 -0
  117. package/apps/storefront/src/lib/placeholder.ts +99 -0
  118. package/apps/storefront/src/lib/previewReload.ts +125 -0
  119. package/apps/storefront/src/lib/rawMarketingHtml.ts +133 -0
  120. package/apps/storefront/src/lib/search/index.ts +74 -0
  121. package/apps/storefront/src/lib/sections.ts +129 -0
  122. package/apps/storefront/src/lib/securityHeaders.ts +31 -0
  123. package/apps/storefront/src/lib/storyblok/content-model.ts +289 -0
  124. package/apps/storefront/src/lib/storyblok/provider.ts +524 -0
  125. package/apps/storefront/src/lib/tenantRouting.ts +91 -0
  126. package/apps/storefront/src/lib/tot/ToTClient.ts +177 -0
  127. package/apps/storefront/src/lib/tot/d1Client.ts +62 -0
  128. package/apps/storefront/src/lib/tot/query.ts +187 -0
  129. package/apps/storefront/src/lib/tot/totClientInterface.ts +30 -0
  130. package/apps/storefront/src/lib/url.ts +119 -0
  131. package/apps/storefront/src/lib/wishlist.ts +63 -0
  132. package/apps/storefront/src/middleware/index.ts +413 -0
  133. package/apps/storefront/src/pages/404.astro +61 -0
  134. package/apps/storefront/src/pages/[...slug].astro +90 -0
  135. package/apps/storefront/src/pages/api/auth/logout.ts +21 -0
  136. package/apps/storefront/src/pages/api/auth/magic-exchange.ts +107 -0
  137. package/apps/storefront/src/pages/api/auth/send.ts +85 -0
  138. package/apps/storefront/src/pages/api/auth/verify.ts +135 -0
  139. package/apps/storefront/src/pages/api/cache-purge.ts +44 -0
  140. package/apps/storefront/src/pages/api/content-edit/ai-edit.ts +64 -0
  141. package/apps/storefront/src/pages/api/csp-report.ts +25 -0
  142. package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +124 -0
  143. package/apps/storefront/src/pages/api/dashboard/vendor-search.ts +120 -0
  144. package/apps/storefront/src/pages/api/dev/cli-signin-code.ts +44 -0
  145. package/apps/storefront/src/pages/api/newsletter.ts +104 -0
  146. package/apps/storefront/src/pages/api/request-access.ts +172 -0
  147. package/apps/storefront/src/pages/auth/login.astro +149 -0
  148. package/apps/storefront/src/pages/auth/magic.astro +105 -0
  149. package/apps/storefront/src/pages/capabilities.astro +292 -0
  150. package/apps/storefront/src/pages/collections/[handle].astro +154 -0
  151. package/apps/storefront/src/pages/collections/index.astro +59 -0
  152. package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +100 -0
  153. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +154 -0
  154. package/apps/storefront/src/pages/dashboard/index.astro +160 -0
  155. package/apps/storefront/src/pages/dev.astro +653 -0
  156. package/apps/storefront/src/pages/index.astro +290 -0
  157. package/apps/storefront/src/pages/llms.txt.ts +92 -0
  158. package/apps/storefront/src/pages/products/[handle].astro +443 -0
  159. package/apps/storefront/src/pages/robots.txt.ts +24 -0
  160. package/apps/storefront/src/pages/saved.astro +35 -0
  161. package/apps/storefront/src/pages/search.astro +150 -0
  162. package/apps/storefront/src/pages/sitemap.xml.ts +78 -0
  163. package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +646 -0
  164. package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +85 -0
  165. package/apps/storefront/src/pages/style-guide/index.astro +94 -0
  166. package/apps/storefront/src/pages/tenants/[id]/[...path].ts +57 -0
  167. package/apps/storefront/src/styles/global.css +277 -0
  168. package/apps/storefront/src/themes/reference.ts +61 -0
  169. package/apps/storefront/src/themes/schema.ts +111 -0
  170. package/apps/storefront/src/themes/tenants/index.ts +51 -0
  171. package/apps/storefront/tsconfig.json +16 -0
  172. package/apps/storefront/vitest.config.ts +22 -0
  173. package/apps/storefront/wrangler.toml +175 -0
  174. package/package.json +23 -0
  175. package/packages/public-runtime/LICENSE +58 -0
  176. package/packages/public-runtime/package.json +22 -0
  177. package/packages/public-runtime/src/binary-path.ts +68 -0
  178. package/packages/public-runtime/src/capabilities.ts +89 -0
  179. package/packages/public-runtime/src/catalog-api.ts +81 -0
  180. package/packages/public-runtime/src/catalog-d1.ts +192 -0
  181. package/packages/public-runtime/src/csp.ts +109 -0
  182. package/packages/public-runtime/src/customization-preview.ts +197 -0
  183. package/packages/public-runtime/src/customization-reconcile.ts +63 -0
  184. package/packages/public-runtime/src/customization-runtime.ts +157 -0
  185. package/packages/public-runtime/src/customization-scripts.ts +64 -0
  186. package/packages/public-runtime/src/customization-versioning.ts +95 -0
  187. package/packages/public-runtime/src/foxy.ts +184 -0
  188. package/packages/public-runtime/src/index.ts +30 -0
  189. package/packages/public-runtime/src/product.ts +159 -0
  190. package/packages/public-runtime/src/search.ts +45 -0
  191. package/packages/public-runtime/src/tenant-assets.ts +444 -0
  192. package/packages/public-runtime/src/tenant.ts +243 -0
  193. package/packages/public-runtime/tsconfig.json +8 -0
  194. package/packages/public-runtime/vitest.config.ts +8 -0
  195. package/pnpm-workspace.yaml +7 -0
  196. package/scripts/build/copy-tenant-assets.mjs +69 -0
  197. package/scripts/tot-dev.mjs +439 -0
  198. package/tenants/bigdvapor/content/blog.json +52 -0
  199. package/tenants/bigdvapor/content/chrome.html +149 -0
  200. package/tenants/bigdvapor/content/chrome.json +47 -0
  201. package/tenants/bigdvapor/content/home.html +463 -0
  202. package/tenants/bigdvapor/content/home.json +73 -0
  203. package/tenants/bigdvapor/content/pages/about.json +5 -0
  204. package/tenants/bigdvapor/content/pages/privacy.json +6 -0
  205. package/tenants/bigdvapor/content/pages/shipping-returns.json +6 -0
  206. package/tenants/bigdvapor/content/pages-html/blogs/news.html +86 -0
  207. package/tenants/bigdvapor/content/pages-html/pages/about-us.html +106 -0
  208. package/tenants/bigdvapor/content/pages-html/pages/contact-us.html +61 -0
  209. package/tenants/bigdvapor/content/pages-html/pages/privacy-policy.html +72 -0
  210. package/tenants/bigdvapor/content/pages-html/pages/shipping-returns.html +172 -0
  211. package/tenants/bigdvapor/content/themes/bigd-navy.json +109 -0
  212. package/tenants/bigdvapor/public/img/brands/adjust-vape-disposable.png +0 -0
  213. package/tenants/bigdvapor/public/img/brands/again-vape-disposable.png +0 -0
  214. package/tenants/bigdvapor/public/img/brands/al-fakher-vape-disposable.png +0 -0
  215. package/tenants/bigdvapor/public/img/brands/arro-vape-disposable.png +0 -0
  216. package/tenants/bigdvapor/public/img/brands/cookies-vape-disposable.png +0 -0
  217. package/tenants/bigdvapor/public/img/brands/core-vape-disposable.png +0 -0
  218. package/tenants/bigdvapor/public/img/brands/cyclone-vape-disposable.png +0 -0
  219. package/tenants/bigdvapor/public/img/brands/dinner-lady-vape-disposable.png +0 -0
  220. package/tenants/bigdvapor/public/img/brands/extre-bar-vape-disposable.png +0 -0
  221. package/tenants/bigdvapor/public/img/brands/fifty-bar-vape-disposable.jpg +0 -0
  222. package/tenants/bigdvapor/public/img/brands/firerose-vape-disposable.jpg +0 -0
  223. package/tenants/bigdvapor/public/img/brands/flavor-beast-vape-disposable.jpg +0 -0
  224. package/tenants/bigdvapor/public/img/brands/foger-vape-disposable.png +0 -0
  225. package/tenants/bigdvapor/public/img/brands/kk-energy-vape-disposable.png +0 -0
  226. package/tenants/bigdvapor/public/img/brands/kumi-vape-disposable.png +0 -0
  227. package/tenants/bigdvapor/public/img/brands/lost-vape-dispoable.png +0 -0
  228. package/tenants/bigdvapor/public/img/brands/melo-labs-vape-disposable.png +0 -0
  229. package/tenants/bigdvapor/public/img/brands/mixo-vape-disposable.webp +0 -0
  230. package/tenants/bigdvapor/public/img/brands/one-tank-vape-disposable.jpg +0 -0
  231. package/tenants/bigdvapor/public/img/brands/oxbar-vape-disposable.webp +0 -0
  232. package/tenants/bigdvapor/public/img/brands/pillow-talk-vape-disposable.jpg +0 -0
  233. package/tenants/bigdvapor/public/img/brands/pod-king-vape-disposable.jpg +0 -0
  234. package/tenants/bigdvapor/public/img/brands/raz-vape-disposable.png +0 -0
  235. package/tenants/bigdvapor/public/img/hero-texas.jpg +0 -0
  236. package/tenants/bigdvapor/public/img/og.jpg +0 -0
  237. package/tenants/bigdvapor/public/img/pages/AdobeStock_202106312_web.jpg +0 -0
  238. package/tenants/bigdvapor/public/img/pages/CREW_web.jpg +0 -0
  239. package/tenants/bigdvapor/public/img/pages/Hero-Image.jpg +0 -0
  240. package/tenants/bigdvapor/public/img/tiles/adjust.png +0 -0
  241. package/tenants/bigdvapor/public/img/tiles/again.png +0 -0
  242. package/tenants/bigdvapor/public/img/tiles/al-fakher.png +0 -0
  243. package/tenants/bigdvapor/public/img/tiles/arro.png +0 -0
  244. package/tenants/bigdvapor/public/img/tiles/cookies.png +0 -0
  245. package/tenants/bigdvapor/public/img/tiles/core.png +0 -0
  246. package/tenants/bigdvapor/public/img/tiles/cyclone.png +0 -0
  247. package/tenants/bigdvapor/public/img/tiles/disposables.svg +23 -0
  248. package/tenants/bigdvapor/public/logo-wordmark.png +0 -0
  249. package/tenants/bigdvapor/public/pages/home.css +118 -0
  250. package/tenants/bigdvapor/public/pages/mkt.css +185 -0
  251. package/tenants/bigdvapor/public/pages/page.css +148 -0
  252. package/tenants/bigdvapor/public/themes/bigd-navy.css +73 -0
  253. package/tenants/bigdvapor/theme.json +12 -0
  254. package/tenants/giantvapes/content/chrome.html +152 -0
  255. package/tenants/giantvapes/content/chrome.json +94 -0
  256. package/tenants/giantvapes/content/home.html +194 -0
  257. package/tenants/giantvapes/content/home.json +50 -0
  258. package/tenants/giantvapes/content/pages/about.json +10 -0
  259. package/tenants/giantvapes/content/pages/privacy.json +6 -0
  260. package/tenants/giantvapes/content/pages/shipping-returns.json +6 -0
  261. package/tenants/giantvapes/content/pages-html/blogs/news.html +68 -0
  262. package/tenants/giantvapes/content/pages-html/pages/about-us.html +95 -0
  263. package/tenants/giantvapes/content/pages-html/pages/contact-us.html +68 -0
  264. package/tenants/giantvapes/content/pages-html/pages/privacy-policy.html +65 -0
  265. package/tenants/giantvapes/content/pages-html/pages/shipping-returns.html +77 -0
  266. package/tenants/giantvapes/content/themes/giant-navy.json +73 -0
  267. package/tenants/giantvapes/public/img/hero-suicide-bunny.jpg +0 -0
  268. package/tenants/giantvapes/public/img/hero.webp +0 -0
  269. package/tenants/giantvapes/public/img/og.jpg +0 -0
  270. package/tenants/giantvapes/public/logo-wordmark.png +0 -0
  271. package/tenants/giantvapes/public/pages/home.css +120 -0
  272. package/tenants/giantvapes/public/pages/mkt.css +185 -0
  273. package/tenants/giantvapes/public/pages/page.css +155 -0
  274. package/tenants/giantvapes/public/themes/giant-navy.css +76 -0
  275. package/tenants/giantvapes/theme.json +39 -0
  276. package/tenants/home/content/chrome.json +11 -0
  277. package/tenants/home/content/home.html +304 -0
  278. package/tenants/home/content/home.json +13 -0
  279. package/tenants/home/public/js/storefront.js +210 -0
  280. package/tenants/home/public/logo-wordmark.png +0 -0
  281. package/tenants/home/public/pages/storefront.css +212 -0
  282. package/tenants/home/theme.json +6 -0
  283. package/tenants/tokenoftrust/.tot/config.json +9 -0
  284. package/tenants/tokenoftrust/content/chrome.json +55 -0
  285. package/tenants/tokenoftrust/content/home.html +723 -0
  286. package/tenants/tokenoftrust/content/home.json +233 -0
  287. package/tenants/tokenoftrust/content/pages-html/careers.html +231 -0
  288. package/tenants/tokenoftrust/content/pages-html/company.html +275 -0
  289. package/tenants/tokenoftrust/content/pages-html/contact/contact-sales.html +188 -0
  290. package/tenants/tokenoftrust/content/pages-html/contact/startup-apply.html +206 -0
  291. package/tenants/tokenoftrust/content/pages-html/contact.html +178 -0
  292. package/tenants/tokenoftrust/content/pages-html/industries/adult-content-age-verification.html +286 -0
  293. package/tenants/tokenoftrust/content/pages-html/industries/cannabis.html +277 -0
  294. package/tenants/tokenoftrust/content/pages-html/pact-act-pricing.html +289 -0
  295. package/tenants/tokenoftrust/content/pages-html/pricing.html +483 -0
  296. package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-estimation.html +278 -0
  297. package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-gate.html +279 -0
  298. package/tenants/tokenoftrust/content/pages-html/product/age-assurance/age-verification.html +265 -0
  299. package/tenants/tokenoftrust/content/pages-html/product/age-assurance.html +173 -0
  300. package/tenants/tokenoftrust/content/pages-html/product/compliance/aml.html +214 -0
  301. package/tenants/tokenoftrust/content/pages-html/product/compliance/pact-act.html +226 -0
  302. package/tenants/tokenoftrust/content/pages-html/product/fraud-prevention.html +254 -0
  303. package/tenants/tokenoftrust/content/pages-html/product/social-profile-verification.html +212 -0
  304. package/tenants/tokenoftrust/content/pages-html/product/tax/excise-tax.html +213 -0
  305. package/tenants/tokenoftrust/content/pages-html/product/verification/aml.html +259 -0
  306. package/tenants/tokenoftrust/content/pages-html/product/verification/biometric-selfie.html +305 -0
  307. package/tenants/tokenoftrust/content/pages-html/product/verification/coverage.html +254 -0
  308. package/tenants/tokenoftrust/content/pages-html/product/verification/document-verification.html +306 -0
  309. package/tenants/tokenoftrust/content/pages-html/product/verification/electronic-identity-verification.html +304 -0
  310. package/tenants/tokenoftrust/content/pages-html/product/verification/government-id-verification.html +308 -0
  311. package/tenants/tokenoftrust/content/pages-html/product/verification.html +183 -0
  312. package/tenants/tokenoftrust/content/pages-html/product.html +228 -0
  313. package/tenants/tokenoftrust/content/pages-html/resources/integrations/bigcommerce-integration.html +220 -0
  314. package/tenants/tokenoftrust/content/pages-html/resources/integrations/shopify-integration.html +221 -0
  315. package/tenants/tokenoftrust/content/pages-html/resources/integrations/wordpress.html +220 -0
  316. package/tenants/tokenoftrust/content/pages-html/resources/integrations.html +172 -0
  317. package/tenants/tokenoftrust/content/pages-html/resources/refer-a-friend-program.html +317 -0
  318. package/tenants/tokenoftrust/content/pages-html/resources.html +177 -0
  319. package/tenants/tokenoftrust/content/pages-html/reviews.html +273 -0
  320. package/tenants/tokenoftrust/content/pages-html/solutions.html +292 -0
  321. package/tenants/tokenoftrust/content/pages-html/vlp-alcohol.html +289 -0
  322. package/tenants/tokenoftrust/content/pages-html/vlp-cigars-and-tobacco.html +286 -0
  323. package/tenants/tokenoftrust/content/pages-html/vlp-firearm-accessories.html +267 -0
  324. package/tenants/tokenoftrust/content/pages-html/vlp-peptides.html +273 -0
  325. package/tenants/tokenoftrust/content/themes/tot-navy.json +88 -0
  326. package/tenants/tokenoftrust/public/favicon.png +0 -0
  327. package/tenants/tokenoftrust/public/logo-icon.png +0 -0
  328. package/tenants/tokenoftrust/public/logo-wordmark.png +0 -0
  329. package/tenants/tokenoftrust/public/pages/company.css +108 -0
  330. package/tenants/tokenoftrust/public/pages/home.css +457 -0
  331. package/tenants/tokenoftrust/public/pages/mkt.css +482 -0
  332. package/tenants/tokenoftrust/public/pages/pricing.css +214 -0
  333. package/tenants/tokenoftrust/public/pages/solutions.css +66 -0
  334. package/tenants/tokenoftrust/public/themes/tot-navy-1.0.0.css +136 -0
  335. package/tenants/tokenoftrust/public/themes/tot-navy.css +358 -0
  336. package/tenants/tokenoftrust/theme.json +31 -0
  337. package/tsconfig.base.json +20 -0
@@ -0,0 +1,646 @@
1
+ ---
2
+ /**
3
+ * Preview/dev-only STANDALONE THEME STYLE GUIDE —
4
+ * `/_style-guide/<tenant>/<theme-id>/`.
5
+ *
6
+ * Independently viewable reference for ONE theme: links that theme's stylesheet
7
+ * and renders its tokens (color/type/space/shape) plus live component samples
8
+ * (buttons, eyebrow, proof strip, footer, card) using the theme's real classes.
9
+ * noindex, never in the sitemap, never production marketing publishing. It does
10
+ * NOT reskin the live marketing pages — it only previews the theme in isolation.
11
+ */
12
+ // Commerce + chrome component library preview. global.css brings the Tailwind
13
+ // utilities + reference theme-token fallbacks so the (token-styled) components
14
+ // render here without the app Layout. The `.sg-commerce` wrapper pins the
15
+ // reference palette so they look coherent regardless of the marketing theme CSS.
16
+ import "@/styles/global.css";
17
+ import PriceDisplay from "@/components/commerce/PriceDisplay.astro";
18
+ import RatingStars from "@/components/commerce/RatingStars.astro";
19
+ import Badge from "@/components/Badge.astro";
20
+ import ProductCard from "@/components/ProductCard.astro";
21
+ import ProductCarousel from "@/components/commerce/ProductCarousel.astro";
22
+ import ProductGrid from "@/components/commerce/ProductGrid.astro";
23
+ import AnnouncementBar from "@/components/chrome/AnnouncementBar.astro";
24
+ import UtilityNav from "@/components/chrome/UtilityNav.astro";
25
+ import SiteHeader from "@/components/chrome/SiteHeader.astro";
26
+ import MegaMenu from "@/components/chrome/MegaMenu.astro";
27
+ import SiteFooter from "@/components/chrome/SiteFooter.astro";
28
+ import { sampleProducts, sampleRatings } from "@/lib/fixtures/sampleProducts";
29
+ import type { ChromeNavItem } from "@/lib/chrome/model";
30
+
31
+ const { tenant, theme } = Astro.params;
32
+ const cspNonce = Astro.locals.cspNonce;
33
+
34
+ // --- Sample chrome data (preview-only; no live tenant content) ----------------
35
+ const sampleNav: ChromeNavItem[] = [
36
+ { label: "New", href: "#", flag: true, badge: "NEW" },
37
+ {
38
+ label: "Shop",
39
+ href: "#",
40
+ columns: [
41
+ { title: "Category", links: [{ label: "Disposables", href: "#" }, { label: "E-Liquid", href: "#" }, { label: "Devices", href: "#" }] },
42
+ { title: "Featured", links: [{ label: "Best Sellers", href: "#" }, { label: "On Sale", href: "#", badge: "%" }] },
43
+ { title: "Brands", links: [{ label: "Northwind", href: "#" }, { label: "Summit Co.", href: "#" }] },
44
+ ],
45
+ },
46
+ { label: "Coils & Parts", href: "#", children: [{ label: "Coils", href: "#" }, { label: "Pods", href: "#" }, { label: "Batteries", href: "#" }] },
47
+ { label: "On Sale", href: "#" },
48
+ ];
49
+ const sampleSocial = [
50
+ { label: "X", href: "#", iconPath: "M18.9 2H22l-7.1 8.1L23 22h-6.6l-5-6.6L5.7 22H2.6l7.6-8.7L1.5 2h6.8l4.5 6 5.1-6z" },
51
+ ];
52
+ const sampleFooterCols = [
53
+ { title: "Shop", links: [{ label: "Disposables", href: "#" }, { label: "E-Liquid", href: "#" }, { label: "Devices", href: "#" }] },
54
+ { title: "Support", links: [{ label: "Contact", href: "#" }, { label: "Shipping", href: "#" }, { label: "Returns", href: "#" }] },
55
+ { title: "Company", links: [{ label: "About", href: "#" }, { label: "Blog", href: "#" }] },
56
+ ];
57
+
58
+ // Colocated repo-root layout: from src/pages/style-guide/[tenant]/ the repo
59
+ // root is six levels up.
60
+ const themeModules = import.meta.glob<Record<string, any>>(
61
+ "../../../../../../tenants/*/content/themes/*.json",
62
+ { eager: true, import: "default" },
63
+ );
64
+ const seg = `/tenants/${tenant}/content/themes/`;
65
+ const t = Object.entries(themeModules)
66
+ .filter(([path]) => path.includes(seg))
67
+ .map(([, mod]) => mod)
68
+ .find((m) => m.id === theme);
69
+
70
+ if (!t) return new Response(null, { status: 404 });
71
+
72
+ const tk = t.tokens ?? {};
73
+ const storyboard = t.storyboard ?? null;
74
+
75
+ // Reference component tokens (the "Northwind" pilot identity from
76
+ // src/themes/reference.ts). Used only as the FALLBACK when a theme descriptor
77
+ // declares no preview.componentVars — never to pin the guide to a fixed palette.
78
+ const REFERENCE_COMPONENT_VARS: Record<string, string> = {
79
+ "--color-bg": "#f4f1ea", "--color-surface": "#fcfaf5", "--color-text": "#1c2624",
80
+ "--color-muted": "#5c6663", "--color-primary": "#1f3a34", "--color-primary-contrast": "#f4f1ea",
81
+ "--color-accent": "#b5612f", "--color-border": "#dcd6c9", "--color-success": "#3f6b4f",
82
+ "--color-sale": "#9e3b2e",
83
+ "--radius-sm": "3px", "--radius-md": "6px", "--radius-lg": "12px", "--radius-full": "999px",
84
+ "--shadow-sm": "0 1px 2px rgba(28,38,36,.06)", "--shadow-md": "0 6px 24px -8px rgba(28,38,36,.14)",
85
+ "--shadow-lg": "0 24px 60px -20px rgba(28,38,36,.22)", "--container-max": "1240px",
86
+ };
87
+
88
+ // The reskin mechanism: emit the SELECTED theme's component tokens onto the
89
+ // preview root so the token-styled commerce/chrome components (and the page-
90
+ // section samples) render under THIS theme, not a fixed reference palette.
91
+ // Descriptors override the reference subset via preview.componentVars.
92
+ const componentVars: Record<string, string> = {
93
+ ...REFERENCE_COMPONENT_VARS,
94
+ ...((t.preview?.componentVars ?? {}) as Record<string, string>),
95
+ };
96
+ const componentVarsInline = Object.entries(componentVars)
97
+ .map(([k, v]) => `${k}:${v}`)
98
+ .join(";");
99
+ ---
100
+
101
+ <!doctype html>
102
+ <html lang="en">
103
+ <head>
104
+ <meta charset="utf-8" />
105
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
106
+ <meta name="robots" content="noindex, nofollow" />
107
+ <link rel="icon" type="image/png" href={`/tenants/${tenant}/favicon.png`} />
108
+ <title>{t.name} — style guide (preview)</title>
109
+ {/* The tenant's OWN CSS (external, CSP-clean 'self'): the theme token/base
110
+ layer under review PLUS the shared marketing composition layer (mkt.css).
111
+ Linked for every tenant so the tenant's component classes render in-brand
112
+ and the preview visibly re-skins with the theme. */}
113
+ <link rel="stylesheet" href={t.stylesheet} />
114
+ <link rel="stylesheet" href={`/tenants/${tenant}/pages/mkt.css`} />
115
+ {/* Guide-only chrome; distinct .sg-* names so it never collides with the theme. */}
116
+ <style nonce={cspNonce}>
117
+ .sg-bar { position: sticky; top: 0; z-index: 200; display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; background: #0f1729; color: #e6edf6; padding: 12px 20px; font: 600 .95rem -apple-system, sans-serif; }
118
+ .sg-bar a { color: #bfe0ff; display: inline-flex; align-items: center; min-height: 44px; }
119
+ .sg-bar .flag { font-size: .875rem; letter-spacing: .1em; text-transform: uppercase; background: #f59e0b; color: #221600; font-weight: 800; padding: 4px 8px; border-radius: 5px; }
120
+ .sg-bar .role { font-size: .875rem; text-transform: uppercase; letter-spacing: .08em; background: #0e9f8e; color: #00201b; font-weight: 800; padding: 4px 8px; border-radius: 999px; }
121
+ .sg-bar .status { margin-left: auto; font-family: ui-monospace, Menlo, monospace; font-size: .875rem; color: #cdd8e8; }
122
+ /* Guide-chrome tokens fall back to a neutral palette so the frame renders
123
+ under ANY tenant theme (the linked theme CSS may not define these vars). */
124
+ .sg-h { font: 800 .9rem/1.3 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; color: var(--teal-ink, #0b6360); margin: 0 0 14px; }
125
+ .sg-block { padding: 40px 0; border-top: 1px solid var(--line, #e2e2e2); }
126
+ .sg-swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 14px; }
127
+ .sg-sw { border: 1px solid var(--line, #e2e2e2); border-radius: 12px; overflow: hidden; background: var(--card, #fff); }
128
+ .sg-sw .chip { height: 62px; }
129
+ .sg-sw .meta { padding: 10px 12px; font-size: .9rem; }
130
+ .sg-sw .meta b { display: block; font-size: .95rem; }
131
+ .sg-sw .meta code { color: var(--muted, #5c6663); font-family: ui-monospace, Menlo, monospace; font-size: .875rem; }
132
+ .sg-sw .meta .role { color: var(--muted, #5c6663); display: block; margin-top: 4px; }
133
+ .sg-row { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; }
134
+ .sg-space { display: flex; align-items: flex-end; gap: 14px; flex-wrap: wrap; }
135
+ .sg-space .bar { background: var(--teal-ink, #0b6360); border-radius: 4px 4px 0 0; }
136
+ .sg-space .lab { font-size: .875rem; color: var(--muted, #5c6663); text-align: center; margin-top: 6px; font-family: ui-monospace, Menlo, monospace; }
137
+ .sg-shape { display: flex; gap: 18px; flex-wrap: wrap; }
138
+ .sg-shape .box { width: 120px; height: 84px; background: var(--card, #fff); display: grid; place-items: center; font-size: .875rem; color: var(--muted, #5c6663); }
139
+ .sg-card { max-width: 320px; background: var(--card, #fff); border: 1px solid var(--line, #e2e2e2); border-radius: var(--r, 12px); box-shadow: var(--shadow, 0 8px 24px rgba(0,0,0,.08)); padding: 22px; }
140
+
141
+ /* Storyboard / inspiration header — "the storyboard opens the guide"
142
+ (playbook/site-migration/style-concept.md). Rendered per style concept
143
+ when the descriptor carries t.storyboard. */
144
+ .sg-story { background: #101b30; color: #e6edf6; padding: 24px 20px 28px; }
145
+ .sg-story .inner { max-width: 1080px; margin: 0 auto; }
146
+ .sg-story h2 { font: 800 .78rem/1.2 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; color: #7fe3d4; margin: 0 0 8px; }
147
+ .sg-story p.summary { margin: 0 0 18px; max-width: 76ch; color: #c6d2e4; font-size: .96rem; }
148
+ .sg-story .insp { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: 14px; }
149
+ .sg-story .insp .card { background: #16223c; border: 1px solid #26365a; border-radius: 12px; padding: 14px 16px; }
150
+ .sg-story .insp .role { display: inline-block; font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; font-weight: 800; color: #0a1a12; background: #7fe3d4; padding: 3px 8px; border-radius: 999px; margin-bottom: 8px; }
151
+ .sg-story .insp .slug { font-family: ui-monospace, Menlo, monospace; font-size: .82rem; color: #9fb0c8; margin-bottom: 8px; }
152
+ .sg-story .insp ul { margin: 0; padding-left: 16px; }
153
+ .sg-story .insp li { font-size: .84rem; color: #c6d2e4; margin-bottom: 3px; }
154
+
155
+ /* Page-section samples — a representative slice of the storefront rethemed:
156
+ hero, promo-card row, category tiles. Token-styled (no per-tenant CSS) so
157
+ they re-skin from the emitted component vars. */
158
+ .sg-hero { display: grid; gap: 24px; grid-template-columns: 1.15fr .85fr; align-items: stretch; }
159
+ .sg-hero .copy { background: var(--color-primary); color: var(--color-primary-contrast); border-radius: var(--radius-lg); padding: clamp(24px, 4vw, 44px); display: flex; flex-direction: column; justify-content: center; }
160
+ .sg-hero .copy .kick { font: 800 .72rem/1 -apple-system, sans-serif; letter-spacing: .14em; text-transform: uppercase; opacity: .82; }
161
+ .sg-hero .copy h3 { font-family: var(--font-display); font-size: clamp(1.6rem, 3.4vw, 2.6rem); line-height: 1.08; margin: 12px 0 10px; color: inherit; }
162
+ .sg-hero .copy p { color: inherit; opacity: .9; margin: 0 0 20px; max-width: 40ch; }
163
+ .sg-hero .promo { border-radius: var(--radius-lg); overflow: hidden; background: var(--color-surface); border: 1px solid var(--color-border); display: flex; align-items: flex-end; min-height: 220px; padding: 22px; color: var(--color-text); box-shadow: var(--shadow-md); }
164
+ .sg-btn { display: inline-flex; align-items: center; gap: .5em; align-self: flex-start; min-height: 44px; padding: .7em 1.5em; border-radius: var(--radius-full); font-weight: 700; background: var(--color-accent); color: #fff; border: 2px solid transparent; }
165
+ .sg-btn.ghost { background: transparent; color: inherit; border-color: currentColor; }
166
+ .sg-promos { display: grid; gap: 16px; grid-template-columns: repeat(3, 1fr); }
167
+ .sg-promo { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-lg); padding: 22px; box-shadow: var(--shadow-sm); }
168
+ .sg-promo .tag { display: inline-block; font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; font-weight: 800; color: #fff; background: var(--color-sale); padding: 3px 8px; border-radius: 999px; margin-bottom: 10px; }
169
+ .sg-promo h4 { font-family: var(--font-display); font-size: 1.1rem; margin: 0 0 6px; color: var(--color-text); }
170
+ .sg-promo p { margin: 0; color: var(--color-muted); font-size: .9rem; }
171
+ .sg-tiles { display: grid; gap: 14px; grid-template-columns: repeat(4, 1fr); }
172
+ .sg-tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; min-height: 132px; text-align: center; border-radius: var(--radius-lg); color: #fff; background: linear-gradient(135deg, var(--color-primary), var(--color-primary) 60%, color-mix(in srgb, var(--color-primary) 70%, #000)); padding: 18px; }
173
+ .sg-tile .ico { width: 40px; height: 40px; border-radius: 999px; background: rgba(255,255,255,.16); display: grid; place-items: center; font-size: 1.1rem; }
174
+ .sg-tile span { font-family: var(--font-display); font-weight: 700; font-size: .95rem; }
175
+ @media (max-width: 900px) { .sg-hero { grid-template-columns: 1fr; } .sg-promos { grid-template-columns: 1fr; } .sg-tiles { grid-template-columns: 1fr 1fr; } }
176
+
177
+ /* Commerce + chrome component library scope. The theme's component tokens
178
+ are supplied at runtime via an inline style attr (componentVarsInline)
179
+ from the SELECTED theme descriptor — so the standard components re-skin
180
+ with the theme. Swap the theme, and every sample below re-skins; the
181
+ components never fork. */
182
+ .sg-commerce {
183
+ background: var(--color-bg); color: var(--color-text);
184
+ max-width: 1240px; margin: 40px auto; padding: 0 20px 60px;
185
+ }
186
+ .sg-commerce .sg-h { color: var(--color-primary); }
187
+ .sg-commerce .sg-block { border-top-color: var(--color-border); }
188
+ </style>
189
+ </head>
190
+ <body>
191
+ <header class="sg-bar">
192
+ <span class="flag">Preview</span>
193
+ <span class="role">{t.role}</span>
194
+ <b>{t.name}</b>
195
+ <span class="status">{t.status} · concept {t.concept?.id}@{t.concept?.version}</span>
196
+ <a href={`/_style-guide/${tenant}/`} style="margin-left:auto">← all guides</a>
197
+ </header>
198
+
199
+ {storyboard && (
200
+ <section class="sg-story">
201
+ <div class="inner">
202
+ <h2>Storyboard · where this look comes from</h2>
203
+ {storyboard.summary && <p class="summary">{storyboard.summary}</p>}
204
+ {Array.isArray(storyboard.inspirationPages) && storyboard.inspirationPages.length > 0 && (
205
+ <div class="insp">
206
+ {storyboard.inspirationPages.map((p: any) => (
207
+ <div class="card">
208
+ {p.role && <span class="role">{p.role}</span>}
209
+ {p.slug && <div class="slug">{p.slug}</div>}
210
+ {Array.isArray(p.captures) && (
211
+ <ul>{p.captures.slice(0, 5).map((c: string) => <li>{c}</li>)}</ul>
212
+ )}
213
+ </div>
214
+ ))}
215
+ </div>
216
+ )}
217
+ </div>
218
+ </section>
219
+ )}
220
+
221
+ <main>
222
+ <div class="container">
223
+ <section class="sg-block">
224
+ <p class="sg-h">Color tokens</p>
225
+ <div class="sg-swatches">
226
+ {(tk.color ?? []).map((c: any) => (
227
+ <div class="sg-sw">
228
+ <div class="chip" style={`background:${c.value}`}></div>
229
+ <div class="meta">
230
+ <b>{c.name}</b>
231
+ <code>{c.var} · {c.value}</code>
232
+ <span class="role">{c.role}</span>
233
+ </div>
234
+ </div>
235
+ ))}
236
+ </div>
237
+ {tk.gradient && (
238
+ <div class="sg-sw" style="margin-top:14px;max-width:320px">
239
+ <div class="chip" style={`background:${tk.gradient.value}`}></div>
240
+ <div class="meta"><b>gradient</b><code>{tk.gradient.var}</code><span class="role">{tk.gradient.role}</span></div>
241
+ </div>
242
+ )}
243
+ </section>
244
+
245
+ {(tk.semantic ?? []).length > 0 && (
246
+ <section class="sg-block">
247
+ <p class="sg-h">Semantic tokens (v1.1)</p>
248
+ <div class="sg-swatches">
249
+ {(tk.semantic ?? []).map((c: any) => (
250
+ <div class="sg-sw">
251
+ <div class="chip" style={`background:${c.value}`}></div>
252
+ <div class="meta">
253
+ <b>{c.name}</b>
254
+ <code>{c.var} · {c.value}</code>
255
+ <span class="role">{c.role}</span>
256
+ </div>
257
+ </div>
258
+ ))}
259
+ </div>
260
+ </section>
261
+ )}
262
+
263
+ <section class="sg-block">
264
+ <p class="sg-h">Typography</p>
265
+ <h1>Heading one with a <span class="grad">gradient</span> accent</h1>
266
+ <h2>Heading two — section title</h2>
267
+ <p class="lede">Lede paragraph — the larger intro copy that sets up a section in muted tone.</p>
268
+ <p>Body copy. {tk.type?.sans}</p>
269
+ <p class="kicker">Kicker label</p>
270
+ <p class="support-line">Support line — warm emphasis (coral), AA on cream.</p>
271
+ </section>
272
+
273
+ <section class="sg-block">
274
+ <p class="sg-h">Buttons — CTA hierarchy & states</p>
275
+ <div class="cta-row" style="margin-bottom:16px">
276
+ <a class="btn btn-primary" href="#">Primary CTA</a>
277
+ <a class="btn btn-secondary" href="#">Secondary</a>
278
+ <a class="btn btn-tertiary" href="#">Tertiary / outline</a>
279
+ </div>
280
+ <div class="cta-row">
281
+ <button class="btn btn-primary" type="button">Default</button>
282
+ <button class="btn btn-primary" type="button" style="transform:translateY(-2px)">Hover</button>
283
+ <button class="btn btn-primary is-loading" type="button" aria-busy="true">Loading</button>
284
+ <button class="btn btn-primary" type="button" disabled>Disabled</button>
285
+ </div>
286
+ <p class="form-help" style="margin-top:12px">All targets ≥44px. Tab to any control to see the <code>:focus-visible</code> ring.</p>
287
+ </section>
288
+
289
+ <section class="sg-block">
290
+ <p class="sg-h">Accessible form</p>
291
+ <form action="#" style="max-width:420px">
292
+ <div class="form-field">
293
+ <label class="form-label" for="sg-email">Work email <span class="req" aria-hidden="true">*</span></label>
294
+ <input class="form-control" id="sg-email" type="email" required aria-describedby="sg-email-help" placeholder="you@company.com" />
295
+ <span class="form-help" id="sg-email-help">We only use this to send your demo link.</span>
296
+ </div>
297
+ <div class="form-field">
298
+ <label class="form-label" for="sg-co">Company <span class="opt">(optional)</span></label>
299
+ <input class="form-control" id="sg-co" type="text" placeholder="Acme Co." />
300
+ </div>
301
+ <div class="form-field">
302
+ <label class="form-label" for="sg-err">Invalid example</label>
303
+ <input class="form-control is-error" id="sg-err" type="text" aria-invalid="true" aria-describedby="sg-err-msg" value="not-an-email" />
304
+ <span class="field-error" id="sg-err-msg">Enter a valid email address.</span>
305
+ </div>
306
+ <span class="field-success">Looks good — success state.</span>
307
+ </form>
308
+ </section>
309
+
310
+ <section class="sg-block">
311
+ <p class="sg-h">Trust & social proof <span class="opt" style="text-transform:none;letter-spacing:0">(placeholder — source before use)</span></p>
312
+ <div class="sg-row" style="margin-bottom:16px;flex-wrap:wrap;gap:14px">
313
+ <span class="rating"><span class="stars" aria-hidden="true">★★★★★</span> <span>4.9 / 5 — needs-review</span></span>
314
+ <span class="trust-badge">🔒 Security / compliance badge — needs-review</span>
315
+ <span class="reassurance">✓ Guarantee / risk-free reassurance — needs-review</span>
316
+ </div>
317
+ <div class="testimonial" style="max-width:520px;margin-bottom:16px">
318
+ <blockquote class="quote">“Testimonial / customer quote placeholder — do not ship until sourced.”</blockquote>
319
+ <p class="cite">— Role, Company · <b class="opt">needs-review</b></p>
320
+ </div>
321
+ <p class="form-help" style="margin-bottom:8px">Logo strip — "as seen in" / customer &amp; partner logos (placeholder):</p>
322
+ <div class="logo-strip">
323
+ <span class="logo">LOGO</span><span class="logo">LOGO</span><span class="logo">LOGO</span><span class="logo">LOGO</span>
324
+ </div>
325
+ </section>
326
+
327
+ <section class="sg-block">
328
+ <p class="sg-h">Components</p>
329
+ <div class="sg-row" style="margin-bottom:20px">
330
+ <span class="eyebrow"><span class="dot"></span> Eyebrow / status chip</span>
331
+ </div>
332
+ <div class="sg-card">
333
+ <p class="kicker">Card</p>
334
+ <h2 style="font-size:1.15rem">Card surface</h2>
335
+ <p class="lede" style="font-size:.95rem">Uses <code>--surface-card</code>, <code>--r</code>, <code>--shadow</code>.</p>
336
+ </div>
337
+ </section>
338
+
339
+ <section class="sg-block">
340
+ <p class="sg-h">Proof strip</p>
341
+ </section>
342
+ </div>
343
+
344
+ <div class="proof">
345
+ <div class="container">
346
+ <span><b>200+</b> countries</span><span class="sep">·</span>
347
+ <span>GDPR · CCPA · PIPEDA</span><span class="sep">·</span>
348
+ <span><b>256-bit</b> SSL</span>
349
+ </div>
350
+ </div>
351
+
352
+ <div class="container">
353
+ <section class="sg-block">
354
+ <p class="sg-h">Spacing scale</p>
355
+ <div class="sg-space">
356
+ {(tk.space ?? []).map((s: any) => (
357
+ <div>
358
+ <div class="bar" style={`width:${s.value};height:${s.value}`}></div>
359
+ <div class="lab">{s.name}<br />{s.value}</div>
360
+ </div>
361
+ ))}
362
+ </div>
363
+ </section>
364
+
365
+ <section class="sg-block">
366
+ <p class="sg-h">Shape</p>
367
+ <div class="sg-shape">
368
+ {(tk.shape ?? []).map((s: any) => (
369
+ <div class="box" style={`border:1px solid var(--line);border-radius:${(s.var === '--r' || s.var === '--r-sm') ? s.value : '12px'};box-shadow:${s.name.includes('shadow') ? s.value : 'none'}`}>
370
+ {s.name}
371
+ </div>
372
+ ))}
373
+ </div>
374
+ </section>
375
+
376
+ {/* ── Marketing page components (mkt.css) ──────────────────────────
377
+ The shared composition palette every ported marketing page draws
378
+ from. Keep this in sync with mkt.css: when a port harvests a new
379
+ reusable pattern into mkt.css, add a sample here (see
380
+ playbook/site-migration/style-concept.md §Harvesting components). */}
381
+ {theme === "tot-navy" && (
382
+ <>
383
+ <section class="sg-block">
384
+ <p class="sg-h">Marketing components — <code>mkt.css</code></p>
385
+ <p class="lede" style="font-size:.95rem">The reusable page-composition layer shared by every ported marketing page. One palette; refine here, and every page inherits it.</p>
386
+ </section>
387
+
388
+ <section class="sg-block">
389
+ <p class="sg-h">Breadcrumb — <code>.crumbs</code></p>
390
+ <nav class="crumbs" aria-label="Breadcrumb sample"><a href="#">Home</a><span class="sep">›</span><a href="#">Platform</a><span class="sep">›</span>This page</nav>
391
+ </section>
392
+
393
+ <section class="sg-block">
394
+ <p class="sg-h">Hero — <code>.hero</code> (centred)</p>
395
+ <div class="hero" style="padding:24px 0 0">
396
+ <span class="eyebrow"><span class="dot"></span> Section kicker</span>
397
+ <h1 style="margin-top:14px">Headline with a <span class="grad">gradient accent</span>.</h1>
398
+ <p class="lede">The lede sets up the page in one muted sentence.</p>
399
+ <div class="cta-row"><a class="btn btn-green" href="#">Primary</a><a class="btn btn-line" href="#">Secondary</a></div>
400
+ </div>
401
+ </section>
402
+
403
+ <section class="sg-block">
404
+ <p class="sg-h">Feature grid — <code>.feature-grid</code> / <code>.feat-card</code></p>
405
+ <div class="feature-grid three">
406
+ <article class="feat-card accent"><h3>Card with accent</h3><p>Top-accent variant for category cards.</p><a class="card-link" href="#">Explore &rarr;</a></article>
407
+ <article class="feat-card"><h3>Plain card</h3><p>Default surface card with hover lift.</p><a class="card-link" href="#">Explore &rarr;</a></article>
408
+ <article class="feat-card"><h3>Third card</h3><p>Grid collapses 3→2→1 responsively.</p><a class="card-link" href="#">Explore &rarr;</a></article>
409
+ </div>
410
+ </section>
411
+
412
+ <section class="sg-block">
413
+ <p class="sg-h">Media split — <code>.split</code> + <code>.check-list</code></p>
414
+ <div class="split">
415
+ <div class="split-copy">
416
+ <span class="kicker">Split section</span>
417
+ <h2>Copy beside a proof list</h2>
418
+ <p>Use for “what you get” sections: narrative on one side, a scannable check-list on the other.</p>
419
+ <a class="btn btn-navy" href="#">Learn more</a>
420
+ </div>
421
+ <ul class="check-list">
422
+ <li>International coverage in 200+ countries</li>
423
+ <li>Document + database verification</li>
424
+ <li>Sanction &amp; watchlist screening</li>
425
+ </ul>
426
+ </div>
427
+ </section>
428
+
429
+ <section class="sg-block">
430
+ <p class="sg-h">Steps — <code>.steps</code> (numbered how-it-works)</p>
431
+ <div class="steps three">
432
+ <div class="step"><span class="num">01</span><h3>Select</h3><p>Choose the verification level.</p></div>
433
+ <div class="step"><span class="num">02</span><h3>Integrate</h3><p>Embed the SDK or API.</p></div>
434
+ <div class="step"><span class="num">03</span><h3>Verify</h3><p>Customers clear in seconds.</p></div>
435
+ </div>
436
+ </section>
437
+
438
+ <section class="sg-block">
439
+ <p class="sg-h">Stat row — <code>.stat-row</code></p>
440
+ <div class="stat-row three">
441
+ <div class="stat"><b>200+</b><span>countries — needs-review</span></div>
442
+ <div class="stat"><b>&lt;30s</b><span>typical verification — needs-review</span></div>
443
+ <div class="stat"><b>24/7</b><span>compliance evidence</span></div>
444
+ </div>
445
+ </section>
446
+
447
+ <section class="sg-block">
448
+ <p class="sg-h">Reassurance row — <code>.reassure-row</code></p>
449
+ <div class="reassure-row">
450
+ <div class="reassurance">256-bit SSL encryption on every device.</div>
451
+ <div class="reassurance">We will <b>never</b> sell your data.</div>
452
+ <div class="reassurance">Compliant with GDPR &amp; global privacy laws.</div>
453
+ </div>
454
+ </section>
455
+
456
+ <section class="sg-block">
457
+ <p class="sg-h">FAQ — <code>.faq</code> (details/summary)</p>
458
+ <div class="faq">
459
+ <details open><summary>How does verification work?</summary><p>A concise, source-copied answer goes here.</p></details>
460
+ <details><summary>Which platforms are supported?</summary><p>Shopify, BigCommerce, WooCommerce, and more.</p></details>
461
+ </div>
462
+ </section>
463
+
464
+ <section class="sg-block">
465
+ <p class="sg-h">CTA band — <code>.cta-band</code></p>
466
+ <div class="cta-band">
467
+ <span class="kicker">Get started</span>
468
+ <h2>Build trust into every transaction</h2>
469
+ <p>Closing conversion band used at the foot of every marketing page.</p>
470
+ <div class="cta-row"><a class="btn btn-ent" href="#">Start For Free</a><a class="btn btn-line" href="#">Contact Sales</a></div>
471
+ </div>
472
+ </section>
473
+ </>
474
+ )}
475
+ </div>
476
+
477
+ {/* ── Commerce + chrome component library ─────────────────────────────
478
+ The reusable, tenant-agnostic ecommerce components (product cards +
479
+ merchandising sections) and site chrome. Rendered from hard-coded FIXTURE
480
+ products so this works with no live catalog. These are STANDARD components:
481
+ fidelity comes from theme tokens + variant props, never a per-tenant fork.
482
+ See playbook/site-migration/shared-chrome.md. */}
483
+ <div class="sg-commerce" style={componentVarsInline}>
484
+ <section class="sg-block">
485
+ <p class="sg-h">Page sections — the site rethemed</p>
486
+ <p class="lede" style="font-size:.95rem;color:var(--color-muted)">Representative storefront sections rendered from theme tokens only. Swap the theme and this whole slice re-skins — hero, promos, category tiles, carousels, and chrome — with no per-tenant component fork.</p>
487
+ <div class="sg-hero" style="margin-top:18px">
488
+ <div class="copy">
489
+ <span class="kick">New this week</span>
490
+ <h3>The look, rethemed end to end.</h3>
491
+ <p>Hero, promos, and tiles inherit the selected theme's color, type, and shape tokens.</p>
492
+ <a class="sg-btn" href="#">Shop new arrivals →</a>
493
+ </div>
494
+ <div class="promo">
495
+ <div>
496
+ <span class="kick" style="color:var(--color-accent);font:800 .72rem/1 -apple-system,sans-serif;letter-spacing:.14em;text-transform:uppercase">Featured</span>
497
+ <h4 style="font-family:var(--font-display);font-size:1.25rem;margin:8px 0 4px">Right-rail promo tile</h4>
498
+ <p style="margin:0;color:var(--color-muted);font-size:.9rem">Two-up hero: banner + promo.</p>
499
+ </div>
500
+ </div>
501
+ </div>
502
+ </section>
503
+
504
+ <section class="sg-block">
505
+ <p class="sg-h">Promo cards</p>
506
+ <div class="sg-promos">
507
+ <div class="sg-promo"><span class="tag">Sale</span><h4>Clearance event</h4><p>Discount accent uses <code>--color-sale</code>.</p></div>
508
+ <div class="sg-promo"><span class="tag" style="background:var(--color-primary)">Compliant</span><h4>Texas-compliant picks</h4><p>Primary brand color on the badge.</p></div>
509
+ <div class="sg-promo"><span class="tag" style="background:var(--color-success)">In stock</span><h4>Ships today</h4><p>Availability accent from <code>--color-success</code>.</p></div>
510
+ </div>
511
+ </section>
512
+
513
+ <section class="sg-block">
514
+ <p class="sg-h">Category tiles</p>
515
+ <div class="sg-tiles">
516
+ <a class="sg-tile" href="#"><span class="ico" aria-hidden="true">◈</span><span>Disposables</span></a>
517
+ <a class="sg-tile" href="#"><span class="ico" aria-hidden="true">◇</span><span>E-Liquid</span></a>
518
+ <a class="sg-tile" href="#"><span class="ico" aria-hidden="true">▣</span><span>Devices</span></a>
519
+ <a class="sg-tile" href="#"><span class="ico" aria-hidden="true">◉</span><span>Coils &amp; Pods</span></a>
520
+ </div>
521
+ </section>
522
+
523
+ <section class="sg-block">
524
+ <p class="sg-h">Commerce atoms — PriceDisplay / Badge / RatingStars</p>
525
+ <div class="sg-row" style="gap:28px;align-items:flex-start">
526
+ <div>
527
+ <PriceDisplay amount={28} currency="USD" />
528
+ <PriceDisplay amount={64} compareAt={96} currency="USD" showBadge class="mt-2" />
529
+ <PriceDisplay amount={42} from currency="USD" class="mt-2" />
530
+ </div>
531
+ <div class="sg-row" style="gap:8px">
532
+ <Badge variant="new" label="New" />
533
+ <Badge variant="sale" label="-33%" />
534
+ <Badge variant="compliant" label="Compliant" />
535
+ <Badge variant="soldout" label="Sold out" />
536
+ <Badge variant="low-stock" label="Low stock" />
537
+ </div>
538
+ <div>
539
+ <RatingStars rating={4.5} count={128} />
540
+ <div class="mt-2"><RatingStars rating={3} count={12} /></div>
541
+ <div class="mt-2"><RatingStars rating={5} count={4} /></div>
542
+ </div>
543
+ </div>
544
+ </section>
545
+
546
+ <section class="sg-block">
547
+ <p class="sg-h">ProductCard — state permutations</p>
548
+ <div class="grid grid-cols-2 gap-5 lg:grid-cols-4">
549
+ {sampleProducts.map((p) => (
550
+ <ProductCard
551
+ product={p}
552
+ rating={sampleRatings[p.handle]?.rating}
553
+ reviewCount={sampleRatings[p.handle]?.count}
554
+ />
555
+ ))}
556
+ </div>
557
+ </section>
558
+
559
+ <section class="sg-block">
560
+ <p class="sg-h">ProductCarousel — horizontal scroll (fixtures)</p>
561
+ <ProductCarousel title="Best Sellers" eyebrow="Shop" products={sampleProducts} tone="surface" />
562
+ </section>
563
+
564
+ <section class="sg-block">
565
+ <p class="sg-h">ProductCarousel — tabbed (each tab its own source)</p>
566
+ <ProductCarousel
567
+ title="Featured"
568
+ tabs={[
569
+ { label: "New", products: sampleProducts.slice(0, 4) },
570
+ { label: "On Sale", products: sampleProducts.slice(1, 5) },
571
+ { label: "Best Sellers", products: sampleProducts.slice(2, 6) },
572
+ ]}
573
+ />
574
+ </section>
575
+
576
+ <section class="sg-block">
577
+ <p class="sg-h">ProductGrid — paginated-look grid (fixtures)</p>
578
+ <ProductGrid title="All Products" products={sampleProducts} columns={3} />
579
+ </section>
580
+
581
+ <section class="sg-block">
582
+ <p class="sg-h">Chrome — AnnouncementBar (static + marquee)</p>
583
+ <AnnouncementBar text="Free US shipping on orders over $100" variant="static" />
584
+ <div class="mt-3">
585
+ <AnnouncementBar text="Free US shipping on orders over $100!" variant="marquee" tone="sale" />
586
+ </div>
587
+ </section>
588
+
589
+ <section class="sg-block">
590
+ <p class="sg-h">Chrome — UtilityNav</p>
591
+ <UtilityNav
592
+ links={[{ label: "News", href: "#" }, { label: "About", href: "#" }, { label: "Contact", href: "#" }]}
593
+ locale="English"
594
+ currency="United States (USD $)"
595
+ social={sampleSocial}
596
+ />
597
+ </section>
598
+
599
+ <section class="sg-block">
600
+ <p class="sg-h">Chrome — SiteHeader (logo + search + account + cart link + nav)</p>
601
+ <SiteHeader
602
+ wordmark="Sample Store"
603
+ nav={sampleNav}
604
+ searchAction="/search"
605
+ accountHref="/account"
606
+ cartHref="/cart"
607
+ cartCount={2}
608
+ sticky={false}
609
+ />
610
+ </section>
611
+
612
+ <section class="sg-block">
613
+ <p class="sg-h">Chrome — MegaMenu / NavDropdown (multi-column + caret + NEW badge)</p>
614
+ <div style="background:var(--color-surface);border:1px solid var(--color-border);border-radius:8px;padding:8px 16px">
615
+ <MegaMenu items={sampleNav} class="!block" />
616
+ </div>
617
+ <p class="form-help" style="margin-top:8px;color:var(--color-muted)">Hover/focus a caret item to reveal its dropdown (CSS-only).</p>
618
+ </section>
619
+
620
+ <section class="sg-block">
621
+ <p class="sg-h">Chrome — SiteFooter (columns + newsletter + payments + compliance)</p>
622
+ <SiteFooter
623
+ brand={{ wordmark: "Sample Store", contact: ["hello@example.com", "1 (800) 555-0100"] }}
624
+ columns={sampleFooterCols}
625
+ newsletter={{ title: "Join the community", body: "New arrivals and exclusive offers.", placeholder: "Email" }}
626
+ payments={["Visa", "Mastercard", "Amex", "Discover", "PayPal", "Apple Pay"]}
627
+ social={sampleSocial}
628
+ compliance="Must be 21+ to purchase. Products intended for adults of legal age only."
629
+ legal="© Sample Store. All rights reserved."
630
+ />
631
+ </section>
632
+ </div>
633
+ </main>
634
+
635
+ <footer class="site">
636
+ <div class="container">
637
+ <div class="foot-grid">
638
+ <div><b>{t.name}</b><p class="copyright">Footer chrome sample · theme preview only.</p></div>
639
+ <div><h3>Platform</h3><ul><li><a href="#">Identity Verification</a></li><li><a href="#">Age Assurance</a></li></ul></div>
640
+ <div><h3>Industries</h3><ul><li><a href="#">Alcohol &amp; Tobacco</a></li><li><a href="#">Marketplaces</a></li></ul></div>
641
+ <div><h3>Company</h3><ul><li><a href="#">Pricing</a></li><li><a href="#">Contact Sales</a></li></ul></div>
642
+ </div>
643
+ </div>
644
+ </footer>
645
+ </body>
646
+ </html>