@mohasinac/appkit 4.53.1 → 4.54.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 (384) hide show
  1. package/dist/.build-stamp.json +3 -3
  2. package/dist/_internal/client/theme/ThemeProvider.js +15 -1
  3. package/dist/_internal/server/features/auth/capabilities.js +7 -5
  4. package/dist/_internal/server/features/categories/price-guidance-resolve.d.ts +66 -0
  5. package/dist/_internal/server/features/categories/price-guidance-resolve.js +138 -0
  6. package/dist/_internal/server/features/checkout/actions.d.ts +22 -6
  7. package/dist/_internal/server/features/checkout/actions.js +96 -51
  8. package/dist/_internal/server/features/checkout/index.d.ts +1 -1
  9. package/dist/_internal/server/features/checkout/index.js +1 -1
  10. package/dist/_internal/server/features/checkout/supplier-identity.js +28 -6
  11. package/dist/_internal/server/features/orders/adapters.js +1 -3
  12. package/dist/_internal/server/features/price-index/market.d.ts +57 -0
  13. package/dist/_internal/server/features/price-index/market.js +120 -0
  14. package/dist/_internal/server/features/products/list-public.d.ts +12 -0
  15. package/dist/_internal/server/features/products/list-public.js +10 -1
  16. package/dist/_internal/server/features/products/listing-tab-counts.d.ts +25 -1
  17. package/dist/_internal/server/features/products/listing-tab-counts.js +184 -10
  18. package/dist/_internal/server/features/search/index-build/sources.js +43 -2
  19. package/dist/_internal/server/features/site-settings/adapters.js +1 -1
  20. package/dist/_internal/server/features/stores/adapters.d.ts +1 -1
  21. package/dist/_internal/server/features/stores/adapters.js +0 -1
  22. package/dist/_internal/server/features/stores/tabs.d.ts +7 -2
  23. package/dist/_internal/server/features/stores/tabs.js +5 -3
  24. package/dist/_internal/server/jobs/core/analyticsAlertEvaluate.js +2 -5
  25. package/dist/_internal/server/jobs/core/jobRunners.js +0 -10
  26. package/dist/_internal/server/jobs/core/onOrderCreate.js +10 -104
  27. package/dist/_internal/server/jobs/core/onOrderStatusChange.d.ts +0 -2
  28. package/dist/_internal/server/jobs/core/onOrderStatusChange.js +0 -1
  29. package/dist/_internal/server/jobs/core/onScamReportCreate.js +0 -1
  30. package/dist/_internal/server/jobs/core/onScamReportRejected.js +0 -1
  31. package/dist/_internal/server/jobs/core/onScamReportVerified.js +0 -1
  32. package/dist/_internal/server/jobs/core/paymentWindowTimeout.js +0 -1
  33. package/dist/_internal/server/jobs/core/pendingOrderTimeout.js +0 -1
  34. package/dist/_internal/server/notifications/channel-health.d.ts +7 -3
  35. package/dist/_internal/server/notifications/channel-health.js +2 -2
  36. package/dist/_internal/server/notifications/send-guard.d.ts +1 -1
  37. package/dist/_internal/server/notifications/send-guard.js +2 -4
  38. package/dist/_internal/shared/actions/action-registry.d.ts +1 -1
  39. package/dist/_internal/shared/actions/action-registry.js +128 -28
  40. package/dist/_internal/shared/checkout/order-math.d.ts +1 -1
  41. package/dist/_internal/shared/checkout/order-math.js +1 -1
  42. package/dist/_internal/shared/features/categories/bundle-copy.d.ts +1 -1
  43. package/dist/_internal/shared/features/checkout/config.d.ts +0 -2
  44. package/dist/_internal/shared/features/checkout/config.js +0 -2
  45. package/dist/_internal/shared/features/messaging/config.d.ts +7 -5
  46. package/dist/_internal/shared/features/messaging/config.js +1 -4
  47. package/dist/_internal/shared/features/site-settings/fees.d.ts +0 -2
  48. package/dist/_internal/shared/features/site-settings/fees.js +0 -2
  49. package/dist/_internal/shared/features/site-settings/supplier-of-record.d.ts +56 -0
  50. package/dist/_internal/shared/features/site-settings/supplier-of-record.js +57 -0
  51. package/dist/_internal/shared/fees/calculator.d.ts +0 -8
  52. package/dist/_internal/shared/fees/calculator.js +0 -7
  53. package/dist/_internal/shared/listing-types/tiers.d.ts +94 -0
  54. package/dist/_internal/shared/listing-types/tiers.js +150 -0
  55. package/dist/_internal/shared/search/match.js +28 -2
  56. package/dist/cli/index.js +0 -2
  57. package/dist/client.d.ts +25 -4
  58. package/dist/client.js +36 -5
  59. package/dist/constants/api-endpoints.d.ts +28 -15
  60. package/dist/constants/api-endpoints.js +14 -8
  61. package/dist/constants/field-names.d.ts +1 -0
  62. package/dist/constants/field-names.js +1 -0
  63. package/dist/constants/notification-types.d.ts +1 -1
  64. package/dist/constants/notification-types.js +1 -1
  65. package/dist/core/integration-keys.d.ts +5 -5
  66. package/dist/core/integration-keys.js +21 -10
  67. package/dist/features/about/components/FeesView.js +0 -6
  68. package/dist/features/about/components/GuidesHubView.js +15 -2
  69. package/dist/features/account/components/NotificationPreferencesPanel.js +3 -4
  70. package/dist/features/account/components/UserOrdersView.js +26 -7
  71. package/dist/features/account/types/index.d.ts +0 -2
  72. package/dist/features/addresses/utils/postal-autofill.d.ts +39 -0
  73. package/dist/features/addresses/utils/postal-autofill.js +54 -0
  74. package/dist/features/admin/actions/notification-actions.d.ts +2 -8
  75. package/dist/features/admin/actions/notification-actions.js +9 -104
  76. package/dist/features/admin/components/AdminGuideHubView.js +1 -8
  77. package/dist/features/admin/components/AdminOrderEditorView.d.ts +1 -1
  78. package/dist/features/admin/components/AdminOrdersView.js +0 -2
  79. package/dist/features/admin/components/AdminSectionsView.js +3 -2
  80. package/dist/features/admin/components/AdminSiteSettingsView.js +22 -68
  81. package/dist/features/admin/components/AdminStoreEditorView.js +72 -34
  82. package/dist/features/admin/components/OwnerQuickActions.d.ts +29 -0
  83. package/dist/features/admin/components/OwnerQuickActions.js +142 -0
  84. package/dist/features/admin/components/sections/adminSectionsTypes.js +13 -4
  85. package/dist/features/admin/components/sections/icon-options.d.ts +21 -0
  86. package/dist/features/admin/components/sections/icon-options.js +23 -0
  87. package/dist/features/admin/components/sections/sectionTemplates.js +4 -1
  88. package/dist/features/admin/constants/site-settings-tabs.d.ts +7 -12
  89. package/dist/features/admin/constants/site-settings-tabs.js +6 -12
  90. package/dist/features/admin/repository/site-settings.repository.js +1 -1
  91. package/dist/features/admin/schemas/admin-editor-forms.d.ts +1 -1
  92. package/dist/features/admin/schemas/admin-editor-forms.js +4 -1
  93. package/dist/features/admin/schemas/admin-user-form.d.ts +0 -61
  94. package/dist/features/admin/schemas/admin-user-form.js +3 -44
  95. package/dist/features/admin/schemas/firestore.d.ts +28 -54
  96. package/dist/features/admin/schemas/firestore.js +40 -18
  97. package/dist/features/auctions/components/AuctionDetailPageView.js +12 -10
  98. package/dist/features/auctions/components/MarketplaceAuctionCard.d.ts +11 -1
  99. package/dist/features/auctions/components/MarketplaceAuctionCard.js +9 -2
  100. package/dist/features/auth/checkout-value-otp.d.ts +1 -1
  101. package/dist/features/auth/checkout-value-otp.js +1 -1
  102. package/dist/features/auth/permissions/constants.d.ts +29 -2
  103. package/dist/features/auth/permissions/constants.js +67 -1
  104. package/dist/features/blog/components/BlogFeaturedCard.d.ts +11 -1
  105. package/dist/features/blog/components/BlogFeaturedCard.js +9 -2
  106. package/dist/features/cart/components/CartDrawer.js +3 -2
  107. package/dist/features/cart/components/CartGroupLineRow.js +2 -1
  108. package/dist/features/cart/components/CartPriceBreakdown.d.ts +0 -2
  109. package/dist/features/cart/components/CartPriceBreakdown.js +1 -1
  110. package/dist/features/cart/components/StoreAddonsPicker.d.ts +2 -5
  111. package/dist/features/cart/components/StoreAddonsPicker.js +4 -5
  112. package/dist/features/cart/hooks/useAddToCart.js +10 -5
  113. package/dist/features/cart/repository/cart.repository.js +1 -2
  114. package/dist/features/cart/schemas/firestore.d.ts +1 -2
  115. package/dist/features/cart/utils/pending-ops.d.ts +11 -1
  116. package/dist/features/cart/utils/pending-ops.js +14 -2
  117. package/dist/features/categories/api/[id]/price-guidance/route.js +1 -24
  118. package/dist/features/categories/components/BrandDetailPageView.js +15 -6
  119. package/dist/features/categories/components/BrandDetailTabs.d.ts +7 -1
  120. package/dist/features/categories/components/BrandDetailTabs.js +18 -3
  121. package/dist/features/categories/components/BundleCollage.js +3 -2
  122. package/dist/features/categories/components/BundleDetailView.js +2 -1
  123. package/dist/features/categories/components/BundleItemsPicker.js +3 -4
  124. package/dist/features/categories/components/CategoryDetailPageView.js +19 -8
  125. package/dist/features/categories/components/CategoryDetailTabs.d.ts +7 -1
  126. package/dist/features/categories/components/CategoryDetailTabs.js +29 -7
  127. package/dist/features/categories/components/CategoryGrid.d.ts +11 -1
  128. package/dist/features/categories/components/CategoryGrid.js +9 -2
  129. package/dist/features/checkout/actions/checkout-value-otp-actions.d.ts +10 -5
  130. package/dist/features/checkout/actions/checkout-value-otp-actions.js +2 -88
  131. package/dist/features/classified/components/ClassifiedDetailPageView.js +12 -2
  132. package/dist/features/digital-codes/components/DigitalCodeDetailPageView.js +12 -2
  133. package/dist/features/events/components/EventCard.d.ts +11 -1
  134. package/dist/features/events/components/EventCard.js +9 -2
  135. package/dist/features/grouped/components/GroupedListingDetailView.js +3 -1
  136. package/dist/features/homepage/components/CTABannerSection.d.ts +3 -1
  137. package/dist/features/homepage/components/CTABannerSection.js +6 -3
  138. package/dist/features/homepage/components/HeroCarousel.js +8 -6
  139. package/dist/features/homepage/components/MarketplaceHomepageView.js +33 -7
  140. package/dist/features/homepage/components/SectionCarousel.js +13 -5
  141. package/dist/features/homepage/components/SecurityHighlightsSection.d.ts +8 -3
  142. package/dist/features/homepage/components/SecurityHighlightsSection.js +2 -2
  143. package/dist/features/homepage/components/StatsCounterSection.d.ts +9 -4
  144. package/dist/features/homepage/components/StatsCounterSection.js +2 -2
  145. package/dist/features/homepage/components/TestimonialsCarousel.js +1 -1
  146. package/dist/features/homepage/components/TrustFeaturesSection.d.ts +18 -4
  147. package/dist/features/homepage/components/TrustFeaturesSection.js +5 -5
  148. package/dist/features/homepage/components/WelcomeSection.d.ts +13 -2
  149. package/dist/features/homepage/components/WelcomeSection.js +3 -3
  150. package/dist/features/homepage/components/WhatsAppCommunitySection.d.ts +28 -0
  151. package/dist/features/homepage/components/WhatsAppCommunitySection.js +42 -6
  152. package/dist/features/homepage/components/WhatsAppGlyph.d.ts +20 -0
  153. package/dist/features/homepage/components/WhatsAppGlyph.js +20 -0
  154. package/dist/features/homepage/constants/hero-carousel-styles.d.ts +8 -6
  155. package/dist/features/homepage/constants/hero-carousel-styles.js +8 -6
  156. package/dist/features/homepage/constants/section-copy.d.ts +12 -10
  157. package/dist/features/homepage/constants/section-copy.js +28 -6
  158. package/dist/features/homepage/constants/stat-icons.d.ts +12 -0
  159. package/dist/features/homepage/constants/stat-icons.js +17 -0
  160. package/dist/features/homepage/constants/trust-icon-aliases.d.ts +8 -0
  161. package/dist/features/homepage/constants/trust-icon-aliases.js +75 -0
  162. package/dist/features/homepage/lib/section-defaults.d.ts +16 -1
  163. package/dist/features/homepage/lib/section-defaults.js +24 -4
  164. package/dist/features/homepage/lib/section-renderer.js +48 -8
  165. package/dist/features/homepage/schemas/firestore.d.ts +18 -1
  166. package/dist/features/layout/AppLayoutShell.js +2 -1
  167. package/dist/features/layout/BottomActions.d.ts +1 -0
  168. package/dist/features/layout/BottomActions.js +330 -0
  169. package/dist/features/layout/BottomChrome.d.ts +45 -0
  170. package/dist/features/layout/BottomChrome.js +5 -17
  171. package/dist/features/layout/SideActionDock.js +36 -13
  172. package/dist/features/layout/index.d.ts +2 -7
  173. package/dist/features/layout/index.js +7 -7
  174. package/dist/features/layout/useIsDesktop.d.ts +36 -0
  175. package/dist/features/layout/useIsDesktop.js +48 -0
  176. package/dist/features/live/components/LiveItemDetailPageView.js +12 -2
  177. package/dist/features/orders/actions/refund-actions.js +0 -1
  178. package/dist/features/orders/components/OrderAddonBadges.d.ts +1 -3
  179. package/dist/features/orders/components/OrderAddonBadges.js +3 -4
  180. package/dist/features/orders/components/OrderPaymentSummary.js +15 -2
  181. package/dist/features/orders/components/YourPurchaseStrip.d.ts +24 -0
  182. package/dist/features/orders/components/YourPurchaseStrip.js +77 -0
  183. package/dist/features/orders/components/index.d.ts +2 -1
  184. package/dist/features/orders/components/index.js +1 -1
  185. package/dist/features/orders/repository/orders.repository.d.ts +0 -8
  186. package/dist/features/orders/repository/orders.repository.js +0 -2
  187. package/dist/features/orders/schemas/firestore.d.ts +17 -9
  188. package/dist/features/orders/types/index.d.ts +2 -5
  189. package/dist/features/orders/utils/order-announcement-message.d.ts +18 -0
  190. package/dist/features/orders/utils/order-announcement-message.js +16 -0
  191. package/dist/features/orders/utils/payment-proof-message.d.ts +20 -0
  192. package/dist/features/orders/utils/payment-proof-message.js +17 -0
  193. package/dist/features/parts/components/PartDetailPageView.js +96 -1
  194. package/dist/features/parts/schemas/firestore.d.ts +247 -0
  195. package/dist/features/parts/schemas/firestore.js +6 -6
  196. package/dist/features/pre-orders/components/MarketplacePreorderCard.d.ts +11 -1
  197. package/dist/features/pre-orders/components/MarketplacePreorderCard.js +10 -3
  198. package/dist/features/pre-orders/components/PreOrderDetailPageView.js +12 -10
  199. package/dist/features/price-index/components/PriceIndexToolView.d.ts +21 -0
  200. package/dist/features/price-index/components/PriceIndexToolView.js +230 -27
  201. package/dist/features/price-index/lookup-target.d.ts +48 -0
  202. package/dist/features/price-index/lookup-target.js +107 -0
  203. package/dist/features/products/api/[id]/route.js +8 -1
  204. package/dist/features/products/api/route.js +16 -4
  205. package/dist/features/products/components/AvailabilityScopeHint.d.ts +22 -0
  206. package/dist/features/products/components/AvailabilityScopeHint.js +27 -0
  207. package/dist/features/products/components/CompareOverlay.d.ts +2 -1
  208. package/dist/features/products/components/CompareOverlay.js +2 -1
  209. package/dist/features/products/components/GroupSettingsPanel.js +2 -1
  210. package/dist/features/products/components/InteractiveProductCard.d.ts +7 -1
  211. package/dist/features/products/components/InteractiveProductCard.js +16 -4
  212. package/dist/features/products/components/MarketplaceBundleCard.d.ts +11 -1
  213. package/dist/features/products/components/MarketplaceBundleCard.js +9 -2
  214. package/dist/features/products/components/MarketplacePrizeDrawCard.d.ts +11 -1
  215. package/dist/features/products/components/MarketplacePrizeDrawCard.js +9 -2
  216. package/dist/features/products/components/PrizeDrawDetailPageView.js +2 -1
  217. package/dist/features/products/components/ProductDetailPageView.js +34 -4
  218. package/dist/features/products/components/ProductGrid.d.ts +14 -1
  219. package/dist/features/products/components/ProductGrid.js +22 -5
  220. package/dist/features/products/components/ProductsIndexListing.js +2 -2
  221. package/dist/features/products/components/SublistingCarouselSection.js +2 -1
  222. package/dist/features/products/repository/products.repository.d.ts +1 -0
  223. package/dist/features/products/repository/products.repository.js +5 -1
  224. package/dist/features/products/utils/group-member-image.d.ts +9 -2
  225. package/dist/features/products/utils/group-member-image.js +2 -1
  226. package/dist/features/reviews/api/[id]/route.js +83 -23
  227. package/dist/features/reviews/components/PurchaseReviewAffordance.d.ts +6 -0
  228. package/dist/features/reviews/components/PurchaseReviewAffordance.js +42 -0
  229. package/dist/features/reviews/components/ReviewFormDrawer.d.ts +34 -0
  230. package/dist/features/reviews/components/ReviewFormDrawer.js +127 -0
  231. package/dist/features/reviews/components/index.d.ts +4 -0
  232. package/dist/features/reviews/components/index.js +2 -0
  233. package/dist/features/scams/schemas/index.d.ts +10 -10
  234. package/dist/features/search/action-index/settings-entries.js +0 -9
  235. package/dist/features/seller/actions/seller-actions.d.ts +1 -1
  236. package/dist/features/seller/actions/seller-actions.js +49 -3
  237. package/dist/features/seller/components/SellerPayoutSettingsView.js +30 -2
  238. package/dist/features/seller/components/SellerProductShell.d.ts +17 -1
  239. package/dist/features/seller/components/SellerProductsView.js +3 -2
  240. package/dist/features/seller/hooks/useStoreListingEntitlements.d.ts +8 -0
  241. package/dist/features/seller/hooks/useStoreListingEntitlements.js +70 -0
  242. package/dist/features/store-extensions/repository/store-extensions.repositories.d.ts +1 -6
  243. package/dist/features/store-extensions/repository/store-extensions.repositories.js +1 -10
  244. package/dist/features/store-extensions/schemas/firestore.d.ts +1 -17
  245. package/dist/features/store-extensions/schemas/firestore.js +0 -10
  246. package/dist/features/stores/components/InteractiveStoreCard.d.ts +11 -1
  247. package/dist/features/stores/components/InteractiveStoreCard.js +9 -2
  248. package/dist/features/stores/components/StoreAuctionsListing.js +2 -1
  249. package/dist/features/stores/components/StoreCapabilitiesGuideView.js +0 -1
  250. package/dist/features/stores/components/StoreGuideHubView.js +2 -8
  251. package/dist/features/stores/components/StoreSettingsGuideView.js +2 -6
  252. package/dist/features/stores/components/index.d.ts +0 -2
  253. package/dist/features/stores/components/index.js +0 -1
  254. package/dist/features/stores/repository/store.repository.d.ts +1 -26
  255. package/dist/features/stores/repository/store.repository.js +5 -60
  256. package/dist/features/stores/schemas/firestore.d.ts +6 -25
  257. package/dist/features/stores/schemas/firestore.js +6 -3
  258. package/dist/features/stores/schemas/index.d.ts +1 -87
  259. package/dist/features/stores/schemas/index.js +10 -15
  260. package/dist/features/tester/seed-data/authored/admin__site-system.js +0 -48
  261. package/dist/features/tester/seed-data/authored/buying__buying-checkout.js +0 -40
  262. package/dist/features/tester/seed-data/authored/content-discovery__authenticity-checker.js +114 -2
  263. package/dist/features/tester/seed-data/authored/selling__quick-add-minimum-details.js +0 -16
  264. package/dist/features/tester/seed-data/authored/selling__seller-guide.js +1 -1
  265. package/dist/features/tester/seed-data/authored/selling__seller-marketing-extras.js +0 -79
  266. package/dist/features/tester/seed-data/authored/selling__seller-orders.js +1 -1
  267. package/dist/features/tester/seed-data/tester-checklist-seed-data.js +427 -69
  268. package/dist/index.d.ts +20 -32
  269. package/dist/index.js +34 -43
  270. package/dist/next/routing/route-map.d.ts +2 -8
  271. package/dist/next/routing/route-map.js +21 -4
  272. package/dist/providers/db-firebase/base.repository.d.ts +1 -1
  273. package/dist/providers/db-firebase/base.repository.js +1 -1
  274. package/dist/providers/payment-razorpay/index.d.ts +125 -0
  275. package/dist/providers/payment-razorpay/index.js +232 -0
  276. package/dist/providers/payment-razorpay/signature.d.ts +53 -0
  277. package/dist/providers/payment-razorpay/signature.js +71 -0
  278. package/dist/providers/shipping-shiprocket/index.d.ts +98 -0
  279. package/dist/providers/shipping-shiprocket/index.js +356 -0
  280. package/dist/providers.d.ts +3 -0
  281. package/dist/providers.js +3 -0
  282. package/dist/react/hooks/useCanSeePrices.d.ts +0 -27
  283. package/dist/react/hooks/useCanSeePrices.js +25 -0
  284. package/dist/repositories/index.d.ts +1 -1
  285. package/dist/repositories/index.js +1 -1
  286. package/dist/schemas/registry.d.ts +10 -115
  287. package/dist/schemas/registry.js +1 -2
  288. package/dist/security/pii-encrypt.js +1 -1
  289. package/dist/seed/_helpers/category-forest.js +27 -0
  290. package/dist/seed/_helpers/category-parts-glossary-map.js +1816 -86
  291. package/dist/seed/_helpers/category-parts.d.ts +1 -1
  292. package/dist/seed/_helpers/category-parts.js +13412 -3020
  293. package/dist/seed/carousel-slides-seed-data.js +47 -10
  294. package/dist/seed/categories-seed-data.js +48 -6
  295. package/dist/seed/faq-seed-data.js +2 -2
  296. package/dist/seed/homepage-sections-seed-data.js +286 -54
  297. package/dist/seed/index.d.ts +1 -1
  298. package/dist/seed/index.js +1 -1
  299. package/dist/seed/manifest.d.ts +1 -1
  300. package/dist/seed/manifest.js +1 -2
  301. package/dist/seed/model-composition-seed-data.js +6 -8
  302. package/dist/seed/part-glossary/chunk0.d.ts +9 -0
  303. package/dist/seed/part-glossary/chunk0.js +35448 -0
  304. package/dist/seed/part-glossary/chunk1.d.ts +9 -0
  305. package/dist/seed/part-glossary/chunk1.js +40494 -0
  306. package/dist/seed/part-glossary/chunk2.d.ts +9 -0
  307. package/dist/seed/part-glossary/chunk2.js +51242 -0
  308. package/dist/seed/part-glossary/chunk3.d.ts +9 -0
  309. package/dist/seed/part-glossary/chunk3.js +53337 -0
  310. package/dist/seed/part-glossary/chunk4.d.ts +9 -0
  311. package/dist/seed/part-glossary/chunk4.js +51454 -0
  312. package/dist/seed/part-glossary-seed-data.d.ts +1 -1
  313. package/dist/seed/part-glossary-seed-data.js +23 -47483
  314. package/dist/seed/products-beyblade-x-seed-data.js +36 -1
  315. package/dist/seed/site-settings-seed-data.js +34 -35
  316. package/dist/seed/store-extensions-seed-data.d.ts +1 -2
  317. package/dist/seed/store-extensions-seed-data.js +1 -23
  318. package/dist/seed/stores-seed-data.js +0 -1
  319. package/dist/server-entry.d.ts +1 -1
  320. package/dist/server-entry.js +1 -1
  321. package/dist/server.d.ts +10 -10
  322. package/dist/server.js +24 -22
  323. package/dist/styles.css +392 -43
  324. package/dist/tailwind-utilities.css +1 -1
  325. package/dist/tokens/themes/default-dark.js +1 -1
  326. package/dist/tokens/themes/default-light.js +2 -1
  327. package/dist/tokens/tokens.css +6 -2
  328. package/dist/ui/components/Button.d.ts +11 -0
  329. package/dist/ui/components/Button.js +11 -0
  330. package/dist/ui/components/Button.style.css +29 -0
  331. package/dist/ui/components/CarouselNav.d.ts +57 -0
  332. package/dist/ui/components/CarouselNav.js +25 -0
  333. package/dist/ui/components/CarouselNav.style.css +265 -0
  334. package/dist/ui/components/GatedPrice.js +30 -3
  335. package/dist/ui/components/GatedPrice.style.css +43 -40
  336. package/dist/ui/components/HorizontalScroller.d.ts +12 -1
  337. package/dist/ui/components/HorizontalScroller.js +43 -3
  338. package/dist/ui/components/ImageMosaic.d.ts +8 -1
  339. package/dist/ui/components/ImageMosaic.js +3 -2
  340. package/dist/ui/components/ImageMosaic.style.css +22 -0
  341. package/dist/ui/components/Layout.style.css +6 -0
  342. package/dist/ui/components/Semantic.d.ts +3 -2
  343. package/dist/ui/components/Semantic.js +1 -0
  344. package/dist/ui/components/Typography.d.ts +2 -0
  345. package/dist/ui/components/Typography.js +2 -0
  346. package/dist/ui/components/Typography.style.css +19 -0
  347. package/dist/ui/components/index.style.css +1 -0
  348. package/dist/ui/index.d.ts +3 -1
  349. package/dist/ui/index.js +4 -0
  350. package/package.json +3 -2
  351. package/scripts/seed-cli.mjs +133 -27
  352. package/dist/_internal/server/jobs/core/whatsappCatalogImport.d.ts +0 -27
  353. package/dist/_internal/server/jobs/core/whatsappCatalogImport.js +0 -172
  354. package/dist/_internal/server/jobs/core/whatsappNotify.d.ts +0 -35
  355. package/dist/_internal/server/jobs/core/whatsappNotify.js +0 -140
  356. package/dist/features/admin/components/AdminWhatsAppGuideView.d.ts +0 -2
  357. package/dist/features/admin/components/AdminWhatsAppGuideView.js +0 -35
  358. package/dist/features/orders/components/MarketplaceOrderCard.d.ts +0 -36
  359. package/dist/features/orders/components/MarketplaceOrderCard.js +0 -57
  360. package/dist/features/stores/components/StoreWhatsAppGuideView.d.ts +0 -3
  361. package/dist/features/stores/components/StoreWhatsAppGuideView.js +0 -12
  362. package/dist/features/whatsapp-bot/api/send-status/route.d.ts +0 -12
  363. package/dist/features/whatsapp-bot/api/send-status/route.js +0 -38
  364. package/dist/features/whatsapp-bot/api/webhook/route.d.ts +0 -12
  365. package/dist/features/whatsapp-bot/api/webhook/route.js +0 -43
  366. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.d.ts +0 -6
  367. package/dist/features/whatsapp-bot/components/SellerWhatsAppSettingsView.js +0 -270
  368. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.d.ts +0 -9
  369. package/dist/features/whatsapp-bot/components/WhatsAppChatButton.js +0 -7
  370. package/dist/features/whatsapp-bot/components/index.d.ts +0 -3
  371. package/dist/features/whatsapp-bot/components/index.js +0 -2
  372. package/dist/features/whatsapp-bot/helpers/payment-proof-message.d.ts +0 -14
  373. package/dist/features/whatsapp-bot/helpers/payment-proof-message.js +0 -17
  374. package/dist/features/whatsapp-bot/helpers/whatsapp.d.ts +0 -52
  375. package/dist/features/whatsapp-bot/helpers/whatsapp.js +0 -283
  376. package/dist/features/whatsapp-bot/index.d.ts +0 -3
  377. package/dist/features/whatsapp-bot/index.js +0 -3
  378. package/dist/features/whatsapp-bot/manifest.d.ts +0 -2
  379. package/dist/features/whatsapp-bot/manifest.js +0 -13
  380. package/dist/features/whatsapp-bot/messages/en.json +0 -7
  381. package/dist/features/whatsapp-bot/server.d.ts +0 -7
  382. package/dist/features/whatsapp-bot/server.js +0 -7
  383. package/dist/features/whatsapp-bot/types/index.d.ts +0 -126
  384. package/dist/features/whatsapp-bot/types/index.js +0 -1
