@deriv-com/dds-marketing 1.0.2 → 1.1.1

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 (315) hide show
  1. package/.llm/components/awards.md +209 -0
  2. package/.llm/components/background.md +89 -40
  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 +9 -12
  7. package/.llm/components/ctabannerslider.md +15 -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 +2 -2
  15. package/.llm/components/illustrationscene.md +6 -10
  16. package/.llm/components/imagebanner.md +278 -0
  17. package/.llm/components/navbar.md +1 -1
  18. package/.llm/components/navbaritem.md +4 -0
  19. package/.llm/components/pageheader.md +4 -3
  20. package/.llm/components/paginationdots.md +6 -1
  21. package/.llm/components/producthero.md +35 -11
  22. package/.llm/components/resourcebanner.md +247 -0
  23. package/.llm/components/scenescroll.md +222 -0
  24. package/.llm/components/select.md +17 -0
  25. package/.llm/components/stats.md +219 -0
  26. package/.llm/components/steps.md +286 -0
  27. package/.llm/components/stickycards.md +251 -0
  28. package/.llm/components/tableheadercell.md +19 -0
  29. package/.llm/components/teamgrid.md +243 -0
  30. package/.llm/components/testimonialrow.md +5 -0
  31. package/.llm/components/testimonialslider.md +14 -1
  32. package/.llm/components/textarea.md +13 -0
  33. package/.llm/components/textinput.md +13 -0
  34. package/.llm/components/textscroll.md +187 -0
  35. package/.llm/components/tiers.md +227 -0
  36. package/.llm/digest/awards.md +45 -0
  37. package/.llm/digest/background.md +11 -10
  38. package/.llm/digest/bottomsheet.md +2 -0
  39. package/.llm/digest/comparisoncards.md +51 -0
  40. package/.llm/digest/comparisontable.md +53 -0
  41. package/.llm/digest/ctabanner.md +4 -4
  42. package/.llm/digest/ctabannerslider.md +4 -0
  43. package/.llm/digest/datatable.md +65 -0
  44. package/.llm/digest/downloadbanner.md +65 -0
  45. package/.llm/digest/featurecards.md +1 -1
  46. package/.llm/digest/featurecardscarousel.md +54 -0
  47. package/.llm/digest/featuresplit.md +1 -0
  48. package/.llm/digest/featurestack.md +48 -0
  49. package/.llm/digest/illustrationscene.md +2 -3
  50. package/.llm/digest/imagebanner.md +64 -0
  51. package/.llm/digest/navbaritem.md +1 -0
  52. package/.llm/digest/pageheader.md +2 -1
  53. package/.llm/digest/paginationdots.md +3 -1
  54. package/.llm/digest/producthero.md +4 -2
  55. package/.llm/digest/resourcebanner.md +53 -0
  56. package/.llm/digest/scenescroll.md +49 -0
  57. package/.llm/digest/select.md +5 -0
  58. package/.llm/digest/stats.md +46 -0
  59. package/.llm/digest/steps.md +55 -0
  60. package/.llm/digest/stickycards.md +52 -0
  61. package/.llm/digest/tableheadercell.md +4 -0
  62. package/.llm/digest/teamgrid.md +53 -0
  63. package/.llm/digest/testimonialrow.md +2 -0
  64. package/.llm/digest/testimonialslider.md +4 -0
  65. package/.llm/digest/textarea.md +4 -0
  66. package/.llm/digest/textinput.md +4 -0
  67. package/.llm/digest/textscroll.md +43 -0
  68. package/.llm/digest/tiers.md +50 -0
  69. package/.llm/index.md +19 -3
  70. package/.llm/tokens.md +26 -1
  71. package/AGENTS.md +17 -1
  72. package/dist/components/awards-data.d.ts +24 -0
  73. package/dist/components/awards-data.js +11 -0
  74. package/dist/components/block-image-data.d.ts +24 -0
  75. package/dist/components/block-image-data.js +9 -0
  76. package/dist/components/blocks/awards/Awards.css +134 -0
  77. package/dist/components/blocks/awards/Awards.d.ts +24 -0
  78. package/dist/components/blocks/awards/Awards.js +114 -0
  79. package/dist/components/blocks/awards/Awards.types.d.ts +31 -0
  80. package/dist/components/blocks/awards/Awards.types.js +16 -0
  81. package/dist/components/blocks/awards/awards-impl.css +222 -0
  82. package/dist/components/blocks/cards-of.d.ts +16 -0
  83. package/dist/components/blocks/cards-of.js +23 -0
  84. package/dist/components/blocks/comparison-cards/ComparisonCards.css +195 -0
  85. package/dist/components/blocks/comparison-cards/ComparisonCards.d.ts +24 -0
  86. package/dist/components/blocks/comparison-cards/ComparisonCards.js +75 -0
  87. package/dist/components/blocks/comparison-cards/ComparisonCards.types.d.ts +49 -0
  88. package/dist/components/blocks/comparison-cards/ComparisonCards.types.js +26 -0
  89. package/dist/components/blocks/comparison-cards/comparison-cards-impl.css +262 -0
  90. package/dist/components/blocks/comparison-table/ComparisonTable.css +111 -0
  91. package/dist/components/blocks/comparison-table/ComparisonTable.d.ts +25 -0
  92. package/dist/components/blocks/comparison-table/ComparisonTable.js +100 -0
  93. package/dist/components/blocks/comparison-table/ComparisonTable.types.d.ts +36 -0
  94. package/dist/components/blocks/comparison-table/ComparisonTable.types.js +15 -0
  95. package/dist/components/blocks/comparison-table/comparison-table-impl.css +143 -0
  96. package/dist/components/blocks/cta-banner/CtaBanner.css +1 -0
  97. package/dist/components/blocks/cta-banner/CtaBanner.js +2 -2
  98. package/dist/components/blocks/cta-banner/CtaBanner.types.d.ts +4 -3
  99. package/dist/components/blocks/cta-banner/CtaBanner.types.js +1 -1
  100. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.css +1 -0
  101. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.d.ts +1 -1
  102. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.js +6 -2
  103. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.d.ts +8 -0
  104. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.js +1 -1
  105. package/dist/components/blocks/data-table/DataTable.css +170 -0
  106. package/dist/components/blocks/data-table/DataTable.d.ts +29 -0
  107. package/dist/components/blocks/data-table/DataTable.js +84 -0
  108. package/dist/components/blocks/data-table/DataTable.types.d.ts +69 -0
  109. package/dist/components/blocks/data-table/DataTable.types.js +19 -0
  110. package/dist/components/blocks/data-table/data-table-impl.css +155 -0
  111. package/dist/components/blocks/download-banner/DownloadBanner.css +228 -0
  112. package/dist/components/blocks/download-banner/DownloadBanner.d.ts +28 -0
  113. package/dist/components/blocks/download-banner/DownloadBanner.js +75 -0
  114. package/dist/components/blocks/download-banner/DownloadBanner.types.d.ts +56 -0
  115. package/dist/components/blocks/download-banner/DownloadBanner.types.js +23 -0
  116. package/dist/components/blocks/download-banner/download-banner-impl.css +216 -0
  117. package/dist/components/blocks/faq-accordion/FaqAccordion.css +1 -0
  118. package/dist/components/blocks/faq-accordion/faq-accordion-impl.css +3 -7
  119. package/dist/components/blocks/feature-bullets/FeatureBullets.css +1 -0
  120. package/dist/components/blocks/feature-bullets/feature-bullets-impl.css +14 -1
  121. package/dist/components/blocks/feature-cards/FeatureCards.css +1 -0
  122. package/dist/components/blocks/feature-cards/FeatureCards.d.ts +2 -1
  123. package/dist/components/blocks/feature-cards/FeatureCards.js +4 -21
  124. package/dist/components/blocks/feature-cards/feature-cards-impl.css +10 -9
  125. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.css +115 -0
  126. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.d.ts +30 -0
  127. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.js +160 -0
  128. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.types.d.ts +52 -0
  129. package/dist/components/blocks/feature-cards-carousel/FeatureCardsCarousel.types.js +17 -0
  130. package/dist/components/blocks/feature-cards-carousel/feature-cards-carousel-impl.css +207 -0
  131. package/dist/components/blocks/feature-scroll/FeatureScroll.css +1 -0
  132. package/dist/components/blocks/feature-split/FeatureSplit.css +1 -0
  133. package/dist/components/blocks/feature-split/feature-split-impl.css +14 -1
  134. package/dist/components/blocks/feature-stack/FeatureStack.css +86 -0
  135. package/dist/components/blocks/feature-stack/FeatureStack.d.ts +19 -0
  136. package/dist/components/blocks/feature-stack/FeatureStack.js +27 -0
  137. package/dist/components/blocks/feature-stack/FeatureStack.types.d.ts +34 -0
  138. package/dist/components/blocks/feature-stack/FeatureStack.types.js +14 -0
  139. package/dist/components/blocks/feature-stack/feature-stack-impl.css +87 -0
  140. package/dist/components/blocks/image-banner/ImageBanner.css +133 -0
  141. package/dist/components/blocks/image-banner/ImageBanner.d.ts +32 -0
  142. package/dist/components/blocks/image-banner/ImageBanner.js +41 -0
  143. package/dist/components/blocks/image-banner/ImageBanner.types.d.ts +54 -0
  144. package/dist/components/blocks/image-banner/ImageBanner.types.js +14 -0
  145. package/dist/components/blocks/image-banner/image-banner-impl.css +281 -0
  146. package/dist/components/blocks/landing-hero/LandingHero.css +1 -0
  147. package/dist/components/blocks/logo-columns/LogoColumns.css +1 -0
  148. package/dist/components/blocks/logo-rows/LogoRows.css +1 -0
  149. package/dist/components/blocks/page-header/PageHeader.css +1 -0
  150. package/dist/components/blocks/page-header/PageHeader.js +2 -2
  151. package/dist/components/blocks/page-header/PageHeader.types.d.ts +4 -2
  152. package/dist/components/blocks/page-header/PageHeader.types.js +1 -1
  153. package/dist/components/blocks/page-header/page-header-impl.css +5 -3
  154. package/dist/components/blocks/product-hero/ProductHero.css +8 -3
  155. package/dist/components/blocks/product-hero/ProductHero.d.ts +1 -1
  156. package/dist/components/blocks/product-hero/ProductHero.js +5 -2
  157. package/dist/components/blocks/product-hero/ProductHero.types.d.ts +5 -1
  158. package/dist/components/blocks/product-hero/ProductHero.types.js +1 -0
  159. package/dist/components/blocks/product-hero/product-hero-impl.css +43 -12
  160. package/dist/components/blocks/resource-banner/ResourceBanner.css +106 -0
  161. package/dist/components/blocks/resource-banner/ResourceBanner.d.ts +32 -0
  162. package/dist/components/blocks/resource-banner/ResourceBanner.js +51 -0
  163. package/dist/components/blocks/resource-banner/ResourceBanner.types.d.ts +44 -0
  164. package/dist/components/blocks/resource-banner/ResourceBanner.types.js +14 -0
  165. package/dist/components/blocks/resource-banner/resource-banner-impl.css +69 -0
  166. package/dist/components/blocks/scene-scroll/SceneScroll.css +93 -0
  167. package/dist/components/blocks/scene-scroll/SceneScroll.d.ts +36 -0
  168. package/dist/components/blocks/scene-scroll/SceneScroll.js +54 -0
  169. package/dist/components/blocks/scene-scroll/SceneScroll.types.d.ts +32 -0
  170. package/dist/components/blocks/scene-scroll/SceneScroll.types.js +15 -0
  171. package/dist/components/blocks/scene-scroll/scene-scroll-impl.css +275 -0
  172. package/dist/components/blocks/stats/Stats.css +139 -0
  173. package/dist/components/blocks/stats/Stats.d.ts +24 -0
  174. package/dist/components/blocks/stats/Stats.js +120 -0
  175. package/dist/components/blocks/stats/Stats.types.d.ts +36 -0
  176. package/dist/components/blocks/stats/Stats.types.js +19 -0
  177. package/dist/components/blocks/stats/stats-count.d.ts +34 -0
  178. package/dist/components/blocks/stats/stats-count.js +61 -0
  179. package/dist/components/blocks/stats/stats-impl.css +284 -0
  180. package/dist/components/blocks/stats/use-wheel.d.ts +37 -0
  181. package/dist/components/blocks/stats/use-wheel.js +126 -0
  182. package/dist/components/blocks/steps/Steps.css +202 -0
  183. package/dist/components/blocks/steps/Steps.d.ts +32 -0
  184. package/dist/components/blocks/steps/Steps.js +65 -0
  185. package/dist/components/blocks/steps/Steps.types.d.ts +48 -0
  186. package/dist/components/blocks/steps/Steps.types.js +21 -0
  187. package/dist/components/blocks/steps/steps-impl.css +216 -0
  188. package/dist/components/blocks/steps/use-turn.d.ts +33 -0
  189. package/dist/components/blocks/steps/use-turn.js +75 -0
  190. package/dist/components/blocks/sticky-cards/StickyCards.css +154 -0
  191. package/dist/components/blocks/sticky-cards/StickyCards.d.ts +35 -0
  192. package/dist/components/blocks/sticky-cards/StickyCards.js +153 -0
  193. package/dist/components/blocks/sticky-cards/StickyCards.types.d.ts +43 -0
  194. package/dist/components/blocks/sticky-cards/StickyCards.types.js +18 -0
  195. package/dist/components/blocks/sticky-cards/sticky-cards-impl.css +393 -0
  196. package/dist/components/blocks/team-grid/TeamGrid.css +159 -0
  197. package/dist/components/blocks/team-grid/TeamGrid.d.ts +28 -0
  198. package/dist/components/blocks/team-grid/TeamGrid.js +74 -0
  199. package/dist/components/blocks/team-grid/TeamGrid.types.d.ts +51 -0
  200. package/dist/components/blocks/team-grid/TeamGrid.types.js +20 -0
  201. package/dist/components/blocks/team-grid/team-grid-impl.css +129 -0
  202. package/dist/components/blocks/testimonial-row/TestimonialRow.css +1 -0
  203. package/dist/components/blocks/testimonial-row/TestimonialRow.d.ts +1 -1
  204. package/dist/components/blocks/testimonial-row/TestimonialRow.js +4 -3
  205. package/dist/components/blocks/testimonial-row/TestimonialRow.types.d.ts +3 -0
  206. package/dist/components/blocks/testimonial-row/TestimonialRow.types.js +1 -1
  207. package/dist/components/blocks/testimonial-row/testimonial-row-impl.css +8 -0
  208. package/dist/components/blocks/testimonial-slider/TestimonialSlider.css +1 -0
  209. package/dist/components/blocks/testimonial-slider/TestimonialSlider.d.ts +1 -1
  210. package/dist/components/blocks/testimonial-slider/TestimonialSlider.js +2 -2
  211. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.d.ts +8 -0
  212. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.js +1 -1
  213. package/dist/components/blocks/text-scroll/TextScroll.css +53 -0
  214. package/dist/components/blocks/text-scroll/TextScroll.d.ts +5 -0
  215. package/dist/components/blocks/text-scroll/TextScroll.js +71 -0
  216. package/dist/components/blocks/text-scroll/TextScroll.types.d.ts +22 -0
  217. package/dist/components/blocks/text-scroll/TextScroll.types.js +10 -0
  218. package/dist/components/blocks/text-scroll/text-scroll-impl.css +115 -0
  219. package/dist/components/blocks/tiers/Tiers.css +233 -0
  220. package/dist/components/blocks/tiers/Tiers.d.ts +32 -0
  221. package/dist/components/blocks/tiers/Tiers.js +68 -0
  222. package/dist/components/blocks/tiers/Tiers.types.d.ts +45 -0
  223. package/dist/components/blocks/tiers/Tiers.types.js +25 -0
  224. package/dist/components/blocks/tiers/tiers-impl.css +185 -0
  225. package/dist/components/blocks/use-rotation.d.ts +12 -2
  226. package/dist/components/blocks/use-rotation.js +6 -28
  227. package/dist/components/comparison-cards-data.d.ts +59 -0
  228. package/dist/components/comparison-cards-data.js +12 -0
  229. package/dist/components/comparison-table-data.d.ts +39 -0
  230. package/dist/components/comparison-table-data.js +11 -0
  231. package/dist/components/core/accordion-item/AccordionItem.css +1 -5
  232. package/dist/components/core/background/Background.css +23 -0
  233. package/dist/components/core/background/Background.d.ts +10 -4
  234. package/dist/components/core/background/Background.js +16 -7
  235. package/dist/components/core/background/Background.types.d.ts +11 -8
  236. package/dist/components/core/background/Background.types.js +3 -1
  237. package/dist/components/core/background/background-impl.css +334 -1
  238. package/dist/components/core/background/halftone.d.ts +11 -0
  239. package/dist/components/core/background/halftone.js +43 -3
  240. package/dist/components/core/background/patterns.d.ts +66 -0
  241. package/dist/components/core/background/patterns.js +244 -0
  242. package/dist/components/core/background/shader.d.ts +44 -0
  243. package/dist/components/core/background/shader.js +307 -0
  244. package/dist/components/core/background/use-shader.d.ts +11 -0
  245. package/dist/components/core/background/use-shader.js +25 -0
  246. package/dist/components/core/background/use-spotlight.d.ts +2 -1
  247. package/dist/components/core/background/use-spotlight.js +9 -1
  248. package/dist/components/core/bottom-sheet/BottomSheet.js +2 -2
  249. package/dist/components/core/bottom-sheet/BottomSheet.types.d.ts +3 -1
  250. package/dist/components/core/breadcrumb/Breadcrumb.d.ts +1 -0
  251. package/dist/components/core/breadcrumb/Breadcrumb.js +1 -0
  252. package/dist/components/core/breadcrumb/breadcrumb-impl.css +11 -0
  253. package/dist/components/core/button/button-impl.css +14 -1
  254. package/dist/components/core/illustration-card/IllustrationCard.js +1 -1
  255. package/dist/components/core/illustration-card/illustration-card-impl.css +20 -0
  256. package/dist/components/core/illustration-scene/IllustrationScene.css +4 -7
  257. package/dist/components/core/illustration-scene/IllustrationScene.types.d.ts +2 -3
  258. package/dist/components/core/illustration-scene/illustration-scene-impl.css +22 -1
  259. package/dist/components/core/link/Link.js +7 -3
  260. package/dist/components/core/link/link-impl.css +29 -2
  261. package/dist/components/core/navbar/Navbar.css +2 -2
  262. package/dist/components/core/navbar/Navbar.types.d.ts +1 -1
  263. package/dist/components/core/navbar-item/NavbarItem.d.ts +2 -1
  264. package/dist/components/core/navbar-item/NavbarItem.js +3 -10
  265. package/dist/components/core/navbar-item/NavbarItem.types.d.ts +4 -1
  266. package/dist/components/core/navbar-item/NavbarItem.types.js +1 -1
  267. package/dist/components/core/navbar-item/navbar-item-impl.css +10 -0
  268. package/dist/components/core/navbar-menu/navbar-menu-impl.css +9 -0
  269. package/dist/components/core/navbar-switcher/navbar-switcher-impl.css +19 -0
  270. package/dist/components/core/pagination/Pagination.js +1 -1
  271. package/dist/components/core/pagination/pagination-impl.css +9 -0
  272. package/dist/components/core/pagination-dots/PaginationDots.d.ts +1 -1
  273. package/dist/components/core/pagination-dots/PaginationDots.js +3 -3
  274. package/dist/components/core/pagination-dots/PaginationDots.types.d.ts +3 -1
  275. package/dist/components/core/segmented-control/SegmentedControl.css +4 -3
  276. package/dist/components/core/segmented-control/SegmentedControl.js +17 -3
  277. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +2 -1
  278. package/dist/components/core/select/Select.js +3 -3
  279. package/dist/components/core/select/Select.types.d.ts +11 -1
  280. package/dist/components/core/select/Select.types.js +1 -1
  281. package/dist/components/core/tab-list/TabList.js +9 -1
  282. package/dist/components/core/table-header-cell/TableHeaderCell.d.ts +1 -1
  283. package/dist/components/core/table-header-cell/TableHeaderCell.js +5 -2
  284. package/dist/components/core/table-header-cell/TableHeaderCell.types.d.ts +7 -1
  285. package/dist/components/core/table-header-cell/TableHeaderCell.types.js +1 -1
  286. package/dist/components/core/text-area/TextArea.d.ts +1 -1
  287. package/dist/components/core/text-area/TextArea.js +2 -2
  288. package/dist/components/core/text-area/TextArea.types.d.ts +9 -1
  289. package/dist/components/core/text-area/TextArea.types.js +1 -1
  290. package/dist/components/core/text-input/TextInput.d.ts +1 -1
  291. package/dist/components/core/text-input/TextInput.js +2 -2
  292. package/dist/components/core/text-input/TextInput.types.d.ts +9 -1
  293. package/dist/components/core/text-input/TextInput.types.js +1 -1
  294. package/dist/components/data-table-data.d.ts +33 -0
  295. package/dist/components/data-table-data.js +12 -0
  296. package/dist/components/download-banner-data.d.ts +52 -0
  297. package/dist/components/download-banner-data.js +11 -0
  298. package/dist/components/index.d.ts +45 -0
  299. package/dist/components/index.js +32 -0
  300. package/dist/components/resource-banner-data.d.ts +34 -0
  301. package/dist/components/resource-banner-data.js +13 -0
  302. package/dist/components/scene-scroll-data.d.ts +24 -0
  303. package/dist/components/scene-scroll-data.js +9 -0
  304. package/dist/components/stats-data.d.ts +28 -0
  305. package/dist/components/stats-data.js +11 -0
  306. package/dist/components/steps-data.d.ts +38 -0
  307. package/dist/components/steps-data.js +13 -0
  308. package/dist/components/sticky-cards-data.d.ts +43 -0
  309. package/dist/components/sticky-cards-data.js +12 -0
  310. package/dist/components/team-grid-data.d.ts +38 -0
  311. package/dist/components/team-grid-data.js +11 -0
  312. package/dist/components/tiers-data.d.ts +47 -0
  313. package/dist/components/tiers-data.js +13 -0
  314. package/dist/marketing.css +77 -28
  315. package/package.json +1 -1
