@deriv-com/dds-marketing 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (336) hide show
  1. package/.llm/components/awards.md +209 -0
  2. package/.llm/components/background.md +420 -0
  3. package/.llm/components/bottomsheet.md +5 -0
  4. package/.llm/components/comparisoncards.md +257 -0
  5. package/.llm/components/comparisontable.md +231 -0
  6. package/.llm/components/ctabanner.md +22 -0
  7. package/.llm/components/ctabannerslider.md +36 -2
  8. package/.llm/components/datatable.md +273 -0
  9. package/.llm/components/downloadbanner.md +283 -0
  10. package/.llm/components/featurecards.md +41 -3
  11. package/.llm/components/featurecardscarousel.md +311 -0
  12. package/.llm/components/featuresplit.md +5 -0
  13. package/.llm/components/featurestack.md +227 -0
  14. package/.llm/components/illustrationcard.md +236 -0
  15. package/.llm/components/illustrationscene.md +229 -0
  16. package/.llm/components/imagebanner.md +278 -0
  17. package/.llm/components/landinghero.md +24 -0
  18. package/.llm/components/navbar.md +1 -1
  19. package/.llm/components/navbaritem.md +4 -0
  20. package/.llm/components/pageheader.md +22 -0
  21. package/.llm/components/paginationdots.md +6 -1
  22. package/.llm/components/producthero.md +35 -11
  23. package/.llm/components/resourcebanner.md +247 -0
  24. package/.llm/components/scenescroll.md +222 -0
  25. package/.llm/components/select.md +17 -0
  26. package/.llm/components/stats.md +219 -0
  27. package/.llm/components/steps.md +286 -0
  28. package/.llm/components/stickycards.md +251 -0
  29. package/.llm/components/tableheadercell.md +19 -0
  30. package/.llm/components/teamgrid.md +243 -0
  31. package/.llm/components/testimonialrow.md +5 -0
  32. package/.llm/components/testimonialslider.md +14 -1
  33. package/.llm/components/textarea.md +13 -0
  34. package/.llm/components/textinput.md +13 -0
  35. package/.llm/components/textscroll.md +187 -0
  36. package/.llm/components/tiers.md +227 -0
  37. package/.llm/digest/awards.md +45 -0
  38. package/.llm/digest/background.md +53 -0
  39. package/.llm/digest/bottomsheet.md +2 -0
  40. package/.llm/digest/comparisoncards.md +51 -0
  41. package/.llm/digest/comparisontable.md +53 -0
  42. package/.llm/digest/ctabanner.md +4 -0
  43. package/.llm/digest/ctabannerslider.md +7 -0
  44. package/.llm/digest/datatable.md +65 -0
  45. package/.llm/digest/downloadbanner.md +65 -0
  46. package/.llm/digest/featurecards.md +1 -1
  47. package/.llm/digest/featurecardscarousel.md +54 -0
  48. package/.llm/digest/featuresplit.md +1 -0
  49. package/.llm/digest/featurestack.md +48 -0
  50. package/.llm/digest/illustrationcard.md +46 -0
  51. package/.llm/digest/illustrationscene.md +50 -0
  52. package/.llm/digest/imagebanner.md +64 -0
  53. package/.llm/digest/landinghero.md +7 -0
  54. package/.llm/digest/navbaritem.md +1 -0
  55. package/.llm/digest/pageheader.md +4 -0
  56. package/.llm/digest/paginationdots.md +3 -1
  57. package/.llm/digest/producthero.md +4 -2
  58. package/.llm/digest/resourcebanner.md +53 -0
  59. package/.llm/digest/scenescroll.md +49 -0
  60. package/.llm/digest/select.md +5 -0
  61. package/.llm/digest/stats.md +46 -0
  62. package/.llm/digest/steps.md +55 -0
  63. package/.llm/digest/stickycards.md +52 -0
  64. package/.llm/digest/tableheadercell.md +4 -0
  65. package/.llm/digest/teamgrid.md +53 -0
  66. package/.llm/digest/testimonialrow.md +2 -0
  67. package/.llm/digest/testimonialslider.md +4 -0
  68. package/.llm/digest/textarea.md +4 -0
  69. package/.llm/digest/textinput.md +4 -0
  70. package/.llm/digest/textscroll.md +43 -0
  71. package/.llm/digest/tiers.md +50 -0
  72. package/.llm/index.md +25 -2
  73. package/.llm/tokens.md +37 -1
  74. package/AGENTS.md +20 -1
  75. package/dist/components/awards-data.d.ts +24 -0
  76. package/dist/components/awards-data.js +11 -0
  77. package/dist/components/block-image-data.d.ts +24 -0
  78. package/dist/components/block-image-data.js +9 -0
  79. package/dist/components/blocks/awards/Awards.css +134 -0
  80. package/dist/components/blocks/awards/Awards.d.ts +24 -0
  81. package/dist/components/blocks/awards/Awards.js +114 -0
  82. package/dist/components/blocks/awards/Awards.types.d.ts +31 -0
  83. package/dist/components/blocks/awards/Awards.types.js +16 -0
  84. package/dist/components/blocks/awards/awards-impl.css +222 -0
  85. package/dist/components/blocks/cards-of.d.ts +16 -0
  86. package/dist/components/blocks/cards-of.js +23 -0
  87. package/dist/components/blocks/comparison-cards/ComparisonCards.css +195 -0
  88. package/dist/components/blocks/comparison-cards/ComparisonCards.d.ts +24 -0
  89. package/dist/components/blocks/comparison-cards/ComparisonCards.js +75 -0
  90. package/dist/components/blocks/comparison-cards/ComparisonCards.types.d.ts +49 -0
  91. package/dist/components/blocks/comparison-cards/ComparisonCards.types.js +26 -0
  92. package/dist/components/blocks/comparison-cards/comparison-cards-impl.css +262 -0
  93. package/dist/components/blocks/comparison-table/ComparisonTable.css +111 -0
  94. package/dist/components/blocks/comparison-table/ComparisonTable.d.ts +25 -0
  95. package/dist/components/blocks/comparison-table/ComparisonTable.js +100 -0
  96. package/dist/components/blocks/comparison-table/ComparisonTable.types.d.ts +36 -0
  97. package/dist/components/blocks/comparison-table/ComparisonTable.types.js +15 -0
  98. package/dist/components/blocks/comparison-table/comparison-table-impl.css +143 -0
  99. package/dist/components/blocks/cta-banner/CtaBanner.css +1 -0
  100. package/dist/components/blocks/cta-banner/CtaBanner.d.ts +1 -1
  101. package/dist/components/blocks/cta-banner/CtaBanner.js +3 -2
  102. package/dist/components/blocks/cta-banner/CtaBanner.types.d.ts +6 -0
  103. package/dist/components/blocks/cta-banner/CtaBanner.types.js +1 -1
  104. package/dist/components/blocks/cta-banner/cta-banner-impl.css +8 -0
  105. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.css +1 -0
  106. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.d.ts +1 -1
  107. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.js +10 -5
  108. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.d.ts +12 -0
  109. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.js +1 -1
  110. package/dist/components/blocks/cta-banner-slider/cta-banner-slider-impl.css +8 -0
  111. package/dist/components/blocks/data-table/DataTable.css +170 -0
  112. package/dist/components/blocks/data-table/DataTable.d.ts +29 -0
  113. package/dist/components/blocks/data-table/DataTable.js +84 -0
  114. package/dist/components/blocks/data-table/DataTable.types.d.ts +69 -0
  115. package/dist/components/blocks/data-table/DataTable.types.js +19 -0
  116. package/dist/components/blocks/data-table/data-table-impl.css +155 -0
  117. package/dist/components/blocks/download-banner/DownloadBanner.css +228 -0
  118. package/dist/components/blocks/download-banner/DownloadBanner.d.ts +28 -0
  119. package/dist/components/blocks/download-banner/DownloadBanner.js +75 -0
  120. package/dist/components/blocks/download-banner/DownloadBanner.types.d.ts +56 -0
  121. package/dist/components/blocks/download-banner/DownloadBanner.types.js +23 -0
  122. package/dist/components/blocks/download-banner/download-banner-impl.css +216 -0
  123. package/dist/components/blocks/faq-accordion/FaqAccordion.css +1 -0
  124. package/dist/components/blocks/faq-accordion/faq-accordion-impl.css +3 -7
  125. package/dist/components/blocks/feature-bullets/FeatureBullets.css +1 -0
  126. package/dist/components/blocks/feature-bullets/feature-bullets-impl.css +14 -1
  127. package/dist/components/blocks/feature-cards/FeatureCards.css +1 -0
  128. package/dist/components/blocks/feature-cards/FeatureCards.d.ts +2 -1
  129. package/dist/components/blocks/feature-cards/FeatureCards.js +4 -21
  130. package/dist/components/blocks/feature-cards/feature-cards-impl.css +10 -9
  131. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.css +115 -0
  132. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.d.ts +30 -0
  133. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.js +160 -0
  134. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.types.d.ts +52 -0
  135. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.types.js +17 -0
  136. package/dist/components/blocks/feature-cards-carousel/feature-cards-carousel-impl.css +207 -0
  137. package/dist/components/blocks/feature-scroll/FeatureScroll.css +1 -0
  138. package/dist/components/blocks/feature-split/FeatureSplit.css +1 -0
  139. package/dist/components/blocks/feature-split/feature-split-impl.css +14 -1
  140. package/dist/components/blocks/feature-stack/FeatureStack.css +86 -0
  141. package/dist/components/blocks/feature-stack/FeatureStack.d.ts +19 -0
  142. package/dist/components/blocks/feature-stack/FeatureStack.js +27 -0
  143. package/dist/components/blocks/feature-stack/FeatureStack.types.d.ts +34 -0
  144. package/dist/components/blocks/feature-stack/FeatureStack.types.js +14 -0
  145. package/dist/components/blocks/feature-stack/feature-stack-impl.css +87 -0
  146. package/dist/components/blocks/image-banner/ImageBanner.css +133 -0
  147. package/dist/components/blocks/image-banner/ImageBanner.d.ts +32 -0
  148. package/dist/components/blocks/image-banner/ImageBanner.js +41 -0
  149. package/dist/components/blocks/image-banner/ImageBanner.types.d.ts +54 -0
  150. package/dist/components/blocks/image-banner/ImageBanner.types.js +14 -0
  151. package/dist/components/blocks/image-banner/image-banner-impl.css +281 -0
  152. package/dist/components/blocks/landing-hero/LandingHero.css +1 -0
  153. package/dist/components/blocks/landing-hero/LandingHero.d.ts +1 -1
  154. package/dist/components/blocks/landing-hero/LandingHero.js +4 -3
  155. package/dist/components/blocks/landing-hero/LandingHero.types.d.ts +7 -3
  156. package/dist/components/blocks/logo-columns/LogoColumns.css +1 -0
  157. package/dist/components/blocks/logo-rows/LogoRows.css +1 -0
  158. package/dist/components/blocks/page-header/PageHeader.css +1 -0
  159. package/dist/components/blocks/page-header/PageHeader.d.ts +1 -1
  160. package/dist/components/blocks/page-header/PageHeader.js +3 -2
  161. package/dist/components/blocks/page-header/PageHeader.types.d.ts +6 -0
  162. package/dist/components/blocks/page-header/PageHeader.types.js +1 -1
  163. package/dist/components/blocks/page-header/page-header-impl.css +10 -0
  164. package/dist/components/blocks/product-hero/ProductHero.css +8 -3
  165. package/dist/components/blocks/product-hero/ProductHero.d.ts +1 -1
  166. package/dist/components/blocks/product-hero/ProductHero.js +5 -2
  167. package/dist/components/blocks/product-hero/ProductHero.types.d.ts +5 -1
  168. package/dist/components/blocks/product-hero/ProductHero.types.js +1 -0
  169. package/dist/components/blocks/product-hero/product-hero-impl.css +43 -12
  170. package/dist/components/blocks/resource-banner/ResourceBanner.css +106 -0
  171. package/dist/components/blocks/resource-banner/ResourceBanner.d.ts +32 -0
  172. package/dist/components/blocks/resource-banner/ResourceBanner.js +51 -0
  173. package/dist/components/blocks/resource-banner/ResourceBanner.types.d.ts +44 -0
  174. package/dist/components/blocks/resource-banner/ResourceBanner.types.js +14 -0
  175. package/dist/components/blocks/resource-banner/resource-banner-impl.css +69 -0
  176. package/dist/components/blocks/scene-scroll/SceneScroll.css +93 -0
  177. package/dist/components/blocks/scene-scroll/SceneScroll.d.ts +36 -0
  178. package/dist/components/blocks/scene-scroll/SceneScroll.js +54 -0
  179. package/dist/components/blocks/scene-scroll/SceneScroll.types.d.ts +32 -0
  180. package/dist/components/blocks/scene-scroll/SceneScroll.types.js +15 -0
  181. package/dist/components/blocks/scene-scroll/scene-scroll-impl.css +275 -0
  182. package/dist/components/blocks/stats/Stats.css +139 -0
  183. package/dist/components/blocks/stats/Stats.d.ts +24 -0
  184. package/dist/components/blocks/stats/Stats.js +120 -0
  185. package/dist/components/blocks/stats/Stats.types.d.ts +36 -0
  186. package/dist/components/blocks/stats/Stats.types.js +19 -0
  187. package/dist/components/blocks/stats/stats-count.d.ts +34 -0
  188. package/dist/components/blocks/stats/stats-count.js +61 -0
  189. package/dist/components/blocks/stats/stats-impl.css +284 -0
  190. package/dist/components/blocks/stats/use-wheel.d.ts +37 -0
  191. package/dist/components/blocks/stats/use-wheel.js +126 -0
  192. package/dist/components/blocks/steps/Steps.css +202 -0
  193. package/dist/components/blocks/steps/Steps.d.ts +32 -0
  194. package/dist/components/blocks/steps/Steps.js +65 -0
  195. package/dist/components/blocks/steps/Steps.types.d.ts +48 -0
  196. package/dist/components/blocks/steps/Steps.types.js +21 -0
  197. package/dist/components/blocks/steps/steps-impl.css +216 -0
  198. package/dist/components/blocks/steps/use-turn.d.ts +33 -0
  199. package/dist/components/blocks/steps/use-turn.js +75 -0
  200. package/dist/components/blocks/sticky-cards/StickyCards.css +154 -0
  201. package/dist/components/blocks/sticky-cards/StickyCards.d.ts +35 -0
  202. package/dist/components/blocks/sticky-cards/StickyCards.js +153 -0
  203. package/dist/components/blocks/sticky-cards/StickyCards.types.d.ts +43 -0
  204. package/dist/components/blocks/sticky-cards/StickyCards.types.js +18 -0
  205. package/dist/components/blocks/sticky-cards/sticky-cards-impl.css +393 -0
  206. package/dist/components/blocks/team-grid/TeamGrid.css +159 -0
  207. package/dist/components/blocks/team-grid/TeamGrid.d.ts +28 -0
  208. package/dist/components/blocks/team-grid/TeamGrid.js +74 -0
  209. package/dist/components/blocks/team-grid/TeamGrid.types.d.ts +51 -0
  210. package/dist/components/blocks/team-grid/TeamGrid.types.js +20 -0
  211. package/dist/components/blocks/team-grid/team-grid-impl.css +129 -0
  212. package/dist/components/blocks/testimonial-row/TestimonialRow.css +1 -0
  213. package/dist/components/blocks/testimonial-row/TestimonialRow.d.ts +1 -1
  214. package/dist/components/blocks/testimonial-row/TestimonialRow.js +4 -3
  215. package/dist/components/blocks/testimonial-row/TestimonialRow.types.d.ts +3 -0
  216. package/dist/components/blocks/testimonial-row/TestimonialRow.types.js +1 -1
  217. package/dist/components/blocks/testimonial-row/testimonial-row-impl.css +8 -0
  218. package/dist/components/blocks/testimonial-slider/TestimonialSlider.css +1 -0
  219. package/dist/components/blocks/testimonial-slider/TestimonialSlider.d.ts +1 -1
  220. package/dist/components/blocks/testimonial-slider/TestimonialSlider.js +2 -2
  221. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.d.ts +8 -0
  222. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.js +1 -1
  223. package/dist/components/blocks/text-scroll/TextScroll.css +53 -0
  224. package/dist/components/blocks/text-scroll/TextScroll.d.ts +5 -0
  225. package/dist/components/blocks/text-scroll/TextScroll.js +71 -0
  226. package/dist/components/blocks/text-scroll/TextScroll.types.d.ts +22 -0
  227. package/dist/components/blocks/text-scroll/TextScroll.types.js +10 -0
  228. package/dist/components/blocks/text-scroll/text-scroll-impl.css +115 -0
  229. package/dist/components/blocks/tiers/Tiers.css +233 -0
  230. package/dist/components/blocks/tiers/Tiers.d.ts +32 -0
  231. package/dist/components/blocks/tiers/Tiers.js +68 -0
  232. package/dist/components/blocks/tiers/Tiers.types.d.ts +45 -0
  233. package/dist/components/blocks/tiers/Tiers.types.js +25 -0
  234. package/dist/components/blocks/tiers/tiers-impl.css +185 -0
  235. package/dist/components/blocks/use-rotation.d.ts +12 -2
  236. package/dist/components/blocks/use-rotation.js +6 -28
  237. package/dist/components/comparison-cards-data.d.ts +59 -0
  238. package/dist/components/comparison-cards-data.js +12 -0
  239. package/dist/components/comparison-table-data.d.ts +39 -0
  240. package/dist/components/comparison-table-data.js +11 -0
  241. package/dist/components/core/accordion-item/AccordionItem.css +1 -5
  242. package/dist/components/core/background/Background.css +92 -0
  243. package/dist/components/core/background/Background.d.ts +27 -0
  244. package/dist/components/core/background/Background.js +45 -0
  245. package/dist/components/core/background/Background.types.d.ts +39 -0
  246. package/dist/components/core/background/Background.types.js +11 -0
  247. package/dist/components/core/background/background-impl.css +760 -0
  248. package/dist/components/core/background/halftone.d.ts +134 -0
  249. package/dist/components/core/background/halftone.js +722 -0
  250. package/dist/components/core/background/patterns.d.ts +66 -0
  251. package/dist/components/core/background/patterns.js +244 -0
  252. package/dist/components/core/background/shader.d.ts +44 -0
  253. package/dist/components/core/background/shader.js +307 -0
  254. package/dist/components/core/background/use-halftone.d.ts +15 -0
  255. package/dist/components/core/background/use-halftone.js +27 -0
  256. package/dist/components/core/background/use-offscreen.d.ts +10 -0
  257. package/dist/components/core/background/use-offscreen.js +30 -0
  258. package/dist/components/core/background/use-shader.d.ts +11 -0
  259. package/dist/components/core/background/use-shader.js +25 -0
  260. package/dist/components/core/background/use-spotlight.d.ts +14 -0
  261. package/dist/components/core/background/use-spotlight.js +73 -0
  262. package/dist/components/core/bottom-sheet/BottomSheet.js +2 -2
  263. package/dist/components/core/bottom-sheet/BottomSheet.types.d.ts +3 -1
  264. package/dist/components/core/breadcrumb/Breadcrumb.d.ts +1 -0
  265. package/dist/components/core/breadcrumb/Breadcrumb.js +1 -0
  266. package/dist/components/core/breadcrumb/breadcrumb-impl.css +11 -0
  267. package/dist/components/core/button/button-impl.css +14 -1
  268. package/dist/components/core/illustration-card/IllustrationCard.css +40 -0
  269. package/dist/components/core/illustration-card/IllustrationCard.d.ts +22 -0
  270. package/dist/components/core/illustration-card/IllustrationCard.js +82 -0
  271. package/dist/components/core/illustration-card/IllustrationCard.types.d.ts +23 -0
  272. package/dist/components/core/illustration-card/IllustrationCard.types.js +8 -0
  273. package/dist/components/core/illustration-card/illustration-card-impl.css +47 -0
  274. package/dist/components/core/illustration-scene/IllustrationScene.css +41 -0
  275. package/dist/components/core/illustration-scene/IllustrationScene.d.ts +14 -0
  276. package/dist/components/core/illustration-scene/IllustrationScene.js +16 -0
  277. package/dist/components/core/illustration-scene/IllustrationScene.types.d.ts +32 -0
  278. package/dist/components/core/illustration-scene/IllustrationScene.types.js +8 -0
  279. package/dist/components/core/illustration-scene/illustration-scene-impl.css +46 -0
  280. package/dist/components/core/link/Link.js +7 -3
  281. package/dist/components/core/link/link-impl.css +29 -2
  282. package/dist/components/core/navbar/Navbar.css +2 -2
  283. package/dist/components/core/navbar/Navbar.types.d.ts +1 -1
  284. package/dist/components/core/navbar-item/NavbarItem.d.ts +2 -1
  285. package/dist/components/core/navbar-item/NavbarItem.js +3 -10
  286. package/dist/components/core/navbar-item/NavbarItem.types.d.ts +4 -1
  287. package/dist/components/core/navbar-item/NavbarItem.types.js +1 -1
  288. package/dist/components/core/navbar-item/navbar-item-impl.css +10 -0
  289. package/dist/components/core/navbar-menu/navbar-menu-impl.css +9 -0
  290. package/dist/components/core/navbar-switcher/navbar-switcher-impl.css +19 -0
  291. package/dist/components/core/pagination/Pagination.js +1 -1
  292. package/dist/components/core/pagination/pagination-impl.css +9 -0
  293. package/dist/components/core/pagination-dots/PaginationDots.d.ts +1 -1
  294. package/dist/components/core/pagination-dots/PaginationDots.js +3 -3
  295. package/dist/components/core/pagination-dots/PaginationDots.types.d.ts +3 -1
  296. package/dist/components/core/segmented-control/SegmentedControl.css +4 -3
  297. package/dist/components/core/segmented-control/SegmentedControl.js +17 -3
  298. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +2 -1
  299. package/dist/components/core/select/Select.js +3 -3
  300. package/dist/components/core/select/Select.types.d.ts +11 -1
  301. package/dist/components/core/select/Select.types.js +1 -1
  302. package/dist/components/core/tab-list/TabList.js +9 -1
  303. package/dist/components/core/table-header-cell/TableHeaderCell.d.ts +1 -1
  304. package/dist/components/core/table-header-cell/TableHeaderCell.js +5 -2
  305. package/dist/components/core/table-header-cell/TableHeaderCell.types.d.ts +7 -1
  306. package/dist/components/core/table-header-cell/TableHeaderCell.types.js +1 -1
  307. package/dist/components/core/text-area/TextArea.d.ts +1 -1
  308. package/dist/components/core/text-area/TextArea.js +2 -2
  309. package/dist/components/core/text-area/TextArea.types.d.ts +9 -1
  310. package/dist/components/core/text-area/TextArea.types.js +1 -1
  311. package/dist/components/core/text-input/TextInput.d.ts +1 -1
  312. package/dist/components/core/text-input/TextInput.js +2 -2
  313. package/dist/components/core/text-input/TextInput.types.d.ts +9 -1
  314. package/dist/components/core/text-input/TextInput.types.js +1 -1
  315. package/dist/components/data-table-data.d.ts +33 -0
  316. package/dist/components/data-table-data.js +12 -0
  317. package/dist/components/download-banner-data.d.ts +52 -0
  318. package/dist/components/download-banner-data.js +11 -0
  319. package/dist/components/index.d.ts +51 -0
  320. package/dist/components/index.js +38 -0
  321. package/dist/components/resource-banner-data.d.ts +34 -0
  322. package/dist/components/resource-banner-data.js +13 -0
  323. package/dist/components/scene-scroll-data.d.ts +24 -0
  324. package/dist/components/scene-scroll-data.js +9 -0
  325. package/dist/components/stats-data.d.ts +28 -0
  326. package/dist/components/stats-data.js +11 -0
  327. package/dist/components/steps-data.d.ts +38 -0
  328. package/dist/components/steps-data.js +13 -0
  329. package/dist/components/sticky-cards-data.d.ts +43 -0
  330. package/dist/components/sticky-cards-data.js +12 -0
  331. package/dist/components/team-grid-data.d.ts +38 -0
  332. package/dist/components/team-grid-data.js +11 -0
  333. package/dist/components/tiers-data.d.ts +47 -0
  334. package/dist/components/tiers-data.js +13 -0
  335. package/dist/marketing.css +101 -28
  336. package/package.json +1 -1