@@ -2,6 +2,8 @@ import React from "react";
2
2
  export type CTABannerHeight = "sm" | "md" | "lg" | "xl";
3
3
  export interface CTABannerSectionProps {
4
4
  title?: string;
5
+ /** Small uppercase label above the headline. Defaults to a generic one. */
6
+ eyebrow?: string;
5
7
  subtitle?: string;
6
8
  /** Longer supporting paragraph below the subtitle. */
7
9
  description?: string;
@@ -25,4 +27,4 @@ export interface CTABannerSectionProps {
25
27
  backgroundImage?: string;
26
28
  className?: string;
27
29
  }
28
- export declare function CTABannerSection({ title, subtitle, description, primaryLabel, primaryHref, secondaryLabel, secondaryHref, height, backgroundImage, className, }: CTABannerSectionProps): React.JSX.Element;
30
+ export declare function CTABannerSection({ title, eyebrow, subtitle, description, primaryLabel, primaryHref, secondaryLabel, secondaryHref, height, backgroundImage, className, }: CTABannerSectionProps): React.JSX.Element;
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import Link from "next/link.js";
3
- import { Div, Heading, Row, Scrim, Section, Span, Text } from "../../../ui/index.js";
3
+ import { Div, Heading, Icon, Row, Scrim, Section, Span, Text } from "../../../ui/index.js";
4
4
  import { MediaImage } from "../../media/MediaImage.js";
5
5
  import { ROUTES } from "../../../next/routing/route-map.js";
6
6
  import { SECTION_TITLE, SECTION_COPY } from "../constants/section-copy.js";
@@ -20,6 +20,9 @@ const HEIGHT_PADDING_Y = {
20
20
  lg: "y-5xl",
21
21
  xl: "y-6xl",
22
22
  };
23
- export function CTABannerSection({ title = SECTION_TITLE.banner, subtitle, description, primaryLabel = SECTION_COPY.bannerPrimaryCta, primaryHref = String(ROUTES.PUBLIC.PRODUCTS), secondaryLabel = SECTION_COPY.bannerSecondaryCta, secondaryHref = String(ROUTES.PUBLIC.AUCTIONS), height = "md", backgroundImage, className = "", }) {
24
- return (_jsxs(Section, { tone: "accent-banner", className: `relative ${className}`, overflow: "hidden", paddingY: HEIGHT_PADDING_Y[height], paddingX: "x-md", children: [backgroundImage && (_jsxs(_Fragment, { children: [_jsx(Div, { className: "absolute inset-0", children: _jsx(MediaImage, { src: backgroundImage, alt: "", size: "banner", objectFit: "cover" }) }), _jsx(Scrim, { direction: "left-to-right", intensity: "strong", className: "absolute inset-0" })] })), _jsxs(Div, { className: "relative mx-auto max-w-3xl text-left", children: [_jsx(Span, { className: "mb-4 inline-block", size: "2xl", "aria-hidden": "true", children: "\u2728" }), _jsx(Heading, { color: "inverse", level: 2, mdSize: "3xl", lgSize: "4xl", size: "2xl", weight: "bold", children: title }), subtitle && (_jsx(Text, { color: "inverse", className: "mt-3 /80", size: "base", children: subtitle })), description && (_jsx(Text, { color: "inverse", className: "mt-2 /70 max-w-2xl", size: "sm", children: description })), _jsxs(Row, { className: "mt-8", align: "center", justify: "start", gap: "md", wrap: true, children: [_jsx(Link, { href: primaryHref, className: "inline-flex items-center rounded-full bg-white px-[var(--appkit-space-8)] py-[var(--appkit-space-3)] text-[length:var(--appkit-text-sm)] font-semibold text-primary-700 shadow-sm transition-all hover:bg-surface-hover hover:shadow-md focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600", children: primaryLabel }), secondaryHref && (_jsx(Link, { href: secondaryHref, className: "inline-flex items-center rounded-full border-2 border-white/80 px-[var(--appkit-space-8)] py-[var(--appkit-space-3)] text-[length:var(--appkit-text-sm)] font-semibold text-white transition-all hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600", children: secondaryLabel }))] })] })] }));
23
+ export function CTABannerSection({ title = SECTION_TITLE.banner, eyebrow = SECTION_COPY.bannerEyebrow, subtitle, description, primaryLabel = SECTION_COPY.bannerPrimaryCta, primaryHref = String(ROUTES.PUBLIC.PRODUCTS), secondaryLabel = SECTION_COPY.bannerSecondaryCta,
24
+ // Pairs with SECTION_COPY.bannerSecondaryCta — see the note there for why
25
+ // this banner must not default to /auctions.
26
+ secondaryHref = String(ROUTES.PUBLIC.CATEGORIES), height = "md", backgroundImage, className = "", }) {
27
+ return (_jsxs(Section, { tone: "accent-banner", className: `relative ${className}`, overflow: "hidden", paddingY: HEIGHT_PADDING_Y[height], paddingX: "x-md", children: [backgroundImage && (_jsxs(_Fragment, { children: [_jsx(Div, { className: "absolute inset-0", children: _jsx(MediaImage, { src: backgroundImage, alt: "", size: "banner", objectFit: "cover" }) }), _jsx(Scrim, { direction: "left-to-right", intensity: "strong", className: "absolute inset-0" })] })), _jsxs(Div, { className: "relative mx-auto max-w-3xl text-left", children: [_jsxs(Div, { layout: "inline-flex", align: "center", gap: "2", surface: "frost", rounded: "full", padding: "x-sm", className: "mb-4 py-[var(--appkit-space-1-5)] backdrop-blur-sm", children: [_jsx(Icon, { name: "deals", size: "sm", tone: "on-solid" }), _jsx(Span, { color: "inverse", size: "xs", weight: "semibold", transform: "uppercase", className: "tracking-[0.18em]", children: eyebrow })] }), _jsx(Heading, { color: "inverse", level: 2, mdSize: "3xl", lgSize: "4xl", size: "2xl", weight: "bold", children: title }), subtitle && (_jsx(Text, { color: "inverse-muted", className: "mt-3", size: "base", children: subtitle })), description && (_jsx(Text, { color: "inverse-muted", className: "mt-2 max-w-2xl", size: "sm", children: description })), _jsxs(Row, { className: "mt-8", align: "center", justify: "start", gap: "md", wrap: true, children: [_jsx(Link, { href: primaryHref, className: "inline-flex items-center rounded-full bg-white px-[var(--appkit-space-8)] py-[var(--appkit-space-3)] text-[length:var(--appkit-text-sm)] font-semibold text-primary-700 shadow-sm transition-all hover:bg-surface-hover hover:shadow-md focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600", children: primaryLabel }), secondaryHref && (_jsx(Link, { href: secondaryHref, className: "inline-flex items-center rounded-full border-2 border-white/80 px-[var(--appkit-space-8)] py-[var(--appkit-space-3)] text-[length:var(--appkit-text-sm)] font-semibold text-white transition-all hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-primary-600", children: secondaryLabel }))] })] })] }));
25
28
  }
@@ -6,8 +6,10 @@ import { Button, Div, Heading, Row, Scrim, Section, Span, Stack, Text } from "..
6
6
  import { MediaImage } from "../../media/MediaImage.js";
7
7
  import { MediaVideo } from "../../media/MediaVideo.js";
8
8
  import { useHeroCarousel } from "../hooks/useHeroCarousel.js";
9
- import { HERO_CAROUSEL_ARROW, HERO_CAROUSEL_DOT_ACTIVE, HERO_CAROUSEL_DOT_INACTIVE, POSITION_FILL, FLEX_CENTER, HERO_PLACEHOLDER_BG } from "../constants/hero-carousel-styles.js";
10
- import { useHandMode } from "../../../_internal/client/hand-mode/index.js";
9
+ import { POSITION_FILL, FLEX_CENTER, HERO_PLACEHOLDER_BG } from "../constants/hero-carousel-styles.js";
10
+ /* The one carousel position/navigation control. The dot and arrow class
11
+ strings this file used to import are deleted — see CarouselNav.style.css. */
12
+ import { CarouselNav } from "../../../ui/components/CarouselNav.js";
11
13
  function makeButtonClickHandler(href, openInNewTab, push) {
12
14
  return () => {
13
15
  if (openInNewTab) {
@@ -128,7 +130,9 @@ function CarouselCardRenderer({ card, isMobile, push, }) {
128
130
  }) }))] })] })), card.isButtonOnly && card.buttons?.[0] && (_jsx(Button, { variant: "ghost", rounded: "none", className: `${POSITION_FILL} ${FLEX_CENTER} font-[600] text-white hover:bg-[rgba(0,0,0,0.2)] transition-colors p-[0]`, onClick: makeButtonClickHandler(card.buttons[0].href, card.buttons[0].openInNewTab, push), children: _jsx(Span, { size: "lg", mdSize: "2xl", children: card.buttons[0].text }) }))] }));
