@deriv-com/dds-marketing 0.2.0 → 1.0.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 (281) hide show
  1. package/.llm/components/accordion.md +9 -1
  2. package/.llm/components/accordionitem.md +9 -1
  3. package/.llm/components/aspectratio.md +9 -1
  4. package/.llm/components/badge.md +9 -1
  5. package/.llm/components/bottomsheet.md +9 -1
  6. package/.llm/components/breadcrumb.md +9 -1
  7. package/.llm/components/breadcrumbitem.md +9 -1
  8. package/.llm/components/button.md +55 -27
  9. package/.llm/components/buttonicon.md +16 -8
  10. package/.llm/components/card.md +16 -2
  11. package/.llm/components/cardbody.md +29 -3
  12. package/.llm/components/cardbutton.md +16 -2
  13. package/.llm/components/checkbox.md +9 -1
  14. package/.llm/components/ctabanner.md +186 -0
  15. package/.llm/components/ctabannerslider.md +204 -0
  16. package/.llm/components/divider.md +9 -1
  17. package/.llm/components/dropdownmenu.md +15 -7
  18. package/.llm/components/faqaccordion.md +217 -0
  19. package/.llm/components/featurebullets.md +254 -0
  20. package/.llm/components/featurecards.md +313 -0
  21. package/.llm/components/featurescroll.md +284 -0
  22. package/.llm/components/featuresplit.md +249 -0
  23. package/.llm/components/filterchip.md +9 -1
  24. package/.llm/components/footer.md +9 -1
  25. package/.llm/components/footergroup.md +9 -1
  26. package/.llm/components/grid.md +9 -1
  27. package/.llm/components/icon.md +21 -3
  28. package/.llm/components/landinghero.md +254 -0
  29. package/.llm/components/link.md +13 -5
  30. package/.llm/components/logocolumns.md +235 -0
  31. package/.llm/components/logorows.md +212 -0
  32. package/.llm/components/menuitem.md +9 -1
  33. package/.llm/components/navbar.md +80 -16
  34. package/.llm/components/navbaritem.md +10 -2
  35. package/.llm/components/navbarmenu.md +9 -1
  36. package/.llm/components/navbarmenugroup.md +9 -1
  37. package/.llm/components/navbarpanel.md +10 -2
  38. package/.llm/components/navbarswitcher.md +10 -2
  39. package/.llm/components/navbarswitcheroption.md +9 -1
  40. package/.llm/components/option.md +9 -1
  41. package/.llm/components/pageheader.md +231 -0
  42. package/.llm/components/pagination.md +27 -90
  43. package/.llm/components/paginationdots.md +215 -0
  44. package/.llm/components/producthero.md +248 -0
  45. package/.llm/components/removablechip.md +9 -1
  46. package/.llm/components/row.md +9 -1
  47. package/.llm/components/scroller.md +9 -1
  48. package/.llm/components/searchinput.md +9 -1
  49. package/.llm/components/segmentedcontrol.md +9 -1
  50. package/.llm/components/segmentedcontrolitem.md +9 -1
  51. package/.llm/components/select.md +9 -1
  52. package/.llm/components/selectchip.md +57 -16
  53. package/.llm/components/spinner.md +9 -1
  54. package/.llm/components/stack.md +9 -1
  55. package/.llm/components/statusdot.md +9 -1
  56. package/.llm/components/subdomainnavbar.md +9 -1
  57. package/.llm/components/tab.md +11 -3
  58. package/.llm/components/table.md +9 -1
  59. package/.llm/components/tablebody.md +9 -1
  60. package/.llm/components/tablecell.md +9 -1
  61. package/.llm/components/tablehead.md +9 -1
  62. package/.llm/components/tableheadercell.md +9 -1
  63. package/.llm/components/tablerow.md +9 -1
  64. package/.llm/components/tablist.md +9 -1
  65. package/.llm/components/testimonialrow.md +235 -0
  66. package/.llm/components/testimonialslider.md +254 -0
  67. package/.llm/components/textarea.md +9 -1
  68. package/.llm/components/textinput.md +9 -1
  69. package/.llm/components/tooltip.md +9 -1
  70. package/.llm/components/typography.md +9 -1
  71. package/.llm/digest/button.md +11 -6
  72. package/.llm/digest/buttonicon.md +2 -2
  73. package/.llm/digest/card.md +1 -0
  74. package/.llm/digest/cardbody.md +3 -1
  75. package/.llm/digest/cardbutton.md +1 -0
  76. package/.llm/digest/ctabanner.md +44 -0
  77. package/.llm/digest/ctabannerslider.md +45 -0
  78. package/.llm/digest/dropdownmenu.md +1 -1
  79. package/.llm/digest/faqaccordion.md +43 -0
  80. package/.llm/digest/featurebullets.md +52 -0
  81. package/.llm/digest/featurecards.md +49 -0
  82. package/.llm/digest/featurescroll.md +52 -0
  83. package/.llm/digest/featuresplit.md +54 -0
  84. package/.llm/digest/landinghero.md +53 -0
  85. package/.llm/digest/logocolumns.md +55 -0
  86. package/.llm/digest/logorows.md +48 -0
  87. package/.llm/digest/navbar.md +18 -3
  88. package/.llm/digest/pageheader.md +49 -0
  89. package/.llm/digest/pagination.md +6 -17
  90. package/.llm/digest/paginationdots.md +43 -0
  91. package/.llm/digest/producthero.md +53 -0
  92. package/.llm/digest/selectchip.md +6 -1
  93. package/.llm/digest/testimonialrow.md +51 -0
  94. package/.llm/digest/testimonialslider.md +51 -0
  95. package/.llm/index.md +24 -3
  96. package/.llm/rules.md +43 -9
  97. package/.llm/tokens.md +56 -12
  98. package/AGENTS.md +32 -8
  99. package/README.md +41 -21
  100. package/dist/components/banner-data.d.ts +38 -0
  101. package/dist/components/banner-data.js +15 -0
  102. package/dist/components/blocks/block-reveal.css +90 -0
  103. package/dist/components/blocks/cta-banner/CtaBanner.css +66 -0
  104. package/dist/components/blocks/cta-banner/CtaBanner.d.ts +22 -0
  105. package/dist/components/blocks/cta-banner/CtaBanner.js +31 -0
  106. package/dist/components/blocks/cta-banner/CtaBanner.types.d.ts +29 -0
  107. package/dist/components/blocks/cta-banner/CtaBanner.types.js +13 -0
  108. package/dist/components/blocks/cta-banner/cta-banner-impl.css +29 -0
  109. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.css +90 -0
  110. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.d.ts +39 -0
  111. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.js +60 -0
  112. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.d.ts +41 -0
  113. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.js +15 -0
  114. package/dist/components/blocks/cta-banner-slider/cta-banner-slider-impl.css +73 -0
  115. package/dist/components/blocks/faq-accordion/FaqAccordion.css +54 -0
  116. package/dist/components/blocks/faq-accordion/FaqAccordion.d.ts +20 -0
  117. package/dist/components/blocks/faq-accordion/FaqAccordion.js +28 -0
  118. package/dist/components/blocks/faq-accordion/FaqAccordion.types.d.ts +25 -0
  119. package/dist/components/blocks/faq-accordion/FaqAccordion.types.js +10 -0
  120. package/dist/components/blocks/faq-accordion/faq-accordion-impl.css +54 -0
  121. package/dist/components/blocks/feature-bullets/FeatureBullets.css +139 -0
  122. package/dist/components/blocks/feature-bullets/FeatureBullets.d.ts +31 -0
  123. package/dist/components/blocks/feature-bullets/FeatureBullets.js +55 -0
  124. package/dist/components/blocks/feature-bullets/FeatureBullets.types.d.ts +39 -0
  125. package/dist/components/blocks/feature-bullets/FeatureBullets.types.js +16 -0
  126. package/dist/components/blocks/feature-bullets/feature-bullets-impl.css +104 -0
  127. package/dist/components/blocks/feature-cards/FeatureCards.css +84 -0
  128. package/dist/components/blocks/feature-cards/FeatureCards.d.ts +24 -0
  129. package/dist/components/blocks/feature-cards/FeatureCards.js +66 -0
  130. package/dist/components/blocks/feature-cards/FeatureCards.types.d.ts +33 -0
  131. package/dist/components/blocks/feature-cards/FeatureCards.types.js +14 -0
  132. package/dist/components/blocks/feature-cards/feature-cards-impl.css +245 -0
  133. package/dist/components/blocks/feature-scroll/FeatureScroll.css +137 -0
  134. package/dist/components/blocks/feature-scroll/FeatureScroll.d.ts +39 -0
  135. package/dist/components/blocks/feature-scroll/FeatureScroll.js +167 -0
  136. package/dist/components/blocks/feature-scroll/FeatureScroll.types.d.ts +40 -0
  137. package/dist/components/blocks/feature-scroll/FeatureScroll.types.js +17 -0
  138. package/dist/components/blocks/feature-scroll/feature-scroll-impl.css +292 -0
  139. package/dist/components/blocks/feature-split/FeatureSplit.css +95 -0
  140. package/dist/components/blocks/feature-split/FeatureSplit.d.ts +30 -0
  141. package/dist/components/blocks/feature-split/FeatureSplit.js +38 -0
  142. package/dist/components/blocks/feature-split/FeatureSplit.types.d.ts +39 -0
  143. package/dist/components/blocks/feature-split/FeatureSplit.types.js +14 -0
  144. package/dist/components/blocks/feature-split/feature-split-impl.css +83 -0
  145. package/dist/components/blocks/landing-hero/LandingHero.css +85 -0
  146. package/dist/components/blocks/landing-hero/LandingHero.d.ts +41 -0
  147. package/dist/components/blocks/landing-hero/LandingHero.js +54 -0
  148. package/dist/components/blocks/landing-hero/LandingHero.types.d.ts +37 -0
  149. package/dist/components/blocks/landing-hero/LandingHero.types.js +15 -0
  150. package/dist/components/blocks/landing-hero/landing-hero-impl.css +355 -0
  151. package/dist/components/blocks/logo-columns/LogoColumns.css +161 -0
  152. package/dist/components/blocks/logo-columns/LogoColumns.d.ts +23 -0
  153. package/dist/components/blocks/logo-columns/LogoColumns.js +46 -0
  154. package/dist/components/blocks/logo-columns/LogoColumns.types.d.ts +46 -0
  155. package/dist/components/blocks/logo-columns/LogoColumns.types.js +18 -0
  156. package/dist/components/blocks/logo-columns/logo-columns-impl.css +188 -0
  157. package/dist/components/blocks/logo-rows/LogoRows.css +122 -0
  158. package/dist/components/blocks/logo-rows/LogoRows.d.ts +20 -0
  159. package/dist/components/blocks/logo-rows/LogoRows.js +43 -0
  160. package/dist/components/blocks/logo-rows/LogoRows.types.d.ts +36 -0
  161. package/dist/components/blocks/logo-rows/LogoRows.types.js +16 -0
  162. package/dist/components/blocks/logo-rows/logo-rows-impl.css +179 -0
  163. package/dist/components/blocks/page-header/PageHeader.css +79 -0
  164. package/dist/components/blocks/page-header/PageHeader.d.ts +34 -0
  165. package/dist/components/blocks/page-header/PageHeader.js +43 -0
  166. package/dist/components/blocks/page-header/PageHeader.types.d.ts +32 -0
  167. package/dist/components/blocks/page-header/PageHeader.types.js +14 -0
  168. package/dist/components/blocks/page-header/page-header-impl.css +176 -0
  169. package/dist/components/blocks/product-hero/ProductHero.css +86 -0
  170. package/dist/components/blocks/product-hero/ProductHero.d.ts +35 -0
  171. package/dist/components/blocks/product-hero/ProductHero.js +48 -0
  172. package/dist/components/blocks/product-hero/ProductHero.types.d.ts +37 -0
  173. package/dist/components/blocks/product-hero/ProductHero.types.js +15 -0
  174. package/dist/components/blocks/product-hero/product-hero-impl.css +354 -0
  175. package/dist/components/blocks/testimonial-row/TestimonialRow.css +245 -0
  176. package/dist/components/blocks/testimonial-row/TestimonialRow.d.ts +20 -0
  177. package/dist/components/blocks/testimonial-row/TestimonialRow.js +128 -0
  178. package/dist/components/blocks/testimonial-row/TestimonialRow.types.d.ts +54 -0
  179. package/dist/components/blocks/testimonial-row/TestimonialRow.types.js +26 -0
  180. package/dist/components/blocks/testimonial-row/testimonial-row-impl.css +195 -0
  181. package/dist/components/blocks/testimonial-slider/TestimonialSlider.css +181 -0
  182. package/dist/components/blocks/testimonial-slider/TestimonialSlider.d.ts +22 -0
  183. package/dist/components/blocks/testimonial-slider/TestimonialSlider.js +36 -0
  184. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.d.ts +49 -0
  185. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.js +21 -0
  186. package/dist/components/blocks/testimonial-slider/testimonial-slider-impl.css +202 -0
  187. package/dist/components/blocks/use-reveal.d.ts +46 -0
  188. package/dist/components/blocks/use-reveal.js +120 -0
  189. package/dist/components/blocks/use-rotation.d.ts +62 -0
  190. package/dist/components/blocks/use-rotation.js +176 -0
  191. package/dist/components/core/accordion-item/AccordionItem.css +6 -5
  192. package/dist/components/core/bottom-sheet/BottomSheet.css +1 -1
  193. package/dist/components/core/button/Button.css +63 -16
  194. package/dist/components/core/button/Button.d.ts +14 -12
  195. package/dist/components/core/button/Button.js +43 -14
  196. package/dist/components/core/button/Button.types.d.ts +9 -14
  197. package/dist/components/core/button/button-impl.css +25 -0
  198. package/dist/components/core/button-icon/ButtonIcon.css +31 -15
  199. package/dist/components/core/button-icon/ButtonIcon.d.ts +2 -2
  200. package/dist/components/core/button-icon/ButtonIcon.js +2 -2
  201. package/dist/components/core/button-icon/ButtonIcon.types.d.ts +4 -4
  202. package/dist/components/core/card/Card.css +13 -4
  203. package/dist/components/core/card/Card.types.d.ts +2 -1
  204. package/dist/components/core/card-body/CardBody.css +11 -6
  205. package/dist/components/core/card-body/CardBody.d.ts +1 -1
  206. package/dist/components/core/card-body/CardBody.js +2 -2
  207. package/dist/components/core/card-body/CardBody.types.d.ts +4 -1
  208. package/dist/components/core/card-body/CardBody.types.js +1 -0
  209. package/dist/components/core/card-button/CardButton.css +13 -4
  210. package/dist/components/core/card-button/CardButton.types.d.ts +2 -1
  211. package/dist/components/core/checkbox/Checkbox.css +8 -1
  212. package/dist/components/core/dropdown-menu/DropdownMenu.css +13 -12
  213. package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +5 -3
  214. package/dist/components/core/dropdown-menu/DropdownMenu.js +5 -3
  215. package/dist/components/core/filter-chip/FilterChip.css +2 -1
  216. package/dist/components/core/footer/footer-impl.css +1 -1
  217. package/dist/components/core/footer-group/FooterGroup.css +8 -7
  218. package/dist/components/core/icon/Icon.css +1 -1
  219. package/dist/components/core/link/Link.css +1 -1
  220. package/dist/components/core/link/Link.js +5 -5
  221. package/dist/components/core/menu-item/MenuItem.css +1 -1
  222. package/dist/components/core/navbar/Navbar.css +7 -8
  223. package/dist/components/core/navbar/Navbar.d.ts +17 -1
  224. package/dist/components/core/navbar/Navbar.js +139 -12
  225. package/dist/components/core/navbar/Navbar.types.d.ts +23 -4
  226. package/dist/components/core/navbar/Navbar.types.js +1 -1
  227. package/dist/components/core/navbar/navbar-impl.css +10 -3
  228. package/dist/components/core/navbar/navbar-material.css +96 -0
  229. package/dist/components/core/navbar-item/NavbarItem.css +4 -4
  230. package/dist/components/core/navbar-menu/NavbarMenu.css +7 -5
  231. package/dist/components/core/navbar-menu/NavbarMenu.d.ts +1 -0
  232. package/dist/components/core/navbar-menu/NavbarMenu.js +1 -0
  233. package/dist/components/core/navbar-menu/navbar-menu-impl.css +7 -7
  234. package/dist/components/core/navbar-switcher/NavbarSwitcher.css +6 -5
  235. package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +1 -0
  236. package/dist/components/core/navbar-switcher/NavbarSwitcher.js +2 -1
  237. package/dist/components/core/option/Option.css +1 -1
  238. package/dist/components/core/pagination/Pagination.css +1 -75
  239. package/dist/components/core/pagination/Pagination.d.ts +4 -4
  240. package/dist/components/core/pagination/Pagination.js +11 -51
  241. package/dist/components/core/pagination/Pagination.types.d.ts +5 -17
  242. package/dist/components/core/pagination/Pagination.types.js +1 -3
  243. package/dist/components/core/pagination-dots/PaginationDots.css +60 -0
  244. package/dist/components/core/pagination-dots/PaginationDots.d.ts +25 -0
  245. package/dist/components/core/pagination-dots/PaginationDots.js +104 -0
  246. package/dist/components/core/pagination-dots/PaginationDots.types.d.ts +38 -0
  247. package/dist/components/core/pagination-dots/PaginationDots.types.js +9 -0
  248. package/dist/components/core/removable-chip/RemovableChip.css +3 -3
  249. package/dist/components/core/search-input/SearchInput.css +1 -1
  250. package/dist/components/core/segmented-control/SegmentedControl.css +1 -1
  251. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +1 -1
  252. package/dist/components/core/select/Select.css +2 -1
  253. package/dist/components/core/select-chip/SelectChip.css +14 -7
  254. package/dist/components/core/select-chip/SelectChip.d.ts +1 -1
  255. package/dist/components/core/select-chip/SelectChip.js +7 -4
  256. package/dist/components/core/select-chip/SelectChip.types.d.ts +7 -1
  257. package/dist/components/core/select-chip/SelectChip.types.js +1 -1
  258. package/dist/components/core/select-chip/select-chip-impl.css +14 -3
  259. package/dist/components/core/status-dot/StatusDot.css +1 -1
  260. package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +3 -3
  261. package/dist/components/core/tab/Tab.css +1 -1
  262. package/dist/components/core/tab/Tab.types.d.ts +1 -1
  263. package/dist/components/core/tab-list/TabList.css +1 -1
  264. package/dist/components/core/table/table-impl.css +36 -14
  265. package/dist/components/core/table-header-cell/TableHeaderCell.css +5 -5
  266. package/dist/components/core/text-area/TextArea.css +1 -1
  267. package/dist/components/core/text-input/TextInput.css +1 -1
  268. package/dist/components/core/tooltip/Tooltip.css +1 -1
  269. package/dist/components/core/typography/Typography.css +5 -5
  270. package/dist/components/index.d.ts +35 -0
  271. package/dist/components/index.js +30 -0
  272. package/dist/components/logo-data.d.ts +24 -0
  273. package/dist/components/logo-data.js +11 -0
  274. package/dist/components/scroll-data.d.ts +64 -0
  275. package/dist/components/scroll-data.js +17 -0
  276. package/dist/components/testimonial-row-data.d.ts +51 -0
  277. package/dist/components/testimonial-row-data.js +11 -0
  278. package/dist/components/testimonial-slider-data.d.ts +26 -0
  279. package/dist/components/testimonial-slider-data.js +10 -0
  280. package/dist/marketing.css +385 -14
  281. package/package.json +1 -6
