@tokenoftrust/storefront-runner 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (310) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +42 -0
  3. package/apps/storefront/astro.config.mjs +66 -0
  4. package/apps/storefront/dev-plugins/dev-loop-state.mjs +147 -0
  5. package/apps/storefront/dev-plugins/tenant-hot-reload.mjs +238 -0
  6. package/apps/storefront/env.d.ts +162 -0
  7. package/apps/storefront/migrations/0000_baseline.sql +54 -0
  8. package/apps/storefront/migrations/0001_products_fts.sql +9 -0
  9. package/apps/storefront/migrations/README.md +54 -0
  10. package/apps/storefront/migrations/meta/0000_snapshot.json +347 -0
  11. package/apps/storefront/migrations/meta/0001_snapshot.json +347 -0
  12. package/apps/storefront/migrations/meta/_journal.json +20 -0
  13. package/apps/storefront/package.json +42 -0
  14. package/apps/storefront/public/brand/northwind-logo-dark.svg +4 -0
  15. package/apps/storefront/public/brand/northwind-logo-light.svg +4 -0
  16. package/apps/storefront/public/brand/northwind-og.svg +13 -0
  17. package/apps/storefront/public/favicon.svg +5 -0
  18. package/apps/storefront/public/js/dashboard-team.js +147 -0
  19. package/apps/storefront/public/js/dashboard-vendor-search.js +115 -0
  20. package/apps/storefront/public/shared/commerce-chrome.css +369 -0
  21. package/apps/storefront/src/components/Badge.astro +34 -0
  22. package/apps/storefront/src/components/Breadcrumbs.astro +45 -0
  23. package/apps/storefront/src/components/CollectionCard.astro +56 -0
  24. package/apps/storefront/src/components/EmptyState.astro +55 -0
  25. package/apps/storefront/src/components/Img.astro +68 -0
  26. package/apps/storefront/src/components/ProductCard.astro +228 -0
  27. package/apps/storefront/src/components/Section.astro +39 -0
  28. package/apps/storefront/src/components/Seo.astro +70 -0
  29. package/apps/storefront/src/components/WidgetFrame.astro +34 -0
  30. package/apps/storefront/src/components/admin/AdminAIWorkflowsTab.astro +531 -0
  31. package/apps/storefront/src/components/admin/AdminCustomersTab.astro +597 -0
  32. package/apps/storefront/src/components/admin/AdminFoxyCartSettingsPanel.astro +227 -0
  33. package/apps/storefront/src/components/admin/AdminFulfillmentTab.astro +465 -0
  34. package/apps/storefront/src/components/admin/AdminProductsTab.astro +901 -0
  35. package/apps/storefront/src/components/admin/AdminReportingTab.astro +435 -0
  36. package/apps/storefront/src/components/admin/AdminSettingsTab.astro +782 -0
  37. package/apps/storefront/src/components/admin/orders/OrdersWorkspace.astro +1223 -0
  38. package/apps/storefront/src/components/auth/AuthBadge.astro +44 -0
  39. package/apps/storefront/src/components/chrome/AnnouncementBar.astro +108 -0
  40. package/apps/storefront/src/components/chrome/MegaMenu.astro +26 -0
  41. package/apps/storefront/src/components/chrome/NavDropdown.astro +201 -0
  42. package/apps/storefront/src/components/chrome/SiteFooter.astro +201 -0
  43. package/apps/storefront/src/components/chrome/SiteHeader.astro +234 -0
  44. package/apps/storefront/src/components/chrome/UtilityNav.astro +79 -0
  45. package/apps/storefront/src/components/commerce/ArticleCard.astro +242 -0
  46. package/apps/storefront/src/components/commerce/BrandGrid.astro +175 -0
  47. package/apps/storefront/src/components/commerce/FoxyLoader.astro +23 -0
  48. package/apps/storefront/src/components/commerce/FoxySidecartStyles.astro +61 -0
  49. package/apps/storefront/src/components/commerce/PriceDisplay.astro +91 -0
  50. package/apps/storefront/src/components/commerce/ProductCarousel.astro +197 -0
  51. package/apps/storefront/src/components/commerce/ProductGrid.astro +75 -0
  52. package/apps/storefront/src/components/commerce/RatingStars.astro +58 -0
  53. package/apps/storefront/src/components/commerce/ReviewList.astro +54 -0
  54. package/apps/storefront/src/components/commerce/ReviewSummary.astro +44 -0
  55. package/apps/storefront/src/components/commerce/TagFilterCloud.astro +149 -0
  56. package/apps/storefront/src/components/compliance/AdultSignatureNotice.astro +37 -0
  57. package/apps/storefront/src/components/compliance/ComplianceNotice.astro +99 -0
  58. package/apps/storefront/src/components/compliance/ExciseTaxNotice.astro +45 -0
  59. package/apps/storefront/src/components/compliance/NicotineWarning.astro +33 -0
  60. package/apps/storefront/src/components/compliance/PactActNotice.astro +35 -0
  61. package/apps/storefront/src/components/compliance/Prop65Warning.astro +80 -0
  62. package/apps/storefront/src/components/compliance/PurchaseLimitNotice.astro +38 -0
  63. package/apps/storefront/src/components/compliance/ShippingRestrictionNotice.astro +35 -0
  64. package/apps/storefront/src/components/compliance/StateEligibilityNotice.astro +53 -0
  65. package/apps/storefront/src/components/home/Hero.astro +164 -0
  66. package/apps/storefront/src/components/islands/AgeGate.tsx +109 -0
  67. package/apps/storefront/src/components/islands/ImageGallery.tsx +237 -0
  68. package/apps/storefront/src/components/islands/IsolatedAgeGate.tsx +73 -0
  69. package/apps/storefront/src/components/islands/MobileNav.tsx +239 -0
  70. package/apps/storefront/src/components/islands/QuickView.tsx +138 -0
  71. package/apps/storefront/src/components/islands/RecentlyViewed.tsx +122 -0
  72. package/apps/storefront/src/components/islands/SavedList.tsx +99 -0
  73. package/apps/storefront/src/components/islands/SearchTypeahead.tsx +248 -0
  74. package/apps/storefront/src/components/islands/VariantSelector.tsx +375 -0
  75. package/apps/storefront/src/components/marketing/CardGrid.astro +72 -0
  76. package/apps/storefront/src/components/marketing/CodeSample.astro +20 -0
  77. package/apps/storefront/src/components/marketing/CtaBand.astro +24 -0
  78. package/apps/storefront/src/components/marketing/Faq.astro +37 -0
  79. package/apps/storefront/src/components/marketing/Integrations.astro +63 -0
  80. package/apps/storefront/src/components/marketing/MarketingBlocks.astro +53 -0
  81. package/apps/storefront/src/components/marketing/MarketingCtas.astro +48 -0
  82. package/apps/storefront/src/components/marketing/MarketingHero.astro +72 -0
  83. package/apps/storefront/src/components/marketing/ProofStrip.astro +37 -0
  84. package/apps/storefront/src/components/marketing/SplitCompare.astro +53 -0
  85. package/apps/storefront/src/components/marketing/Steps.astro +36 -0
  86. package/apps/storefront/src/components/marketing/Testimonials.astro +38 -0
  87. package/apps/storefront/src/components/marketing/TrustBar.astro +22 -0
  88. package/apps/storefront/src/components/membership/IllustrativeLabel.astro +56 -0
  89. package/apps/storefront/src/components/membership/TierCards.astro +164 -0
  90. package/apps/storefront/src/components/membership/TierComparisonTable.astro +148 -0
  91. package/apps/storefront/src/components/plp/ActiveFilters.astro +79 -0
  92. package/apps/storefront/src/components/plp/FacetSidebar.astro +199 -0
  93. package/apps/storefront/src/components/plp/Pagination.astro +99 -0
  94. package/apps/storefront/src/components/plp/SortSelect.astro +64 -0
  95. package/apps/storefront/src/components/style-guide/StyleGuideNav.astro +95 -0
  96. package/apps/storefront/src/components/subscription/HowItWorksSteps.astro +67 -0
  97. package/apps/storefront/src/components/subscription/ManageSubscriptionEntry.astro +67 -0
  98. package/apps/storefront/src/components/subscription/SavingsExplainer.astro +101 -0
  99. package/apps/storefront/src/config/adminTargetTenant.ts +28 -0
  100. package/apps/storefront/src/config/devTenantSeed.ts +78 -0
  101. package/apps/storefront/src/config/devTenants.ts +16 -0
  102. package/apps/storefront/src/config/kvTenantResolver.ts +87 -0
  103. package/apps/storefront/src/config/resolver.ts +102 -0
  104. package/apps/storefront/src/config/tenants.ts +87 -0
  105. package/apps/storefront/src/layouts/Layout.astro +368 -0
  106. package/apps/storefront/src/lib/admin/README.md +122 -0
  107. package/apps/storefront/src/lib/admin/ai/approvalMode.ts +21 -0
  108. package/apps/storefront/src/lib/admin/ai/askEnvelope.ts +48 -0
  109. package/apps/storefront/src/lib/admin/ai/audit.ts +14 -0
  110. package/apps/storefront/src/lib/admin/ai/index.ts +6 -0
  111. package/apps/storefront/src/lib/admin/ai/operationalRuns.ts +155 -0
  112. package/apps/storefront/src/lib/admin/ai/recommendation.ts +20 -0
  113. package/apps/storefront/src/lib/admin/checkoutStyleInput.ts +172 -0
  114. package/apps/storefront/src/lib/admin/checkoutStyleTarget.ts +65 -0
  115. package/apps/storefront/src/lib/admin/envelope.ts +10 -0
  116. package/apps/storefront/src/lib/admin/evidence/evidenceReference.ts +32 -0
  117. package/apps/storefront/src/lib/admin/memoizeByEnvelope.ts +27 -0
  118. package/apps/storefront/src/lib/admin/orderClient.ts +146 -0
  119. package/apps/storefront/src/lib/admin/seed.ts +54 -0
  120. package/apps/storefront/src/lib/admin/services/mock/aiWorkflows.ts +59 -0
  121. package/apps/storefront/src/lib/admin/services/mock/customers.ts +86 -0
  122. package/apps/storefront/src/lib/admin/services/mock/evidence.ts +99 -0
  123. package/apps/storefront/src/lib/admin/services/mock/foxyCartSettings.ts +78 -0
  124. package/apps/storefront/src/lib/admin/services/mock/fulfillment.ts +62 -0
  125. package/apps/storefront/src/lib/admin/services/mock/index.ts +12 -0
  126. package/apps/storefront/src/lib/admin/services/mock/orders.ts +184 -0
  127. package/apps/storefront/src/lib/admin/services/mock/products.ts +105 -0
  128. package/apps/storefront/src/lib/admin/services/mock/reporting.ts +51 -0
  129. package/apps/storefront/src/lib/admin/services/mock/settings.ts +70 -0
  130. package/apps/storefront/src/lib/admin/services/mock/tenants.ts +29 -0
  131. package/apps/storefront/src/lib/admin/services/orders.ts +300 -0
  132. package/apps/storefront/src/lib/admin/viewmodels/aiWorkflows.ts +67 -0
  133. package/apps/storefront/src/lib/admin/viewmodels/customers.ts +56 -0
  134. package/apps/storefront/src/lib/admin/viewmodels/fulfillment.ts +49 -0
  135. package/apps/storefront/src/lib/admin/viewmodels/orders.ts +92 -0
  136. package/apps/storefront/src/lib/admin/viewmodels/products.ts +74 -0
  137. package/apps/storefront/src/lib/admin/viewmodels/reporting.ts +34 -0
  138. package/apps/storefront/src/lib/admin/viewmodels/settings.ts +64 -0
  139. package/apps/storefront/src/lib/adminTenantEnvelope.ts +90 -0
  140. package/apps/storefront/src/lib/analytics/index.ts +47 -0
  141. package/apps/storefront/src/lib/auth/brokerAssertion.ts +136 -0
  142. package/apps/storefront/src/lib/auth/devAuth.ts +90 -0
  143. package/apps/storefront/src/lib/auth/gatePage.ts +81 -0
  144. package/apps/storefront/src/lib/auth/identityToken.ts +341 -0
  145. package/apps/storefront/src/lib/auth/loginGate.ts +119 -0
  146. package/apps/storefront/src/lib/auth/route.ts +146 -0
  147. package/apps/storefront/src/lib/auth/session.ts +203 -0
  148. package/apps/storefront/src/lib/auth/totAccessClient.ts +503 -0
  149. package/apps/storefront/src/lib/basePath.ts +41 -0
  150. package/apps/storefront/src/lib/cfImage.ts +55 -0
  151. package/apps/storefront/src/lib/chrome/model.ts +244 -0
  152. package/apps/storefront/src/lib/chrome/parseConfig.ts +34 -0
  153. package/apps/storefront/src/lib/colors.ts +97 -0
  154. package/apps/storefront/src/lib/commerce/foxyCartSettings.ts +253 -0
  155. package/apps/storefront/src/lib/content-edit/applyDiff.ts +91 -0
  156. package/apps/storefront/src/lib/content-edit/client.ts +230 -0
  157. package/apps/storefront/src/lib/content-edit/index.ts +14 -0
  158. package/apps/storefront/src/lib/content-edit/route.ts +25 -0
  159. package/apps/storefront/src/lib/content-edit/types.ts +19 -0
  160. package/apps/storefront/src/lib/cspStaticHashes.ts +24 -0
  161. package/apps/storefront/src/lib/d1/catalog.ts +366 -0
  162. package/apps/storefront/src/lib/dashboard/staffAdmission.ts +43 -0
  163. package/apps/storefront/src/lib/dashboard/staffVendorAccess.ts +449 -0
  164. package/apps/storefront/src/lib/dashboard/tenantSelection.ts +136 -0
  165. package/apps/storefront/src/lib/dashboard/vendorQuery.ts +61 -0
  166. package/apps/storefront/src/lib/demoGate.ts +113 -0
  167. package/apps/storefront/src/lib/dev/activityIngestToken.ts +78 -0
  168. package/apps/storefront/src/lib/dev/activityStore.ts +72 -0
  169. package/apps/storefront/src/lib/dev/ai-widget-client.js +308 -0
  170. package/apps/storefront/src/lib/dev/apiBase.ts +14 -0
  171. package/apps/storefront/src/lib/dev/cliSignInCode.ts +155 -0
  172. package/apps/storefront/src/lib/dev/devDraft.ts +133 -0
  173. package/apps/storefront/src/lib/dev/hostedCockpit.ts +169 -0
  174. package/apps/storefront/src/lib/dev/livePreview.ts +77 -0
  175. package/apps/storefront/src/lib/dev/runtimeStore.ts +120 -0
  176. package/apps/storefront/src/lib/dev/storeStatus.ts +142 -0
  177. package/apps/storefront/src/lib/diag/redact.ts +20 -0
  178. package/apps/storefront/src/lib/edgeCache.ts +128 -0
  179. package/apps/storefront/src/lib/email/magicLinkInviteEmail.ts +62 -0
  180. package/apps/storefront/src/lib/env.ts +60 -0
  181. package/apps/storefront/src/lib/fixtures/sampleProducts.ts +130 -0
  182. package/apps/storefront/src/lib/format.ts +38 -0
  183. package/apps/storefront/src/lib/foxyCommerce.ts +49 -0
  184. package/apps/storefront/src/lib/imageAttrs.ts +55 -0
  185. package/apps/storefront/src/lib/jsonld.ts +166 -0
  186. package/apps/storefront/src/lib/maintenance.ts +71 -0
  187. package/apps/storefront/src/lib/membership/model.ts +97 -0
  188. package/apps/storefront/src/lib/memoryKv.ts +32 -0
  189. package/apps/storefront/src/lib/messaging/messagesClient.ts +143 -0
  190. package/apps/storefront/src/lib/placeholder.ts +99 -0
  191. package/apps/storefront/src/lib/previewReload.ts +125 -0
  192. package/apps/storefront/src/lib/priceBuckets.ts +33 -0
  193. package/apps/storefront/src/lib/rawChrome.ts +505 -0
  194. package/apps/storefront/src/lib/rawMarketingHtml.ts +136 -0
  195. package/apps/storefront/src/lib/search/index.ts +74 -0
  196. package/apps/storefront/src/lib/sections.ts +129 -0
  197. package/apps/storefront/src/lib/securityHeaders.ts +31 -0
  198. package/apps/storefront/src/lib/storyblok/content-model.ts +289 -0
  199. package/apps/storefront/src/lib/storyblok/provider.ts +607 -0
  200. package/apps/storefront/src/lib/subscription/model.ts +68 -0
  201. package/apps/storefront/src/lib/tenantRouting.ts +91 -0
  202. package/apps/storefront/src/lib/tot/ToTClient.ts +177 -0
  203. package/apps/storefront/src/lib/tot/d1Client.ts +62 -0
  204. package/apps/storefront/src/lib/tot/query.ts +249 -0
  205. package/apps/storefront/src/lib/tot/totClientInterface.ts +30 -0
  206. package/apps/storefront/src/lib/url.ts +142 -0
  207. package/apps/storefront/src/lib/wishlist.ts +63 -0
  208. package/apps/storefront/src/middleware/index.ts +455 -0
  209. package/apps/storefront/src/pages/404.astro +61 -0
  210. package/apps/storefront/src/pages/[...slug].astro +90 -0
  211. package/apps/storefront/src/pages/admin.astro +1675 -0
  212. package/apps/storefront/src/pages/api/admin/orders/[id].ts +53 -0
  213. package/apps/storefront/src/pages/api/admin/orders.ts +71 -0
  214. package/apps/storefront/src/pages/api/auth/logout.ts +21 -0
  215. package/apps/storefront/src/pages/api/auth/magic-exchange.ts +107 -0
  216. package/apps/storefront/src/pages/api/auth/send.ts +85 -0
  217. package/apps/storefront/src/pages/api/auth/verify.ts +135 -0
  218. package/apps/storefront/src/pages/api/cache-purge.ts +44 -0
  219. package/apps/storefront/src/pages/api/checkout-style.css.ts +43 -0
  220. package/apps/storefront/src/pages/api/cli/policy.ts +70 -0
  221. package/apps/storefront/src/pages/api/content-edit/ai-edit.ts +164 -0
  222. package/apps/storefront/src/pages/api/csp-report.ts +25 -0
  223. package/apps/storefront/src/pages/api/dashboard/enter-vendor.ts +124 -0
  224. package/apps/storefront/src/pages/api/dashboard/vendor-search.ts +120 -0
  225. package/apps/storefront/src/pages/api/dev/activity.ts +124 -0
  226. package/apps/storefront/src/pages/api/dev/cli-signin-code.ts +73 -0
  227. package/apps/storefront/src/pages/api/dev/diff.ts +68 -0
  228. package/apps/storefront/src/pages/api/dev/file.ts +57 -0
  229. package/apps/storefront/src/pages/api/dev/locate.ts +125 -0
  230. package/apps/storefront/src/pages/api/dev/publish.ts +128 -0
  231. package/apps/storefront/src/pages/api/dev/tree.ts +70 -0
  232. package/apps/storefront/src/pages/api/dev/write.ts +116 -0
  233. package/apps/storefront/src/pages/api/newsletter.ts +104 -0
  234. package/apps/storefront/src/pages/api/request-access.ts +172 -0
  235. package/apps/storefront/src/pages/auth/login.astro +149 -0
  236. package/apps/storefront/src/pages/auth/magic.astro +105 -0
  237. package/apps/storefront/src/pages/capabilities.astro +292 -0
  238. package/apps/storefront/src/pages/collections/[handle].astro +177 -0
  239. package/apps/storefront/src/pages/collections/index.astro +59 -0
  240. package/apps/storefront/src/pages/dashboard/[appDomain]/index.astro +100 -0
  241. package/apps/storefront/src/pages/dashboard/[appDomain]/team.astro +154 -0
  242. package/apps/storefront/src/pages/dashboard/index.astro +160 -0
  243. package/apps/storefront/src/pages/index.astro +290 -0
  244. package/apps/storefront/src/pages/llms.txt.ts +92 -0
  245. package/apps/storefront/src/pages/products/[handle].astro +402 -0
  246. package/apps/storefront/src/pages/robots.txt.ts +24 -0
  247. package/apps/storefront/src/pages/saved.astro +35 -0
  248. package/apps/storefront/src/pages/search.astro +150 -0
  249. package/apps/storefront/src/pages/sitemap.xml.ts +78 -0
  250. package/apps/storefront/src/pages/style-guide/[tenant]/[theme].astro +1280 -0
  251. package/apps/storefront/src/pages/style-guide/[tenant]/chrome/[theme].astro +229 -0
  252. package/apps/storefront/src/pages/style-guide/[tenant]/guide/[theme].astro +144 -0
  253. package/apps/storefront/src/pages/style-guide/[tenant]/index.astro +116 -0
  254. package/apps/storefront/src/pages/style-guide/index.astro +98 -0
  255. package/apps/storefront/src/pages/tenants/[id]/[...path].ts +57 -0
  256. package/apps/storefront/src/styles/global.css +292 -0
  257. package/apps/storefront/src/themes/reference.ts +68 -0
  258. package/apps/storefront/src/themes/schema.ts +111 -0
  259. package/apps/storefront/src/themes/tenants/index.ts +51 -0
  260. package/apps/storefront/tsconfig.json +16 -0
  261. package/apps/storefront/vitest.config.ts +22 -0
  262. package/package.json +26 -0
  263. package/packages/public-runtime/LICENSE +58 -0
  264. package/packages/public-runtime/package.json +22 -0
  265. package/packages/public-runtime/src/binary-path.ts +68 -0
  266. package/packages/public-runtime/src/capabilities.ts +89 -0
  267. package/packages/public-runtime/src/catalog-api.ts +81 -0
  268. package/packages/public-runtime/src/catalog-d1.ts +192 -0
  269. package/packages/public-runtime/src/checkout-style-publish.ts +200 -0
  270. package/packages/public-runtime/src/checkout-style.ts +375 -0
  271. package/packages/public-runtime/src/csp.ts +109 -0
  272. package/packages/public-runtime/src/customization-preview.ts +197 -0
  273. package/packages/public-runtime/src/customization-reconcile.ts +63 -0
  274. package/packages/public-runtime/src/customization-runtime.ts +157 -0
  275. package/packages/public-runtime/src/customization-scripts.ts +64 -0
  276. package/packages/public-runtime/src/customization-versioning.ts +95 -0
  277. package/packages/public-runtime/src/foxy-orders.ts +136 -0
  278. package/packages/public-runtime/src/foxy.ts +196 -0
  279. package/packages/public-runtime/src/hot-standby-readiness.ts +140 -0
  280. package/packages/public-runtime/src/index.ts +34 -0
  281. package/packages/public-runtime/src/product.ts +159 -0
  282. package/packages/public-runtime/src/search.ts +45 -0
  283. package/packages/public-runtime/src/tenant-assets.ts +444 -0
  284. package/packages/public-runtime/src/tenant.ts +384 -0
  285. package/packages/public-runtime/tsconfig.json +8 -0
  286. package/packages/public-runtime/vitest.config.ts +8 -0
  287. package/pnpm-workspace.yaml +7 -0
  288. package/scripts/build/copy-tenant-assets.mjs +69 -0
  289. package/scripts/dev/ai-edit.mjs +183 -0
  290. package/scripts/dev/checkout-watch.mjs +116 -0
  291. package/scripts/dev/file-browser.mjs +159 -0
  292. package/scripts/dev/file-writer.mjs +141 -0
  293. package/scripts/dev/git-status.mjs +171 -0
  294. package/scripts/dev/locate-handler.mjs +163 -0
  295. package/scripts/dev/locate.mjs +112 -0
  296. package/scripts/dev/port-check.mjs +48 -0
  297. package/scripts/dev/safe-path.mjs +109 -0
  298. package/scripts/dev/shot.mjs +46 -0
  299. package/scripts/dev/tenant-source-root.mjs +76 -0
  300. package/scripts/dev/unified-diff.mjs +81 -0
  301. package/scripts/tot-dev.mjs +376 -0
  302. package/tenants/README.md +14 -0
  303. package/tenants/home/content/chrome.json +7 -0
  304. package/tenants/home/content/home.html +58 -0
  305. package/tenants/home/content/home.json +11 -0
  306. package/tenants/home/public/js/storefront.js +210 -0
  307. package/tenants/home/public/logo-wordmark.png +0 -0
  308. package/tenants/home/public/pages/storefront.css +212 -0
  309. package/tenants/home/theme.json +6 -0
  310. package/tsconfig.base.json +20 -0