129
131
  }
130
132
  export function HeroCarousel({ initialSlides, push, height, defaultAutoplayDelayMs, pauseOnHover = true, showDots = true, showArrows = true, title, } = {}) {
131
- const { hand } = useHandMode();
133
+ /* `useHandMode()` was read only to pick which bottom corner the arrow pair
134
+ sat in. The nav is centred and symmetrical now, so there is no corner to
135
+ choose and no reason for this surface to know about handedness. */
132
136
  const [currentSlide, setCurrentSlide] = useState(0);
133
137
  const [isPaused, setIsPaused] = useState(false);
134
138
  const sectionRef = useRef(null);
@@ -206,7 +210,5 @@ export function HeroCarousel({ initialSlides, push, height, defaultAutoplayDelay
206
210
  alignContent: "center",
207
211
  alignItems: "stretch",
208
212
  }, children: slide.cards.slice(0, 6).map((card) => (_jsx(CarouselCardRenderer, { card: card, isMobile: isMobile, push: push }, card.id))) }))] }, slide.id));
209
- }) }) }), showDots && slides.length > 1 && (_jsx(Row, { gap: "sm", className: "absolute bottom-4 left-1/2 -translate-x-1/2 z-10", children: slides.map((_, index) => (_jsx(Button, { variant: "ghost", className: `relative overflow-hidden rounded-full transition-all duration-500 p-[var(--appkit-space-0)] !min-h-0 ${index === currentSlide
210
- ? HERO_CAROUSEL_DOT_ACTIVE
211
- : `${HERO_CAROUSEL_DOT_INACTIVE} hover:bg-white/75`}`, onClick: () => goToSlide(index), "aria-label": `Go to slide ${index + 1}`, children: index === currentSlide && (_jsx(Span, { className: "absolute inset-y-0 left-0 bg-[rgba(0,0,0,0.2)] animate-[progress-fill_4s_linear_forwards]", rounded: "full", "aria-hidden": "true" })) }, index))) })), showArrows && slides.length > 1 && (_jsxs(Row, { gap: "sm", className: `absolute bottom-4 ${hand === "left" ? "left-4" : "right-4"} z-20`, children: [_jsx(Button, { variant: "ghost", className: `p-[0] ${HERO_CAROUSEL_ARROW}`, onClick: goPrev, "aria-label": "Previous slide", children: _jsx("svg", { className: "w-7 h-7 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M15 19l-7-7 7-7" }) }) }), _jsx(Button, { variant: "ghost", className: `p-[0] ${HERO_CAROUSEL_ARROW}`, onClick: goNext, "aria-label": "Next slide", children: _jsx("svg", { className: "w-7 h-7 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2.5, d: "M9 5l7 7-7 7" }) }) })] }))] }));
213
+ }) }) }), (showDots || showArrows) && slides.length > 1 && (_jsx(Row, { justify: "center", className: "absolute bottom-4 inset-x-0 z-20 px-[var(--appkit-space-4)]", children: _jsx(CarouselNav, { count: slides.length, index: currentSlide, onSelect: showDots ? goToSlide : undefined, onPrev: showArrows ? goPrev : undefined, onNext: showArrows ? goNext : undefined, tone: "on-media", progressMs: prefersReducedMotion ? 0 : autoplayDelay, paused: isPaused, loop: true, ariaLabel: "Featured promotions" }) }))] }));
212
214
  }