@@ -0,0 +1,34 @@
1
+ /**
2
+ * The arithmetic of a Stats figure counting up: which figures can, what one reads partway there,
3
+ * and the curve it climbs on. Pure, so it is tested without a browser to animate in.
4
+ */
5
+ /** A figure that can count: the one number in it, and what is written either side. */
6
+ export interface Countable {
7
+ before: string;
8
+ whole: number;
9
+ /** How many places after the point the figure is written to — '1.2B' counts in tenths. */
10
+ places: number;
11
+ /** Whether the figure groups its thousands with commas — '1,000+' climbs as '640', '1,000'. */
12
+ grouped: boolean;
13
+ after: string;
14
+ }
15
+ /**
16
+ * The number in a figure, where it has exactly one.
17
+ *
18
+ * Exactly one, because a value with two is not a quantity: '24/7' counted up is '3/7' on the way,
19
+ * which is a different claim rather than a smaller one. A value with none — 'Free', 'Always' —
20
+ * simply shows. Everything either side of the number is kept as written, so '$' and 'M+' stand
21
+ * still while the digits climb.
22
+ */
23
+ export declare function countable(value: string): Countable | null;
24
+ /** The figure at a share of the way to its value, written the way the value is. */
25
+ export declare function partway(figure: Countable, share: number): string;
26
+ /**
27
+ * A `cubic-bezier()` easing, as a function of time.
28
+ *
29
+ * The count moves on motion.easing.reveal, the curve the figure itself rises on, so the number and
30
+ * the words under it settle together. A transition can name the token; a number drawn frame by
31
+ * frame cannot, so the curve is read off the token and walked here. Anything that is not a
32
+ * `cubic-bezier()` — a keyword, or nothing — counts evenly rather than on a curve invented here.
33
+ */
34
+ export declare function easing(value: string): (time: number) => number;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * The arithmetic of a Stats figure counting up: which figures can, what one reads partway there,
3
+ * and the curve it climbs on. Pure, so it is tested without a browser to animate in.
4
+ */
5
+ /**
6
+ * The number in a figure, where it has exactly one.
7
+ *
8
+ * Exactly one, because a value with two is not a quantity: '24/7' counted up is '3/7' on the way,
9
+ * which is a different claim rather than a smaller one. A value with none — 'Free', 'Always' —
10
+ * simply shows. Everything either side of the number is kept as written, so '$' and 'M+' stand
11
+ * still while the digits climb.
12
+ */
13
+ export function countable(value) {
14
+ const match = /^(\D*)(\d{1,3}(?:,\d{3})+|\d+)(?:\.(\d+))?(\D*)$/.exec(value);
15
+ if (match === null)
16
+ return null;
17
+ const [, before = '', digits = '', fraction = '', after = ''] = match;
18
+ return {
19
+ before,
20
+ whole: Number.parseFloat(`${digits.replace(/,/g, '')}.${fraction || '0'}`),
21
+ places: fraction.length,
22
+ grouped: digits.includes(','),
23
+ after,
24
+ };
25
+ }
26
+ /** The figure at a share of the way to its value, written the way the value is. */
27
+ export function partway(figure, share) {
28
+ const [whole = '0', fraction] = (figure.whole * share).toFixed(figure.places).split('.');
29
+ const digits = figure.grouped ? whole.replace(/\B(?=(\d{3})+(?!\d))/g, ',') : whole;
30
+ return `${figure.before}${digits}${fraction === undefined ? '' : `.${fraction}`}${figure.after}`;
31
+ }
32
+ /**
33
+ * A `cubic-bezier()` easing, as a function of time.
34
+ *
35
+ * The count moves on motion.easing.reveal, the curve the figure itself rises on, so the number and
36
+ * the words under it settle together. A transition can name the token; a number drawn frame by
37
+ * frame cannot, so the curve is read off the token and walked here. Anything that is not a
38
+ * `cubic-bezier()` — a keyword, or nothing — counts evenly rather than on a curve invented here.
39
+ */
40
+ export function easing(value) {
41
+ const points = /cubic-bezier\(([^)]*)\)/.exec(value)?.[1]?.split(',').map(Number);
42
+ if (points?.length !== 4 || points.some((point) => !Number.isFinite(point)))
43
+ return (time) => time;
44
+ const [x1 = 0, y1 = 0, x2 = 1, y2 = 1] = points;
45
+ const along = (a, b, s) => 3 * a * s * (1 - s) ** 2 + 3 * b * s * s * (1 - s) + s ** 3;
46
+ return (time) => {
47
+ // Halving for the point on the curve whose x is the time: monotonic in x, so it always lands,
48
+ // and twenty halvings is closer than a pixel of any figure this draws.
49
+ let low = 0;
50
+ let high = 1;
51
+ let s = time;
52
+ for (let step = 0; step < 20; step += 1) {
53
+ s = (low + high) / 2;
54
+ if (along(x1, x2, s) < time)
55
+ low = s;
56
+ else
57
+ high = s;
58
+ }
59
+ return along(y1, y2, s);
60
+ };
61
+ }
@@ -0,0 +1,284 @@
1
+ /*
2
+ * Scoped to this package, like the generated sheet beside it.
3
+ */
4
+
5
+ /*
6
+ * A heading with no line under it closes up. Its bound step is the distance to the line, and with
7
+ * nothing there it would only add to the step from the header to the figures. `:last-child` is the
8
+ * condition itself, TestimonialRow's way, rather than a prop standing in for it.
9
+ */
10
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__title:last-child {
11
+ margin-block-end: 0;
12
+ }
13
+
14
+ /*
15
+ * The figure as written and the running number share one cell.
16
+ *
17
+ * Both in the first row and column, so the cell is as wide as the wider of the two — which is the
18
+ * final figure, the running number never having more digits than the one it is climbing to. That
19
+ * is what holds the width while it counts: the label under it and the figures beside it stay where
20
+ * they are. A grid area is a pair of lines rather than a keyword, so it cannot sit in the contract.
21
+ */
22
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__value > * {
23
+ grid-area: 1 / 1;
24
+ }
25
+
26
+ /*
27
+ * While it counts, the figure as written steps back behind the running number.
28
+ *
29
+ * Transparent rather than hidden: `visibility` and `display` would take it out of the accessibility
30
+ * tree, and it is the one thing there a screen reader should hear — the final figure, once. It also
31
+ * still holds the cell's width, which a hidden element would not.
32
+ */
33
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__value[data-counting="true"] > .dds-stats__amount {
34
+ opacity: var(--opacity-hidden);
35
+ }
36
+
37
+ /*
38
+ * Two to a row on a phone. `minmax(0, 1fr)` rather than `1fr`, so a figure that will not break —
39
+ * a long one, at the figure's size — shrinks to its column instead of pushing the row past the page.
40
+ */
41
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list {
42
+ grid-template-columns: repeat(2, minmax(0, 1fr));
43
+ }
44
+
45
+ /*
46
+ * On a phone, the wheel: one figure in place, the one before it smaller above, the next smaller
47
+ * below, turning on every motion.duration.hold — the reference site's mobile stats. useWheel sets
48
+ * `data-wheel` only below the fold, for two figures or more, and never for a reader who asked for
49
+ * less motion; without it the figures are the grid above.
50
+ *
51
+ * Start-aligned, as the heading is on a phone, and larger than the grid's figures — font.figure-lg
52
+ * for the number and body.lg for its label: one figure has the row to itself, and it is the one
53
+ * thing the band is showing.
54
+ *
55
+ * Every figure stands in the same cell, so the list is as tall as the tallest figure and each one
56
+ * is moved off it rather than laid out beside it. A step is a whole figure's own height — `100%` of
57
+ * the item, which the cell stretches to the tallest — rather than the arithmetic below: that sum is
58
+ * one line of label, and a label that wraps to two in German, or stands taller in Tamil, set every
59
+ * figure on the wheel into the next. The sum still sizes the room above and below. `--item` is a figure's height, the figure's line
60
+ * and the label's under it, so a step on the wheel is one figure: the one above sits a whole figure
61
+ * higher, at --dds-stats-wheel-side of its size (0.65) — the reference's scale, small enough that the one in place is plainly
62
+ * the one being read. The block padding is the room the side figures need, which is what is left of
63
+ * a figure's height once it is that far out and that much smaller.
64
+ *
65
+ * The side figures fade towards the band by a mask rather than by an ink of their own, so the wheel
66
+ * reads on every ground without a colour per ground.
67
+ */
68
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] {
69
+ --dds-stats-wheel-item: calc(
70
+ var(--font-figure-lg-size) * var(--font-figure-lg-line-height) + var(--space-gap-sm) + var(--font-body-lg-size) *
71
+ var(--font-body-lg-line-height)
72
+ );
73
+
74
+ /* The wheel's geometry, the reference's numbers, named once. The side figures' scale; the scale a
75
+ figure shrinks to out of sight; the share of a figure's height the side figures need as room
76
+ above and below; and where the mask's fade stops, from either edge. */
77
+ --dds-stats-wheel-side: 0.65;
78
+ --dds-stats-wheel-away: 0.4;
79
+ --dds-stats-wheel-room: 0.85;
80
+ --dds-stats-wheel-fade: 35%;
81
+
82
+ grid-template-columns: minmax(0, 1fr);
83
+ mask-image: linear-gradient(
84
+ transparent,
85
+ black var(--dds-stats-wheel-fade),
86
+ black calc(100% - var(--dds-stats-wheel-fade)),
87
+ transparent
88
+ );
89
+ padding-block: calc(var(--dds-stats-wheel-item) * var(--dds-stats-wheel-room));
90
+ }
91
+
92
+ /*
93
+ * The wheel is a tab stop while it turns — focus holds it still — so it shows where focus is. The
94
+ * ring is drawn inside: the mask would fade one drawn outside at its top and foot.
95
+ */
96
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel]:focus-visible {
97
+ outline: var(--border-width-focus) solid var(--color-border-focus);
98
+ outline-offset: calc(-1 * var(--border-width-focus));
99
+ }
100
+
101
+ :where([data-dds-context="marketing"]) .dds-stats[data-ground="strong"] .dds-stats__list[data-wheel]:focus-visible {
102
+ outline-color: var(--color-border-focus-on-brand-strong);
103
+ }
104
+
105
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] > .dds-stats__item {
106
+ grid-area: 1 / 1;
107
+ transform-origin: left center;
108
+ transition-duration: var(--motion-duration-turn);
109
+ transition-property: opacity, scale, translate;
110
+ transition-timing-function: var(--motion-easing-reveal);
111
+ }
112
+
113
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] .dds-stats__value {
114
+ font-family: var(--font-figure-lg-family);
115
+ font-size: var(--font-figure-lg-size);
116
+ font-weight: var(--font-figure-lg-weight);
117
+ letter-spacing: var(--font-figure-lg-letter-spacing);
118
+ line-height: var(--font-figure-lg-line-height);
119
+ }
120
+
121
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] .dds-stats__label {
122
+ font-family: var(--font-body-lg-family);
123
+ font-size: var(--font-body-lg-size);
124
+ font-weight: var(--font-body-lg-weight);
125
+ letter-spacing: var(--font-body-lg-letter-spacing);
126
+ line-height: var(--font-body-lg-line-height);
127
+ }
128
+
129
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] > [data-slot='above'] {
130
+ scale: var(--dds-stats-wheel-side);
131
+ translate: 0 -100%;
132
+ }
133
+
134
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] > [data-slot='below'] {
135
+ animation: dds-stats-wheel-in var(--motion-duration-turn) var(--motion-easing-reveal);
136
+ scale: var(--dds-stats-wheel-side);
137
+ translate: 0 100%;
138
+ }
139
+
140
+ /*
141
+ * Out of sight, a figure waits where the one above leaves to — risen and shrunk away — so leaving is
142
+ * a movement on, never back. It comes in below by an arrival of its own, from further down and
143
+ * smaller, rather than by crossing the wheel to get there.
144
+ */
145
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] > [data-slot='hidden'] {
146
+ opacity: var(--opacity-hidden);
147
+ scale: var(--dds-stats-wheel-away);
148
+ translate: 0 -100%;
149
+ }
150
+
151
+ @keyframes dds-stats-wheel-in {
152
+ from {
153
+ opacity: var(--opacity-hidden);
154
+ scale: var(--dds-stats-wheel-away);
155
+ translate: 0 200%;
156
+ }
157
+ }
158
+
159
+ /*
160
+ * A reader who asked for less motion never gets the wheel — useWheel leaves the figures a grid — so
161
+ * this only says so in the sheet as well: were a wheel ever drawn for them, it would change places
162
+ * without moving.
163
+ */
164
+ @media (prefers-reduced-motion: reduce) {
165
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list[data-wheel] > .dds-stats__item {
166
+ animation: none;
167
+ transition: none;
168
+ }
169
+
170
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__dot {
171
+ transition: none;
172
+ }
173
+ }
174
+
175
+ /*
176
+ * The wheel's dots on its start edge, and the figures beside them.
177
+ *
178
+ * While the wheel turns the section is a grid of two columns: the dots as wide as a dot, the figures
179
+ * the rest, the heading across both. The dots stand level with the figure in place, which is the
180
+ * middle of the list. Between the two, space.gap.md — the step between a control and what it
181
+ * describes.
182
+ *
183
+ * The dot in place is drawn long, size.dot.current, at full strength: PaginationDots' current dot
184
+ * on end, growing as the next figure turns in, the dots after it moving along to make room. It is
185
+ * the brand's coral, color.bg.brand, where the rest take the band's ink: the one mark of colour in
186
+ * the section says which figure is being read, and it holds on all three grounds.
187
+ */
188
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__inner:has(> .dds-stats__list[data-wheel]) {
189
+ column-gap: var(--space-gap-md);
190
+ display: grid;
191
+ grid-template-columns: auto minmax(0, 1fr);
192
+ }
193
+
194
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__inner:has(> .dds-stats__list[data-wheel]) > .dds-stats__header {
195
+ grid-column: 1 / -1;
196
+ }
197
+
198
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__inner:has(> .dds-stats__list[data-wheel]) > .dds-stats__dots {
199
+ align-self: center;
200
+ display: flex;
201
+ }
202
+
203
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__dot {
204
+ transition-duration: var(--motion-duration-turn);
205
+ transition-property: background-color, block-size, opacity;
206
+ transition-timing-function: var(--motion-easing-reveal);
207
+ }
208
+
209
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__dot[data-current="true"] {
210
+ background-color: var(--color-bg-brand);
211
+ block-size: var(--size-dot-current);
212
+ opacity: var(--opacity-dot-current);
213
+ }
214
+
215
+ /*
216
+ * The figures shrink towards the edge they start at, so the one above and the one below stay in line
217
+ * with the one in place and with the heading over them.
218
+ */
219
+ :where([data-dds-context="marketing"]) .dds-stats:dir(rtl) .dds-stats__list[data-wheel] > .dds-stats__item {
220
+ transform-origin: right center;
221
+ }
222
+
223
+ /*
224
+ * From the fold, the header and every figure are centred, the heading over the set it names.
225
+ *
226
+ * FeatureCards' rule and its reason: centred text starts every line at a different edge, which
227
+ * costs little across a wide measure and a great deal across a narrow one. The header and the line
228
+ * under it are capped narrower than the column, so `margin-inline: auto` is what centres those
229
+ * boxes rather than their words inside a box left at the start edge. A figure is centred in its
230
+ * column, so a row of them sits under the middle of the heading rather than to its start.
231
+ *
232
+ * `48rem` longhand because `var()` is not permitted in a container query condition, and it is the
233
+ * width the rest of this package folds at.
234
+ */
235
+ @container (min-width: 48rem) {
236
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__header {
237
+ align-items: center;
238
+ margin-inline: auto;
239
+ text-align: center;
240
+ }
241
+
242
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__description {
243
+ margin-inline: auto;
244
+ }
245
+
246
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__item {
247
+ align-items: center;
248
+ text-align: center;
249
+ }
250
+
251
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__value {
252
+ justify-items: center;
253
+ }
254
+
255
+ /*
256
+ * How many figures share a row, read from the figures — FeatureCards' way, `:has()` asking the
257
+ * markup for the count it already holds rather than a prop restating it.
258
+ *
259
+ * Three to a row by default, which is five as three and two, and six as two rows of three. Three
260
+ * or fewer take one row of their own. Four are two rows of two here and one row at full width:
261
+ * four figures across a tablet's column are each narrower than a figure is wide at this size.
262
+ *
263
+ * Where `:has()` is not supported every count takes three to a row: the set still reads, only
264
+ * less exactly.
265
+ */
266
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list {
267
+ grid-template-columns: repeat(3, minmax(0, 1fr));
268
+ }
269
+
270
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list:has(> :nth-child(4):last-child),
271
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list:has(> :nth-child(2):last-child) {
272
+ grid-template-columns: repeat(2, minmax(0, 1fr));
273
+ }
274
+
275
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list:has(> :only-child) {
276
+ grid-template-columns: minmax(0, 1fr);
277
+ }
278
+ }
279
+
280
+ @container (min-width: 64rem) {
281
+ :where([data-dds-context="marketing"]) .dds-stats .dds-stats__list:has(> :nth-child(4):last-child) {
282
+ grid-template-columns: repeat(4, minmax(0, 1fr));
283
+ }
284
+ }
@@ -0,0 +1,37 @@
1
+ import { type FocusEvent, type PointerEvent, type RefObject } from 'react';
2
+ /** Where a figure stands on the wheel, relative to the one in place. */
3
+ export type WheelSlot = 'active' | 'above' | 'below' | 'hidden';
4
+ /**
5
+ * A figure's place on the wheel at a given turn: the one in place, the one it replaced above it, the
6
+ * one coming in below it, and every other figure out of sight.
7
+ *
8
+ * With two figures there is no "above" — the one that leaves comes straight back in below — and with
9
+ * three the one above goes straight to below, which the stylesheet draws as an arrival from below
10
+ * rather than as a figure crossing the wheel.
11
+ */
12
+ export declare function slotOf(at: number, turn: number, count: number): WheelSlot;
13
+ /**
14
+ * The phone's wheel of figures — the reference site's mobile stats: one figure in place, the one
15
+ * before it smaller above and the next smaller below, turning on to the next every
16
+ * motion.duration.hold plus motion.duration.turn.
17
+ *
18
+ * It turns only where every condition for it holds, and otherwise hands back `wheeling: false` and
19
+ * the figures are the grid they are from the fold:
20
+ * - the section is narrower than the fold, read off the section itself — a container, not the
21
+ * viewport, as the stylesheet reads it;
22
+ * - there are two figures or more;
23
+ * - the reader has not asked for less motion — the grid is the still version of the same set;
24
+ * - the section is on screen. A wheel nobody can see does not turn, and starts again where it was;
25
+ * - nothing holds or has stopped it — see `hold`.
26
+ */
27
+ export declare function useWheel(section: RefObject<HTMLElement | null>, count: number): {
28
+ wheeling: boolean;
29
+ turn: number;
30
+ hold: {
31
+ onPointerEnter: (event: PointerEvent<HTMLElement>) => void;
32
+ onPointerLeave: (event: PointerEvent<HTMLElement>) => void;
33
+ onFocus: () => void;
34
+ onBlur: (event: FocusEvent<HTMLElement>) => void;
35
+ onPointerDownCapture: (event: PointerEvent<HTMLElement>) => void;
36
+ };
37
+ };
@@ -0,0 +1,126 @@
1
+ 'use client';
2
+ import { useEffect, useState } from 'react';
3
+ import { milliseconds } from '../../css-time.js';
4
+ /**
5
+ * The width the figures stop turning at and lay out as a grid: the package's fold, in rem. A
6
+ * number here rather than a token read, because the stylesheet's container query states the same
7
+ * width longhand — `var()` is not permitted in one — and the two have to agree.
8
+ */
9
+ const FOLD_REM = 48;
10
+ /**
11
+ * A figure's place on the wheel at a given turn: the one in place, the one it replaced above it, the
12
+ * one coming in below it, and every other figure out of sight.
13
+ *
14
+ * With two figures there is no "above" — the one that leaves comes straight back in below — and with
15
+ * three the one above goes straight to below, which the stylesheet draws as an arrival from below
16
+ * rather than as a figure crossing the wheel.
17
+ */
18
+ export function slotOf(at, turn, count) {
19
+ const place = (((at - turn) % count) + count) % count;
20
+ if (place === 0)
21
+ return 'active';
22
+ if (place === 1)
23
+ return 'below';
24
+ if (place === count - 1)
25
+ return 'above';
26
+ return 'hidden';
27
+ }
28
+ /**
29
+ * The phone's wheel of figures — the reference site's mobile stats: one figure in place, the one
30
+ * before it smaller above and the next smaller below, turning on to the next every
31
+ * motion.duration.hold plus motion.duration.turn.
32
+ *
33
+ * It turns only where every condition for it holds, and otherwise hands back `wheeling: false` and
34
+ * the figures are the grid they are from the fold:
35
+ * - the section is narrower than the fold, read off the section itself — a container, not the
36
+ * viewport, as the stylesheet reads it;
37
+ * - there are two figures or more;
38
+ * - the reader has not asked for less motion — the grid is the still version of the same set;
39
+ * - the section is on screen. A wheel nobody can see does not turn, and starts again where it was;
40
+ * - nothing holds or has stopped it — see `hold`.
41
+ */
42
+ export function useWheel(section, count) {
43
+ const [narrow, setNarrow] = useState(false);
44
+ const [seen, setSeen] = useState(false);
45
+ const [turn, setTurn] = useState(0);
46
+ const [still, setStill] = useState(false);
47
+ /*
48
+ A pointer over the wheel or focus on it holds it for as long as it lasts; a press anywhere on
49
+ it stops it for good — CtaBannerSlider's rule, by way of the WAI carousel pattern: a reader who
50
+ has touched the thing is reading it. Together they are the way to stop a wheel that would
51
+ otherwise turn for as long as it is on screen, which WCAG 2.2.2 asks of anything that moves on
52
+ its own for more than five seconds: the keyboard's way is the wheel's own tab stop, the
53
+ pointer's is resting on it, and a touch screen's is a tap.
54
+ */
55
+ const [held, setHeld] = useState(false);
56
+ const [stopped, setStopped] = useState(false);
57
+ const wheeling = narrow && count > 1 && !still;
58
+ // Asked live rather than once: a reader who turns on reduced motion mid-visit stops the wheel then.
59
+ useEffect(() => {
60
+ if (typeof window.matchMedia !== 'function')
61
+ return undefined;
62
+ const query = window.matchMedia('(prefers-reduced-motion: reduce)');
63
+ const follow = () => setStill(query.matches);
64
+ follow();
65
+ query.addEventListener?.('change', follow);
66
+ return () => query.removeEventListener?.('change', follow);
67
+ }, []);
68
+ useEffect(() => {
69
+ const element = section.current;
70
+ if (element === null || typeof ResizeObserver === 'undefined')
71
+ return undefined;
72
+ const measure = () => {
73
+ const rem = Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;
74
+ // The layout width, not the drawn one: getBoundingClientRect reports the box after
75
+ // transforms, so a section shown scaled down — a thumbnail of the page, a zoomed preview —
76
+ // measured as a phone and turned into the wheel at desktop width. offsetWidth is the width
77
+ // the section is laid out at, the same one its container queries read.
78
+ setNarrow(element.offsetWidth < FOLD_REM * rem);
79
+ };
80
+ measure();
81
+ const observer = new ResizeObserver(measure);
82
+ observer.observe(element);
83
+ return () => observer.disconnect();
84
+ }, [section]);
85
+ useEffect(() => {
86
+ const element = section.current;
87
+ if (element === null || typeof IntersectionObserver === 'undefined')
88
+ return undefined;
89
+ const observer = new IntersectionObserver(([entry]) => setSeen(entry?.isIntersecting ?? false));
90
+ observer.observe(element);
91
+ return () => observer.disconnect();
92
+ }, [section]);
93
+ useEffect(() => {
94
+ const element = section.current;
95
+ if (!wheeling || !seen || held || stopped || element === null)
96
+ return undefined;
97
+ const style = getComputedStyle(element);
98
+ const every = (milliseconds(style.getPropertyValue('--motion-duration-hold')) ?? 0) +
99
+ (milliseconds(style.getPropertyValue('--motion-duration-turn')) ?? 0);
100
+ if (every <= 0)
101
+ return undefined;
102
+ const timer = window.setInterval(() => setTurn((at) => at + 1), every);
103
+ return () => window.clearInterval(timer);
104
+ }, [section, wheeling, seen, held, stopped]);
105
+ /** Spread on the wheel's list: what holds it, and what stops it. */
106
+ const hold = {
107
+ onPointerEnter: (event) => {
108
+ if (event.pointerType === 'mouse')
109
+ setHeld(true);
110
+ },
111
+ onPointerLeave: (event) => {
112
+ if (event.pointerType === 'mouse')
113
+ setHeld(false);
114
+ },
115
+ onFocus: () => setHeld(true),
116
+ onBlur: (event) => {
117
+ if (!event.currentTarget.contains(event.relatedTarget))
118
+ setHeld(false);
119
+ },
120
+ onPointerDownCapture: (event) => {
121
+ if (event.isPrimary && (event.pointerType !== 'mouse' || event.button === 0))
122
+ setStopped(true);
123
+ },
124
+ };
125
+ return { wheeling, turn, hold };
126
+ }