@@ -0,0 +1,782 @@
1
+ ---
2
+ import { getSettingsViewModel } from "@/lib/admin/services/mock";
3
+ import AdminFoxyCartSettingsPanel from "@/components/admin/AdminFoxyCartSettingsPanel.astro";
4
+ import { withBase } from "@/lib/basePath";
5
+
6
+ const { envelope } = Astro.props;
7
+ const settings = getSettingsViewModel(envelope);
8
+
9
+ // Checkout styling editor (U12). Renders the current CheckoutStyle and saves it
10
+ // through the versioned publish spine (POST /api/preview/checkout-style —
11
+ // colocated with reconcile/promote in the control-plane publish cluster). The
12
+ // endpoint is base-path-prefixed so it stays inside a path-routed tenant, and
13
+ // the client script is nonce'd (CSP: script-src is 'self' + nonce).
14
+ const { cspNonce, basePath } = Astro.locals;
15
+ const checkoutStyle = settings.checkoutStyle;
16
+ const checkoutStyleEndpoint = withBase(basePath || "", "/api/preview/checkout-style");
17
+ const colorFields = [
18
+ { key: "background", label: "Page background" },
19
+ { key: "surface", label: "Card surface" },
20
+ { key: "primary", label: "Primary" },
21
+ { key: "primaryContrast", label: "On-primary text" },
22
+ { key: "accent", label: "Accent" },
23
+ { key: "text", label: "Body text" },
24
+ ] as const;
25
+ // Initial CSS custom properties for the live preview (inline style ATTRIBUTES
26
+ // are CSP-allowed via style-src-attr 'unsafe-inline'; no <style> is injected).
27
+ const previewVars = [
28
+ `--cs-bg:${checkoutStyle.colors.background}`,
29
+ `--cs-surface:${checkoutStyle.colors.surface}`,
30
+ `--cs-primary:${checkoutStyle.colors.primary}`,
31
+ `--cs-primary-contrast:${checkoutStyle.colors.primaryContrast}`,
32
+ `--cs-accent:${checkoutStyle.colors.accent}`,
33
+ `--cs-text:${checkoutStyle.colors.text}`,
34
+ `--cs-font:${checkoutStyle.typography.fontFamily}`,
35
+ `--cs-size:${checkoutStyle.typography.baseSize}`,
36
+ `--cs-radius:${checkoutStyle.button.radius}`,
37
+ ].join(";");
38
+
39
+ const APPROVAL_MODE_LABEL: Record<string, string> = {
40
+ draft_only: "Draft only",
41
+ approval_required: "Approval required",
42
+ guarded_automation: "Guarded automation",
43
+ };
44
+
45
+ const APPROVAL_MODE_DETAIL: Record<string, string> = {
46
+ draft_only: "AI can propose changes, but an operator must publish them.",
47
+ approval_required: "AI can draft and stage a change; it takes effect only after explicit approval.",
48
+ guarded_automation: "Pre-approved, narrowly-scoped changes may apply automatically within policy limits.",
49
+ };
50
+
51
+ const riskyCount = settings.sections.filter((s) => s.riskyChangeReview).length;
52
+
53
+ function formatChangeSummary(change: string): string {
54
+ return change.replace(/^./, (c) => c.toUpperCase());
55
+ }
56
+ ---
57
+
58
+ <!-- agent-hook:settings-tab -->
59
+ <section id="settings" class="band settings-tab" aria-labelledby="admin-tab-settings settings-title" data-admin-panel data-agent-scope="settings" role="tabpanel">
60
+ <div class="section-title">
61
+ <div>
62
+ <h2 id="settings-title">Settings</h2>
63
+ <p>Store configuration, operational policy, access, regulated storefront controls, and audited changes.</p>
64
+ </div>
65
+ <div class="actions">
66
+ <button class="btn" type="button"><svg><use href="#i-refresh"></use></svg>Sync policies</button>
67
+ <button class="btn primary" type="button"><svg><use href="#i-check"></use></svg>Review changes</button>
68
+ </div>
69
+ </div>
70
+
71
+ <div class="grid cols-4">
72
+ <div class="metric">
73
+ <span>Sections</span>
74
+ <strong>{settings.sections.length}</strong>
75
+ <small>Store, checkout, payments, shipping, taxes, and more</small>
76
+ </div>
77
+ <div class="metric">
78
+ <span>Risky review</span>
79
+ <strong>{riskyCount}</strong>
80
+ <small>Sections whose changes require review before they apply</small>
81
+ </div>
82
+ <div class="metric">
83
+ <span>Shipping restrictions</span>
84
+ <strong>{settings.shippingRestrictions.length}</strong>
85
+ <small>Regions with a destination or product restriction on file</small>
86
+ </div>
87
+ <div class="metric">
88
+ <span>AI / admin policy</span>
89
+ <strong>{APPROVAL_MODE_LABEL[settings.aiPolicyMode] ?? settings.aiPolicyMode}</strong>
90
+ <small>{APPROVAL_MODE_DETAIL[settings.aiPolicyMode] ?? ""}</small>
91
+ </div>
92
+ </div>
93
+
94
+ {riskyCount > 0 && (
95
+ <div class="ship-gate amber">
96
+ <div class="ship-gate-main">
97
+ <span class="seal"><svg><use href="#i-alert"></use></svg></span>
98
+ <div>
99
+ <b>{riskyCount} section{riskyCount === 1 ? "" : "s"} need review before changes apply</b>
100
+ <span>Risky-change review is required for payments, shipping, taxes, users &amp; access, and AI/admin policy.</span>
101
+ </div>
102
+ </div>
103
+ <a class="btn" href="#settings-sections">Review sections</a>
104
+ </div>
105
+ )}
106
+
107
+ <div class="settings-workspace">
108
+ <aside class="settings-menu" aria-label="Settings sections">
109
+ <div class="settings-search">
110
+ <label for="settings-search">Search settings</label>
111
+ <input id="settings-search" type="search" placeholder="Search settings" />
112
+ </div>
113
+ <div class="settings-section-list" role="list">
114
+ {settings.sections.map((section) => (
115
+ <a class:list={["settings-section-link", { active: section.key === "compliance" }]} href="#settings-sections" role="listitem">
116
+ <span>
117
+ <strong>{section.label}</strong>
118
+ <small>{section.summary}</small>
119
+ </span>
120
+ <span class:list={["chip", section.riskyChangeReview ? "amber" : "green"]}>
121
+ {section.riskyChangeReview ? "Review" : "Standard"}
122
+ </span>
123
+ </a>
124
+ ))}
125
+ </div>
126
+ </aside>
127
+
128
+ <div class="settings-detail">
129
+ <div id="settings-sections" class="panel">
130
+ <div class="panel-head settings-panel-head">
131
+ <h3><svg><use href="#i-gear"></use></svg>Settings Overview</h3>
132
+ <span class="chip blue">Draft-safe controls</span>
133
+ </div>
134
+ <div class="panel-body grid">
135
+ <div class="table-wrap">
136
+ <table class="settings-table">
137
+ <thead>
138
+ <tr>
139
+ <th>Section</th>
140
+ <th>Review</th>
141
+ <th class="action">Action</th>
142
+ </tr>
143
+ </thead>
144
+ <tbody>
145
+ {settings.sections.map((section) => (
146
+ <tr>
147
+ <td><strong>{section.label}</strong><span class="subtle">{section.summary}</span></td>
148
+ <td><span class:list={["chip", section.riskyChangeReview ? "amber" : "green"]}>{section.riskyChangeReview ? "Review required" : "No blocker"}</span></td>
149
+ <td class="action"><button class="btn" type="button">{section.riskyChangeReview ? "Review" : "Manage"}</button></td>
150
+ </tr>
151
+ ))}
152
+ </tbody>
153
+ </table>
154
+ </div>
155
+ </div>
156
+ </div>
157
+
158
+ <div id="settings-checkout-styling" class="panel" data-agent-scope="settings-checkout-styling">
159
+ <div class="panel-head settings-panel-head">
160
+ <h3><svg><use href="#i-card"></use></svg>Checkout styling</h3>
161
+ <span class="chip blue">Versioned publish</span>
162
+ </div>
163
+ <div class="panel-body grid">
164
+ <p class="note">
165
+ Style the hosted checkout your buyers see. Saving publishes a versioned
166
+ draft to your <b>test</b> environment — preview it, then promote it live
167
+ from the go-live gate. Keep values ASCII-only; the checkout cache is not
168
+ Unicode-safe.
169
+ </p>
170
+
171
+ <form class="checkout-style-editor" data-checkout-style-form data-endpoint={checkoutStyleEndpoint} data-target-tenant={settings.targetTenant}>
172
+ <div class="grid cols-2">
173
+ <div class="cs-fields">
174
+ <fieldset class="cs-fieldset">
175
+ <legend>Colors</legend>
176
+ <div class="cs-color-grid">
177
+ {colorFields.map((f) => (
178
+ <div class="cs-color-row">
179
+ <span class="cs-swatch" data-cs-swatch={`colors.${f.key}`} style={`background:${checkoutStyle.colors[f.key]}`} aria-hidden="true"></span>
180
+ <label for={`cs-color-${f.key}`}>{f.label}</label>
181
+ <input
182
+ id={`cs-color-${f.key}`}
183
+ type="text"
184
+ spellcheck="false"
185
+ autocomplete="off"
186
+ data-cs-field={`colors.${f.key}`}
187
+ value={checkoutStyle.colors[f.key]}
188
+ />
189
+ </div>
190
+ ))}
191
+ </div>
192
+ </fieldset>
193
+
194
+ <fieldset class="cs-fieldset">
195
+ <legend>Typography &amp; shape</legend>
196
+ <div class="cs-field">
197
+ <label for="cs-font-family">Font family</label>
198
+ <input id="cs-font-family" type="text" spellcheck="false" autocomplete="off" data-cs-field="typography.fontFamily" value={checkoutStyle.typography.fontFamily} />
199
+ </div>
200
+ <div class="cs-field-row">
201
+ <div class="cs-field">
202
+ <label for="cs-base-size">Base size</label>
203
+ <input id="cs-base-size" type="text" spellcheck="false" autocomplete="off" data-cs-field="typography.baseSize" value={checkoutStyle.typography.baseSize} />
204
+ </div>
205
+ <div class="cs-field">
206
+ <label for="cs-radius">Button radius</label>
207
+ <input id="cs-radius" type="text" spellcheck="false" autocomplete="off" data-cs-field="button.radius" value={checkoutStyle.button.radius} />
208
+ </div>
209
+ </div>
210
+ <div class="cs-field">
211
+ <label for="cs-logo">Logo URL (optional)</label>
212
+ <input id="cs-logo" type="url" spellcheck="false" autocomplete="off" placeholder="https://…" data-cs-field="logoUrl" value={checkoutStyle.logoUrl ?? ""} />
213
+ </div>
214
+ </fieldset>
215
+ </div>
216
+
217
+ <div class="cs-preview-wrap">
218
+ <span class="cs-preview-label">Live preview</span>
219
+ <div class="cs-preview" data-cs-preview style={previewVars}>
220
+ <div class="cs-preview-card">
221
+ <div class="cs-preview-brand">
222
+ <img data-cs-logo src={checkoutStyle.logoUrl || undefined} alt="" hidden={!checkoutStyle.logoUrl} />
223
+ <strong>Checkout</strong>
224
+ </div>
225
+ <div class="cs-preview-line"><span>Order total</span><b>$48.00</b></div>
226
+ <a class="cs-preview-link" href="#settings-checkout-styling" data-checkout-styling-noop>Have a coupon code?</a>
227
+ <button class="cs-preview-pay" type="button" tabindex="-1">Pay now</button>
228
+ </div>
229
+ </div>
230
+ </div>
231
+ </div>
232
+
233
+ <div class="cs-actions">
234
+ <button class="btn primary" type="button" data-checkout-style-save><svg><use href="#i-check"></use></svg>Save checkout styling</button>
235
+ <p class="note cs-status" data-checkout-style-status role="status" aria-live="polite"></p>
236
+ </div>
237
+ </form>
238
+ </div>
239
+ </div>
240
+
241
+ <div class="panel">
242
+ <div class="panel-head settings-panel-head">
243
+ <h3><svg><use href="#i-truck"></use></svg>Shipping Restrictions</h3>
244
+ <span class:list={["chip", settings.shippingRestrictions.length > 0 ? "amber" : "green"]}>
245
+ {settings.shippingRestrictions.length > 0 ? `${settings.shippingRestrictions.length} active` : "None"}
246
+ </span>
247
+ </div>
248
+ <div class="panel-body grid">
249
+ {settings.shippingRestrictions.length === 0 ? (
250
+ <p class="note">No destination or product shipping restrictions on file for this tenant.</p>
251
+ ) : (
252
+ <div class="readiness-list" aria-label="Shipping restrictions">
253
+ {settings.shippingRestrictions.map((restriction) => (
254
+ <div class="check-row blocking">
255
+ <div><b>{restriction.region}</b><p>{restriction.reason}</p></div>
256
+ <span class="chip amber">Action</span>
257
+ </div>
258
+ ))}
259
+ </div>
260
+ )}
261
+ </div>
262
+ </div>
263
+
264
+ <AdminFoxyCartSettingsPanel envelope={envelope} />
265
+
266
+ <div class="grid cols-2">
267
+ <div class="panel">
268
+ <div class="panel-head">
269
+ <h3><svg><use href="#i-alert"></use></svg>AI / Admin Policy</h3>
270
+ <span class="chip blue">Guardrails</span>
271
+ </div>
272
+ <div class="panel-body grid">
273
+ <div class="policy-row">
274
+ <div>
275
+ <b>AI drafting mode</b>
276
+ <p>{APPROVAL_MODE_DETAIL[settings.aiPolicyMode] ?? ""}</p>
277
+ </div>
278
+ <span class="chip blue">{APPROVAL_MODE_LABEL[settings.aiPolicyMode] ?? settings.aiPolicyMode}</span>
279
+ </div>
280
+ <div class="policy-row">
281
+ <div>
282
+ <b>Internal tenant picker</b>
283
+ <p>Only internal staff sessions can see or use the "Operating as" tenant picker in the admin shell.</p>
284
+ </div>
285
+ <span class:list={["chip", settings.internalTenantPickerEnabled ? "teal" : ""]}>
286
+ {settings.internalTenantPickerEnabled ? "Enabled" : "Disabled"}
287
+ </span>
288
+ </div>
289
+ <div class="policy-row">
290
+ <div>
291
+ <b>Risky policy changes</b>
292
+ <p>{riskyCount} of {settings.sections.length} sections require review before a change takes effect.</p>
293
+ </div>
294
+ <span class="chip blue">Require review</span>
295
+ </div>
296
+ </div>
297
+ </div>
298
+
299
+ <div class="panel">
300
+ <div class="panel-head">
301
+ <h3><svg><use href="#i-file"></use></svg>Audit Activity</h3>
302
+ <button class="btn" type="button"><svg><use href="#i-export"></use></svg>Export</button>
303
+ </div>
304
+ <div class="panel-body grid">
305
+ {settings.auditTrail.length === 0 ? (
306
+ <p class="note">No audited changes yet for this tenant.</p>
307
+ ) : (
308
+ settings.auditTrail.map((event) => (
309
+ <div class="audit-row">
310
+ <time datetime={event.at}>{new Date(event.at).toLocaleString()}</time>
311
+ <div>
312
+ <b>{formatChangeSummary(event.change)}</b>
313
+ <p>{event.operator} &middot; {event.targetTenant}</p>
314
+ </div>
315
+ <span class="chip teal">Logged</span>
316
+ </div>
317
+ ))
318
+ )}
319
+ </div>
320
+ </div>
321
+ </div>
322
+ </div>
323
+ </div>
324
+ </section>
325
+
326
+ <script is:inline nonce={cspNonce}>
327
+ (() => {
328
+ const form = document.querySelector("[data-checkout-style-form]");
329
+ if (!form) return;
330
+ const endpoint = form.dataset.endpoint || "/api/preview/checkout-style";
331
+ // The tenant this save targets — the routed tenant for a merchant, or the
332
+ // staff picker's "operating as" tenant. The endpoint re-authorizes it.
333
+ const targetTenant = form.dataset.targetTenant || "";
334
+ const preview = form.querySelector("[data-cs-preview]");
335
+ const logoImg = form.querySelector("[data-cs-logo]");
336
+ const status = form.querySelector("[data-checkout-style-status]");
337
+ const saveBtn = form.querySelector("[data-checkout-style-save]");
338
+
339
+ // data-cs-field → the preview CSS custom property it drives.
340
+ const CSS_VAR = {
341
+ "colors.background": "--cs-bg",
342
+ "colors.surface": "--cs-surface",
343
+ "colors.primary": "--cs-primary",
344
+ "colors.primaryContrast": "--cs-primary-contrast",
345
+ "colors.accent": "--cs-accent",
346
+ "colors.text": "--cs-text",
347
+ "typography.fontFamily": "--cs-font",
348
+ "typography.baseSize": "--cs-size",
349
+ "button.radius": "--cs-radius",
350
+ };
351
+
352
+ const fields = Array.from(form.querySelectorAll("[data-cs-field]"));
353
+
354
+ const setStatus = (message, state) => {
355
+ if (!status) return;
356
+ status.textContent = message;
357
+ if (state) status.dataset.state = state;
358
+ else delete status.dataset.state;
359
+ };
360
+
361
+ // Reflect edits into the preview live. Inline style ATTRIBUTES are the one
362
+ // CSP-tolerated relaxation (style-src-attr 'unsafe-inline'); no <style> tag is
363
+ // injected, so script-src/style-src stay fully strict.
364
+ const applyPreview = () => {
365
+ for (const el of fields) {
366
+ const path = el.dataset.csField;
367
+ const value = el.value.trim();
368
+ const cssVar = CSS_VAR[path];
369
+ if (cssVar && preview) preview.style.setProperty(cssVar, value);
370
+ const swatch = form.querySelector('[data-cs-swatch="' + path + '"]');
371
+ if (swatch) swatch.style.background = value;
372
+ if (path === "logoUrl" && logoImg) {
373
+ if (value) {
374
+ logoImg.src = value;
375
+ logoImg.hidden = false;
376
+ } else {
377
+ logoImg.removeAttribute("src");
378
+ logoImg.hidden = true;
379
+ }
380
+ }
381
+ }
382
+ };
383
+
384
+ // Gather the fields into the CheckoutStyle partial the save endpoint validates.
385
+ const collect = () => {
386
+ const style = { colors: {}, typography: {}, button: {} };
387
+ for (const el of fields) {
388
+ const path = el.dataset.csField;
389
+ const value = el.value.trim();
390
+ if (path === "logoUrl") {
391
+ if (value) style.logoUrl = value;
392
+ continue;
393
+ }
394
+ const dot = path.indexOf(".");
395
+ const group = path.slice(0, dot);
396
+ const key = path.slice(dot + 1);
397
+ if (style[group]) style[group][key] = value;
398
+ }
399
+ return style;
400
+ };
401
+
402
+ for (const el of fields) {
403
+ el.addEventListener("input", applyPreview);
404
+ }
405
+
406
+ saveBtn?.addEventListener("click", async () => {
407
+ setStatus("Saving…");
408
+ saveBtn.disabled = true;
409
+ try {
410
+ const res = await fetch(endpoint, {
411
+ method: "POST",
412
+ headers: { "content-type": "application/json" },
413
+ body: JSON.stringify(targetTenant ? { ...collect(), targetTenant } : collect()),
414
+ });
415
+ let data = {};
416
+ try {
417
+ data = await res.json();
418
+ } catch {
419
+ /* non-JSON error body */
420
+ }
421
+ if (res.ok) {
422
+ const v = typeof data.versionId === "string" ? data.versionId.slice(0, 8) : "";
423
+ setStatus(v ? "Saved to test · version " + v : "Saved to test", "ok");
424
+ } else {
425
+ const detail =
426
+ Array.isArray(data.errors) && data.errors.length
427
+ ? data.errors.join("; ")
428
+ : data.error || "Save failed (" + res.status + ")";
429
+ setStatus(detail, "err");
430
+ }
431
+ } catch {
432
+ setStatus("Save failed — network error", "err");
433
+ } finally {
434
+ saveBtn.disabled = false;
435
+ }
436
+ });
437
+
438
+ // Preview coupon link is illustrative only; don't navigate.
439
+ form.querySelector("[data-checkout-styling-noop]")?.addEventListener("click", (e) => e.preventDefault());
440
+ })();
441
+ </script>
442
+
443
+ <style>
444
+ .settings-workspace {
445
+ display: grid;
446
+ grid-template-columns: minmax(240px, 300px) minmax(0, 1fr);
447
+ gap: 14px;
448
+ align-items: start;
449
+ }
450
+
451
+ .settings-menu,
452
+ .settings-detail {
453
+ min-width: 0;
454
+ }
455
+
456
+ .settings-menu {
457
+ position: sticky;
458
+ top: 84px;
459
+ display: grid;
460
+ gap: 10px;
461
+ max-height: calc(100vh - 104px);
462
+ overflow: auto;
463
+ }
464
+
465
+ .settings-search {
466
+ display: grid;
467
+ gap: 6px;
468
+ padding: 12px;
469
+ border: 1px solid var(--admin-line);
470
+ border-radius: var(--admin-radius);
471
+ background: var(--admin-surface);
472
+ }
473
+
474
+ .settings-search label {
475
+ color: var(--admin-muted);
476
+ font-size: 11px;
477
+ font-weight: 760;
478
+ text-transform: uppercase;
479
+ }
480
+
481
+ .settings-search input {
482
+ width: 100%;
483
+ min-height: 38px;
484
+ padding: 0 10px;
485
+ border: 1px solid var(--admin-line-strong);
486
+ border-radius: var(--admin-radius-sm);
487
+ background: var(--admin-surface);
488
+ color: var(--admin-ink);
489
+ }
490
+
491
+ .settings-section-list {
492
+ display: grid;
493
+ gap: 6px;
494
+ }
495
+
496
+ .settings-section-link {
497
+ display: grid;
498
+ grid-template-columns: minmax(0, 1fr) auto;
499
+ gap: 10px;
500
+ align-items: center;
501
+ min-height: 58px;
502
+ padding: 10px;
503
+ border: 1px solid var(--admin-line);
504
+ border-radius: var(--admin-radius-sm);
505
+ background: var(--admin-surface);
506
+ color: var(--admin-ink);
507
+ text-decoration: none;
508
+ }
509
+
510
+ .settings-section-link.active {
511
+ border-color: #8bcac4;
512
+ background: var(--admin-teal-soft);
513
+ }
514
+
515
+ .settings-section-link strong,
516
+ .settings-section-link small {
517
+ display: block;
518
+ overflow-wrap: anywhere;
519
+ }
520
+
521
+ .settings-section-link small {
522
+ margin-top: 2px;
523
+ color: var(--admin-muted);
524
+ font-size: 12px;
525
+ }
526
+
527
+ .settings-detail {
528
+ display: grid;
529
+ gap: 14px;
530
+ }
531
+
532
+ .settings-panel-head {
533
+ flex-wrap: wrap;
534
+ }
535
+
536
+ .settings-table {
537
+ min-width: 640px;
538
+ }
539
+
540
+ .readiness-list {
541
+ display: grid;
542
+ gap: 0;
543
+ }
544
+
545
+ .policy-row,
546
+ .audit-row {
547
+ display: grid;
548
+ gap: 10px;
549
+ align-items: center;
550
+ padding: 10px 0;
551
+ border-bottom: 1px solid var(--admin-line);
552
+ }
553
+
554
+ .policy-row {
555
+ grid-template-columns: minmax(0, 1fr) auto;
556
+ }
557
+
558
+ .audit-row {
559
+ grid-template-columns: 150px minmax(0, 1fr) auto;
560
+ }
561
+
562
+ .policy-row:last-child,
563
+ .audit-row:last-child {
564
+ border-bottom: 0;
565
+ }
566
+
567
+ .policy-row b,
568
+ .audit-row b {
569
+ display: block;
570
+ font-size: 13px;
571
+ }
572
+
573
+ .policy-row p,
574
+ .audit-row p {
575
+ margin: 2px 0 0;
576
+ color: var(--admin-muted);
577
+ font-size: 12px;
578
+ }
579
+
580
+ .audit-row time {
581
+ color: var(--admin-muted);
582
+ font-size: 12px;
583
+ font-weight: 760;
584
+ }
585
+
586
+ @media (max-width: 1180px) {
587
+ .settings-workspace {
588
+ grid-template-columns: 1fr;
589
+ }
590
+
591
+ .settings-menu {
592
+ position: static;
593
+ max-height: none;
594
+ overflow: visible;
595
+ }
596
+
597
+ .settings-section-list {
598
+ grid-template-columns: repeat(2, minmax(0, 1fr));
599
+ }
600
+ }
601
+
602
+ @media (max-width: 720px) {
603
+ .settings-section-list,
604
+ .policy-row,
605
+ .audit-row {
606
+ grid-template-columns: 1fr;
607
+ }
608
+ }
609
+
610
+ /* Checkout styling editor (U12) */
611
+ .checkout-style-editor {
612
+ display: grid;
613
+ gap: 14px;
614
+ }
615
+
616
+ .cs-fields {
617
+ display: grid;
618
+ gap: 12px;
619
+ min-width: 0;
620
+ }
621
+
622
+ .cs-fieldset {
623
+ display: grid;
624
+ gap: 10px;
625
+ margin: 0;
626
+ padding: 12px;
627
+ border: 1px solid var(--admin-line);
628
+ border-radius: var(--admin-radius-sm);
629
+ background: #fcfdfc;
630
+ }
631
+
632
+ .cs-fieldset legend {
633
+ padding: 0 4px;
634
+ color: var(--admin-muted);
635
+ font-size: 11px;
636
+ font-weight: 760;
637
+ text-transform: uppercase;
638
+ }
639
+
640
+ .cs-color-grid {
641
+ display: grid;
642
+ gap: 8px;
643
+ }
644
+
645
+ .cs-color-row {
646
+ display: grid;
647
+ grid-template-columns: 24px minmax(90px, 0.5fr) minmax(0, 1fr);
648
+ gap: 8px;
649
+ align-items: center;
650
+ }
651
+
652
+ .cs-swatch {
653
+ width: 24px;
654
+ height: 24px;
655
+ border: 1px solid var(--admin-line-strong);
656
+ border-radius: var(--admin-radius-sm);
657
+ }
658
+
659
+ .cs-color-row label,
660
+ .cs-field label {
661
+ color: var(--admin-muted);
662
+ font-size: 12px;
663
+ font-weight: 680;
664
+ }
665
+
666
+ .cs-field {
667
+ display: grid;
668
+ gap: 5px;
669
+ min-width: 0;
670
+ }
671
+
672
+ .cs-field-row {
673
+ display: grid;
674
+ grid-template-columns: repeat(2, minmax(0, 1fr));
675
+ gap: 10px;
676
+ }
677
+
678
+ .checkout-style-editor input {
679
+ width: 100%;
680
+ min-width: 0;
681
+ min-height: 36px;
682
+ padding: 0 10px;
683
+ border: 1px solid var(--admin-line-strong);
684
+ border-radius: var(--admin-radius-sm);
685
+ background: var(--admin-surface);
686
+ color: var(--admin-ink);
687
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
688
+ font-size: 12px;
689
+ }
690
+
691
+ .cs-preview-wrap {
692
+ display: grid;
693
+ gap: 6px;
694
+ align-content: start;
695
+ }
696
+
697
+ .cs-preview-label {
698
+ color: var(--admin-muted);
699
+ font-size: 11px;
700
+ font-weight: 760;
701
+ text-transform: uppercase;
702
+ }
703
+
704
+ .cs-preview {
705
+ display: grid;
706
+ place-items: center;
707
+ padding: 18px;
708
+ border: 1px solid var(--admin-line);
709
+ border-radius: var(--admin-radius);
710
+ background: var(--cs-bg, #ffffff);
711
+ }
712
+
713
+ .cs-preview-card {
714
+ display: grid;
715
+ gap: 12px;
716
+ width: 100%;
717
+ max-width: 280px;
718
+ padding: 16px;
719
+ border: 1px solid rgba(0, 0, 0, 0.08);
720
+ border-radius: var(--cs-radius, 6px);
721
+ background: var(--cs-surface, #f7f7f8);
722
+ color: var(--cs-text, #1a1a1a);
723
+ font-family: var(--cs-font, system-ui, sans-serif);
724
+ font-size: var(--cs-size, 16px);
725
+ }
726
+
727
+ .cs-preview-brand {
728
+ display: flex;
729
+ align-items: center;
730
+ gap: 8px;
731
+ color: var(--cs-primary, #111111);
732
+ }
733
+
734
+ .cs-preview-brand img {
735
+ max-height: 24px;
736
+ max-width: 96px;
737
+ }
738
+
739
+ .cs-preview-line {
740
+ display: flex;
741
+ align-items: center;
742
+ justify-content: space-between;
743
+ font-size: 0.85em;
744
+ }
745
+
746
+ .cs-preview-link {
747
+ color: var(--cs-accent, #2563eb);
748
+ font-size: 0.8em;
749
+ text-decoration: none;
750
+ }
751
+
752
+ .cs-preview-pay {
753
+ min-height: 40px;
754
+ border: 0;
755
+ border-radius: var(--cs-radius, 6px);
756
+ background: var(--cs-primary, #111111);
757
+ color: var(--cs-primary-contrast, #ffffff);
758
+ font: inherit;
759
+ font-weight: 680;
760
+ }
761
+
762
+ .cs-actions {
763
+ display: flex;
764
+ flex-wrap: wrap;
765
+ align-items: center;
766
+ gap: 12px;
767
+ }
768
+
769
+ .cs-status[data-state="ok"] {
770
+ color: var(--admin-green);
771
+ }
772
+
773
+ .cs-status[data-state="err"] {
774
+ color: var(--admin-red);
775
+ }
776
+
777
+ @media (max-width: 720px) {
778
+ .cs-field-row {
779
+ grid-template-columns: 1fr;
780
+ }
781
+ }
782
+ </style>