@@ -19,7 +19,7 @@ import { fetchLiveStats } from "../lib/live-stats.js";
19
19
  import { renderSection, AnnouncementBar } from "../lib/section-renderer.js";
20
20
  import { SECTION_COPY } from "../constants/section-copy.js";
21
21
  import { homepageSectionsRepository } from "../repository/homepage-sections.repository.js";
22
- import { isListingTypeEnabled } from "../../../_internal/shared/listing-types/feature-flags.js";
22
+ import { isListingTypeEnabled, isCategoryTypeEnabled, } from "../../../_internal/shared/listing-types/feature-flags.js";
23
23
  /**
24
24
  * Homepage sections that advertise a specific listing type, and must therefore
25
25
  * disappear when the site stops offering it. A section type absent from this
@@ -30,6 +30,18 @@ const HOMEPAGE_SECTION_LISTING_TYPE = {
30
30
  "pre-orders": "pre-order",
31
31
  "prize-draws": "prize-draw",
32
32
  };
33
+ /**
34
+ * The same idea for the CATEGORY types, added 2026-10-20.
35
+ *
36
+ * 🛑 Bundles are not a `ListingType`, so `featured-bundles` sat outside the
37
+ * map above and rendered unconditionally — the one merchandise rail on the
38
+ * homepage with no off switch at all, while every neighbouring rail had one.
39
+ * `listings.categoryTypes.bundle` is the control that already exists for
40
+ * exactly this, and the admin Site Settings screen already shows it.
41
+ */
42
+ const HOMEPAGE_SECTION_CATEGORY_TYPE = {
43
+ "featured-bundles": "bundle",
44
+ };
33
45
  import { getFeaturedProducts, getFeaturedAuctions, getFeaturedPreOrders } from "../../products/actions/product-actions.js";
34
46
  import { listTopLevelCategories, listBrandCategories } from "../../categories/actions/category-actions.js";
35
47
  import { listFeaturedBundles } from "../../../_internal/server/features/bundles/data.js";
@@ -83,12 +95,21 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
83
95
  // half of it had a real successor (`settings.listings.listingTypes`).
84
96
  //
85
97
  // So auctions / pre-orders / prize-draws are gated by the same control that
86
- // hides them on every other surface, and the `events` / `blog` sections are
87
- // now unconditional — there is no product control for "we don't run events",
88
- // and there never was one that anything but this line read.
98
+ // hides them on every other surface, `featured-bundles` joined them on
99
+ // 2026-10-20 via the category-type half of the same setting, and the
100
+ // `events` / `blog` / `event-raffles` sections stay unconditional — there is
101
+ // no product control for "we don't run events", and there never was one that
102
+ // anything but this line read. Those are switched off per-document instead
103
+ // (`enabled: false`), which is the only lever they have.
89
104
  const enabledSections = allSections.filter((section) => {
90
- const gated = HOMEPAGE_SECTION_LISTING_TYPE[section.type];
91
- return !gated || isListingTypeEnabled(gated, siteSettings);
105
+ const type = section.type;
106
+ const gatedListing = HOMEPAGE_SECTION_LISTING_TYPE[type];
107
+ if (gatedListing && !isListingTypeEnabled(gatedListing, siteSettings))
108
+ return false;
109
+ const gatedCategory = HOMEPAGE_SECTION_CATEGORY_TYPE[type];
110
+ if (gatedCategory && !isCategoryTypeEnabled(gatedCategory, siteSettings))
111
+ return false;
112
+ return true;
92
113
  });
93
114
  // Collect live metric requests from all enabled stats sections
94
115
  const liveStatRequests = [];