@@ -0,0 +1,216 @@
1
+ /*
2
+ * Scoped to this package, like the generated sheet beside it.
3
+ *
4
+ * `:where([data-dds-context="marketing"])` confines these rules without contributing specificity,
5
+ * so each is decided against the generated rule on its own terms.
6
+ */
7
+
8
+ /*
9
+ * The first step is not ruled off from what is above it, because nothing is.
10
+ *
11
+ * Every step carries a rule on its start edge, which is what puts a line between each pair and
12
+ * none under the last. The cost is one at the top of the list, where it reads as a lid rather than
13
+ * a separator — and the list is already bounded by the title's own step above it.
14
+ *
15
+ * `:first-child` is the condition itself. Nothing about a step knows it is first, and a prop
16
+ * standing in for the question would be the page answering something the DOM already has.
17
+ */
18
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__step:first-child {
19
+ border-block-start-width: 0;
20
+ padding-block-start: 0;
21
+ }
22
+
23
+ /*
24
+ * One column below the fold, and the picture leads it.
25
+ *
26
+ * The row direction is the contract's to say — it varies by a styling axis, which is what
27
+ * `structure[]` is for, and the generated sheet carries both values. What is left here is the
28
+ * fold, which a binding cannot express: `structure` has no width to attach a rule to.
29
+ *
30
+ * `column` rather than `column-reverse` for both positions, because the picture is first in the
31
+ * markup: the reference design stacks it above the steps on a phone whichever side it takes on a
32
+ * desktop, and a sequence reads that way — the scene, then the steps through it.
33
+ *
34
+ * Written a class deeper than it looks so it wins against the generated
35
+ * `.dds-steps[data-media-position="end"] .dds-steps__split`, which a plainer selector here would
36
+ * lose to however late it is loaded — the fault FeatureBullets shipped with for an afternoon.
37
+ *
38
+ * `48rem` longhand because `var()` is not permitted in a container query condition, and it is the
39
+ * width the rest of this package folds at.
40
+ */
41
+ @container (max-width: 47.9375rem) {
42
+ :where([data-dds-context="marketing"]) .dds-steps[data-media-position] .dds-steps__split {
43
+ flex-direction: column;
44
+ }
45
+ }
46
+
47
+ /*
48
+ * At full width the steps take a measure and the picture takes the rest.
49
+ *
50
+ * The reference design splits the row evenly at its own breakpoint. A share holds everywhere, and
51
+ * it is the one FeatureSplit and FeatureBullets take, so three splits down a page put their
52
+ * pictures on the same line; the picture growing into whatever is left is what keeps the square
53
+ * square without either half naming a height.
54
+ */
55
+ @container (min-width: 48rem) {
56
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__split {
57
+ align-items: center;
58
+ }
59
+
60
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__content {
61
+ flex: 0 0 45%;
62
+ }
63
+
64
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__media {
65
+ flex: 1 1 0;
66
+ }
67
+ }
68
+
69
+ /*
70
+ * Whatever the page put in the picture fills the square.
71
+ *
72
+ * The slot takes a node rather than a source, so what arrives is the page's element and this
73
+ * cannot know whether it carries dimensions. `cover` rather than `contain`, because the slot is a
74
+ * square the section decided on and a picture letterboxed inside it would show the ground through
75
+ * a corner the section rounded.
76
+ */
77
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__media > *,
78
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__media img {
79
+ block-size: 100%;
80
+ inline-size: 100%;
81
+ object-fit: cover;
82
+ }
83
+
84
+ /*
85
+ * Bare media is a block; a component keeps its own display.
86
+ *
87
+ * `display: block` is for what arrives as a raw element — an image, a video, an inline SVG — which
88
+ * sits on a text baseline otherwise and leaves a gap under it. Written at no weight at all, so a
89
+ * component the page placed here — an IllustrationScene, whose grid lays its pane over its photo —
90
+ * keeps the display its own sheet gives it. In the rule above, a class deeper than the component's
91
+ * root, it turned the scene's grid into a block, and the pane fell below the photo and was clipped.
92
+ */
93
+ :where([data-dds-context="marketing"] .dds-steps .dds-steps__media > *, [data-dds-context="marketing"] .dds-steps .dds-steps__media img) {
94
+ display: block;
95
+ }
96
+
97
+
98
+ /*
99
+ * The number's line is the title's line, so the figure is centred on it.
100
+ *
101
+ * Top-aligned in the row, the number and the title each start their own line box; a line of the
102
+ * same height for both puts the larger figure's middle on the title's first line, overhanging it
103
+ * evenly above and below. The height is the title's own type, font.h5's size by its leading, so it
104
+ * follows the title down to a phone's sizes without a number here.
105
+ *
106
+ * Written a class deeper than it looks, so it wins against the generated `line-height` from the
107
+ * number's font.h4 binding on weight rather than on load order.
108
+ */
109
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__step > .dds-steps__number {
110
+ line-height: calc(var(--font-h5-size) * var(--font-h5-line-height));
111
+ }
112
+
113
+ /*
114
+ * Under `autoplay`: the steps take their turn.
115
+ *
116
+ * Every step keeps its rule, the first included — the current step's fill runs along it, and the
117
+ * first step's turn needs a rule to run on as much as the others'.
118
+ */
119
+ :where([data-dds-context="marketing"]) .dds-steps[data-autoplay] .dds-steps__step:first-child {
120
+ border-block-start-width: var(--border-width-default);
121
+ padding-block-start: var(--space-inset-md);
122
+ }
123
+
124
+ /*
125
+ * The current step's number at full strength, the others receded: opacity.dot-current against
126
+ * opacity.dot-rest, the pagination dots' pair, because the numbers are doing the dots' job here —
127
+ * saying where in the set the reader is. Only the number recedes. The titles and lines stay at full
128
+ * ink, so every step is as readable while it waits as when it is current.
129
+ */
130
+ :where([data-dds-context="marketing"]) .dds-steps[data-autoplay] .dds-steps__number {
131
+ opacity: var(--opacity-dot-rest);
132
+ transition: opacity var(--motion-duration-shift) var(--motion-easing-standard);
133
+ }
134
+
135
+ :where([data-dds-context="marketing"]) .dds-steps[data-autoplay] .dds-steps__step[data-current="true"] .dds-steps__number {
136
+ opacity: var(--opacity-dot-current);
137
+ }
138
+
139
+ /*
140
+ * The whole row is the step's button, not only its title: the title's box stretched over the row,
141
+ * which the row's `position: relative` holds. The text stays where it is and a press anywhere on the
142
+ * step chooses it.
143
+ */
144
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__trigger::after {
145
+ content: '';
146
+ inset: 0;
147
+ position: absolute;
148
+ }
149
+
150
+ :where([data-dds-context="marketing"]) .dds-steps[data-ground="strong"] .dds-steps__trigger:focus-visible {
151
+ outline-color: var(--color-border-focus-on-brand-strong);
152
+ }
153
+
154
+ /*
155
+ * The fill: the current step's rule, drawn from the start edge over motion.duration.dwell. When it
156
+ * ends the next step takes over — the component listens for the end, so the bar and the turn are
157
+ * one clock. Paused wherever the turn is held; full and still where the turn has stopped or never
158
+ * runs, so the current step is still marked.
159
+ */
160
+ @keyframes dds-steps-fill {
161
+ from {
162
+ scale: 0 1;
163
+ }
164
+ }
165
+
166
+ :where([data-dds-context="marketing"]) .dds-steps[data-autoplay] .dds-steps__step[data-current="true"] > .dds-steps__progress {
167
+ display: block;
168
+ inset-block-start: calc(-1 * var(--border-width-default));
169
+ inset-inline: 0;
170
+ transform-origin: left center;
171
+ }
172
+
173
+ :where([data-dds-context="marketing"]) .dds-steps[data-autoplay]:dir(rtl) .dds-steps__step > .dds-steps__progress {
174
+ transform-origin: right center;
175
+ }
176
+
177
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__list[data-turning="true"] > .dds-steps__step[data-current="true"] > .dds-steps__progress {
178
+ animation: dds-steps-fill var(--motion-duration-dwell) linear;
179
+ }
180
+
181
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__list[data-playing="false"] > .dds-steps__step[data-current="true"] > .dds-steps__progress {
182
+ animation-play-state: paused;
183
+ }
184
+
185
+ /*
186
+ * The steps' own pictures share the media cell, and the current step's is the one shown — the
187
+ * first while the list is still. They cross over rather than cut, in motion.duration.shift.
188
+ */
189
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__media:has(> .dds-steps__image) {
190
+ display: grid;
191
+ }
192
+
193
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__media > .dds-steps__image {
194
+ grid-area: 1 / 1;
195
+ opacity: 0;
196
+ transition-property: opacity;
197
+ }
198
+
199
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__media > .dds-steps__image[data-current="true"] {
200
+ opacity: 1;
201
+ }
202
+
203
+ /*
204
+ * A reader who asked for less motion: no fill, no crossing over. The list never turns for them — the
205
+ * component asks too, but only once it runs, and the server's first paint is drawn before it does.
206
+ */
207
+ @media (prefers-reduced-motion: reduce) {
208
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__list[data-turning] > .dds-steps__step[data-current] > .dds-steps__progress {
209
+ animation: none;
210
+ }
211
+
212
+ :where([data-dds-context="marketing"]) .dds-steps .dds-steps__media > .dds-steps__image,
213
+ :where([data-dds-context="marketing"]) .dds-steps[data-autoplay] .dds-steps__number {
214
+ transition: none;
215
+ }
216
+ }
@@ -0,0 +1,33 @@
1
+ import { type FocusEvent, type PointerEvent } from 'react';
2
+ /**
3
+ * The steps taking their turn under `autoplay`: which step is current, and whether the turn is
4
+ * running.
5
+ *
6
+ * The timing is not here. The current step's rule fills over motion.duration.dwell as a CSS
7
+ * animation, and the turn moves on when that animation ends (`next`), so the bar a reader watches
8
+ * and the step changing are one clock rather than two that drift. Holding the turn is pausing that
9
+ * animation, which is what `playing` is for: the stylesheet pauses the fill wherever it is false.
10
+ *
11
+ * It turns only where every condition for it holds:
12
+ * - `autoplay` is on and there are two steps or more;
13
+ * - the reader has not asked for less motion — asked live, so turning it on mid-visit stops it;
14
+ * - the section is on screen. A turn nobody can see does not run, and starts again where it was;
15
+ * - nothing holds it: a pointer over the section or focus inside it holds it for as long as it
16
+ * lasts, and pressing a step stops it for good — CtaBannerSlider's rule, by way of the WAI
17
+ * carousel pattern: a reader who has chosen a step is reading it. The pointer's way, the
18
+ * keyboard's and a touch screen's, which WCAG 2.2.2 asks for of anything that moves on its own.
19
+ */
20
+ export declare function useTurn(count: number, autoplay: boolean): {
21
+ current: number;
22
+ turning: boolean;
23
+ playing: boolean;
24
+ next: () => void;
25
+ choose: (at: number) => void;
26
+ section: import("react").RefObject<HTMLElement | null>;
27
+ hold: {
28
+ onPointerEnter: (event: PointerEvent<HTMLElement>) => void;
29
+ onPointerLeave: (event: PointerEvent<HTMLElement>) => void;
30
+ onFocus: () => void;
31
+ onBlur: (event: FocusEvent<HTMLElement>) => void;
32
+ };
33
+ };
@@ -0,0 +1,75 @@
1
+ 'use client';
2
+ import { useCallback, useEffect, useRef, useState } from 'react';
3
+ /**
4
+ * The steps taking their turn under `autoplay`: which step is current, and whether the turn is
5
+ * running.
6
+ *
7
+ * The timing is not here. The current step's rule fills over motion.duration.dwell as a CSS
8
+ * animation, and the turn moves on when that animation ends (`next`), so the bar a reader watches
9
+ * and the step changing are one clock rather than two that drift. Holding the turn is pausing that
10
+ * animation, which is what `playing` is for: the stylesheet pauses the fill wherever it is false.
11
+ *
12
+ * It turns only where every condition for it holds:
13
+ * - `autoplay` is on and there are two steps or more;
14
+ * - the reader has not asked for less motion — asked live, so turning it on mid-visit stops it;
15
+ * - the section is on screen. A turn nobody can see does not run, and starts again where it was;
16
+ * - nothing holds it: a pointer over the section or focus inside it holds it for as long as it
17
+ * lasts, and pressing a step stops it for good — CtaBannerSlider's rule, by way of the WAI
18
+ * carousel pattern: a reader who has chosen a step is reading it. The pointer's way, the
19
+ * keyboard's and a touch screen's, which WCAG 2.2.2 asks for of anything that moves on its own.
20
+ */
21
+ export function useTurn(count, autoplay) {
22
+ const [current, setCurrent] = useState(0);
23
+ const [seen, setSeen] = useState(false);
24
+ const [still, setStill] = useState(false);
25
+ const [held, setHeld] = useState(false);
26
+ const [stopped, setStopped] = useState(false);
27
+ const section = useRef(null);
28
+ const turning = autoplay && count > 1 && !still && !stopped;
29
+ const playing = turning && seen && !held;
30
+ useEffect(() => {
31
+ if (typeof window.matchMedia !== 'function')
32
+ return undefined;
33
+ const query = window.matchMedia('(prefers-reduced-motion: reduce)');
34
+ const follow = () => setStill(query.matches);
35
+ follow();
36
+ query.addEventListener?.('change', follow);
37
+ return () => query.removeEventListener?.('change', follow);
38
+ }, []);
39
+ useEffect(() => {
40
+ const element = section.current;
41
+ if (!autoplay || element === null || typeof IntersectionObserver === 'undefined')
42
+ return undefined;
43
+ const observer = new IntersectionObserver(([entry]) => setSeen(entry?.isIntersecting ?? false));
44
+ observer.observe(element);
45
+ return () => observer.disconnect();
46
+ }, [autoplay]);
47
+ /** The current step's fill has run: the next step takes over, and the first after the last. */
48
+ const next = useCallback(() => {
49
+ if (count > 0)
50
+ setCurrent((at) => (at + 1) % count);
51
+ }, [count]);
52
+ /** A step pressed: it is current, and the turn stops for good. */
53
+ const choose = useCallback((at) => {
54
+ setCurrent(at);
55
+ setStopped(true);
56
+ }, []);
57
+ /** Spread on the section: what holds the turn. */
58
+ const hold = {
59
+ onPointerEnter: (event) => {
60
+ if (event.pointerType === 'mouse')
61
+ setHeld(true);
62
+ },
63
+ onPointerLeave: (event) => {
64
+ if (event.pointerType === 'mouse')
65
+ setHeld(false);
66
+ },
67
+ onFocus: () => setHeld(true),
68
+ onBlur: (event) => {
69
+ if (!event.currentTarget.contains(event.relatedTarget))
70
+ setHeld(false);
71
+ },
72
+ };
73
+ // A list that shrank under the current step falls back to its first.
74
+ return { current: current < count ? current : 0, turning, playing, next, choose, section, hold };
75
+ }
@@ -0,0 +1,154 @@
1
+ /* GENERATED from stickycards.contract.json. Do not edit. */
2
+
3
+ :where([data-dds-context="marketing"]) .dds-stickycards {
4
+ box-sizing: border-box;
5
+ container-type: inline-size;
6
+ display: flex;
7
+ inline-size: 100%;
8
+ justify-content: center;
9
+ overflow-wrap: anywhere;
10
+ }
11
+
12
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__inner {
13
+ box-sizing: border-box;
14
+ display: flex;
15
+ flex-direction: column;
16
+ inline-size: 100%;
17
+ min-inline-size: 0;
18
+ max-inline-size: var(--size-content-max);
19
+ padding-block: var(--space-section-default);
20
+ padding-inline: var(--space-inset-page);
21
+ row-gap: var(--space-heading-content);
22
+ }
23
+
24
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__header {
25
+ display: flex;
26
+ flex-direction: column;
27
+ min-inline-size: 0;
28
+ max-inline-size: var(--size-measure-heading);
29
+ row-gap: var(--space-gap-none);
30
+ }
31
+
32
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__title {
33
+ margin-block: 0;
34
+ text-wrap: balance;
35
+ font-family: var(--font-h2-family);
36
+ font-size: var(--font-h2-size);
37
+ font-weight: var(--font-h2-weight);
38
+ letter-spacing: var(--font-h2-letter-spacing);
39
+ line-height: var(--font-h2-line-height);
40
+ margin-block-end: var(--space-heading-title-description);
41
+ }
42
+
43
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__description {
44
+ margin-block: 0;
45
+ font-family: var(--font-body-md-family);
46
+ font-size: var(--font-body-md-size);
47
+ font-weight: var(--font-body-md-weight);
48
+ letter-spacing: var(--font-body-md-letter-spacing);
49
+ line-height: var(--font-body-md-line-height);
50
+ max-inline-size: var(--size-measure-description);
51
+ }
52
+
53
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__list {
54
+ box-sizing: border-box;
55
+ display: grid;
56
+ inline-size: 100%;
57
+ list-style: none;
58
+ margin-block: 0;
59
+ margin-inline: auto;
60
+ min-inline-size: 0;
61
+ padding: 0;
62
+ row-gap: var(--space-grid-gutter);
63
+ }
64
+
65
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__item {
66
+ display: flex;
67
+ flex-direction: column;
68
+ min-inline-size: 0;
69
+ position: relative;
70
+ }
71
+
72
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__backdrop {
73
+ inset: 0;
74
+ overflow: clip;
75
+ pointer-events: none;
76
+ position: absolute;
77
+ }
78
+
79
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__body {
80
+ box-sizing: border-box;
81
+ display: flex;
82
+ flex: auto;
83
+ flex-direction: column;
84
+ min-block-size: 0;
85
+ min-inline-size: 0;
86
+ gap: var(--space-gap-none);
87
+ }
88
+
89
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__media {
90
+ min-inline-size: 0;
91
+ overflow: clip;
92
+ }
93
+
94
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__image {
95
+ display: block;
96
+ }
97
+
98
+ :where([data-dds-context="marketing"]) .dds-stickycards .dds-stickycards__scrim {
99
+ display: none;
100
+ inset: 0;
101
+ pointer-events: none;
102
+ position: absolute;
103
+ background-color: var(--color-bg-overlay);
104
+ border-radius: var(--radius-surface);
105
+ }
106
+
107
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-ground="page"] {
108
+ background-color: var(--color-bg-page);
109
+ color: var(--color-fg-default);
110
+ }
111
+
112
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-ground="strong"] {
113
+ background-color: var(--color-bg-brand-strong);
114
+ color: var(--color-fg-on-brand-strong);
115
+ }
116
+
117
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-ground="subtle"] {
118
+ background-color: var(--color-bg-page);
119
+ background-image: linear-gradient(var(--color-bg-band-subtle), var(--color-bg-band-subtle));
120
+ color: var(--color-fg-default);
121
+ }
122
+
123
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="compact"] .dds-stickycards__image {
124
+ border-radius: var(--radius-surface-compact);
125
+ }
126
+
127
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="compact"] .dds-stickycards__item {
128
+ min-block-size: var(--size-sticky-cards-compact-min);
129
+ }
130
+
131
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="compact"] .dds-stickycards__list {
132
+ max-inline-size: var(--size-sticky-cards-compact-max);
133
+ }
134
+
135
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="compact"] .dds-stickycards__media {
136
+ border-radius: var(--radius-surface-compact);
137
+ }
138
+
139
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="feature"] .dds-stickycards__image {
140
+ border-radius: var(--radius-none);
141
+ }
142
+
143
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="feature"] .dds-stickycards__item {
144
+ min-block-size: var(--size-sticky-cards-feature-min);
145
+ }
146
+
147
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="feature"] .dds-stickycards__list {
148
+ max-inline-size: var(--size-content-max);
149
+ }
150
+
151
+ :where([data-dds-context="marketing"]) .dds-stickycards[data-layout="feature"] .dds-stickycards__media {
152
+ border-radius: var(--radius-none);
153
+ }
154
+
@@ -0,0 +1,35 @@
1
+ import './StickyCards.css';
2
+ import './sticky-cards-impl.css';
3
+ import '../block-reveal.css';
4
+ import { type StickyCardsProps } from './StickyCards.types.js';
5
+ export type { StickyCardsProps };
6
+ /**
7
+ * A heading over a pile of cards that builds as the page scrolls — the reference design's
8
+ * StickyMarketCards (`layout="compact"`), StickyMarketCardsLottie (the `media` callback) and
9
+ * StickyStackedCards (`layout="feature"`), as one block.
10
+ *
11
+ * The pile is CSS. Each card's place in the list is sticky, a step lower than the one before, and
12
+ * every row of the list is as tall as the tallest card, so the card arriving hides the one under it
13
+ * entirely and leaves only its edge. The reference measured the cards with a script and wrote the
14
+ * tallest height onto each; a grid's equal rows say the same thing before any script runs.
15
+ *
16
+ * The covered card draws back and darkens on a scroll timeline: each card's place names a view
17
+ * timeline, and the card before it runs its drawing back down that timeline — so a card recedes as
18
+ * the *next* one crosses it, which is the reference's own measure (the overlap of the next card
19
+ * over this one) said as a range. The names are per card and set here, inline, because a timeline
20
+ * a sibling reads has to be named uniquely and declared in scope on the list; the stylesheet does
21
+ * the rest. See sticky-cards-impl.css for the ranges and the fallbacks.
22
+ *
23
+ * The cards are records, drawn into Card and CardBody: Card for the fill and the corner, CardBody
24
+ * for the words at the card's inset, and the picture beside them. A record rather than a Card the
25
+ * page composes, because the pile needs to know each card's place — its step, its timeline — and
26
+ * a list of markets or steps is what a content system hands over. The one thing a record cannot
27
+ * carry is a player; `media` is how the page puts one in a card's picture slot.
28
+ *
29
+ * Nothing is hidden from assistive technology. The pile is how the list looks, not what it holds:
30
+ * every card is in the list, in order, at every scroll position.
31
+ *
32
+ * `'use client'` for the arrival, and for `useId`, which names the region by its heading and keeps
33
+ * the timeline names of two piles on one page apart.
34
+ */
35
+ export declare function StickyCards({ ground, layout, title, description, cards, media, }: StickyCardsProps): import("react").JSX.Element;
@@ -0,0 +1,153 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useRef, useState } from 'react';
4
+ import './StickyCards.css';
5
+ import './sticky-cards-impl.css';
6
+ import '../block-reveal.css';
7
+ import { given } from '../../given.js';
8
+ import { Card } from '../../core/card/Card.js';
9
+ import { CardBody } from '../../core/card-body/CardBody.js';
10
+ import { arriving, useReveal } from '../use-reveal.js';
11
+ import { stickyCardsDefaults, stickyCardsParts } from './StickyCards.types.js';
12
+ /**
13
+ * How many edges the pile shows at most — the reference design's four.
14
+ *
15
+ * Only the last four cards step down by space.pile.peek; every card before them takes the first
16
+ * card's place, so in a long set the earliest are covered whole rather than adding a fifth, sixth
17
+ * and seventh strip until the pile is taller than the card on top of it.
18
+ */
19
+ const MOST_EDGES = 4;
20
+ /** A card's step down the pile: 0 for the first of the last four and everything before it. */
21
+ const depthOf = (at, count) => Math.max(0, at - Math.max(0, count - MOST_EDGES));
22
+ /** Nothing a `media` callback can return that would draw something. */
23
+ const drawn = (node) => node !== undefined && node !== null && node !== false && node !== '';
24
+ /**
25
+ * A heading over a pile of cards that builds as the page scrolls — the reference design's
26
+ * StickyMarketCards (`layout="compact"`), StickyMarketCardsLottie (the `media` callback) and
27
+ * StickyStackedCards (`layout="feature"`), as one block.
28
+ *
29
+ * The pile is CSS. Each card's place in the list is sticky, a step lower than the one before, and
30
+ * every row of the list is as tall as the tallest card, so the card arriving hides the one under it
31
+ * entirely and leaves only its edge. The reference measured the cards with a script and wrote the
32
+ * tallest height onto each; a grid's equal rows say the same thing before any script runs.
33
+ *
34
+ * The covered card draws back and darkens on a scroll timeline: each card's place names a view
35
+ * timeline, and the card before it runs its drawing back down that timeline — so a card recedes as
36
+ * the *next* one crosses it, which is the reference's own measure (the overlap of the next card
37
+ * over this one) said as a range. The names are per card and set here, inline, because a timeline
38
+ * a sibling reads has to be named uniquely and declared in scope on the list; the stylesheet does
39
+ * the rest. See sticky-cards-impl.css for the ranges and the fallbacks.
40
+ *
41
+ * The cards are records, drawn into Card and CardBody: Card for the fill and the corner, CardBody
42
+ * for the words at the card's inset, and the picture beside them. A record rather than a Card the
43
+ * page composes, because the pile needs to know each card's place — its step, its timeline — and
44
+ * a list of markets or steps is what a content system hands over. The one thing a record cannot
45
+ * carry is a player; `media` is how the page puts one in a card's picture slot.
46
+ *
47
+ * Nothing is hidden from assistive technology. The pile is how the list looks, not what it holds:
48
+ * every card is in the list, in order, at every scroll position.
49
+ *
50
+ * `'use client'` for the arrival, and for `useId`, which names the region by its heading and keeps
51
+ * the timeline names of two piles on one page apart.
52
+ */
53
+ export function StickyCards({ ground = stickyCardsDefaults.ground, layout = stickyCardsDefaults.layout, title, description, cards, media, }) {
54
+ const titleId = useId();
55
+ const [band, revealed] = useReveal();
56
+ // The preview's bare view and a content system that has not loaded both hand over nothing; the
57
+ // heading alone is the honest drawing of an empty set.
58
+ const set = Array.isArray(cards) ? cards : [];
59
+ /*
60
+ Whether the tallest card fits the window below the bar, where the pile pins it. One that does
61
+ not would be covered before its foot was ever on screen — words a reader cannot reach — and a
62
+ translation is what makes a card that tall: German runs a third longer than the English the
63
+ pile was drawn for. The stylesheet pins nothing while this says so, and every card shows in full.
64
+
65
+ Measured rather than guessed, because only the browser knows how tall the words came out. Every
66
+ row is the tallest card's height, so the list's first item is the measure. Starts false, so the
67
+ server's HTML and the first render agree and a reader with no script still gets the pile.
68
+ */
69
+ const list = useRef(null);
70
+ const [tall, setTall] = useState(false);
71
+ /*
72
+ The heading's height and the gap under it, once measured: the heading pins above the pile and
73
+ each card stops this much lower, so the cards gather under it rather than over it. Undefined
74
+ until then, and the heading does not pin without it — on a server render, or with no script, the
75
+ cards would otherwise come to rest on top of the words.
76
+ */
77
+ const [head, setHead] = useState(undefined);
78
+ /*
79
+ How far below the heading the card on top reaches — the gap and one card's height. The heading
80
+ carries it as a margin, so it is held only while that much of the list is still to come, and
81
+ lets go at the moment the top card does: the two then scroll up as one, rather than the heading
82
+ staying behind for the cards to scroll up over it. The edges peeking under the top card do not
83
+ count: they close up into it before it moves.
84
+ */
85
+ const [tail, setTail] = useState(undefined);
86
+ useEffect(() => {
87
+ const element = list.current;
88
+ if (element === null || typeof ResizeObserver === 'undefined')
89
+ return undefined;
90
+ const measure = () => {
91
+ const item = element.firstElementChild;
92
+ if (item === null)
93
+ return;
94
+ const style = getComputedStyle(element);
95
+ const px = (name) => Number.parseFloat(style.getPropertyValue(name)) || 0;
96
+ const header = element.parentElement?.querySelector(`:scope > .${stickyCardsParts.header}`);
97
+ const under = header === null || header === undefined
98
+ ? 0
99
+ : header.offsetHeight + (Number.parseFloat(getComputedStyle(element.parentElement).rowGap) || 0);
100
+ setHead(under);
101
+ const gap = Number.parseFloat(getComputedStyle(element.parentElement).rowGap) || 0;
102
+ setTail(gap + item.offsetHeight);
103
+ // The pinned top, the heading pinned above it, and the four edges a pile can show.
104
+ const top = px('--size-bar-height') + px('--space-inset-page') + under + 4 * px('--space-pile-peek');
105
+ setTall(item.getBoundingClientRect().height + top > window.innerHeight);
106
+ };
107
+ measure();
108
+ const observer = new ResizeObserver(measure);
109
+ observer.observe(element);
110
+ window.addEventListener('resize', measure);
111
+ return () => {
112
+ observer.disconnect();
113
+ window.removeEventListener('resize', measure);
114
+ };
115
+ }, []);
116
+ // A dashed ident for each card's timeline. `useId` returns `:r1:`-style ids, which are not valid
117
+ // in an ident, so only the letters and digits are kept.
118
+ const scope = `--dds-stickycards-${titleId.replace(/[^a-zA-Z0-9]/g, '')}`;
119
+ const nameAt = (at) => `${scope}-${at}`;
120
+ /*
121
+ What each card's picture slot holds, worked out once for the whole pile. A pile is one set, so
122
+ it takes one arrangement: the words-only arrangement — title beside sentence, in the middle of
123
+ the card — only when no card in it has a picture. A pile where some do keeps every card's words
124
+ stacked at the top, so a card without a picture reads as one of the set rather than a different
125
+ kind of card.
126
+ */
127
+ const slots = set.map((card, at) => {
128
+ const player = media?.(card, at);
129
+ const hasPlayer = drawn(player);
130
+ const image = hasPlayer ? undefined : card.image;
131
+ const hasImage = image !== undefined && given(image.src);
132
+ return { player, hasPlayer, image, hasImage };
133
+ });
134
+ const pictured = slots.some((slot) => slot.hasPlayer || slot.hasImage);
135
+ return (_jsx("section", { className: stickyCardsParts.root, "data-ground": ground, "data-layout": layout, "data-pile": pictured ? 'pictured' : 'words', "data-head-pinned": head === undefined ? undefined : 'true',
136
+ // On the section, where the heading and the list under it both read it.
137
+ style: tail === undefined ? undefined : { '--dds-stickycards-tail': `${tail}px` }, "aria-labelledby": titleId, children: _jsxs("div", { className: stickyCardsParts.inner, ref: band, "data-revealed": revealed, children: [_jsxs("div", { className: stickyCardsParts.header, children: [_jsx("h2", { className: stickyCardsParts.title, id: titleId, ...arriving(0), children: title }), given(description) ? (_jsx("p", { className: stickyCardsParts.description, ...arriving(1), children: description })) : null] }), _jsx("ul", { ref: list, className: stickyCardsParts.list, "data-tall": tall || undefined, role: "list", style: set.length > 0
138
+ ? {
139
+ '--dds-stickycards-scope': set.map((_, at) => nameAt(at)).join(', '),
140
+ ...(head === undefined ? {} : { '--dds-stickycards-head': `${head}px` }),
141
+ }
142
+ : undefined, children: set.map((card, at) => {
143
+ const { player, hasPlayer, image, hasImage } = slots[at];
144
+ const depth = depthOf(at, set.length);
145
+ const next = at + 1 < set.length ? depthOf(at + 1, set.length) : depth;
146
+ return (_jsxs("li", { className: stickyCardsParts.item, "data-media": hasPlayer ? 'node' : hasImage ? 'image' : 'none', style: {
147
+ '--dds-stickycards-depth': depth,
148
+ '--dds-stickycards-next-depth': next,
149
+ '--dds-stickycards-own': nameAt(at),
150
+ ...(at + 1 < set.length ? { '--dds-stickycards-next': nameAt(at + 1) } : {}),
151
+ }, children: [_jsxs(Card, { variant: card.variant ?? 'accent-strong', children: [layout === 'compact' && card.background && given(card.background.src) ? (_jsx("span", { className: stickyCardsParts.backdrop, children: _jsx("img", { src: card.background.src, alt: card.background.alt, width: card.background.width, height: card.background.height, loading: "lazy", decoding: "async" }) })) : null, _jsxs("div", { className: stickyCardsParts.body, children: [_jsx(CardBody, { title: card.title, description: card.description }), hasPlayer || hasImage ? (_jsx("div", { className: stickyCardsParts.media, children: hasPlayer ? (player) : (_jsx("img", { className: stickyCardsParts.image, src: image.src, alt: image.alt, width: image.width, height: image.height, loading: "lazy", decoding: "async" })) })) : null] })] }), _jsx("span", { className: stickyCardsParts.scrim })] }, `${card.title}-${at}`));
152
+ }) })] }) }));
153
+ }