@@ -0,0 +1,84 @@
1
+ /* GENERATED from featurecards.contract.json. Do not edit. */
2
+
3
+ :where([data-dds-context="marketing"]) .dds-featurecards {
4
+ box-sizing: border-box;
5
+ container-type: inline-size;
6
+ display: flex;
7
+ inline-size: 100%;
8
+ justify-content: center;
9
+ }
10
+
11
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__inner {
12
+ box-sizing: border-box;
13
+ display: flex;
14
+ flex-direction: column;
15
+ inline-size: 100%;
16
+ min-inline-size: 0;
17
+ max-inline-size: var(--size-content-max);
18
+ padding-block: var(--space-section-default);
19
+ padding-inline: var(--space-inset-page);
20
+ row-gap: var(--space-heading-content);
21
+ }
22
+
23
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__header {
24
+ display: flex;
25
+ flex-direction: column;
26
+ min-inline-size: 0;
27
+ max-inline-size: var(--size-measure-heading);
28
+ row-gap: var(--space-gap-none);
29
+ }
30
+
31
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__title {
32
+ margin-block: 0;
33
+ text-wrap: balance;
34
+ font-family: var(--font-h2-family);
35
+ font-size: var(--font-h2-size);
36
+ font-weight: var(--font-h2-weight);
37
+ letter-spacing: var(--font-h2-letter-spacing);
38
+ line-height: var(--font-h2-line-height);
39
+ margin-block-end: var(--space-heading-title-description);
40
+ }
41
+
42
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__description {
43
+ margin-block: 0;
44
+ font-family: var(--font-body-md-family);
45
+ font-size: var(--font-body-md-size);
46
+ font-weight: var(--font-body-md-weight);
47
+ letter-spacing: var(--font-body-md-letter-spacing);
48
+ line-height: var(--font-body-md-line-height);
49
+ max-inline-size: var(--size-measure-description);
50
+ }
51
+
52
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__link {
53
+ display: flex;
54
+ margin-block-start: var(--space-heading-description-actions);
55
+ }
56
+
57
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid {
58
+ display: grid;
59
+ min-inline-size: 0;
60
+ column-gap: var(--space-grid-gutter);
61
+ row-gap: var(--space-grid-gutter);
62
+ }
63
+
64
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__item {
65
+ display: grid;
66
+ min-inline-size: 0;
67
+ }
68
+
69
+ :where([data-dds-context="marketing"]) .dds-featurecards[data-ground="page"] {
70
+ background-color: var(--color-bg-page);
71
+ color: var(--color-fg-default);
72
+ }
73
+
74
+ :where([data-dds-context="marketing"]) .dds-featurecards[data-ground="strong"] {
75
+ background-color: var(--color-bg-brand-strong);
76
+ color: var(--color-fg-on-brand-strong);
77
+ }
78
+
79
+ :where([data-dds-context="marketing"]) .dds-featurecards[data-ground="subtle"] {
80
+ background-color: var(--color-bg-page);
81
+ background-image: linear-gradient(var(--color-bg-band-subtle), var(--color-bg-band-subtle));
82
+ color: var(--color-fg-default);
83
+ }
84
+
@@ -0,0 +1,24 @@
1
+ import './FeatureCards.css';
2
+ import './feature-cards-impl.css';
3
+ import '../block-reveal.css';
4
+ import { type FeatureCardsProps } from './FeatureCards.types.js';
5
+ export type { FeatureCardsProps };
6
+ /**
7
+ * A heading over a grid of cards — the reference site's FeatureCards in its grid form.
8
+ *
9
+ * The cards are the page's own Card or CardButton, each holding a CardBody, rather than records
10
+ * this draws. A card already says everything a card can say — its fill, its picture, its mark,
11
+ * whether the whole of it is pressed — and a list of records here would be a second, smaller Card
12
+ * API to keep in step with the first. What this decides is the rest: the heading, the column, and
13
+ * how many cards share a row.
14
+ *
15
+ * The row is read from the cards. One column on a phone and two from the fold; at full width three,
16
+ * four when there are exactly four, and one or two held to two thirds of the row, centred. A card
17
+ * alone lays its words beside a portrait picture. The stylesheet asks all of it of the markup — the
18
+ * count is already there, and a prop restating it is a second place for the two to disagree.
19
+ *
20
+ * It arrives the way every block does: the heading, the line and the way on, then each card's cell
21
+ * a step behind the one before, in reading order. `'use client'` for that and for `useId`, which
22
+ * names the region by its heading.
23
+ */
24
+ export declare function FeatureCards({ ground, title, description, link, children, }: FeatureCardsProps): import("react").JSX.Element;
@@ -0,0 +1,66 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Children, Fragment, isValidElement, useId } from 'react';
4
+ import './FeatureCards.css';
5
+ import './feature-cards-impl.css';
6
+ import '../block-reveal.css';
7
+ import { given } from '../../given.js';
8
+ import { arriving, useReveal } from '../use-reveal.js';
9
+ import { featureCardsDefaults, featureCardsParts } from './FeatureCards.types.js';
10
+ /**
11
+ * The cards, with any fragment opened out.
12
+ *
13
+ * `Children.toArray` flattens arrays and leaves a fragment whole, so a page writing
14
+ * `<>{cards}</>` handed over one child: every card in a single cell, and the grid reading the set
15
+ * as one card alone. A fragment is the page grouping its own markup, never a card, so it is opened
16
+ * out here and the grid counts what is inside it.
17
+ */
18
+ function cardsOf(children, within = '') {
19
+ return Children.toArray(children).flatMap((child, at) => {
20
+ // `toArray` keys a fragment's children afresh — `.0`, `.1` — so a card is keyed by the
21
+ // fragment it came out of as well as its own place, or two cards from different groups share a
22
+ // key and React reconciles one into the other's cell.
23
+ const key = `${within}${isValidElement(child) && child.key !== null ? child.key : at}`;
24
+ return isValidElement(child) && child.type === Fragment
25
+ ? cardsOf(child.props.children, `${key}/`)
26
+ : [{ key, card: child }];
27
+ });
28
+ }
29
+ /**
30
+ * Where a card comes in the arrival, capped so a long set does not keep a reader waiting.
31
+ *
32
+ * The heading, the line and the way on take the first three steps. The cards follow one step
33
+ * apart up to the fourth, and the rest arrive with it: block-reveal.css keeps a block's trail
34
+ * inside its own movement, and eight cards a step apart would trail the heading by most of a
35
+ * second.
36
+ */
37
+ const FIRST_CARD = 3;
38
+ const LAST_STEP = FIRST_CARD + 3;
39
+ /**
40
+ * A heading over a grid of cards — the reference site's FeatureCards in its grid form.
41
+ *
42
+ * The cards are the page's own Card or CardButton, each holding a CardBody, rather than records
43
+ * this draws. A card already says everything a card can say — its fill, its picture, its mark,
44
+ * whether the whole of it is pressed — and a list of records here would be a second, smaller Card
45
+ * API to keep in step with the first. What this decides is the rest: the heading, the column, and
46
+ * how many cards share a row.
47
+ *
48
+ * The row is read from the cards. One column on a phone and two from the fold; at full width three,
49
+ * four when there are exactly four, and one or two held to two thirds of the row, centred. A card
50
+ * alone lays its words beside a portrait picture. The stylesheet asks all of it of the markup — the
51
+ * count is already there, and a prop restating it is a second place for the two to disagree.
52
+ *
53
+ * It arrives the way every block does: the heading, the line and the way on, then each card's cell
54
+ * a step behind the one before, in reading order. `'use client'` for that and for `useId`, which
55
+ * names the region by its heading.
56
+ */
57
+ export function FeatureCards({ ground = featureCardsDefaults.ground, title, description, link, children, }) {
58
+ const titleId = useId();
59
+ const [band, revealed] = useReveal();
60
+ return (_jsx("section", { className: featureCardsParts.root, "data-ground": ground, "aria-labelledby": titleId, children: _jsxs("div", { className: featureCardsParts.inner, ref: band, "data-revealed": revealed, children: [_jsxs("div", { className: featureCardsParts.header, children: [_jsx("h2", { className: featureCardsParts.title, id: titleId, ...arriving(0), children: title }), given(description) ? (_jsx("p", { className: featureCardsParts.description, ...arriving(1), children: description })) : null, link ? (_jsx("div", { className: featureCardsParts.link, ...arriving(2), children: link })) : null] }), _jsx("div", { className: featureCardsParts.grid, children: cardsOf(children).map(({ key, card }, at) => (
61
+ /* Each card in a cell of its own, and the cell is what arrives: the card is the page's
62
+ element and keeps its own transitions, which an arrival set on it would overwrite.
63
+ Keyed by the card's own key, made unique across fragments by cardsOf, so a set the
64
+ page reorders moves its cards rather than remounting them. */
65
+ _jsx("div", { className: featureCardsParts.item, ...arriving(Math.min(FIRST_CARD + at, LAST_STEP)), children: card }, key))) })] }) }));
66
+ }
@@ -0,0 +1,33 @@
1
+ import type { ReactNode } from 'react';
2
+ export interface FeatureCardsOwnProps {
3
+ /**
4
+ * `page` — The default, and the page's own white. A section that has nothing to separate itself from what is above it — most of them — and the ground a reader is already on
5
+ * `subtle` — A quiet step off the page, for a band that wants to read as its own section without changing the page's voice. The one to reach for first when two sections need telling apart. A light card — surface-light — turns white on it, color.bg.surface-card-light-raised, because its own gray.50 is the band's and would vanish into it. A dark card — accent-strong — is lifted to color.bg.surface-card-strong-raised, a step lighter in dark mode, where the band is within a shade of its gray.900. A plain surface card is raised off it the same way, to color.bg.surface-card-raised, because the recessed fill is the band's gray too. Painted as the band's tint laid over the page's own ground, so it is the same grey whatever is behind the section — in dark mode the tint alone took on whatever it was set against, and on a light surface it was light ink on white.
6
+ * `strong` — `color.bg.brand-strong`, the dark band. It stops the page rather than dividing it, so it is for a section a reader should arrive at — and one per page is usually one more than enough. The coloured cards keep their own grounds on it; a neutral card — surface or surface-raised — turns to Card's inverse fill and white ink, and a plain card takes the white ink alone, because their own would be dark ink on near-black; an eyebrow inside any of them takes the band's quieter ink
7
+ */
8
+ ground?: 'page' | 'subtle' | 'strong';
9
+ /** Always. What the cards are, in the fewest words that name them — "Why trade with Deriv", "Markets you can trade". */
10
+ title: string;
11
+ /** A line saying what the set has in common, when the title alone does not. */
12
+ description?: string;
13
+ /** A way on to the page the whole set belongs to — "See all markets". A standalone Link, under the line. */
14
+ link?: ReactNode;
15
+ /** Allowed: Card, CardButton */
16
+ children: ReactNode;
17
+ }
18
+ export type FeatureCardsProps = FeatureCardsOwnProps;
19
+ /** The class each part carries. Apply these — do not retype them. */
20
+ export declare const featureCardsParts: {
21
+ readonly root: "dds-featurecards";
22
+ readonly inner: "dds-featurecards__inner";
23
+ readonly header: "dds-featurecards__header";
24
+ readonly title: "dds-featurecards__title";
25
+ readonly description: "dds-featurecards__description";
26
+ readonly link: "dds-featurecards__link";
27
+ readonly grid: "dds-featurecards__grid";
28
+ readonly item: "dds-featurecards__item";
29
+ };
30
+ /** Generated so defaults cannot drift from the contract. */
31
+ export declare const featureCardsDefaults: {
32
+ readonly ground: "page";
33
+ };
@@ -0,0 +1,14 @@
1
+ // GENERATED from feature-cards.contract.json. Do not edit.
2
+ /** The class each part carries. Apply these — do not retype them. */
3
+ export const featureCardsParts = {
4
+ root: 'dds-featurecards',
5
+ inner: 'dds-featurecards__inner',
6
+ header: 'dds-featurecards__header',
7
+ title: 'dds-featurecards__title',
8
+ description: 'dds-featurecards__description',
9
+ link: 'dds-featurecards__link',
10
+ grid: 'dds-featurecards__grid',
11
+ item: 'dds-featurecards__item',
12
+ };
13
+ /** Generated so defaults cannot drift from the contract. */
14
+ export const featureCardsDefaults = { ground: 'page' };
@@ -0,0 +1,245 @@
1
+ /*
2
+ * Scoped to this package, like the generated sheet beside it.
3
+ */
4
+
5
+ /*
6
+ * The header starts on a phone and is centred once the band is wide enough to hold a line.
7
+ *
8
+ * PageHeader's rule and its reason: centred text starts every line at a different edge, which
9
+ * costs little across a wide measure and a great deal across a narrow one. The header and the
10
+ * line under it are capped narrower than the column, so `margin-inline: auto` is what centres
11
+ * those boxes rather than their words inside a box left at the start edge.
12
+ *
13
+ * `48rem` longhand because `var()` is not permitted in a container query condition, and it is
14
+ * the width the rest of this package folds at.
15
+ */
16
+ @container (min-width: 48rem) {
17
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__header {
18
+ align-items: center;
19
+ margin-inline: auto;
20
+ text-align: center;
21
+ }
22
+
23
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__description {
24
+ margin-inline: auto;
25
+ }
26
+
27
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__link {
28
+ justify-content: center;
29
+ }
30
+ }
31
+
32
+ /*
33
+ * One column on a phone. `minmax(0, 1fr)` rather than `1fr`, so a card holding a long unbroken
34
+ * word or a wide picture shrinks to the column instead of pushing the grid past the page.
35
+ */
36
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid {
37
+ grid-template-columns: minmax(0, 1fr);
38
+ }
39
+
40
+ /*
41
+ * How many cards share a row, read from the cards.
42
+ *
43
+ * Two from the fold, three at full width, four when there are exactly four — the reference
44
+ * design's rule, so a set of four is one row rather than a row of three and an orphan — and a pair
45
+ * as two columns. `:has()` asks the markup how many there are; the count is already there, and a
46
+ * prop restating it would be a second place for the two to disagree. 62rem is the reference's
47
+ * desktop step.
48
+ *
49
+ * Where `:has()` is not supported every count takes the three columns and a single card stays
50
+ * stacked: the set still reads, only less exactly.
51
+ */
52
+ @container (min-width: 48rem) {
53
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid {
54
+ grid-template-columns: repeat(2, minmax(0, 1fr));
55
+ }
56
+
57
+ /* One card takes the row. Above the three- and four-column rules below by specificity, not by
58
+ order — `:has()` counts the selector inside it — so it holds at every width from here up. */
59
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid:has(> :only-child) {
60
+ grid-template-columns: minmax(0, 1fr);
61
+ }
62
+
63
+ /*
64
+ * And a card alone lays its words and its picture side by side.
65
+ *
66
+ * A card the width of the section with its picture under the words is a strip of copy over a
67
+ * letterbox. The reference design's single panel is a split instead — words at the start, the
68
+ * picture at the end — and the block is what knows the card is alone, so the row is said here
69
+ * rather than asked of CardBody. Its parts keep their own order: a body whose picture leads
70
+ * (mediaPosition="above") leads with it here too. Only a body with its picture in the column;
71
+ * one whose copy sits over its picture is already the whole card and has nothing to split.
72
+ *
73
+ * The two halves share the width, and the words start at the top of theirs, level with the top
74
+ * of the picture, the way a card's words start at the top when they are stacked.
75
+ */
76
+ :where([data-dds-context="marketing"])
77
+ .dds-featurecards
78
+ .dds-featurecards__grid:has(> :only-child)
79
+ .dds-cardbody[data-over-media="false"] {
80
+ flex-direction: row;
81
+ }
82
+
83
+ :where([data-dds-context="marketing"])
84
+ .dds-featurecards
85
+ .dds-featurecards__grid:has(> :only-child)
86
+ .dds-cardbody[data-over-media="false"]
87
+ > :is(.dds-cardbody__content, .dds-cardbody__media-frame) {
88
+ flex: 1 1 0;
89
+ min-inline-size: 0;
90
+ }
91
+
92
+ /*
93
+ * The picture beside a single card's words is portrait, aspect.portrait.
94
+ *
95
+ * Half a wide card is a tall column, and a landscape picture in it is a letterbox with the words
96
+ * running past its lower edge. Portrait fills the half the way the reference's single panel does.
97
+ * `align-self: flex-start` so the ratio decides the frame's height rather than the row stretching
98
+ * it to the words; the picture inside covers, so whatever shape the source is, the frame is
99
+ * portrait — unless the page set CardBody's `aspect`, whose inline ratio is the page's to choose.
100
+ */
101
+ :where([data-dds-context="marketing"])
102
+ .dds-featurecards
103
+ .dds-featurecards__grid:has(> :only-child)
104
+ .dds-cardbody[data-over-media="false"]
105
+ > .dds-cardbody__media-frame {
106
+ align-self: flex-start;
107
+ aspect-ratio: var(--aspect-portrait);
108
+ /* Half the card when CardBody's own `aspect` is set: that writes `flex: none` and the page's
109
+ ratio inline, which win over the rule above, and a frame with no flex and no width sizes to
110
+ the picture's own pixels — eight hundred of them, past the card's edge. The width is what
111
+ holds it to its half; where the flex rule does apply, its zero basis overrides this. */
112
+ inline-size: 50%;
113
+ }
114
+ }
115
+
116
+ @container (min-width: 62rem) {
117
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid {
118
+ grid-template-columns: repeat(3, minmax(0, 1fr));
119
+ }
120
+
121
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid:has(> :nth-child(4):last-child) {
122
+ grid-template-columns: repeat(4, minmax(0, 1fr));
123
+ }
124
+
125
+ /* A pair as two columns of their own, rather than two of three with an empty third beside them —
126
+ the rule below then holds the pair to the width two columns take in a row of three. */
127
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid:has(> :nth-child(2):last-child) {
128
+ grid-template-columns: repeat(2, minmax(0, 1fr));
129
+ }
130
+
131
+ /*
132
+ * One or two cards hold to two thirds of the row, centred, rather than the whole of it.
133
+ *
134
+ * Two cards across the full width are each half as wide again as a card in a row of three, and
135
+ * one alone is a banner. Two thirds is exactly two of the three columns and the gutter between
136
+ * them, so a pair is the width a pair is in any other set, and a single card the width of that
137
+ * pair. Computed from the row's own width and gutter rather than a fixed measure, so it follows
138
+ * the grid wherever the grid is.
139
+ */
140
+ :where([data-dds-context="marketing"]) .dds-featurecards .dds-featurecards__grid:is(:has(> :only-child), :has(> :nth-child(2):last-child)) {
141
+ margin-inline: auto;
142
+ max-inline-size: calc((100% - 2 * var(--space-grid-gutter)) * 2 / 3 + var(--space-grid-gutter));
143
+ inline-size: 100%;
144
+ }
145
+ }
146
+
147
+ /*
148
+ * A light card turns white on the subtle band.
149
+ *
150
+ * surface-light is gray.50 in both themes so it stays light beside a dark card, and the subtle
151
+ * band is gray.50 too — so on that band the light card had no edge at all. The block knows its
152
+ * ground and the card does not, so the answer is here rather than in Card: the card keeps its
153
+ * variant, its ink and its hover (a lift, which this leaves alone), and only its fill moves to
154
+ * color.bg.surface-card-light-raised. White in light mode; in dark mode the band is a white tint
155
+ * over near-black rather than gray.50, so the role is the card's own gray.50 there and nothing
156
+ * changes — a white card on the dark band was brighter than every card beside it.
157
+ */
158
+ :where([data-dds-context="marketing"])
159
+ .dds-featurecards[data-ground="subtle"]
160
+ .dds-featurecards__item
161
+ > :is(.dds-card, .dds-cardbutton)[data-variant="surface-light"] {
162
+ background-color: var(--color-bg-surface-card-light-raised);
163
+ }
164
+
165
+ /*
166
+ * A neutral card turns round on the dark band.
167
+ *
168
+ * surface and surface-raised carry the page's dark ink and a fill made for a light page, which on
169
+ * color.bg.brand-strong is dark words on near-black. Card answers that with tone="inverse", and
170
+ * CardButton has no tone to answer with — so the block, which knows its ground, gives both the
171
+ * values Card's own inverse uses: the inverse surface, the raised veil, and white ink. The coloured
172
+ * cards — surface-light, accent, accent-strong — already paint their own ground and ink and are
173
+ * left as they are.
174
+ */
175
+ :where([data-dds-context="marketing"])
176
+ .dds-featurecards[data-ground="strong"]
177
+ .dds-featurecards__item
178
+ > :is(.dds-card, .dds-cardbutton)[data-variant="surface"] {
179
+ background-color: var(--color-bg-surface-inverse);
180
+ color: var(--color-fg-on-brand-strong);
181
+ }
182
+
183
+ :where([data-dds-context="marketing"])
184
+ .dds-featurecards[data-ground="strong"]
185
+ .dds-featurecards__item
186
+ > :is(.dds-card, .dds-cardbutton)[data-variant="surface-raised"] {
187
+ background-color: var(--color-bg-surface-raised-on-brand-strong);
188
+ color: var(--color-fg-on-brand-strong);
189
+ }
190
+
191
+ /*
192
+ * A plain card has no ground of its own, so on the dark band it is the band's words: white ink,
193
+ * the value Card's own plain-and-inverse takes. Without it a plain CardButton drew the page's
194
+ * near-black ink on the near-black band.
195
+ */
196
+ :where([data-dds-context="marketing"])
197
+ .dds-featurecards[data-ground="strong"]
198
+ .dds-featurecards__item
199
+ > :is(.dds-card, .dds-cardbutton)[data-variant="plain"] {
200
+ color: var(--color-fg-on-brand-strong);
201
+ }
202
+
203
+ /*
204
+ * And the eyebrow inside a card turned round. CardBody quietens its eyebrow by its own tone, which
205
+ * a card recoloured here does not change, so the eyebrow kept the page's muted grey on a dark card.
206
+ * It takes the band's own quieter ink, the value CardBody's inverse tone uses.
207
+ */
208
+ :where([data-dds-context="marketing"])
209
+ .dds-featurecards[data-ground="strong"]
210
+ .dds-featurecards__item
211
+ > :is(.dds-card, .dds-cardbutton):is([data-variant="surface"], [data-variant="surface-raised"], [data-variant="plain"])
212
+ .dds-cardbody__eyebrow {
213
+ color: var(--color-fg-muted-inverse);
214
+ }
215
+
216
+ /*
217
+ * And a dark card is lifted a step in dark mode.
218
+ *
219
+ * accent-strong is gray.900, and in dark mode the subtle band is a white tint over near-black that
220
+ * lands within a shade of it — the card blended into the band the way the light card did in light
221
+ * mode. color.bg.surface-card-strong-raised is the same gray.900 in light, where the dark card
222
+ * already stands off the band, and gray.800 in dark, a step up so it lifts off it. The ink is
223
+ * unchanged: white on either.
224
+ */
225
+ :where([data-dds-context="marketing"])
226
+ .dds-featurecards[data-ground="subtle"]
227
+ .dds-featurecards__item
228
+ > :is(.dds-card, .dds-cardbutton)[data-variant="accent-strong"] {
229
+ background-color: var(--color-bg-surface-card-strong-raised);
230
+ }
231
+
232
+ /*
233
+ * And a plain card is raised off it.
234
+ *
235
+ * surface is the recessed fill for a card on the page, color.bg.surface — the same gray the subtle
236
+ * band is, so on the band it vanished exactly as the light card did. It takes the raised fill,
237
+ * color.bg.surface-card-raised, which is what Card's surface-raised variant paints: white on the
238
+ * light band and the raised veil on the dark one, following the theme as surface does.
239
+ */
240
+ :where([data-dds-context="marketing"])
241
+ .dds-featurecards[data-ground="subtle"]
242
+ .dds-featurecards__item
243
+ > :is(.dds-card, .dds-cardbutton)[data-variant="surface"] {
244
+ background-color: var(--color-bg-surface-card-raised);
245
+ }
@@ -0,0 +1,137 @@
1
+ /* GENERATED from featurescroll.contract.json. Do not edit. */
2
+
3
+ :where([data-dds-context="marketing"]) .dds-featurescroll {
4
+ box-sizing: border-box;
5
+ container-type: inline-size;
6
+ display: flex;
7
+ inline-size: 100%;
8
+ justify-content: center;
9
+ }
10
+
11
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__inner {
12
+ box-sizing: border-box;
13
+ display: flex;
14
+ flex-direction: column;
15
+ inline-size: 100%;
16
+ min-inline-size: 0;
17
+ max-inline-size: var(--size-content-max);
18
+ padding-block: var(--space-section-default);
19
+ padding-inline: var(--space-inset-page);
20
+ row-gap: var(--space-heading-content);
21
+ }
22
+
23
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__heading {
24
+ margin-block: 0;
25
+ text-wrap: balance;
26
+ font-family: var(--font-h2-family);
27
+ font-size: var(--font-h2-size);
28
+ font-weight: var(--font-h2-weight);
29
+ letter-spacing: var(--font-h2-letter-spacing);
30
+ line-height: var(--font-h2-line-height);
31
+ max-inline-size: var(--size-measure-heading);
32
+ }
33
+
34
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__steps {
35
+ display: flex;
36
+ flex-direction: column;
37
+ min-inline-size: 0;
38
+ column-gap: var(--space-gap-3xl);
39
+ row-gap: var(--space-gap-2xl);
40
+ }
41
+
42
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__step {
43
+ box-sizing: border-box;
44
+ display: flex;
45
+ min-inline-size: 0;
46
+ row-gap: var(--space-gap-md);
47
+ }
48
+
49
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__content {
50
+ display: flex;
51
+ flex-direction: column;
52
+ justify-content: center;
53
+ min-inline-size: 0;
54
+ row-gap: var(--space-gap-none);
55
+ }
56
+
57
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__title {
58
+ margin-block: 0;
59
+ text-wrap: balance;
60
+ font-family: var(--font-h3-family);
61
+ font-size: var(--font-h3-size);
62
+ font-weight: var(--font-h3-weight);
63
+ letter-spacing: var(--font-h3-letter-spacing);
64
+ line-height: var(--font-h3-line-height);
65
+ margin-block-end: var(--space-heading-title-description);
66
+ }
67
+
68
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__description {
69
+ margin-block: 0;
70
+ font-family: var(--font-body-md-family);
71
+ font-size: var(--font-body-md-size);
72
+ font-weight: var(--font-body-md-weight);
73
+ letter-spacing: var(--font-body-md-letter-spacing);
74
+ line-height: var(--font-body-md-line-height);
75
+ margin-block-end: var(--space-heading-description-actions);
76
+ max-inline-size: var(--size-measure-description);
77
+ }
78
+
79
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__link {
80
+ display: flex;
81
+ margin-block-start: var(--space-gap-none);
82
+ }
83
+
84
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__media {
85
+ align-items: center;
86
+ display: flex;
87
+ justify-content: center;
88
+ min-inline-size: 0;
89
+ padding-block: var(--space-gap-lg);
90
+ transition-duration: var(--motion-duration-media-hover);
91
+ transition-timing-function: var(--motion-easing-media-hover);
92
+ }
93
+
94
+ :where([data-dds-context="marketing"]) .dds-featurescroll .dds-featurescroll__picture {
95
+ display: block;
96
+ object-fit: cover;
97
+ aspect-ratio: var(--aspect-square);
98
+ border-radius: var(--radius-container);
99
+ }
100
+
101
+ :where([data-dds-context="marketing"]) .dds-featurescroll[data-media-position="end"] .dds-featurescroll__content {
102
+ grid-column: words;
103
+ }
104
+
105
+ :where([data-dds-context="marketing"]) .dds-featurescroll[data-media-position="start"] .dds-featurescroll__content {
106
+ grid-column: picture;
107
+ }
108
+
109
+ :where([data-dds-context="marketing"]) .dds-featurescroll[data-media-position="end"] .dds-featurescroll__media {
110
+ grid-column: picture;
111
+ }
112
+
113
+ :where([data-dds-context="marketing"]) .dds-featurescroll[data-media-position="start"] .dds-featurescroll__media {
114
+ grid-column: words;
115
+ }
116
+
117
+ :where([data-dds-context="marketing"]) .dds-featurescroll[data-ground="page"] {
118
+ background-color: var(--color-bg-page);
119
+ color: var(--color-fg-default);
120
+ }
121
+
122
+ :where([data-dds-context="marketing"]) .dds-featurescroll[data-ground="strong"] {
123
+ background-color: var(--color-bg-brand-strong);
124
+ color: var(--color-fg-on-brand-strong);
125
+ }
126
+
127
+ :where([data-dds-context="marketing"]) .dds-featurescroll[data-ground="subtle"] {
128
+ background-color: var(--color-bg-page);
129
+ background-image: linear-gradient(var(--color-bg-band-subtle), var(--color-bg-band-subtle));
130
+ color: var(--color-fg-default);
131
+ }
132
+
133
+ @media (prefers-reduced-motion: reduce) {
134
+ :where([data-dds-context="marketing"]) .dds-featurescroll,
135
+ :where([data-dds-context="marketing"]) .dds-featurescroll * { transition: none !important; }
136
+ }
137
+
@@ -0,0 +1,39 @@
1
+ import './FeatureScroll.css';
2
+ import './feature-scroll-impl.css';
3
+ import '../block-reveal.css';
4
+ import { type FeatureScrollProps } from './FeatureScroll.types.js';
5
+ export type { FeatureScrollProps };
6
+ /**
7
+ * A section that gives a set of things one screen each, with the picture pinned beside the words.
8
+ *
9
+ * Two mechanisms, and which does what is the thing to understand here. Holding a picture in place
10
+ * while words move past it is `position: sticky`, and nothing in this file measures it. Knowing
11
+ * *which* picture belongs to the words a reader has reached is a question about where each title
12
+ * has got to, and no stylesheet can ask it — so that much is below, and only that much.
13
+ *
14
+ * The rule the reference design settles on: a stop's picture is the one showing once the *next*
15
+ * stop's title has risen to the line the pictures are pinned at. Read as "the last title at or
16
+ * above the line" plus one, clamped to the end. It means the square changes at the moment a reader
17
+ * reaches a new heading rather than at some fraction of the way through, which is the only moment
18
+ * they would notice either way.
19
+ *
20
+ * Throttled to one read per frame through `requestAnimationFrame`, on a passive listener, and the
21
+ * read itself is `getBoundingClientRect` on the titles — no layout is written back, so the loop
22
+ * cannot thrash. `useLayoutEffect` rather than `useEffect` so the first measurement lands before
23
+ * the browser paints; the effect otherwise ran after the first frame and the section opened on
24
+ * step one for that frame however far down the page a reader had already scrolled.
25
+ *
26
+ * It measures the section's own width rather than the window's, because the fold is a container
27
+ * query on the section and the two disagree wherever a frame stands in for a window. The fold is
28
+ * the stylesheet's own `48rem`, turned into pixels against the root font size each time it is
29
+ * asked: a fixed 768 agreed with it only while the root stayed at sixteen, and a page that set it
30
+ * smaller pinned the picture on the first stop for the width in between.
31
+ *
32
+ * The parts of a stop are in the order a phone reads them, which is the order they are written:
33
+ * name, picture, line, way onward. At full width each stop gives up its box — `display: contents`
34
+ * — and the grid places the words in one column and every picture in the other, stacked, so the
35
+ * change is a change in one square rather than one picture leaving and another arriving. The
36
+ * reference design ships two DOM trees to get that; one tree means a reader's assistive technology
37
+ * and anybody reading the markup meet each stop once.
38
+ */
39
+ export declare function FeatureScroll({ ground, title, steps, mediaPosition, }: FeatureScrollProps): import("react").JSX.Element;