@@ -136,7 +157,12 @@ export async function MarketplaceHomepageView({ adSlots, newsletterFormSlot, onB
136
157
  activeTypes.has("products") ? getFeaturedProducts(12) : null,
137
158
  activeTypes.has("auctions") ? getFeaturedAuctions(12) : null,
138
159
  activeTypes.has("pre-orders") ? getFeaturedPreOrders(12) : null,
139
- activeTypes.has("categories")
160
+ // `welcome` is a second trigger, not a typo: its hero mosaic is built from
161
+ // these categories' cover images. Gating the fetch on `categories` alone
162
+ // meant a homepage without a categories section rendered the hero's
163
+ // brand-mark fallback with nothing anywhere saying the imagery had simply
164
+ // not been fetched.
165
+ activeTypes.has("categories") || activeTypes.has("welcome")
140
166
  ? safeRead(() => listTopLevelCategories(12), { route: "/", key: "homepage.categories", fallback: null })
141
167
  : null,
142
168
  activeTypes.has("brands")
@@ -44,9 +44,17 @@ export function SectionCarousel({ title, description, headingVariant = "editoria
44
44
  headingClass,
45
45
  ]
46
46
  .filter(Boolean)
47
- .join(" "), children: title }), headingVariant === "editorial" && (_jsxs(Row, { align: "center", justify: "center", gap: "sm", textSize: "xs", color: "faint", className: "mt-1 select-none", "aria-hidden": "true", children: [_jsx(Span, { className: "h-px w-6 bg-current" }), _jsx(Span, { size: "xs", children: "\u2736" }), _jsx(Span, { className: "h-px w-6 bg-current" })] })), description && (_jsx(Text, { className: `${descVariant} mt-2`, size: "base", children: description }))] }), isLoading ? (_jsx(CarouselSkeleton, { count: skeletonCount })) : (_jsx(HorizontalScroller, { items: items, renderItem: renderItem, perView: perView, gap: gap, autoScroll: autoScroll, autoScrollInterval: autoScrollInterval, loop: loop, keyExtractor: keyExtractor, rows: rows, minItemWidth: minItemWidth, showArrows: true,
48
- // Double-row grids (e.g. the homepage Auctions section's
49
- // rows:2 config) get the full-height sliver arrows — much
50
- // easier to hit than a small circle when the track is tall.
51
- arrowStyle: rows > 1 ? "full-height" : "circle", snapToItems: true, showScrollbar: false, pauseOnHover: true })), viewMoreHref && !isLoading && (_jsx(Row, { className: "mt-6", justify: hand === "left" ? "end" : "start", children: _jsx(TextLink, { rounded: "lg", paddingX: "xl", paddingY: "sm", href: viewMoreHref, shadow: useLightText ? "lg" : "none", layout: "inline-flex", align: "center", className: "gap-[0.375rem] transition-colors bg-primary text-white hover:bg-primary-600", size: "sm", weight: "semibold", children: viewMoreLabel }) }))] })] }));
47
+ .join(" "), children: title }), headingVariant === "editorial" && (_jsxs(Row, { align: "center", justify: "center", gap: "sm", textSize: "xs", color: "faint", className: "mt-1 select-none", "aria-hidden": "true", children: [_jsx(Span, { className: "h-px w-6 bg-current" }), _jsx(Span, { size: "xs", children: "\u2736" }), _jsx(Span, { className: "h-px w-6 bg-current" })] })), description && (_jsx(Text, { className: `${descVariant} mt-2`, size: "base", children: description }))] }), isLoading ? (_jsx(CarouselSkeleton, { count: skeletonCount })) : (_jsx(HorizontalScroller, { items: items, renderItem: renderItem, perView: perView, gap: gap, autoScroll: autoScroll, autoScrollInterval: autoScrollInterval, loop: loop, keyExtractor: keyExtractor, rows: rows, minItemWidth: minItemWidth,
48
+ /*
49
+ * One in-flow control instead of two absolute arrows.
50
+ *
51
+ * The arrows were `display:none` below 640px, so on a phone every
52
+ * rail on the homepage had no affordance at all — only a hidden
53
+ * scrollbar and the hope that a visitor would try swiping. They
54
+ * also cost the rail 2 × 44px of wrapper gutter at EVERY width to
55
+ * reserve space for themselves. `showNav` carries arrows AND a
56
+ * position indicator in flow, so the control exists on a phone and
57
+ * the gutter goes back to the cards.
58
+ */
59
+ showArrows: false, showNav: true, navAriaLabel: title, snapToItems: true, showScrollbar: false, pauseOnHover: true })), viewMoreHref && !isLoading && (_jsx(Row, { className: "mt-6", justify: hand === "left" ? "end" : "start", children: _jsx(TextLink, { rounded: "lg", paddingX: "xl", paddingY: "sm", href: viewMoreHref, shadow: useLightText ? "lg" : "none", layout: "inline-flex", align: "center", className: "gap-[0.375rem] transition-colors bg-primary text-white hover:bg-primary-600", size: "sm", weight: "semibold", children: viewMoreLabel }) }))] })] }));
52
60
  }
@@ -1,11 +1,16 @@
1
1
  import React from "react";
2
+ import type { IconKey } from "../../../ui/icons/icon-registry";
2
3
  export interface SecurityHighlightItem {
3
4
  key: string;
4
5
  title: string;
5
6
  description: string;
6
- renderIcon?: (props: {
7
- className?: string;
8
- }) => React.ReactNode;
7
+ /**
8
+ * 🛑 Replaces `renderIcon?: (props) => ReactNode`, which was unreachable: the
9
+ * items come from a Firestore section config and a function cannot round-trip
10
+ * through a document, so the renderer never passed one and the icon row below
11
+ * never rendered at all. See constants/trust-icon-aliases.ts.
12
+ */
13
+ iconName?: IconKey;
9
14
  colorClass?: string;
10
15
  iconColorClass?: string;
11
16
  }
@@ -2,7 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState } from "react";
4
4
  import { THEMED_TEXT_PRIMARY } from "../../../_internal/shared/styles/themed.js";
5
- import { Div, Grid, Heading, Row, Section, Span, Text, TextLink } from "../../../ui/index.js";
5
+ import { Div, Grid, Heading, Icon, Row, Section, Span, Text, TextLink } from "../../../ui/index.js";
6
6
  // --- Constants ---------------------------------------------------------------
7
7
  const CARD_DELAYS = ["delay-0", "delay-100", "delay-200", "delay-300", "delay-[400ms]", "delay-500"];
8
8
  // --- Single card -------------------------------------------------------------
@@ -15,7 +15,7 @@ function SecurityCard({ item, visible, delayClass, }) {
15
15
  colorClass,
16
16
  delayClass,
17
17
  visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4",
18
- ].join(" "), "data-section": "securityhighlightssection-div-357", children: [item.renderIcon && (_jsx(Row, { className: "w-10 h-10 mb-3", surface: "default", align: "center", justify: "center", rounded: "lg", children: _jsx(Span, { className: iconColorClass, "aria-hidden": "true", children: item.renderIcon({ className: "w-6 h-6" }) }) })), _jsx(Text, { className: "mb-1", weight: "semibold", children: item.title }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", size: "sm", children: item.description })] }));
18
+ ].join(" "), "data-section": "securityhighlightssection-div-357", children: [item.iconName && (_jsx(Row, { className: "w-10 h-10 mb-3", surface: "default", align: "center", justify: "center", rounded: "lg", children: _jsx(Icon, { name: item.iconName, size: "xl", className: iconColorClass }) })), _jsx(Text, { className: "mb-1", weight: "semibold", children: item.title }), _jsx(Text, { variant: "secondary", className: "leading-relaxed", size: "sm", children: item.description })] }));
19
19
  }
20
20
  // --- Section -----------------------------------------------------------------
21
21
  export function SecurityHighlightsSection({ title, subtitle, pillLabel, items, learnMoreHref, learnMoreLabel = "Learn more →", className = "", }) {
@@ -1,11 +1,16 @@
1
- import type { ReactNode } from "react";
1
+ import type { IconKey } from "../../../ui/icons/icon-registry";
2
2
  export interface StatItem {
3
3
  key: string;
4
4
  value: string;
5
5
  label: string;
6
- renderIcon?: (props: {
7
- className?: string;
8
- }) => ReactNode;
6
+ /**
7
+ * 🛑 Replaces `renderIcon?: (props) => ReactNode`, which was unreachable — a
8
+ * function has no representation in the Firestore section config these stats
9
+ * come from, so the icon box below never rendered once. For a LIVE stat the
10
+ * renderer derives this from `metric` via STAT_PRESET_ICON, so a correct icon
11
+ * needs no extra config at all.
12
+ */
13
+ iconName?: IconKey;
9
14
  }
10
15
  export interface StatsCounterSectionProps {
11
16
  stats: StatItem[];
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState } from "react";
4
- import { Div, Grid, Heading, Row, Section, Text } from "../../../ui/index.js";
4
+ import { Div, Grid, Heading, Icon, Row, Section, Text } from "../../../ui/index.js";
5
5
  // --- Constants ---------------------------------------------------------------
6
6
  const STAT_DELAYS = ["delay-0", "delay-[120ms]", "delay-[240ms]", "delay-[360ms]"];
7
7
  // --- Smngle stat mtem ---------------------------------------------------------
@@ -12,7 +12,7 @@ function StatCard({ stat, visible, delayClass, isLast, }) {
12
12
  delayClass,
13
13
  visible ? "translate-y-0 opacity-100" : "translate-y-6 opacity-0",
14
14
  !isLast ? "border-r border-[var(--appkit-color-border)]" : "",
15
- ].join(" "), children: [stat.renderIcon && (_jsx(Row, { className: "mb-4 h-14 w-14 bg-primary-50 dark:bg-primary-950/40 border border-[var(--appkit-color-primary-100)] dark:border-[var(--appkit-color-primary-900)]/30", align: "center", justify: "center", rounded: "2xl", children: stat.renderIcon({ className: "w-7 h-7" }) })), _jsx(Heading, { level: 3, variant: "none", gradient: "brand", className: "mb-1 font-display font-black", mdSize: "5xl", size: "4xl", children: stat.value }), _jsx(Text, { variant: "none", className: "uppercase tracking-widest", color: "muted", size: "xs", weight: "medium", children: stat.label })] }));
15
+ ].join(" "), children: [stat.iconName && (_jsx(Row, { className: "mb-4 h-14 w-14 bg-primary-50 dark:bg-primary-950/40 border border-[var(--appkit-color-primary-100)] dark:border-[var(--appkit-color-primary-900)]/30", align: "center", justify: "center", rounded: "2xl", children: _jsx(Icon, { name: stat.iconName, size: "xl", tone: "primary" }) })), _jsx(Heading, { level: 3, variant: "none", gradient: "brand", className: "mb-1 font-display font-black", mdSize: "5xl", size: "4xl", children: stat.value }), _jsx(Text, { variant: "none", className: "uppercase tracking-widest", color: "muted", size: "xs", weight: "medium", children: stat.label })] }));
16
16
  }
17
17
  // --- Sectmon -----------------------------------------------------------------
18
18
  export function StatsCounterSection({ stats, title, className = "", }) {
@@ -3,5 +3,5 @@ import { Div, Heading, Stack, StarRating, Text } from "../../../ui/index.js";
3
3
  export function TestimonialsCarousel({ testimonials, eyebrow = "COLLECTOR REVIEWS", heading = "WHAT OUR COLLECTORS SAY", }) {
4
4
  if (testimonials.length === 0)
5
5
  return null;
6
- return (_jsx(Stack, { as: "section", justify: "center", surface: "muted", border: "subtle", className: "min-h-[calc(100svh-var(--header-height,4rem))] [padding-block:clamp(3rem,6vh,5rem)]", children: _jsxs(Stack, { className: "mx-auto w-full max-w-7xl sm:px-[2rem] min-h-0", padding: "x-lg", children: [_jsxs(Div, { className: "mb-6 text-left shrink-0", children: [_jsx(Text, { className: "mb-1 font-black uppercase tracking-widest text-error tracking-[0.18em]", size: "xs", children: eyebrow }), _jsx(Heading, { level: 2, family: "display", className: "tracking-[0.08em] leading-none", size: "2xl", mdSize: "3xl", weight: "bold", color: "primary", children: heading })] }), _jsx(Stack, { wrap: true, className: "overflow-x-auto scrollbar-none max-h-[50svh] content-start", gap: "md", children: testimonials.map((t) => (_jsxs(Stack, { padding: "5", surface: "card", border: "subtle", className: "shrink-0 w-[clamp(260px,28vw,360px)]", shadow: "card", gap: "3", children: [_jsx(StarRating, { value: t.rating, readOnly: true, size: "sm" }), _jsxs(Text, { className: "flex-1 leading-relaxed", size: "sm", color: "muted", children: ["\u201C", t.text, "\u201D"] }), _jsxs(Text, { className: "font-black uppercase text-[var(--color-yellow)] tracking-[0.06em]", size: "xs", children: ["\u2014 ", t.name] })] }, t.id))) })] }) }));
6
+ return (_jsx(Stack, { as: "section", justify: "center", surface: "muted", border: "subtle", className: "min-h-[calc(100svh-var(--header-height,4rem))] [padding-block:clamp(3rem,6vh,5rem)]", children: _jsxs(Stack, { className: "mx-auto w-full max-w-7xl sm:px-[2rem] min-h-0", padding: "x-lg", children: [_jsxs(Div, { className: "mb-6 text-left shrink-0", children: [_jsx(Text, { className: "mb-1 font-black uppercase tracking-widest text-error tracking-[0.18em]", size: "xs", children: eyebrow }), _jsx(Heading, { level: 2, family: "display", className: "tracking-[0.08em] leading-none", size: "2xl", mdSize: "3xl", weight: "bold", color: "primary", children: heading })] }), _jsx(Stack, { wrap: true, className: "overflow-x-auto max-h-[50svh] content-start", gap: "md", children: testimonials.map((t) => (_jsxs(Stack, { padding: "5", surface: "card", border: "subtle", className: "shrink-0 w-[clamp(260px,28vw,360px)]", shadow: "card", gap: "3", children: [_jsx(StarRating, { value: t.rating, readOnly: true, size: "sm" }), _jsxs(Text, { className: "flex-1 leading-relaxed", size: "sm", color: "muted", children: ["\u201C", t.text, "\u201D"] }), _jsxs(Text, { className: "font-black uppercase text-[var(--color-yellow)] tracking-[0.06em]", size: "xs", children: ["\u2014 ", t.name] })] }, t.id))) })] }) }));
7
7
  }
@@ -1,11 +1,25 @@
1
1
  import React from "react";
2
+ import type { IconKey } from "../../../ui/icons/icon-registry";
3
+ /**
4
+ * 🛑 `renderIcon?: (props) => ReactNode` was removed, not renamed.
5
+ *
6
+ * It was unreachable by construction: every item here comes from a Firestore
7
+ * section config, and a function has no representation in a document — so the
8
+ * section renderer never passed one, and all four tiles fell through to a
9
+ * hardcoded `✓`. Four different promises ("Authenticity checked", "Escrow-backed
10
+ * payments", "Straightforward returns", "Real human support") rendered the same
11
+ * glyph. `iconName` is data, so it survives the document round-trip.
12
+ *
13
+ * `id` is now a separate field because `iconName` used to serve as BOTH the
14
+ * icon and the React key — two indicators sharing an icon produced duplicate
15
+ * keys, and giving the icon a correct default would have made that collision
16
+ * likely rather than rare.
17
+ */
2
18
  export interface TrustFeatureItem {
3
- iconName: string;
19
+ id: string;
4
20
  title: string;
5
21
  description: string;
6
- renderIcon?: (props: {
7
- className?: string;
8
- }) => React.ReactNode;
22
+ iconName?: IconKey;
9
23
  }
10
24
  export interface TrustFeaturesSectionProps {
11
25
  items: TrustFeatureItem[];
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useEffect, useRef, useState } from "react";
4
- import { Div, Grid, Heading, Row, Section, Span, Text } from "../../../ui/index.js";
4
+ import { Div, Grid, Heading, Icon, Row, Section, Text } from "../../../ui/index.js";
5
5
  // --- Constants ---------------------------------------------------------------
6
6
  const CARD_DELAYS = ["delay-0", "delay-100", "delay-200", "delay-300", "delay-[400ms]", "delay-500"];
7
7
  // --- Single cards-variant card -----------------------------------------------
@@ -11,11 +11,11 @@ function TrustFeatureCard({ item, visible, delayClass, }) {
11
11
  "transition-all duration-500",
12
12
  delayClass,
13
13
  visible ? "opacity-100 translate-y-0" : "opacity-0 translate-y-4",
14
- ].join(" "), "data-section": "trustfeaturessection-div-373", children: [_jsx(Row, { className: "h-14 w-14 bg-primary-50 dark:bg-primary-950/40 border border-[var(--appkit-color-primary-100)] dark:border-[var(--appkit-color-primary-900)]/30 flex-shrink-0", align: "center", justify: "center", rounded: "2xl", children: item.renderIcon ? (item.renderIcon({ className: "w-7 h-7" })) : (_jsx(Span, { className: "text-primary-600 dark:text-secondary-400", size: "2xl", "aria-hidden": "true", children: "\u2713" })) }), _jsx(Heading, { level: 3, className: "mt-3 mb-1 tracking-wide uppercase", color: "primary", size: "sm", weight: "bold", children: item.title }), _jsx(Text, { className: "leading-relaxed", color: "muted", size: "xs", children: item.description })] }));
14
+ ].join(" "), "data-section": "trustfeaturessection-div-373", children: [item.iconName && (_jsx(Row, { className: "h-14 w-14 bg-primary-50 dark:bg-primary-950/40 border border-[var(--appkit-color-primary-100)] dark:border-[var(--appkit-color-primary-900)]/30 flex-shrink-0", align: "center", justify: "center", rounded: "2xl", children: _jsx(Icon, { name: item.iconName, size: "xl", tone: "primary" }) })), _jsx(Heading, { level: 3, className: "mt-3 mb-1 tracking-wide uppercase", color: "primary", size: "sm", weight: "bold", children: item.title }), _jsx(Text, { className: "leading-relaxed", color: "muted", size: "xs", children: item.description })] }));
15
15
  }
16
16
  // --- Single strip-variant item -----------------------------------------------
17
17
  function TrustStripItem({ item }) {
18
- return (_jsxs(Div, { layout: "inline-flex", gap: "2", align: "center", className: "flex-shrink-0", padding: "x-lg", children: [item.renderIcon ? (item.renderIcon({ className: "w-5 h-5" })) : (_jsx(Span, { className: "text-primary-600 dark:text-primary-400", size: "lg", "aria-hidden": "true", children: "\u2713" })), _jsx(Text, { className: "whitespace-nowrap", color: "muted", size: "sm", weight: "medium", children: item.title })] }));
18
+ return (_jsxs(Div, { layout: "inline-flex", gap: "2", align: "center", className: "flex-shrink-0", padding: "x-lg", children: [item.iconName && _jsx(Icon, { name: item.iconName, size: "lg", tone: "primary" }), _jsx(Text, { className: "whitespace-nowrap", color: "muted", size: "sm", weight: "medium", children: item.title })] }));
19
19
  }
20
20
  // --- Section -----------------------------------------------------------------
21
21
  export function TrustFeaturesSection({ items, title, variant = "cards", className = "", }) {
@@ -36,7 +36,7 @@ export function TrustFeaturesSection({ items, title, variant = "cards", classNam
36
36
  }, []);
37
37
  if (variant === "strip") {
38
38
  const doubled = [...items, ...items];
39
- return (_jsx(Section, { border: "subtle", ref: sectionRef, className: `overflow-hidden border-y ${className}`, padding: "y-md", children: _jsx(Div, { layout: "flex", className: "animate-marquee", children: doubled.map((item, i) => (_jsx(TrustStripItem, { item: item }, `${item.iconName}-${i}`))) }) }));
39
+ return (_jsx(Section, { border: "subtle", ref: sectionRef, className: `overflow-hidden border-y ${className}`, padding: "y-md", children: _jsx(Div, { layout: "flex", className: "animate-marquee", children: doubled.map((item, i) => (_jsx(TrustStripItem, { item: item }, `${item.id}-${i}`))) }) }));
40
40
  }
41
- return (_jsx(Section, { ref: sectionRef, paddingY: "y-2-5xl", className: className, paddingX: "x-md", surface: "muted", children: _jsxs(Div, { className: "max-w-6xl mx-auto", children: [title && (_jsx(Div, { className: "text-left mb-8", children: _jsx(Heading, { level: 2, color: "primary", size: "3xl", weight: "bold", mdSize: "4xl", children: title }) })), _jsx(Grid, { cols: "statTiles", gap: "lg", children: items.map((item, index) => (_jsx(TrustFeatureCard, { item: item, visible: visible, delayClass: CARD_DELAYS[Math.min(index, CARD_DELAYS.length - 1)] }, item.iconName))) })] }) }));
41
+ return (_jsx(Section, { ref: sectionRef, paddingY: "y-2-5xl", className: className, paddingX: "x-md", surface: "muted", children: _jsxs(Div, { className: "max-w-6xl mx-auto", children: [title && (_jsx(Div, { className: "text-left mb-8", children: _jsx(Heading, { level: 2, color: "primary", size: "3xl", weight: "bold", mdSize: "4xl", children: title }) })), _jsx(Grid, { cols: "statTiles", gap: "lg", children: items.map((item, index) => (_jsx(TrustFeatureCard, { item: item, visible: visible, delayClass: CARD_DELAYS[Math.min(index, CARD_DELAYS.length - 1)] }, item.id))) })] }) }));
42
42
  }
@@ -1,7 +1,9 @@
1
1
  import React from "react";
2
+ import type { IconKey } from "../../../ui/icons/icon-registry";
2
3
  export interface WelcomeSectionChip {
3
4
  key: string;
4
- emoji: string;
5
+ /** Registry icon key. Replaces `emoji`, which no utility could size. */
6
+ iconName: IconKey;
5
7
  label: string;
6
8
  }
7
9
  export interface WelcomeSectionProps {
@@ -16,8 +18,17 @@ export interface WelcomeSectionProps {
16
18
  secondaryCtaHref?: string;
17
19
  onSecondaryCtaClick?: () => void;
18
20
  trustChips?: WelcomeSectionChip[];
21
+ /**
22
+ * Decorative hero imagery, MOST IMPORTANT FIRST — the first takes the large
23
+ * mosaic cell. Below `MOSAIC_MIN` (3) the brand-mark panel is used instead.
24
+ *
25
+ * Must be deterministic: `ImageMosaic` is explicit that `Math.random()` here
26
+ * would break SSR/hydration agreement, so the caller passes a stable
27
+ * configured order rather than a shuffle.
28
+ */
29
+ heroImages?: readonly string[];
19
30
  isLoading?: boolean;
20
31
  brandLogoText?: string;
21
32
  className?: string;
22
33
  }
23
- export declare function WelcomeSection({ title, subtitle, pillLabel, showCTA, ctaLabel, ctaHref, onCtaClick, secondaryCtaLabel, secondaryCtaHref, onSecondaryCtaClick, trustChips, isLoading, brandLogoText, className, }: WelcomeSectionProps): React.JSX.Element;
34
+ export declare function WelcomeSection({ title, subtitle, pillLabel, showCTA, ctaLabel, ctaHref, onCtaClick, secondaryCtaLabel, secondaryCtaHref, onSecondaryCtaClick, trustChips, heroImages, isLoading, brandLogoText, className, }: WelcomeSectionProps): React.JSX.Element;
@@ -1,13 +1,13 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { THEMED_TEXT_SECONDARY, FLEX_CENTER } from "../../../_internal/shared/styles/themed.js";
4
- import { Button, Div, Grid, Heading, Row, Section, SiteLogo, SiteMark, Span, Stack, Text, TextLink } from "../../../ui/index.js";
4
+ import { Button, Div, Grid, Heading, Icon, ImageMosaic, MOSAIC_MIN, Row, Section, SiteLogo, SiteMark, Span, Stack, Text, TextLink } from "../../../ui/index.js";
5
5
  // --- Component ---------------------------------------------------------------
6
- export function WelcomeSection({ title, subtitle, pillLabel, showCTA = true, ctaLabel = "Shop now", ctaHref, onCtaClick, secondaryCtaLabel = "Browse products", secondaryCtaHref, onSecondaryCtaClick, trustChips = [], isLoading = false, brandLogoText = "", className = "", }) {
6
+ export function WelcomeSection({ title, subtitle, pillLabel, showCTA = true, ctaLabel = "Shop now", ctaHref, onCtaClick, secondaryCtaLabel = "Browse products", secondaryCtaHref, onSecondaryCtaClick, trustChips = [], heroImages, isLoading = false, brandLogoText = "", className = "", }) {
7
7
  const themed = { textSecondary: THEMED_TEXT_SECONDARY };
8
8
  const flex = { center: FLEX_CENTER };
9
9
  if (isLoading) {
10
10
  return (_jsx(Section, { className: `relative overflow-hidden pt-[0px] pb-[var(--appkit-space-16)] md:pt-[0px] md:pb-[6rem] ${className}`, paddingX: "x-md", children: _jsxs(Div, { className: "animate-pulse max-w-4xl mx-auto text-left", children: [_jsx(Div, { className: "h-6 w-52 mb-6", surface: "subtle", rounded: "full" }), _jsx(Div, { className: "h-20 mb-4 max-w-2xl", surface: "subtle", rounded: "lg" }), _jsx(Div, { className: "h-6 mb-8 max-w-lg", surface: "subtle", rounded: "lg" }), _jsxs(Row, { justify: "start", gap: "md", children: [_jsx(Div, { className: "h-12 w-36", surface: "subtle", rounded: "xl" }), _jsx(Div, { className: "h-12 w-36", surface: "subtle", rounded: "xl" })] })] }) }));
11
11
  }
12
- return (_jsxs(Section, { className: `relative overflow-hidden pt-[0px] pb-[var(--appkit-space-20)] md:pt-[0px] md:pb-[7rem] ${className}`, paddingX: "x-md", children: [_jsx(Div, { className: "pointer-events-none absolute -top-32 -left-32 w-[28rem] h-[28rem] bg-primary/10 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "pointer-events-none absolute -bottom-40 -right-40 w-[36rem] h-[36rem] bg-secondary/10 dark:bg-secondary/15 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "relative z-10 max-w-7xl mx-auto", children: _jsxs(Grid, { align: "center", gap: "2xl", className: "grid-cols-1 lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2", children: [_jsxs(Div, { className: "text-left", children: [pillLabel && (_jsx(Div, { children: _jsxs(Span, { layout: "inline-flex", gap: "md", size: "xs", weight: "medium", className: /* audit-variant-ok: colour+alpha border (primary-500/30); the `border` variant takes a token name, not an rgba step */ "border border-primary-500/30 bg-primary-500/10 px-[1.25rem] py-[0.375rem] tracking-[0.2em] text-primary-700 dark:text-primary-400 backdrop-blur-sm", rounded: "full", transform: "uppercase", children: [_jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" }), pillLabel, _jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" })] }) })), _jsx(Heading, { level: 1, variant: "none", gradient: "brand-tri", className: "mt-4 font-display leading-[1.1] tracking-tight break-words", size: "5xl", mdSize: "6xl", lgSize: "7xl", xlSize: "7xl", children: title }), subtitle && (_jsx(Text, { className: `mt-4 ${themed.textSecondary} max-w-xl leading-relaxed`, size: "xl", children: subtitle })), showCTA && (_jsxs(Row, { wrap: true, gap: "md", className: "mt-8", justify: "start", children: [ctaHref ? (_jsx(TextLink, { rounded: "xl", href: ctaHref, layout: "inline-flex", align: "center", justify: "center", className: "px-[2rem] py-[0.875rem] !bg-primary hover:!bg-primary-600 text-white dark:!bg-primary dark:hover:!bg-primary-600 dark:text-white btn-glow transition-all hover:scale-[1.02]", size: "base", weight: "bold", children: ctaLabel })) : (_jsx(Button, { variant: "primary", size: "lg", onClick: onCtaClick, children: ctaLabel })), secondaryCtaHref ? (_jsx(TextLink, { rounded: "xl", href: secondaryCtaHref, layout: "inline-flex", align: "center", justify: "center", className: "border-2 border-cobalt/40 dark:border-cobalt-400/40 px-[2rem] py-[0.875rem] text-cobalt-700 dark:text-cobalt-300 hover:bg-primary-surface transition-all hover:scale-[1.02]", size: "base", weight: "semibold", children: secondaryCtaLabel })) : (_jsx(Button, { variant: "outline", size: "lg", onClick: onSecondaryCtaClick, children: secondaryCtaLabel }))] })), trustChips.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mt-6", justify: "start", children: trustChips.map((chip) => (_jsxs(Span, { layout: "inline-flex", gap: "xs", size: "xs", weight: "medium", className: "border border-[var(--appkit-color-border)] px-[0.875rem] py-[0.375rem]", rounded: "full", surface: "subtle", color: "muted", children: [chip.emoji, " ", chip.label] }, chip.key))) }))] }), _jsx(Div, { className: "hidden lg:block", children: _jsxs(Div, { className: `relative overflow-hidden aspect-[4/3] bg-[image:var(--appkit-gradient-section-mesh)]`, shadow: "2xl", border: "default", rounded: "3xl", children: [_jsx(Div, { className: "absolute inset-0 bg-[image:var(--appkit-gradient-glass)]" }), _jsxs(Stack, { centered: true, gap: "sm", className: `absolute inset-0 ${flex.center} p-[2.5rem]`, children: [_jsx(SiteMark, { title: brandLogoText || "LetItRip.in", size: "xl" }), _jsx(SiteLogo, { title: brandLogoText || "LetItRip.in", size: "xl" })] })] }) })] }) })] }));
12
+ return (_jsxs(Section, { className: `relative overflow-hidden pt-[0px] pb-[var(--appkit-space-20)] md:pt-[0px] md:pb-[7rem] ${className}`, paddingX: "x-md", children: [_jsx(Div, { className: "pointer-events-none absolute -top-32 -left-32 w-[28rem] h-[28rem] bg-primary/10 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "pointer-events-none absolute -bottom-40 -right-40 w-[36rem] h-[36rem] bg-secondary/10 dark:bg-secondary/15 blur-3xl", rounded: "full", "aria-hidden": "true" }), _jsx(Div, { className: "relative z-10 max-w-7xl mx-auto", children: _jsxs(Grid, { align: "center", gap: "2xl", className: "grid-cols-1 lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2", children: [_jsxs(Div, { className: "text-left", children: [pillLabel && (_jsx(Div, { children: _jsxs(Span, { layout: "inline-flex", gap: "md", size: "xs", weight: "medium", className: /* audit-variant-ok: colour+alpha border (primary-500/30); the `border` variant takes a token name, not an rgba step */ "border border-primary-500/30 bg-primary-500/10 px-[1.25rem] py-[0.375rem] tracking-[0.2em] text-primary-700 dark:text-primary-400 backdrop-blur-sm", rounded: "full", transform: "uppercase", children: [_jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" }), pillLabel, _jsx(Span, { className: "w-1.5 h-1.5 bg-primary-500 inline-block", rounded: "full", "aria-hidden": "true" })] }) })), _jsx(Heading, { level: 1, variant: "none", gradient: "brand-tri", className: "mt-4 font-display leading-[1.1] tracking-tight break-words", size: "5xl", mdSize: "6xl", lgSize: "7xl", xlSize: "7xl", children: title }), subtitle && (_jsx(Text, { className: `mt-4 ${themed.textSecondary} max-w-xl leading-relaxed`, size: "xl", children: subtitle })), showCTA && (_jsxs(Row, { wrap: true, gap: "md", className: "mt-8", justify: "start", children: [ctaHref ? (_jsx(TextLink, { rounded: "xl", href: ctaHref, layout: "inline-flex", align: "center", justify: "center", className: "px-[2rem] py-[0.875rem] !bg-primary hover:!bg-primary-600 text-white dark:!bg-primary dark:hover:!bg-primary-600 dark:text-white btn-glow transition-all hover:scale-[1.02]", size: "base", weight: "bold", children: ctaLabel })) : (_jsx(Button, { variant: "primary", size: "lg", onClick: onCtaClick, children: ctaLabel })), secondaryCtaHref ? (_jsx(TextLink, { rounded: "xl", href: secondaryCtaHref, layout: "inline-flex", align: "center", justify: "center", className: "border-2 border-cobalt/40 dark:border-cobalt-400/40 px-[2rem] py-[0.875rem] text-cobalt-700 dark:text-cobalt-300 hover:bg-primary-surface transition-all hover:scale-[1.02]", size: "base", weight: "semibold", children: secondaryCtaLabel })) : (_jsx(Button, { variant: "outline", size: "lg", onClick: onSecondaryCtaClick, children: secondaryCtaLabel }))] })), trustChips.length > 0 && (_jsx(Row, { wrap: true, gap: "sm", className: "mt-6", justify: "start", children: trustChips.map((chip) => (_jsxs(Row, { align: "center", gap: "xs", surface: "default", border: "subtle", rounded: "full", shadow: "sm", className: "px-[0.875rem] py-[0.375rem]", children: [_jsx(Icon, { name: chip.iconName, size: "sm", tone: "success" }), _jsx(Span, { size: "xs", weight: "medium", color: "muted", children: chip.label })] }, chip.key))) }))] }), _jsx(Div, { className: "hidden lg:block", children: heroImages && heroImages.length >= MOSAIC_MIN ? (_jsx(ImageMosaic, { size: "hero", images: heroImages, alt: `${brandLogoText || "Marketplace"} collection highlights` })) : (_jsxs(Div, { className: `relative overflow-hidden aspect-[4/3] bg-[image:var(--appkit-gradient-section-mesh)]`, shadow: "2xl", border: "default", rounded: "3xl", children: [_jsx(Div, { className: "absolute inset-0 bg-[image:var(--appkit-gradient-glass)]" }), _jsxs(Stack, { centered: true, gap: "sm", className: `absolute inset-0 ${flex.center} p-[2.5rem]`, children: [_jsx(SiteMark, { title: brandLogoText || "LetItRip.in", size: "xl" }), _jsx(SiteLogo, { title: brandLogoText || "LetItRip.in", size: "xl" })] })] })) })] }) })] }));
13
13
  }
@@ -11,4 +11,32 @@ export interface WhatsAppCommunitySectionProps {
11
11
  isLoading?: boolean;
12
12
  className?: string;
13
13
  }
14
+ /**
15
+ * The community invite.
16
+ *
17
+ * ## 🛑 It looks like a chat because it IS a chat invite
18
+ *
19
+ * This was a single flat card: icon row → heading → description → a 2-column
20
+ * grid of four identical `✓` circles → an italic blockquote → a button, all
21
+ * left-aligned in one top-down stack. Two of those blocks (the `✓` grid and the
22
+ * blockquote) spent a lot of vertical space *telling* you the group is useful.
23
+ * As bubbles on WhatsApp's own wallpaper they *show* it, in less room.
24
+ *
25
+ * Everything needed already existed and had no consumer: `Card`'s
26
+ * `chat-bubble-mine` / `chat-bubble-theirs` variants (with the correct corner
27
+ * notches and an auto-margin for right alignment) and the
28
+ * `--appkit-color-whatsapp-bg` beige token.
29
+ *
30
+ * ## 🛑 Three things that are deliberate
31
+ *
32
+ * 1. **No fabricated timestamps and no `✓✓` read receipts.** Tempting, and the
33
+ * same category of claim as a made-up member count — which this feature
34
+ * already refuses to invent. The bubble shape carries the motif on its own.
35
+ * 2. **`align="start"` on the thread is load-bearing.** `chat-bubble-*` is
36
+ * `display:inline-block; max-width:80%`, and a stretched flex item defeats
37
+ * both, so the bubbles would become full-width boxes.
38
+ * 3. **`tone="whatsapp"`, not `tone="accent-banner"`.** The old tone is brand
39
+ * primary→secondary — the SAME gradient as `CTABannerSection` a couple of
40
+ * sections below, which is a real part of why the page read monotonous.
41
+ */
14
42
  export declare function WhatsAppCommunitySection({ title, descriptionHtml, memberCount, memberCountLabel, testimonial, benefits, buttonText, groupLink, isLoading, className, }: WhatsAppCommunitySectionProps): React.JSX.Element | null;
@@ -1,12 +1,38 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Blockquote, Button, Div, Heading, RichText, Row, Section, Span, Text } from "../../../ui/index.js";
4
- import { Users } from "lucide-react";
3
+ import { Button, Card, Div, Grid, Heading, Icon, RichText, Row, Section, Span, Stack, Text } from "../../../ui/index.js";
5
4
  import { getDefaultLocale } from "../../../core/baseline-resolver.js";
6
- import { useHandMode } from "../../../_internal/client/hand-mode/index.js";
5
+ import { WhatsAppGlyph } from "./WhatsAppGlyph.js";
7
6
  // --- Section -----------------------------------------------------------------
7
+ /**
8
+ * The community invite.
9
+ *
10
+ * ## 🛑 It looks like a chat because it IS a chat invite
11
+ *
12
+ * This was a single flat card: icon row → heading → description → a 2-column
13
+ * grid of four identical `✓` circles → an italic blockquote → a button, all
14
+ * left-aligned in one top-down stack. Two of those blocks (the `✓` grid and the
15
+ * blockquote) spent a lot of vertical space *telling* you the group is useful.
16
+ * As bubbles on WhatsApp's own wallpaper they *show* it, in less room.
17
+ *
18
+ * Everything needed already existed and had no consumer: `Card`'s
19
+ * `chat-bubble-mine` / `chat-bubble-theirs` variants (with the correct corner
20
+ * notches and an auto-margin for right alignment) and the
21
+ * `--appkit-color-whatsapp-bg` beige token.
22
+ *
23
+ * ## 🛑 Three things that are deliberate
24
+ *
25
+ * 1. **No fabricated timestamps and no `✓✓` read receipts.** Tempting, and the
26
+ * same category of claim as a made-up member count — which this feature
27
+ * already refuses to invent. The bubble shape carries the motif on its own.
28
+ * 2. **`align="start"` on the thread is load-bearing.** `chat-bubble-*` is
29
+ * `display:inline-block; max-width:80%`, and a stretched flex item defeats
30
+ * both, so the bubbles would become full-width boxes.
31
+ * 3. **`tone="whatsapp"`, not `tone="accent-banner"`.** The old tone is brand
32
+ * primary→secondary — the SAME gradient as `CTABannerSection` a couple of
33
+ * sections below, which is a real part of why the page read monotonous.
34
+ */
8
35
  export function WhatsAppCommunitySection({ title, descriptionHtml, memberCount, memberCountLabel = "members", testimonial, benefits = [], buttonText = "Join our WhatsApp community", groupLink, isLoading = false, className = "", }) {
9
- const { hand } = useHandMode();
10
36
  if (isLoading) {
11
37
  return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsx(Div, { className: "h-72 animate-pulse", surface: "subtle", rounded: "2xl" }) }) }));
12
38
  }
@@ -14,7 +40,17 @@ export function WhatsAppCommunitySection({ title, descriptionHtml, memberCount,
14
40
  return null;
15
41
  const handleJoin = () => {
16
42
  if (groupLink)
17
- window.open(groupLink, "_blank");
43
+ window.open(groupLink, "_blank", "noopener,noreferrer");
18
44
  };
19
- return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsxs(Section, { color: "inverse", tone: "accent-banner", rounded: "2xl", shadow: "lg", className: "relative overflow-hidden", children: [_jsx(Div, { className: "absolute inset-0 opacity-[0.06] pointer-events-none bg-[repeating-linear-gradient(45deg,white_0,white_1px,transparent_0,transparent_50%)] bg-[size:10px_10px]", "aria-hidden": true }), _jsxs(Div, { className: "relative z-10 px-[1.5rem] sm:px-[2.5rem] sm:py-[3rem]", padding: "y-2xl", children: [_jsxs(Row, { align: "center", justify: "between", gap: "md", wrap: true, className: "mb-8", reverse: hand === "left", children: [_jsxs(Row, { align: "center", gap: "3", children: [_jsx(Row, { className: "w-12 h-12 bg-[var(--appkit-color-whatsapp)] flex-shrink-0", align: "center", justify: "center", rounded: "xl", shadow: "lg", children: _jsx("svg", { className: "w-7 h-7 text-white", fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }) }), _jsx(Span, { color: "inverse", size: "sm", weight: "medium", className: "/80 tracking-wide", transform: "uppercase", children: "WhatsApp Community" })] }), memberCount && (_jsxs(Row, { paddingY: "y-2xs-tall", className: "backdrop-blur-sm", surface: "frost", padding: "x-md", align: "center", gap: "sm", rounded: "full", children: [_jsx(Users, { className: "w-4 h-4 text-white/80" }), _jsxs(Span, { color: "inverse", size: "sm", weight: "semibold", children: [memberCount.toLocaleString(getDefaultLocale()), "+ ", memberCountLabel] })] }))] }), _jsx(Heading, { color: "inverse", level: 2, className: "mb-3 leading-tight", smSize: "3xl", size: "2xl", weight: "bold", children: title }), descriptionHtml && (_jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm max-w-none prose-invert", className: "text-white/80 text-[length:var(--appkit-text-base)] mb-6 max-w-2xl leading-relaxed" })), benefits.length > 0 && (_jsx(Div, { layout: "grid", gap: "3", className: "grid-cols-1 sm:grid-cols-2 mb-8 max-w-2xl", children: benefits.slice(0, 4).map((benefit, i) => (_jsxs(Row, { align: "start", gap: "2.5", children: [_jsx(Span, { layout: "flex-center", className: "mt-0.5 flex-shrink-0 w-5 h-5 bg-[rgba(255,255,255,0.2)]", rounded: "full", children: _jsx("svg", { className: "w-3 h-3 text-white", fill: "currentColor", viewBox: "0 0 20 20", "aria-hidden": "true", children: _jsx("path", { fillRule: "evenodd", d: "M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z", clipRule: "evenodd" }) }) }), _jsx(Span, { color: "inverse", size: "sm", className: "/90 leading-snug", children: benefit })] }, i))) })), testimonial && (_jsx(Blockquote, { paddingX: "x-md", className: "border-l-2 border-white/30 mb-8 max-w-xl", children: _jsxs(Text, { color: "inverse", variant: "none", className: "/75 italic leading-relaxed", size: "sm", children: ["\u201C", testimonial, "\u201D"] }) })), groupLink && (_jsxs(Button, { gap: "md", variant: "primary", size: "lg", onClick: handleJoin, "aria-label": buttonText, className: "!bg-[var(--appkit-color-whatsapp)] hover:!bg-[var(--appkit-color-whatsapp-light)] !text-white !border-0 font-[600]", shadow: "lg", children: [_jsx("svg", { className: "w-5 h-5 shrink-0", fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }), buttonText] }))] })] }) }) }));
45
+ /* The thread. Benefits read as incoming messages; the testimonial closes it.
46
+ Below two there is no conversation to show, so the panel stands down and
47
+ the pitch column takes the full width rather than sitting beside an
48
+ almost-empty box. */
49
+ const thread = [...benefits.slice(0, 4), ...(testimonial ? [`“${testimonial}”`] : [])];
50
+ const showThread = thread.length >= 2;
51
+ return (_jsx(Section, { paddingX: "x-md-2xl", className: className, surface: "subtle", paddingY: "y-4xl", children: _jsx(Div, { className: "w-full max-w-7xl mx-auto", children: _jsxs(Section, { color: "inverse", tone: "whatsapp", rounded: "3xl", shadow: "xl", className: "relative overflow-hidden", children: [_jsx(Div, { className: "absolute inset-0 opacity-[0.10] pointer-events-none bg-[radial-gradient(circle_at_1px_1px,white_1px,transparent_0)] bg-[size:18px_18px]", "aria-hidden": true }), _jsxs(Grid, { cols: showThread ? "halves" : "autoLg", gap: "hero", align: "center", className: "relative z-10 px-[1.5rem] py-[2.5rem] sm:px-[2.5rem] sm:py-[3rem]", children: [_jsxs(Stack, { gap: "lg", children: [_jsxs(Row, { align: "center", gap: "md", wrap: true, children: [_jsxs(Row, { surface: "frost", rounded: "full", padding: "x-sm", paddingY: "y-2xs-tall", align: "center", gap: "xs", className: "backdrop-blur-sm", children: [_jsx(WhatsAppGlyph, { className: "h-4 w-4" }), _jsx(Span, { color: "inverse", size: "xs", weight: "semibold", transform: "uppercase", className: "tracking-[0.18em]", children: "WhatsApp Community" })] }), memberCount && (_jsxs(Row, { align: "center", gap: "xs", children: [_jsxs(Span, { layout: "flex", className: "relative h-2 w-2", "aria-hidden": true, children: [_jsx(Span, { rounded: "full", className: "absolute inline-flex h-full w-full animate-ping bg-[var(--appkit-color-surface)] opacity-75" }), _jsx(Span, { rounded: "full", className: "relative inline-flex h-2 w-2 bg-[var(--appkit-color-surface)]" })] }), _jsxs(Span, { color: "inverse-muted", size: "xs", weight: "medium", numeric: true, children: [memberCount.toLocaleString(getDefaultLocale()), "+ ", memberCountLabel] })] }))] }), _jsx(Heading, { color: "inverse", level: 2, size: "3xl", mdSize: "4xl", weight: "bold", className: "leading-[1.1] tracking-tight", children: title }), descriptionHtml && (
52
+ /* No colour class here. `prose-invert` sets `--tw-prose-body`
53
+ itself, so ANY wrapper colour loses to it — the previous
54
+ `text-white/80` on this element did nothing. */
55
+ _jsx(RichText, { html: descriptionHtml, proseClass: "prose prose-sm prose-invert max-w-none", className: "max-w-md text-[length:var(--appkit-text-base)] leading-relaxed" })), groupLink && (_jsx(Row, { children: _jsxs(Button, { variant: "inverse", size: "lg", shadow: "lg", gap: "md", onClick: handleJoin, "aria-label": buttonText, children: [_jsx(WhatsAppGlyph, { className: "h-5 w-5" }), buttonText] }) }))] }), showThread && (_jsxs(Stack, { gap: "sm", align: "start", rounded: "2xl", padding: "md", shadow: "2xl", className: "bg-[var(--appkit-color-whatsapp-bg)]", role: "img", "aria-label": "Example messages from the community group", children: [thread.map((line, i) => (_jsx(Card, { padding: "none", variant: i % 2 === 1 ? "chat-bubble-mine" : "chat-bubble-theirs", children: _jsx(Text, { size: "sm", className: "leading-snug", children: line }) }, i))), _jsxs(Row, { align: "center", gap: "xs", className: "self-end pt-[var(--appkit-space-1)]", children: [_jsx(Icon, { name: "lock", size: "xs", tone: "muted" }), _jsx(Span, { size: "xs", color: "muted", children: "End-to-end encrypted by WhatsApp" })] })] }))] })] }) }) }));
20
56
  }
@@ -0,0 +1,20 @@
1
+ import React from "react";
2
+ /**
3
+ * The WhatsApp brand mark.
4
+ *
5
+ * ## 🛑 Why this is NOT in `icon-registry.ts`
6
+ *
7
+ * That registry's keys are INTENT names (`verify`, `restore`, `ship`) resolving
8
+ * to lucide glyphs, and its header is explicit that it is deliberately small
9
+ * and not a re-export of an icon set. A third-party brand mark is neither an
10
+ * intent nor a lucide glyph — registering it would make "which icon set is this
11
+ * key from?" a question with two answers.
12
+ *
13
+ * It lives here because it was inlined TWICE in `WhatsAppCommunitySection`
14
+ * (~1.2KB of identical path data in one file), and the second copy had no
15
+ * `shrink-0`, so inside a padded flex control it could shrink below its stated
16
+ * size — Root Cause #80's `UNSHRINKABLE_GLYPH`.
17
+ */
18
+ export declare function WhatsAppGlyph({ className }: {
19
+ className?: string;
20
+ }): React.JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * The WhatsApp brand mark.
4
+ *
5
+ * ## 🛑 Why this is NOT in `icon-registry.ts`
6
+ *
7
+ * That registry's keys are INTENT names (`verify`, `restore`, `ship`) resolving
8
+ * to lucide glyphs, and its header is explicit that it is deliberately small
9
+ * and not a re-export of an icon set. A third-party brand mark is neither an
10
+ * intent nor a lucide glyph — registering it would make "which icon set is this
11
+ * key from?" a question with two answers.
12
+ *
13
+ * It lives here because it was inlined TWICE in `WhatsAppCommunitySection`
14
+ * (~1.2KB of identical path data in one file), and the second copy had no
15
+ * `shrink-0`, so inside a padded flex control it could shrink below its stated
16
+ * size — Root Cause #80's `UNSHRINKABLE_GLYPH`.
17
+ */
18
+ export function WhatsAppGlyph({ className = "" }) {
19
+ return (_jsx("svg", { className: `shrink-0 ${className}`, fill: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: _jsx("path", { d: "M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.653-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z" }) }));
20
+ }