@deriv-com/dds-marketing 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (460) hide show
  1. package/.llm/components/accordion.md +193 -0
  2. package/.llm/components/accordionitem.md +236 -0
  3. package/.llm/components/aspectratio.md +212 -0
  4. package/.llm/components/badge.md +231 -0
  5. package/.llm/components/bottomsheet.md +404 -0
  6. package/.llm/components/breadcrumb.md +197 -0
  7. package/.llm/components/breadcrumbitem.md +178 -0
  8. package/.llm/components/button.md +271 -0
  9. package/.llm/components/buttonicon.md +313 -0
  10. package/.llm/components/card.md +313 -0
  11. package/.llm/components/cardbody.md +409 -0
  12. package/.llm/components/cardbutton.md +259 -0
  13. package/.llm/components/checkbox.md +285 -0
  14. package/.llm/components/divider.md +230 -0
  15. package/.llm/components/dropdownmenu.md +453 -0
  16. package/.llm/components/filterchip.md +314 -0
  17. package/.llm/components/footer.md +408 -0
  18. package/.llm/components/footergroup.md +241 -0
  19. package/.llm/components/grid.md +659 -0
  20. package/.llm/components/icon.md +194 -0
  21. package/.llm/components/link.md +354 -0
  22. package/.llm/components/menuitem.md +218 -0
  23. package/.llm/components/navbar.md +458 -0
  24. package/.llm/components/navbaritem.md +238 -0
  25. package/.llm/components/navbarmenu.md +319 -0
  26. package/.llm/components/navbarmenugroup.md +184 -0
  27. package/.llm/components/navbarpanel.md +255 -0
  28. package/.llm/components/navbarswitcher.md +343 -0
  29. package/.llm/components/navbarswitcheroption.md +156 -0
  30. package/.llm/components/option.md +268 -0
  31. package/.llm/components/pagination.md +361 -0
  32. package/.llm/components/removablechip.md +247 -0
  33. package/.llm/components/row.md +381 -0
  34. package/.llm/components/scroller.md +470 -0
  35. package/.llm/components/searchinput.md +279 -0
  36. package/.llm/components/segmentedcontrol.md +358 -0
  37. package/.llm/components/segmentedcontrolitem.md +272 -0
  38. package/.llm/components/select.md +509 -0
  39. package/.llm/components/selectchip.md +334 -0
  40. package/.llm/components/spinner.md +222 -0
  41. package/.llm/components/stack.md +334 -0
  42. package/.llm/components/statusdot.md +205 -0
  43. package/.llm/components/subdomainnavbar.md +327 -0
  44. package/.llm/components/tab.md +291 -0
  45. package/.llm/components/table.md +660 -0
  46. package/.llm/components/tablebody.md +258 -0
  47. package/.llm/components/tablecell.md +248 -0
  48. package/.llm/components/tablehead.md +248 -0
  49. package/.llm/components/tableheadercell.md +298 -0
  50. package/.llm/components/tablerow.md +285 -0
  51. package/.llm/components/tablist.md +210 -0
  52. package/.llm/components/textarea.md +362 -0
  53. package/.llm/components/textinput.md +467 -0
  54. package/.llm/components/tooltip.md +267 -0
  55. package/.llm/components/typography.md +245 -0
  56. package/.llm/digest/accordion.md +43 -0
  57. package/.llm/digest/accordionitem.md +47 -0
  58. package/.llm/digest/aspectratio.md +47 -0
  59. package/.llm/digest/badge.md +45 -0
  60. package/.llm/digest/bottomsheet.md +69 -0
  61. package/.llm/digest/breadcrumb.md +38 -0
  62. package/.llm/digest/breadcrumbitem.md +43 -0
  63. package/.llm/digest/button.md +48 -0
  64. package/.llm/digest/buttonicon.md +61 -0
  65. package/.llm/digest/card.md +50 -0
  66. package/.llm/digest/cardbody.md +68 -0
  67. package/.llm/digest/cardbutton.md +49 -0
  68. package/.llm/digest/checkbox.md +63 -0
  69. package/.llm/digest/divider.md +52 -0
  70. package/.llm/digest/dropdownmenu.md +67 -0
  71. package/.llm/digest/filterchip.md +68 -0
  72. package/.llm/digest/footer.md +57 -0
  73. package/.llm/digest/footergroup.md +42 -0
  74. package/.llm/digest/grid.md +62 -0
  75. package/.llm/digest/icon.md +45 -0
  76. package/.llm/digest/link.md +59 -0
  77. package/.llm/digest/menuitem.md +46 -0
  78. package/.llm/digest/navbar.md +60 -0
  79. package/.llm/digest/navbaritem.md +54 -0
  80. package/.llm/digest/navbarmenu.md +54 -0
  81. package/.llm/digest/navbarmenugroup.md +40 -0
  82. package/.llm/digest/navbarpanel.md +53 -0
  83. package/.llm/digest/navbarswitcher.md +51 -0
  84. package/.llm/digest/navbarswitcheroption.md +37 -0
  85. package/.llm/digest/option.md +54 -0
  86. package/.llm/digest/pagination.md +71 -0
  87. package/.llm/digest/removablechip.md +51 -0
  88. package/.llm/digest/row.md +60 -0
  89. package/.llm/digest/scroller.md +59 -0
  90. package/.llm/digest/searchinput.md +56 -0
  91. package/.llm/digest/segmentedcontrol.md +59 -0
  92. package/.llm/digest/segmentedcontrolitem.md +59 -0
  93. package/.llm/digest/select.md +92 -0
  94. package/.llm/digest/selectchip.md +68 -0
  95. package/.llm/digest/spinner.md +52 -0
  96. package/.llm/digest/stack.md +56 -0
  97. package/.llm/digest/statusdot.md +46 -0
  98. package/.llm/digest/subdomainnavbar.md +54 -0
  99. package/.llm/digest/tab.md +60 -0
  100. package/.llm/digest/table.md +71 -0
  101. package/.llm/digest/tablebody.md +49 -0
  102. package/.llm/digest/tablecell.md +55 -0
  103. package/.llm/digest/tablehead.md +50 -0
  104. package/.llm/digest/tableheadercell.md +65 -0
  105. package/.llm/digest/tablerow.md +56 -0
  106. package/.llm/digest/tablist.md +46 -0
  107. package/.llm/digest/textarea.md +78 -0
  108. package/.llm/digest/textinput.md +95 -0
  109. package/.llm/digest/tooltip.md +58 -0
  110. package/.llm/digest/typography.md +59 -0
  111. package/.llm/index.md +86 -0
  112. package/.llm/rules.md +122 -0
  113. package/.llm/tokens.md +341 -0
  114. package/AGENTS.md +164 -0
  115. package/LICENSE +21 -0
  116. package/README.md +63 -15
  117. package/dist/components/core/accordion/Accordion.css +10 -0
  118. package/dist/components/core/accordion/Accordion.d.ts +20 -0
  119. package/dist/components/core/accordion/Accordion.js +69 -0
  120. package/dist/components/core/accordion/Accordion.types.d.ts +20 -0
  121. package/dist/components/core/accordion/Accordion.types.js +7 -0
  122. package/dist/components/core/accordion-item/AccordionItem.css +98 -0
  123. package/dist/components/core/accordion-item/AccordionItem.d.ts +44 -0
  124. package/dist/components/core/accordion-item/AccordionItem.js +63 -0
  125. package/dist/components/core/accordion-item/AccordionItem.types.d.ts +32 -0
  126. package/dist/components/core/accordion-item/AccordionItem.types.js +13 -0
  127. package/dist/components/core/accordion-item/accordion-item-impl.css +107 -0
  128. package/dist/components/core/badge/Badge.css +37 -0
  129. package/dist/components/core/badge/Badge.d.ts +37 -0
  130. package/dist/components/core/badge/Badge.js +40 -0
  131. package/dist/components/core/badge/Badge.types.d.ts +24 -0
  132. package/dist/components/core/badge/Badge.types.js +8 -0
  133. package/dist/components/core/badge/badge-impl.css +32 -0
  134. package/dist/components/core/bottom-sheet/BottomSheet.css +178 -0
  135. package/dist/components/core/bottom-sheet/BottomSheet.d.ts +22 -0
  136. package/dist/components/core/bottom-sheet/BottomSheet.js +359 -0
  137. package/dist/components/core/bottom-sheet/BottomSheet.types.d.ts +67 -0
  138. package/dist/components/core/bottom-sheet/BottomSheet.types.js +18 -0
  139. package/dist/components/core/bottom-sheet/bottom-sheet-impl.css +57 -0
  140. package/dist/components/core/breadcrumb/Breadcrumb.css +19 -0
  141. package/dist/components/core/breadcrumb/Breadcrumb.d.ts +16 -0
  142. package/dist/components/core/breadcrumb/Breadcrumb.js +22 -0
  143. package/dist/components/core/breadcrumb/Breadcrumb.types.d.ts +18 -0
  144. package/dist/components/core/breadcrumb/Breadcrumb.types.js +9 -0
  145. package/dist/components/core/breadcrumb-item/BreadcrumbItem.css +34 -0
  146. package/dist/components/core/breadcrumb-item/BreadcrumbItem.d.ts +12 -0
  147. package/dist/components/core/breadcrumb-item/BreadcrumbItem.js +15 -0
  148. package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.d.ts +22 -0
  149. package/dist/components/core/breadcrumb-item/BreadcrumbItem.types.js +9 -0
  150. package/dist/components/core/button/Button.css +141 -0
  151. package/dist/components/core/button/Button.d.ts +25 -0
  152. package/dist/components/core/button/Button.js +28 -0
  153. package/dist/components/core/button/Button.types.d.ts +40 -0
  154. package/dist/components/core/button/Button.types.js +9 -0
  155. package/dist/components/core/button/button-impl.css +46 -0
  156. package/dist/components/core/button-icon/ButtonIcon.css +135 -0
  157. package/dist/components/core/button-icon/ButtonIcon.d.ts +34 -0
  158. package/dist/components/core/button-icon/ButtonIcon.js +117 -0
  159. package/dist/components/core/button-icon/ButtonIcon.types.d.ts +41 -0
  160. package/dist/components/core/button-icon/ButtonIcon.types.js +8 -0
  161. package/dist/components/core/card/Card.css +65 -0
  162. package/dist/components/core/card/Card.d.ts +24 -0
  163. package/dist/components/core/card/Card.js +26 -0
  164. package/dist/components/core/card/Card.types.d.ts +33 -0
  165. package/dist/components/core/card/Card.types.js +7 -0
  166. package/dist/components/core/card-body/CardBody.css +139 -0
  167. package/dist/components/core/card-body/CardBody.d.ts +62 -0
  168. package/dist/components/core/card-body/CardBody.js +97 -0
  169. package/dist/components/core/card-body/CardBody.types.d.ts +61 -0
  170. package/dist/components/core/card-body/CardBody.types.js +15 -0
  171. package/dist/components/core/card-body/card-body-impl.css +87 -0
  172. package/dist/components/core/card-button/CardButton.css +73 -0
  173. package/dist/components/core/card-button/CardButton.d.ts +27 -0
  174. package/dist/components/core/card-button/CardButton.js +37 -0
  175. package/dist/components/core/card-button/CardButton.types.d.ts +24 -0
  176. package/dist/components/core/card-button/CardButton.types.js +7 -0
  177. package/dist/components/core/card-button/card-button-impl.css +39 -0
  178. package/dist/components/core/checkbox/Checkbox.css +149 -0
  179. package/dist/components/core/checkbox/Checkbox.d.ts +21 -0
  180. package/dist/components/core/checkbox/Checkbox.js +97 -0
  181. package/dist/components/core/checkbox/Checkbox.types.d.ts +46 -0
  182. package/dist/components/core/checkbox/Checkbox.types.js +15 -0
  183. package/dist/components/core/checkbox/checkbox-impl.css +90 -0
  184. package/dist/components/core/divider/Divider.css +41 -0
  185. package/dist/components/core/divider/Divider.d.ts +46 -0
  186. package/dist/components/core/divider/Divider.js +51 -0
  187. package/dist/components/core/divider/Divider.types.d.ts +25 -0
  188. package/dist/components/core/divider/Divider.types.js +9 -0
  189. package/dist/components/core/dropdown-menu/DropdownMenu.css +146 -0
  190. package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +22 -0
  191. package/dist/components/core/dropdown-menu/DropdownMenu.js +309 -0
  192. package/dist/components/core/dropdown-menu/DropdownMenu.types.d.ts +62 -0
  193. package/dist/components/core/dropdown-menu/DropdownMenu.types.js +12 -0
  194. package/dist/components/core/dropdown-menu/dropdown-menu-impl.css +70 -0
  195. package/dist/components/core/filter-chip/FilterChip.css +149 -0
  196. package/dist/components/core/filter-chip/FilterChip.d.ts +23 -0
  197. package/dist/components/core/filter-chip/FilterChip.js +37 -0
  198. package/dist/components/core/filter-chip/FilterChip.types.d.ts +53 -0
  199. package/dist/components/core/filter-chip/FilterChip.types.js +12 -0
  200. package/dist/components/core/footer/Footer.css +104 -0
  201. package/dist/components/core/footer/Footer.d.ts +43 -0
  202. package/dist/components/core/footer/Footer.js +53 -0
  203. package/dist/components/core/footer/Footer.types.d.ts +47 -0
  204. package/dist/components/core/footer/Footer.types.js +18 -0
  205. package/dist/components/core/footer/footer-impl.css +218 -0
  206. package/dist/components/core/footer-group/FooterGroup.css +90 -0
  207. package/dist/components/core/footer-group/FooterGroup.d.ts +32 -0
  208. package/dist/components/core/footer-group/FooterGroup.js +64 -0
  209. package/dist/components/core/footer-group/FooterGroup.types.d.ts +25 -0
  210. package/dist/components/core/footer-group/FooterGroup.types.js +12 -0
  211. package/dist/components/core/footer-group/footer-group-impl.css +78 -0
  212. package/dist/components/core/icon/Icon.css +40 -0
  213. package/dist/components/core/icon/Icon.d.ts +23 -0
  214. package/dist/components/core/icon/Icon.js +79 -0
  215. package/dist/components/core/icon/Icon.types.d.ts +24 -0
  216. package/dist/components/core/icon/Icon.types.js +7 -0
  217. package/dist/components/core/link/Link.css +89 -0
  218. package/dist/components/core/link/Link.d.ts +37 -0
  219. package/dist/components/core/link/Link.js +141 -0
  220. package/dist/components/core/link/Link.types.d.ts +41 -0
  221. package/dist/components/core/link/Link.types.js +9 -0
  222. package/dist/components/core/link/link-impl.css +168 -0
  223. package/dist/components/core/menu-item/MenuItem.css +70 -0
  224. package/dist/components/core/menu-item/MenuItem.d.ts +11 -0
  225. package/dist/components/core/menu-item/MenuItem.js +26 -0
  226. package/dist/components/core/menu-item/MenuItem.types.d.ts +28 -0
  227. package/dist/components/core/menu-item/MenuItem.types.js +9 -0
  228. package/dist/components/core/navbar/Navbar.css +135 -0
  229. package/dist/components/core/navbar/Navbar.d.ts +36 -0
  230. package/dist/components/core/navbar/Navbar.js +371 -0
  231. package/dist/components/core/navbar/Navbar.types.d.ts +49 -0
  232. package/dist/components/core/navbar/Navbar.types.js +17 -0
  233. package/dist/components/core/navbar/navbar-impl.css +590 -0
  234. package/dist/components/core/navbar-item/NavbarItem.css +75 -0
  235. package/dist/components/core/navbar-item/NavbarItem.d.ts +22 -0
  236. package/dist/components/core/navbar-item/NavbarItem.js +40 -0
  237. package/dist/components/core/navbar-item/NavbarItem.types.d.ts +34 -0
  238. package/dist/components/core/navbar-item/NavbarItem.types.js +10 -0
  239. package/dist/components/core/navbar-menu/NavbarMenu.css +128 -0
  240. package/dist/components/core/navbar-menu/NavbarMenu.d.ts +5 -0
  241. package/dist/components/core/navbar-menu/NavbarMenu.js +186 -0
  242. package/dist/components/core/navbar-menu/NavbarMenu.types.d.ts +45 -0
  243. package/dist/components/core/navbar-menu/NavbarMenu.types.js +12 -0
  244. package/dist/components/core/navbar-menu/navbar-menu-impl.css +186 -0
  245. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.css +26 -0
  246. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.d.ts +17 -0
  247. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.js +22 -0
  248. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.d.ts +14 -0
  249. package/dist/components/core/navbar-menu-group/NavbarMenuGroup.types.js +7 -0
  250. package/dist/components/core/navbar-panel/NavbarPanel.css +87 -0
  251. package/dist/components/core/navbar-panel/NavbarPanel.d.ts +34 -0
  252. package/dist/components/core/navbar-panel/NavbarPanel.js +46 -0
  253. package/dist/components/core/navbar-panel/NavbarPanel.types.d.ts +29 -0
  254. package/dist/components/core/navbar-panel/NavbarPanel.types.js +12 -0
  255. package/dist/components/core/navbar-panel/navbar-panel-impl.css +104 -0
  256. package/dist/components/core/navbar-panel/use-navbar-panel.d.ts +26 -0
  257. package/dist/components/core/navbar-panel/use-navbar-panel.js +135 -0
  258. package/dist/components/core/navbar-switcher/NavbarSwitcher.css +117 -0
  259. package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +20 -0
  260. package/dist/components/core/navbar-switcher/NavbarSwitcher.js +90 -0
  261. package/dist/components/core/navbar-switcher/NavbarSwitcher.types.d.ts +46 -0
  262. package/dist/components/core/navbar-switcher/NavbarSwitcher.types.js +13 -0
  263. package/dist/components/core/navbar-switcher/navbar-switcher-impl.css +179 -0
  264. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.css +39 -0
  265. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.d.ts +16 -0
  266. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.js +19 -0
  267. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.d.ts +18 -0
  268. package/dist/components/core/navbar-switcher-option/NavbarSwitcherOption.types.js +7 -0
  269. package/dist/components/core/option/Option.css +133 -0
  270. package/dist/components/core/option/Option.d.ts +25 -0
  271. package/dist/components/core/option/Option.js +31 -0
  272. package/dist/components/core/option/Option.types.d.ts +44 -0
  273. package/dist/components/core/option/Option.types.js +14 -0
  274. package/dist/components/core/pagination/Pagination.css +237 -0
  275. package/dist/components/core/pagination/Pagination.d.ts +30 -0
  276. package/dist/components/core/pagination/Pagination.js +406 -0
  277. package/dist/components/core/pagination/Pagination.types.d.ts +59 -0
  278. package/dist/components/core/pagination/Pagination.types.js +14 -0
  279. package/dist/components/core/pagination/pagination-impl.css +17 -0
  280. package/dist/components/core/removable-chip/RemovableChip.css +125 -0
  281. package/dist/components/core/removable-chip/RemovableChip.d.ts +25 -0
  282. package/dist/components/core/removable-chip/RemovableChip.js +36 -0
  283. package/dist/components/core/removable-chip/RemovableChip.types.d.ts +38 -0
  284. package/dist/components/core/removable-chip/RemovableChip.types.js +13 -0
  285. package/dist/components/core/search-input/SearchInput.css +205 -0
  286. package/dist/components/core/search-input/SearchInput.d.ts +5 -0
  287. package/dist/components/core/search-input/SearchInput.js +81 -0
  288. package/dist/components/core/search-input/SearchInput.types.d.ts +43 -0
  289. package/dist/components/core/search-input/SearchInput.types.js +13 -0
  290. package/dist/components/core/search-input/search-input-impl.css +20 -0
  291. package/dist/components/core/segmented-control/SegmentedControl.css +57 -0
  292. package/dist/components/core/segmented-control/SegmentedControl.d.ts +37 -0
  293. package/dist/components/core/segmented-control/SegmentedControl.js +269 -0
  294. package/dist/components/core/segmented-control/SegmentedControl.types.d.ts +38 -0
  295. package/dist/components/core/segmented-control/SegmentedControl.types.js +8 -0
  296. package/dist/components/core/segmented-control/segmented-control-impl.css +57 -0
  297. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +151 -0
  298. package/dist/components/core/segmented-control-item/SegmentedControlItem.d.ts +50 -0
  299. package/dist/components/core/segmented-control-item/SegmentedControlItem.js +101 -0
  300. package/dist/components/core/segmented-control-item/SegmentedControlItem.types.d.ts +37 -0
  301. package/dist/components/core/segmented-control-item/SegmentedControlItem.types.js +10 -0
  302. package/dist/components/core/segmented-control-item/segmented-control-item-impl.css +69 -0
  303. package/dist/components/core/select/Select.css +400 -0
  304. package/dist/components/core/select/Select.d.ts +29 -0
  305. package/dist/components/core/select/Select.js +524 -0
  306. package/dist/components/core/select/Select.types.d.ts +96 -0
  307. package/dist/components/core/select/Select.types.js +26 -0
  308. package/dist/components/core/select/select-impl.css +114 -0
  309. package/dist/components/core/select-chip/SelectChip.css +155 -0
  310. package/dist/components/core/select-chip/SelectChip.d.ts +20 -0
  311. package/dist/components/core/select-chip/SelectChip.js +273 -0
  312. package/dist/components/core/select-chip/SelectChip.types.d.ts +56 -0
  313. package/dist/components/core/select-chip/SelectChip.types.js +14 -0
  314. package/dist/components/core/select-chip/select-chip-impl.css +38 -0
  315. package/dist/components/core/spinner/Spinner.css +76 -0
  316. package/dist/components/core/spinner/Spinner.d.ts +5 -0
  317. package/dist/components/core/spinner/Spinner.js +29 -0
  318. package/dist/components/core/spinner/Spinner.types.d.ts +37 -0
  319. package/dist/components/core/spinner/Spinner.types.js +10 -0
  320. package/dist/components/core/spinner/spinner-impl.css +27 -0
  321. package/dist/components/core/status-dot/StatusDot.css +43 -0
  322. package/dist/components/core/status-dot/StatusDot.d.ts +35 -0
  323. package/dist/components/core/status-dot/StatusDot.js +46 -0
  324. package/dist/components/core/status-dot/StatusDot.types.d.ts +29 -0
  325. package/dist/components/core/status-dot/StatusDot.types.js +7 -0
  326. package/dist/components/core/status-dot/status-dot-impl.css +42 -0
  327. package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +89 -0
  328. package/dist/components/core/subdomain-navbar/SubdomainNavbar.d.ts +21 -0
  329. package/dist/components/core/subdomain-navbar/SubdomainNavbar.js +127 -0
  330. package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.d.ts +43 -0
  331. package/dist/components/core/subdomain-navbar/SubdomainNavbar.types.js +13 -0
  332. package/dist/components/core/subdomain-navbar/subdomain-navbar-impl.css +147 -0
  333. package/dist/components/core/tab/Tab.css +113 -0
  334. package/dist/components/core/tab/Tab.d.ts +36 -0
  335. package/dist/components/core/tab/Tab.js +53 -0
  336. package/dist/components/core/tab/Tab.types.d.ts +42 -0
  337. package/dist/components/core/tab/Tab.types.js +13 -0
  338. package/dist/components/core/tab/tab-impl.css +49 -0
  339. package/dist/components/core/tab-list/TabList.css +40 -0
  340. package/dist/components/core/tab-list/TabList.d.ts +26 -0
  341. package/dist/components/core/tab-list/TabList.js +124 -0
  342. package/dist/components/core/tab-list/TabList.types.d.ts +20 -0
  343. package/dist/components/core/tab-list/TabList.types.js +7 -0
  344. package/dist/components/core/tab-list/tab-list-impl.css +56 -0
  345. package/dist/components/core/table/Table.css +40 -0
  346. package/dist/components/core/table/Table.d.ts +19 -0
  347. package/dist/components/core/table/Table.js +55 -0
  348. package/dist/components/core/table/Table.types.d.ts +59 -0
  349. package/dist/components/core/table/Table.types.js +9 -0
  350. package/dist/components/core/table/table-impl.css +75 -0
  351. package/dist/components/core/table/use-table-sort.d.ts +43 -0
  352. package/dist/components/core/table/use-table-sort.js +51 -0
  353. package/dist/components/core/table-body/TableBody.css +6 -0
  354. package/dist/components/core/table-body/TableBody.d.ts +12 -0
  355. package/dist/components/core/table-body/TableBody.js +26 -0
  356. package/dist/components/core/table-body/TableBody.types.d.ts +36 -0
  357. package/dist/components/core/table-body/TableBody.types.js +7 -0
  358. package/dist/components/core/table-cell/TableCell.css +76 -0
  359. package/dist/components/core/table-cell/TableCell.d.ts +21 -0
  360. package/dist/components/core/table-cell/TableCell.js +31 -0
  361. package/dist/components/core/table-cell/TableCell.types.d.ts +43 -0
  362. package/dist/components/core/table-cell/TableCell.types.js +7 -0
  363. package/dist/components/core/table-head/TableHead.css +6 -0
  364. package/dist/components/core/table-head/TableHead.d.ts +22 -0
  365. package/dist/components/core/table-head/TableHead.js +52 -0
  366. package/dist/components/core/table-head/TableHead.types.d.ts +39 -0
  367. package/dist/components/core/table-head/TableHead.types.js +7 -0
  368. package/dist/components/core/table-head/table-head-impl.css +51 -0
  369. package/dist/components/core/table-header-cell/TableHeaderCell.css +126 -0
  370. package/dist/components/core/table-header-cell/TableHeaderCell.d.ts +21 -0
  371. package/dist/components/core/table-header-cell/TableHeaderCell.js +34 -0
  372. package/dist/components/core/table-header-cell/TableHeaderCell.types.d.ts +56 -0
  373. package/dist/components/core/table-header-cell/TableHeaderCell.types.js +9 -0
  374. package/dist/components/core/table-header-cell/table-header-cell-impl.css +74 -0
  375. package/dist/components/core/table-row/TableRow.css +18 -0
  376. package/dist/components/core/table-row/TableRow.d.ts +17 -0
  377. package/dist/components/core/table-row/TableRow.js +32 -0
  378. package/dist/components/core/table-row/TableRow.types.d.ts +45 -0
  379. package/dist/components/core/table-row/TableRow.types.js +7 -0
  380. package/dist/components/core/table-row/table-row-impl.css +31 -0
  381. package/dist/components/core/text-area/TextArea.css +325 -0
  382. package/dist/components/core/text-area/TextArea.d.ts +13 -0
  383. package/dist/components/core/text-area/TextArea.js +133 -0
  384. package/dist/components/core/text-area/TextArea.types.d.ts +67 -0
  385. package/dist/components/core/text-area/TextArea.types.js +19 -0
  386. package/dist/components/core/text-area/text-area-impl.css +36 -0
  387. package/dist/components/core/text-input/TextInput.css +400 -0
  388. package/dist/components/core/text-input/TextInput.d.ts +5 -0
  389. package/dist/components/core/text-input/TextInput.js +130 -0
  390. package/dist/components/core/text-input/TextInput.types.d.ts +96 -0
  391. package/dist/components/core/text-input/TextInput.types.js +24 -0
  392. package/dist/components/core/text-input/text-input-impl.css +36 -0
  393. package/dist/components/core/tooltip/Tooltip.css +101 -0
  394. package/dist/components/core/tooltip/Tooltip.d.ts +51 -0
  395. package/dist/components/core/tooltip/Tooltip.js +87 -0
  396. package/dist/components/core/tooltip/Tooltip.types.d.ts +38 -0
  397. package/dist/components/core/tooltip/Tooltip.types.js +9 -0
  398. package/dist/components/core/tooltip/TooltipAnchor.d.ts +52 -0
  399. package/dist/components/core/tooltip/TooltipAnchor.js +69 -0
  400. package/dist/components/core/tooltip/tooltip-anchor.css +145 -0
  401. package/dist/components/core/tooltip/tooltip-impl.css +54 -0
  402. package/dist/components/core/tooltip/use-tooltip.d.ts +111 -0
  403. package/dist/components/core/tooltip/use-tooltip.js +189 -0
  404. package/dist/components/core/typography/Typography.css +96 -0
  405. package/dist/components/core/typography/Typography.d.ts +297 -0
  406. package/dist/components/core/typography/Typography.js +28 -0
  407. package/dist/components/core/typography/Typography.types.d.ts +40 -0
  408. package/dist/components/core/typography/Typography.types.js +7 -0
  409. package/dist/components/css-time.d.ts +20 -0
  410. package/dist/components/css-time.js +30 -0
  411. package/dist/components/given.d.ts +7 -0
  412. package/dist/components/given.js +9 -0
  413. package/dist/components/hover-open.d.ts +34 -0
  414. package/dist/components/hover-open.js +90 -0
  415. package/dist/components/index.d.ts +114 -1
  416. package/dist/components/index.js +115 -2
  417. package/dist/components/layout/aspect-ratio/AspectRatio.css +29 -0
  418. package/dist/components/layout/aspect-ratio/AspectRatio.d.ts +24 -0
  419. package/dist/components/layout/aspect-ratio/AspectRatio.js +26 -0
  420. package/dist/components/layout/aspect-ratio/AspectRatio.types.d.ts +22 -0
  421. package/dist/components/layout/aspect-ratio/AspectRatio.types.js +7 -0
  422. package/dist/components/layout/aspect-ratio/aspect-ratio-impl.css +44 -0
  423. package/dist/components/layout/grid/Grid.css +76 -0
  424. package/dist/components/layout/grid/Grid.d.ts +31 -0
  425. package/dist/components/layout/grid/Grid.js +33 -0
  426. package/dist/components/layout/grid/Grid.types.d.ts +48 -0
  427. package/dist/components/layout/grid/Grid.types.js +7 -0
  428. package/dist/components/layout/grid/grid-impl.css +62 -0
  429. package/dist/components/layout/row/Row.css +85 -0
  430. package/dist/components/layout/row/Row.d.ts +32 -0
  431. package/dist/components/layout/row/Row.js +34 -0
  432. package/dist/components/layout/row/Row.types.d.ts +45 -0
  433. package/dist/components/layout/row/Row.types.js +7 -0
  434. package/dist/components/layout/scroller/Scroller.css +59 -0
  435. package/dist/components/layout/scroller/Scroller.d.ts +34 -0
  436. package/dist/components/layout/scroller/Scroller.js +36 -0
  437. package/dist/components/layout/scroller/Scroller.types.d.ts +38 -0
  438. package/dist/components/layout/scroller/Scroller.types.js +7 -0
  439. package/dist/components/layout/scroller/scroller-impl.css +45 -0
  440. package/dist/components/layout/stack/Stack.css +73 -0
  441. package/dist/components/layout/stack/Stack.d.ts +28 -0
  442. package/dist/components/layout/stack/Stack.js +30 -0
  443. package/dist/components/layout/stack/Stack.types.d.ts +41 -0
  444. package/dist/components/layout/stack/Stack.types.js +7 -0
  445. package/dist/components/visually-hidden.d.ts +22 -0
  446. package/dist/components/visually-hidden.js +31 -0
  447. package/dist/fonts/LICENSE-inter.txt +93 -0
  448. package/dist/fonts/LICENSE-red-hat-mono.txt +93 -0
  449. package/dist/fonts/fonts.css +111 -0
  450. package/dist/fonts/inter-cyrillic-ext-wght-normal.woff2 +0 -0
  451. package/dist/fonts/inter-cyrillic-wght-normal.woff2 +0 -0
  452. package/dist/fonts/inter-greek-ext-wght-normal.woff2 +0 -0
  453. package/dist/fonts/inter-greek-wght-normal.woff2 +0 -0
  454. package/dist/fonts/inter-latin-ext-wght-normal.woff2 +0 -0
  455. package/dist/fonts/inter-latin-wght-normal.woff2 +0 -0
  456. package/dist/fonts/inter-vietnamese-wght-normal.woff2 +0 -0
  457. package/dist/fonts/red-hat-mono-latin-ext-wght-normal.woff2 +0 -0
  458. package/dist/fonts/red-hat-mono-latin-wght-normal.woff2 +0 -0
  459. package/dist/marketing.css +289 -241
  460. package/package.json +18 -4
@@ -0,0 +1,194 @@
1
+ <!-- GENERATED from icon.contract.json. Do not edit. -->
2
+
3
+ # Icon
4
+
5
+ Renders a Quill system glyph at a token size, taking its colour from the text around it. The glyph is imported from @deriv-com/quill-icons-web and passed as the only child. Its components are named shape, then weight, then Icon — MagnifyingGlassRegularIcon, EnvelopeRegularIcon, CircleCheckSolidIcon — and the weight is chosen at the import site because Icon has no weight prop and cannot have one.
6
+
7
+ The same component Product has, on Marketing's own ramp. The last one here was a copy that nothing had asked for and it was deleted for that; what asks for this one is three components already drawing glyphs by hand — Breadcrumb's separator, AccordionItem's chevron and whatever a page puts in CardBody's mark — each repeating the same two bindings and the same reason.
8
+
9
+ ## Use when
10
+
11
+ - A glyph stands beside words to speed recognition — a mark on a feature card, a chevron on a row, a separator in a trail
12
+ - A page is composing something a component offers a slot for, and the slot takes a mark rather than a component that draws one
13
+
14
+ ## Do not use
15
+
16
+ - The mark identifies a company or a product — a payment method, an app store, a social network → `Logo` *(not built yet — raise it with the design system team)*
17
+ - The artwork is a scene rather than a symbol → `Illustration` *(not built yet — raise it with the design system team)*
18
+ - Flag, market, currency or payment glyphs — they carry fixed brand colour, and tinting them corrupts the mark while still rendering. Render one bare, outside an Icon: it keeps its own colour and its own proportions, which is what a mark is
19
+ - Information that appears nowhere else. A glyph a reader has to interpret unaided is a label the page failed to write, and a marketing page has room for the words
20
+ - The picture in a card. A mark is a symbol at a step on this ramp; a photograph or a render is CardBody's `src`, which reaches the card's edges and is measured by the card rather than by a scale of glyph sizes
21
+
22
+ ## Anatomy
23
+
24
+ Icon renders one element.
25
+
26
+ - `root` — `<svg>`, class `dds-icon`. The glyph itself. Icon applies its class to the SVG it is handed rather than wrapping it, so the size tokens land on the element that renders — and a CSS width overrides the width attribute every Quill glyph ships with. That is not a detail: sizing a box around a glyph does nothing to the glyph, which is the mistake CardBody's mark had to answer with an impl sheet and a rule reaching into a child.
27
+
28
+ It can turn. A mark that says whether something is open — a chevron on an accordion row, a fold in a menu — is one glyph rotated rather than two swapped, and the rotation wants a duration. Here rather than in each of them, because every such mark is an Icon and none of them owns the box it sits in. Only `rotate` transitions, so an icon taking a new colour still takes it at once.
29
+
30
+ Apply these classes from the generated `iconParts` constant rather than writing the strings by hand.
31
+
32
+ ## Composition
33
+
34
+ - Can contain: `QuillSystemIcon`
35
+ - Never contains: `Icon`, `Card`, `CardButton`, `Accordion`, `AccordionItem` — in children or in any prop that takes a node
36
+ - Holds at least 1 and at most 1
37
+
38
+ ## Props
39
+
40
+ ### size — `xs` | `sm` | `md` | `lg` | `xl` (default `md`)
41
+
42
+ - `xs` — Inline and supporting content — a separator in a trail, a mark against small text
43
+ - `sm` — A mark beside text that must not outweigh it: the chevron on a list row, an affordance next to a label
44
+ - `md` — The default. Body content and lists, where the glyph sits with the words rather than above them
45
+ - `lg` — Cards and content sections — the mark a feature card leads with, read before its title is
46
+ - `xl` — The largest step, for a callout or a highlighted block where the glyph does as much work as the copy
47
+
48
+ Use when: The step the glyph is drawn at. It is a size and not an instruction: what a mark means comes from where it is, and this decides only how large it is drawn there
49
+ Never for: Setting the step of a glyph you are handing to a component. A slot takes the glyph and its component draws it at the step its own contract names, so an Icon arriving there is a call site written against something else — it is unwrapped and the outer step is what draws. A name on the inner one is carried out, so nothing announced is lost on the way
50
+
51
+ ### label — `string`
52
+
53
+ Use when: The glyph is the only thing naming its control — an icon-only button, a mark with no words beside it
54
+ Never for: A glyph beside a label that already says the same thing, which makes a screen reader announce it twice
55
+
56
+ ## Accessibility
57
+
58
+ Guaranteed by the component. Write none of it by hand: the ids these attributes point at are generated per instance, so an attribute set from outside either says the same thing twice or points at nothing.
59
+
60
+ - Announced as: `presentation`
61
+ - role="presentation" and no accessible name when label is omitted, so a decorative glyph is not announced. A label of no characters, or of spaces, counts as omitted: an empty aria-label is a name of no characters rather than no name.
62
+ - role="img" and an accessible name taken from label when label is given.
63
+
64
+ ## Rules
65
+
66
+ - **On a phone a section's actions stack and each fills the width, including when there is only one** — On a phone a page's actions stack, and each one fills the width. Not most of it, and not the width its label happens to need — the whole column.
67
+
68
+ Two side by side is what this replaces. On the narrowest screen each gets half a column minus the gap, which is rarely enough for a real label: the words wrap inside the pills, the two buttons come out different heights, and the pair reads as a broken row rather than as a choice. Stacked, each has the whole width and neither has to shorten its words to fit.
69
+
70
+ A single action fills too, and that is the part worth saying, because it is the one that looks unnecessary. A lone button has the room to sit at its natural width and still should not: a full-width control is the phone's convention for the thing the screen is asking you to do, and a pill hugging its label reads as one option among others that are not there. It also makes the target predictable — the whole width, wherever the thumb lands — which a centred pill does not.
71
+
72
+ Filling is the row's job rather than the button's. A button has no width of its own and is not given one; the row it sits in becomes a column and stretches its children, so nothing about the control changes and the same button is full width here and its own size on a desktop.
73
+
74
+ This is the phone's breakpoint, size.breakpoint.md, and not the wider one that decides whether a heading is centred. Those are different questions and they break at different widths: a heading stops being centred when the measure is the screen, while a button stops being full width much sooner than that — stretched across a tablet it is a long way from its own label, and a label centred in a metre of pill is harder to hit than one in a pill the size of the words.
75
+
76
+ What this is not about is every row of controls. A set of filter chips, a pagination strip, a toolbar, a link sitting after a sentence — none of these is the page asking for something, and stacking them to full width would turn a strip the eye skims into a list it has to read. The test is whether the row is the call to action the section was written for.
77
+ Guidance only — cannot be checked automatically.
78
+ - **Solid weight means selected** *(applies to a variant not built yet)* — Solid is not an alternative style, it is what a selected icon looks like. A tab or a navigation item renders regular at rest and swaps to solid when it becomes the current one, so the weight change is what carries the selection. The swap changes weight only — the same glyph at the same size, so the shape stays recognisable and just fills in. Marketing has fewer selected states than Product does, which is the reason to hold the meaning rather than to relax it: a solid glyph used decoratively here teaches a reader that solid means nothing, and they carry that into the product.
79
+ Guidance only — cannot be checked automatically.
80
+ - **Match the glyph weight to the icon size** *(applies to a variant not built yet)* — Quill ships every system glyph three times — light, regular and solid — as separate components chosen at the import site. Icon has no weight prop and cannot have one, so nothing in this system can observe the choice, let alone enforce it. Size is what should decide it: a glyph carries its stroke weight through any scale, so a regular-weight glyph drawn for 24px renders its strokes at over three times that width when placed at display size, and reads as heavy rather than confident. At rest, use regular from sm through lg, and light at xl, 2xl and display — selection is the one thing that overrides this, and it only ever moves regular to solid.
81
+ Guidance only — cannot be checked automatically.
82
+ - **Never nest one interactive element inside another** — Nested interactive elements produce ambiguous hit targets and an unreachable inner control for keyboard and screen-reader users. This is why the rule cannot live on any single component — it constrains Button, Link, Input and Switch simultaneously.
83
+ Guidance only — cannot be checked automatically.
84
+ - **A section that paints a ground sets the ink to go with it** — A page sits on color.bg.page, and a section that separates itself from it takes one of three grounds. color.bg.subtle is the light one and needs nothing further — the page's own ink still reads on it. The other two are dark and do not: color.bg.brand-strong takes color.fg.on-brand-strong, and color.bg.brand takes color.fg.on-solid. Both are white, and both are written as the role rather than the white they resolve to. Set one of those backgrounds without its ink and the text inherits whatever the page was already using, which is near-black on a dark band — legible to nobody, and invisible to every check here, because each pair passes contrast on its own and nothing can tell whether a section used both.
85
+
86
+ color.bg.brand carries a second limit that is not about forgetting. Its ink measures 3.39:1, which clears the 3:1 a heading needs and misses the 4.5:1 running copy needs. A coral band may carry a headline and a call to action; a paragraph on one is text the reader has to work through at a ratio the waiver on that role does not cover — the waiver says so itself. A section with copy in it takes color.bg.brand-strong, which is near-black and carries white at full contrast.
87
+
88
+ color.bg.strong is not a section ground. It is the inverted fill for an action that has to outrank what surrounds it, and the components that paint it — Button and ButtonIcon in their inverse form — already set both halves in one rule, which is the pattern a hand-painted section has to copy.
89
+ Guidance only — cannot be checked automatically.
90
+ - **Every gap inside a section names the relationship it expresses, and the same relationship keeps its measure when it turns on its side** — A section's spacing is named by the relationship it expresses, not chosen by size. Every gap in a section has a role token, and reaching for a step off the generic scale because it happens to be the right number is how two sections written by two people stop lining up: the numbers agree today and drift the first time one of them is tuned.
91
+
92
+ The heading group is three steps, not one gap. An eyebrow sits nearer its title than the title sits to its description, and the actions sit further from the description than either — space.heading.eyebrow-title, space.heading.title-description, space.heading.description-actions, in that order. A single `gap` on the group cannot say this; it sets all three the same and the block reads as evenly spaced lines rather than as a mark, a name and a paragraph. The eyebrow has to identify itself for this to work, because a group that opens with a title must not give its description the eyebrow's tighter step.
93
+
94
+ The step between a title and its description follows the size of the title, which is why there are two of it. What a reader sees is not the gap but the gap plus the leading above it, and leading scales with the type: under a display title the leading is most of the space, under a card's title it is half as deep. One value for both makes a card look loose at the size that made a section look right. So space.heading.title-description is the display step and space.heading.title-description-compact is the step at a card's size, and the choice is made by how big the title is rather than by what kind of block it sits in.
95
+
96
+ Every one of those steps is smaller than the gap below the group, and that ordering is what holds the group together as one thing. space.heading.content is the step between a heading group and the content it introduces, and it is the widest measure inside a section: the one gap the eye reads as a change of subject rather than as a continuation.
97
+
98
+ That step is the same whether the content is under the heading or beside it. A split is the same relationship turned on its side — a heading group and the content it introduces — so the space between the two halves is space.heading.content, not a gutter. When the split collapses to one column on a phone the gap becomes vertical again, which is where it started, and nothing has to change for that to be right.
99
+
100
+ space.grid.gutter is between two things of the same kind. Two cards in a row are the same kind; the two halves of a split are not, which is why the gutter is the wrong measure there even when the number would have looked acceptable. The gutter runs on both axes, so a grid reads as an even field rather than as rows with a seam down them.
101
+
102
+ space.inset.card is the card's, not the page's. A row of cards padded differently is a row of different cards, and the fill is the only edge they have. A page composing a row does not get to choose it.
103
+
104
+ Column count is not a breakpoint decision. A row holds as many columns as fit before a column would be narrower than size.grid.column-min, and drops one when they would not. Written as a fixed count that collapses at a breakpoint, a four-up row keeps four columns at every width above the phone and sets its copy two or three words to a line through the whole of the tablet range — and on a narrow desktop, which no breakpoint sits on at all. The threshold is a property of the row rather than of a card: a card fills whatever cell it is given.
105
+
106
+ What this does not cover is the space above and below a section, which is space.section.default and space.section.compact, and the page's own side margin, which is space.inset.page. Those are the section's outside; everything here is its inside.
107
+ Guidance only — cannot be checked automatically.
108
+ - **A section's title is centred over stacked content, starts beside content in columns, and starts on a phone** — Two arrangements, and the title's alignment is decided by which one it is introducing rather than chosen per section.
109
+
110
+ Content stacked under the title — a row of cards, an accordion, a set of steps — takes a centred title. The heading group and the block below it share one axis, so a centred title is symmetric with the thing it names, and the eye drops from the middle of the words to the middle of the set. A title starting at the left over a centred or full-width block reads as belonging to the first column rather than to all of them.
111
+
112
+ Content beside the title — a split, a picture in the other half, anything laid out in columns — takes a title that starts where its content starts. The two share a left edge, and that edge is what says they are one thing read across rather than two stacked. Centring the title there breaks the only alignment the reader has to hold the halves together, and it drifts further from its content the wider the page gets.
113
+
114
+ The heading group is what carries this, not the heading alone. An eyebrow, a title and a description are read as one block and align together; aligning the title without them leaves a centred heading over start-aligned copy, which reads as a mistake rather than as a choice.
115
+
116
+ Centred means all of it, not just the words. A badge, a row of actions, a picture — these are flex children, and a flex child is placed by align-items rather than by text-align, so a block that only sets the text leaves everything that is not text at the start. A hero is the case that shows it: its title and copy centred while its badge and its buttons did not.
117
+
118
+ A capped block centres itself as well as its words. A heading group takes size.heading-group.max, and a cap that is not centred leaves the measure at the start of the column with the words centred inside it — composed, and a long way left of the middle it appears to be in.
119
+
120
+ Both arrangements go to the start on a phone. A centred block reverts below the breakpoint, and the reason is the measure: on a phone the measure is the screen, so a centred title wraps to three or four ragged lines and the eye loses the left edge it was tracking — the same symmetry that reads as composure on a desktop is what makes it hard to scan on a phone. Centring there has to be asked for twice, and a section title is not one of the things that asks: it is centred because there is room for it, and on a phone there is not. Going back to the start means all of it too, and a capped block is the one that hides a leftover: its words go to the start while its measure stays in the middle of the column, which reads as a title still centred over a badge and buttons that are not — the box in the middle and the line inside it at the edge.
121
+
122
+ A hero is a section like any other: its badge, title, copy and actions are one stacked block, so it is centred on a desktop and starts on a phone with everything else.
123
+
124
+ What this is not about is a page whose body is a form or a document. A title over a sign-up form or a guide is not introducing a set of content — it is the first line of the thing itself, and it keeps the alignment the body has, which for running text is the start. The distinction is whether the block below is content the title names or content the title is part of.
125
+ Guidance only — cannot be checked automatically.
126
+ - **Anything a pointer has to hit is at least 24px in both directions** — A control sized by its contents is as big as its contents, and a glyph is chosen for how it reads rather than for how easily it is hit. An icon-only button with no padding is a 16px target — smaller than the pad of a finger, and smaller than the tremor of a hand using a mouse.
127
+
128
+ WCAG 2.2 asks for 24 by 24 CSS pixels at AA. The exceptions are narrower than they look: inline targets inside a sentence are exempt, and so is a small target with 24px of clear space around it — but a clear button sits against the field it empties, and a field is itself a target, so the spacing exemption does not apply to the case that keeps arising.
129
+
130
+ The target and the mark are separate decisions, and conflating them is what produces both faults. Growing the glyph to 24px makes it shout; leaving the button at 16px makes it hard to hit. So the glyph keeps the size that reads correctly beside its text, and the box around it declares a minimum of its own — which is what size.target.min is for.
131
+
132
+ Declared rather than emergent. Padding plus contents does clear 24px in several components today, and it is the weaker statement: it is a size nobody wrote down, so it moves when the type scale or the glyph does, and nothing says it was meant to be a target at all.
133
+ Guidance only — cannot be checked automatically.
134
+
135
+ ## Anti-examples
136
+
137
+ ❌ Icon for: The mark identifies a company or a product — a payment method, an app store, a social network
138
+ A brand mark carries fixed colour, and Icon tints whatever it is given
139
+ → `Logo` is not built yet. Raise it with the design system team.
140
+
141
+ ❌ Icon for: The artwork is a scene rather than a symbol
142
+ A marketing page reaches for illustration where Product reaches for a glyph, and an illustration is raster, sized by its own proportions rather than by this ramp. It is also the more likely of the two to be wanted here
143
+ → `Illustration` is not built yet. Raise it with the design system team.
144
+
145
+ ## Example
146
+
147
+ ```tsx
148
+ import { Icon } from '@deriv-com/dds-marketing'
149
+ import { EnvelopeRegularIcon } from '@deriv-com/quill-icons-web'
150
+ import { EnvelopeRegularIcon } from '@deriv-com/quill-icons-web'
151
+
152
+ <Icon><EnvelopeRegularIcon /></Icon>
153
+ ```
154
+
155
+ ## In use
156
+
157
+ ### The ramp, at the steps a page uses
158
+
159
+ One glyph at every step, because the variable is the size. A new shape in each row is noise a reader has to look past to compare the thing the rows are for.
160
+
161
+ ```tsx
162
+ import { Icon } from '@deriv-com/dds-marketing'
163
+ import { EnvelopeRegularIcon } from '@deriv-com/quill-icons-web'
164
+
165
+ // xs — inline and supporting, against small text
166
+ <Icon size="xs"><EnvelopeRegularIcon /></Icon>
167
+
168
+ // sm — beside text it must not outweigh
169
+ <Icon size="sm"><EnvelopeRegularIcon /></Icon>
170
+
171
+ // md — the default — body content and lists
172
+ <Icon size="md"><EnvelopeRegularIcon /></Icon>
173
+
174
+ // lg — the mark a feature card leads with
175
+ <Icon size="lg"><EnvelopeRegularIcon /></Icon>
176
+
177
+ // xl — the largest step, and the end of the ramp
178
+ <Icon size="xl"><EnvelopeRegularIcon /></Icon>
179
+ ```
180
+
181
+ ### Named, or not announced at all
182
+
183
+ A glyph beside words that already say the same thing is announced twice, so it stays decorative. One that is the only thing naming its control takes a label.
184
+
185
+ ```tsx
186
+ import { Icon } from '@deriv-com/dds-marketing'
187
+ import { EnvelopeRegularIcon } from '@deriv-com/quill-icons-web'
188
+
189
+ // Decorative — role="presentation", no name
190
+ <Icon><EnvelopeRegularIcon /></Icon>
191
+
192
+ // Named — role="img", announced as its label
193
+ <Icon label="Email us"><EnvelopeRegularIcon /></Icon>
194
+ ```
@@ -0,0 +1,354 @@
1
+ <!-- GENERATED from link.contract.json. Do not edit. -->
2
+
3
+ # Link
4
+
5
+ A destination named inside a sentence, or standing on its own under one. Inside a sentence it takes everything from the copy around it — the size, the face, the ink — and is told apart by an underline alone. On its own line it takes the brand ink and a mark instead, because there is no sentence to belong to.
6
+
7
+ Button is the other half of this, and the two are the same act — go somewhere — at different volumes. A Button is a pill a reader aims at; a Link is words a reader is already reading. The test is whether taking it out would leave a hole in the sentence: if it would, it is a link, and if the sentence would read fine without it, the page wanted a Button.
8
+
9
+ That boundary is worth stating because Marketing's Button is also an anchor, so nothing about the element tells the two apart. What tells them apart is position: one interrupts the copy to ask for a press, and the other is copy.
10
+
11
+ ## Use when
12
+
13
+ - A term inside running copy has a page of its own — a market named in a paragraph, a fee mentioned in a sentence, a product referred to in passing
14
+ - The page must offer a destination without pushing it: terms, a full fee schedule, a regulatory notice. A pill would give it the weight of the thing the page is actually asking for
15
+ - A second destination beside the call to action, where a second pill would be two things asking to be pressed and a reader would have to choose between them before reading either
16
+
17
+ ## Do not use
18
+
19
+ - The destination is the step the page was built to produce → `Button`
20
+ - Pressing it does something on this page rather than going somewhere → nothing here does this
21
+ - The whole card or panel is the target rather than some words in it → `CardButton`
22
+ - The page's main call to action. That is Button, and a page whose primary step is a link in a paragraph has hidden it in the copy
23
+ - Words that do not name the destination — 'click here', 'read more', 'this page'. The words are the link's accessible name, and a screen reader offering a list of links reads that list on its own: a page of 'read more' is a menu of identical entries
24
+ - A disabled or pending state. There is none, for the reason Button has none: the browser owns a navigation in flight, and an anchor cannot be honestly disabled — stripping the href is the only thing that truly stops it, and that costs the link role and the focus with it
25
+ - Opening a new tab because the page would rather keep the reader. `external` exists for a destination that is genuinely elsewhere; taking over tab management for its own sake is a decision that belongs to the reader
26
+
27
+ ## Anatomy
28
+
29
+ Link renders 3 elements. A token binding names the part it applies to.
30
+
31
+ - `root` — `<a>`, class `dds-link`. The words, and the whole of the control. An `<a>` with a real `href`, so the browser's own affordances all work: cmd-click opens a tab, the status bar shows the destination before the press, the address can be copied, and a screen reader announces a link.
32
+
33
+ A standalone link is `inline-flex` and an inline one is `inline`, which is the difference from every other pressable thing in this package and the one place the two variants disagree about layout.
34
+
35
+ The flex line is what centres the mark. `vertical-align: middle` puts a box's centre at the baseline plus half the x-height, which is below the optical centre of cap-height text — measured, the arrow's ink sat 1.73px low beside a sixteen-pixel label. Centring on the line box instead puts it within a hundredth of a pixel. An inline link cannot have that: it has to break across lines with the sentence it is part of, and a flex box does not wrap. It keeps the alignment `vertical-align` can give and the small offset that comes with it, which is the price of being part of a line rather than a line of its own.
36
+
37
+ `display: inline` for that variant, which is the difference from every other pressable thing in this package. A link is part of a line of text and has to break across lines with it — a Button is `inline-flex` because it is a box the copy flows around, and a link that behaved that way would leave a hole at the end of a line rather than wrapping.
38
+
39
+ The type is inherited rather than bound, in the inline variant. `font-size`, `font-family` and `line-height` all take `inherit`, so a link in a body paragraph is body copy and a link in a caption is caption — which is the whole idea, and the thing that would break if the component set a size of its own. Only `standalone` binds a step — `font.label.md`, sixteen — because a link sitting on its own line has no sentence to take one from. One step and no axis to choose another: Product's Link carries three and this package has shown twice now that it does not need them, Tab having settled the same question the same way. Eighteen exists in the ramp and a standalone link set in it would be a heading that happens to navigate.
40
+
41
+ The underline belongs to the inline variant and not to the component, and inside a sentence it is the whole of what marks the link. Not most of it — all of it: an inline link takes the paragraph's ink as well as its type, so there is no colour difference to fall back on. That is deliberate rather than a concession. A word set in brand red mid-paragraph has been shouted, and what a link in running copy needs is to be findable, which an underline does without interrupting the line. It thickens on hover.
42
+
43
+ A standalone link has no sentence to be told apart from. It is on its own line, in brand ink, usually beside a mark, and an underline there reads as an inline link that has lost its paragraph. So the rule is bound per variant rather than once: `underline` for inline, `none` for standalone.
44
+
45
+ `focusable`, declared rather than inferred. An anchor takes focus only because it carries an href, and no element name reveals that — so a reader and a check see the same answer the browser will give only if the contract states it.
46
+
47
+ The ink is `color.bg.brand`, which is a background role doing a foreground's job, and that is worth naming rather than hiding. `color.fg.brand` exists and is the readable one at 7.75:1 — but it is the dark red a Badge sets on a pale tint, not the coral the page is built from, and a link that did not match the buttons would read as a different kind of thing. The brand primary is one colour in this system and it is spelled `color.bg.brand`; a `fg` alias for the same value would be a second name for one decision.
48
+
49
+ A link whose ink is the ground's gets its underline back on hover, and only on hover. That covers a standalone link at `tone: inherit` — one on a brand card, a dark band, a scrim. The list variant has the same problem and answers it with its mark instead: a column whose rows underline one at a time reads as a table of contents being corrected. At rest they are told apart by position, which is what a column of links or a line of its own already provides; under the pointer there was nothing at all, because the colour cannot change when it belongs to the ground and there is no mark to move. Product reaches the same conclusion from the other side, keeping the underline at all times for `tone: inherit` — these designs do not have one at rest, so it arrives with the pointer instead. It is in the impl sheet because `structure` carries no state.
50
+ - `icon-leading` — `<span>`, class `dds-link__icon-leading`. A glyph before the words, when the destination has a mark a reader recognises faster than its name — a document, a download, a platform. Rare in running copy and ordinary in the standalone variant, which is where it earns its place.
51
+
52
+ A box of the tab's own rather than the glyph itself, because Icon clones onto the SVG and this part is the place in the line. Drawn at `icon.size.xs` — sixteen, a step below what a control takes, because this sits beside words rather than inside a target and twenty next to a sixteen-pixel label outweighs the words it is there to qualify. The part carries the gap and nothing else: the colour comes from the link, which is what `fill="currentColor"` on the glyph is for.
53
+
54
+ Solid, like the arrow after the words. Both marks on a link take the same weight, and what earns it is the size rather than emphasis — see the trailing slot, which carries the argument and the exception it makes to `icon-solid-marks-selection`. Rendered only when `iconLeading` is set.
55
+ - `icon-trailing` — `<span>`, class `dds-link__icon-trailing`. The mark after the words, and the component decides all of it — whether there is one, which one it is, and when it shows.
56
+
57
+ Three answers. An external link is always marked. A standalone or list link is marked unless it opts out, though a list one holds its mark at zero until the pointer arrives. An inline link is bare unless it asks.
58
+
59
+ `presentWhen` names the two props that force the part and cannot name the rest: the variant decides the default, and a list of prop names has no way to say "unless the variant already did". So the part reaches the DOM in more cases than the field lists, which is a simplification rather than a contradiction — everything it does name is true.
60
+
61
+ Which arrow depends on where the link goes: `arrow-right` for a destination on this site, `arrow-up-right` for one off it, and nothing a page passes can change either. That is the point of owning it — an external link that carried a plain right arrow would be telling the reader their tab is about to stay put.
62
+
63
+ The weight follows the words the mark sits beside, which is the only thing the variants disagree about here.
64
+
65
+ A standalone link sets its label at `font.label.md` — semibold — and against that the regular cut's strokes read as a smudge rather than a direction, so its arrow is solid, and so is its leading glyph. That is a deliberate exception to `icon-solid-marks-selection`: the rule reserves the weight for a selected item, this is not one, and what earns it is legibility at sixteen pixels beside a heavier neighbour. Named here so the exception is on the record rather than discovered.
66
+
67
+ An inline link has no label of its own — it takes the paragraph, which is body copy at the regular weight. A solid arrow there outweighs every word around it, so the exception does not reach it and the regular cut is what it draws. The mark matches its neighbours in both cases; only the neighbours differ.
68
+
69
+ Drawn at `icon.size.xs` like the leading slot, so a link carrying both draws them alike. It is decorative and announced as nothing, which is why the accessibility requirement below asks an external link to say so in its words as well.
70
+
71
+ On hover it moves a little way in the direction it is already pointing, and stays there until the pointer leaves. Right for the arrow that points right, up and to the right for the one that points that way — a mark that slid sideways while pointing diagonally would be moving across its own direction. That is the hover affordance for a standalone link, which has no underline to thicken the way an inline one does: the movement says the link is live where the line would have.
72
+
73
+ A transition rather than a keyframe animation, on `motion.duration.normal` and `motion.easing.standard` — the same two tokens ButtonIcon transitions its background and outline on. What was here before sent the arrow out past its own edge, faded it to nothing and brought it back from the other side over `motion.duration.reveal`, which is a gesture with a beginning, a middle and an end for what is a hover on a link. Losing it loses the split `exit`/`enter` curves and the fade at the edges, both of which only existed because something was making a round trip.
74
+
75
+ The distance is 25% of the glyph, which at sixteen pixels is the four pixels `motion.translate.hover` already moves anything else that shifts under a pointer. Of the glyph rather than the box around it: that box carries the gap between the words and the arrow as padding, so it is twenty by sixteen, and a percentage measured on it moved five pixels across and turned the external arrow's diagonal into 39 degrees. A percentage rather than that token because an inline link's mark is `1.1em` and tracks the paragraph, so a fixed nudge would be proportionally large in fourteen-pixel copy and small in twenty. The external arrow takes 18% on each axis, which is that same distance measured along the diagonal rather than four pixels twice.
76
+
77
+ `inline-flex` and `vertical-align: middle` are what make it possible rather than being decisions: a transform does not apply to a non-replaced inline element, so the mark needs a box, and the alignment keeps that box on the words. `overflow: hidden` used to sit beside them and has gone with the keyframes — it was there for the arrow to disappear behind rather than slide out over the words, and a box clipped to its own contents would now cut four pixels off a mark that only means to lean.
78
+
79
+ In a list it is drawn and held at zero until the pointer arrives — see the variant. Drawn rather than rendered on hover, so the row does not change width when it appears and the column does not shift under the reader.
80
+
81
+ Where it travels is the component's to say, handed over as a custom property. `external` decides it and is not a styling axis — it cannot honestly become one, because the only thing it changes is a pair of offsets, and the check asked what `external="true"` changes and the honest answer was nothing a stylesheet can see. A list link's mark rests displaced the other way and at zero opacity, so its arrival and every other mark's nudge are the same declarations read in opposite directions — it travels further to reach the place every hovered mark ends up, rather than having an arrival of its own. Rendered when any of `showIcon`, `external` is set, and not otherwise.
82
+
83
+ Apply these classes from the generated `linkParts` constant rather than writing the strings by hand.
84
+
85
+ ## Composition
86
+
87
+ - Can contain: `text`
88
+ - Never contains: `Link`, `Button`, `CardButton`, `Card`, `Accordion`, `AccordionItem`, `Tab`, `TabList` — in children or in any prop that takes a node
89
+
90
+ ## Props
91
+
92
+ ### variant — `standalone` | `list` | `inline` (default `standalone`)
93
+
94
+ - `standalone` — The default, and what a marketing page mostly has: a link on its own line — under a card, at the foot of a section, beside a call to action. Brand ink and a mark, no underline, because there is no sentence for it to be told apart from.
95
+ - `list` — One of a column of links — a footer sitemap, a navigation menu, a set of related pages under a heading. It takes the ink around it, because a column of coral is a column nobody reads.
96
+
97
+ Its mark waits for the pointer. A mark on every row of a column distinguishes nothing, and a column with none has no way of saying which row is live — its ink cannot change, because the ink belongs to the column. So the arrow is drawn and held at zero, and the pointer brings it in.
98
+
99
+ An external link's mark stays. That one is a fact about the destination rather than an affordance, and it is what lets one row in a list of fifty say something before anybody has touched it.
100
+ - `inline` — Inside a sentence, and it takes the sentence's type and the sentence's colour. Nothing about it is coloured brand: a word set in a different ink mid-paragraph is a word that has been shouted, and what it needs is to be findable rather than loud. The underline is what tells it apart, and it is the only thing that does — which is why it is not optional here.
101
+ Never for: Making a link louder or quieter. The three are positions rather than volumes: standalone is alone on its line, list is one of a column, and inline is part of a sentence. None of them means important.
102
+
103
+ ### tone — `brand` | `inherit` (default `brand`)
104
+
105
+ - `brand` — The default. The brand primary — the same coral the buttons are filled with — so a standalone link and a call to action are recognisably the same colour of intent, and a reader scanning for the way onward finds both.
106
+
107
+ It is 3.39:1 against the page, below the 4.5:1 that normal text is held to. This package already carries an unsigned waiver for that pairing on a button's label, and this is the second thing leaning on it. What makes it survivable is that it is never the only signal — a standalone link sits on its own line beside a mark — but the ink alone does not carry it, and if the waiver is ever refused this is the binding that moves. color.bg.brand-active is the same hue at 5.56:1 and is what it would move to.
108
+ - `inherit` — A standalone link on a ground that has already set its ink — a brand card, a dark band, a scrim over an image. There the brand ink is either invisible or wrong, and the mark is left to carry the link alone. It is the same argument CardBody makes for setting no colour in its regions.
109
+
110
+ Use when: Which ink a standalone link takes. It reaches no other variant: an inline link takes the paragraph's colour and a list link takes the column's, which are decisions those positions have already made — the same shape `showIcon` has here.
111
+ Never for: Reaching an inline link. One takes the paragraph's colour already and there is nothing here to choose — this prop governs a standalone link and no other.
112
+
113
+ ### external — `boolean` (default `false`)
114
+
115
+ Use when: The destination is off this site. Sets `target="_blank"` and `rel="noopener noreferrer"` together — the rel is not optional and not the consumer's job, which is how a page ends up handing `window.opener` to a site it does not control. It also fills the trailing slot with the box-and-arrow, so every external link on the site is marked the same way
116
+ Never for: A new tab on a destination that is not external. Taking over tab management is a decision the reader has already made in their own browser, and a page that overrides it has told them their back button is not to be trusted
117
+
118
+ ### href — `string` **Required.**
119
+
120
+ Use when: Always. An anchor without one is not a link: it takes no focus, is announced as plain text, and none of the browser's navigation affordances work — so there is no default that could stand in for one, and it is required for exactly that reason
121
+
122
+ ### iconLeading — `node`
123
+
124
+ Accepts: QuillSystemIcon
125
+ Use when: A mark the destination is known by, before its name — a document, a download. Pass the glyph; the link draws it at sixteen, which is icon.size.xs.
126
+
127
+ The solid weight, always: `FileSolidIcon` rather than `FileRegularIcon` or `FileLightIcon`. Both marks on a standalone link are solid, which is what keeps one carrying two from wearing two weights. Nothing here can enforce it — Icon has no weight prop and cannot have one, because a Quill glyph's weight is chosen when it is imported — so this is the call site's to get right and the guidance is the only place the rule can live.
128
+
129
+ Standalone only, and the type says so. This is the slot a page chooses, unlike the trailing one: what a destination is known by is the page's to say, where which direction an arrow points is the system's.
130
+ Never for: Naming the destination. The words are the accessible name and the glyph is announced as nothing, so a link whose meaning is its mark is a link with no meaning at all to a screen reader.
131
+
132
+ The regular or light weights. Every glyph on a *standalone* link is solid — this slot only reaches one — and the argument is size rather than emphasis: at sixteen pixels beside a semibold label the regular cut's strokes are thin enough to read as a smudge. That applies to a document or a download exactly as it applies to the arrow beside it. An inline link's arrow is the regular cut instead, because there the neighbours are body copy; the rule is that a mark takes the weight of the words beside it, not that this component is solid.
133
+
134
+ An inline link, which will not compile. There is no version of a glyph mid-sentence that reads as anything but an interruption — the words are the link and the underline is the mark.
135
+
136
+ ### showIcon — `boolean`
137
+
138
+ Use when: Whether the link carries a mark after its words. It reaches both variants: a standalone link on its own line, and an inline one that wants the arrow inside a sentence.
139
+
140
+ Left unset it follows the variant, which is the only sensible default and is not one a contract can write: a standalone link is marked, because it is alone on its line with nothing else saying it goes anywhere, and an inline link is not, because an arrow after every linked word would interrupt every sentence carrying one. Set it either way to override that — false for a footer column, where a column of arrows is a column of noise; true for a sentence whose link is the thing being pointed at.
141
+
142
+ An external link draws its mark whether or not this is set, and draws a different one.
143
+ Never for: Suppressing the external mark. Leaving the site is a fact about the destination rather than a flourish, so `external` marks itself whatever this says — a page that could turn it off could hand a reader a new tab with no warning.
144
+
145
+ Also accepts everything from `AnchorHTMLAttributes<HTMLAnchorElement>`.
146
+
147
+ ## Accessibility
148
+
149
+ Guaranteed by the component. Write none of it by hand: the ids these attributes point at are generated per instance, so an attribute set from outside either says the same thing twice or points at nothing.
150
+
151
+ - Announced as: `link`
152
+ - `Tab` — Reaches the link. It is an ordinary stop in the reading order, which is where a link inside a sentence belongs
153
+ - `Enter` — Follows it, which is what an anchor does and what a button would not
154
+ - accessible name from the words, which have to name the destination. A screen reader can list a page's links on their own, out of the sentences that held them — so 'read more' three times is a menu of three identical entries, and the reader has to visit each to learn which is which
155
+ - No link without an href. An anchor missing one takes no focus and is announced as plain text, which removes the destination from anyone not using a mouse — the prop is required rather than optional for that reason and no other.
156
+ - rel="noopener noreferrer" wherever target is _blank, which `external` sets for itself. Without noopener the opened page can reach back through window.opener to the page that opened it.
157
+ - An external link says so in its words, not only in its glyph. The arrow is decorative and announced as nothing, so "(opens in a new tab)" belongs in the link's text — a reader who cannot see the mark is otherwise told nothing before their tab changes under them.
158
+ - An inline link is underlined, always, and it is the only thing marking it. The link takes the paragraph's colour, so there is no second signal and no tone that changes that — remove the line and a reader has an ordinary word that happens to navigate.
159
+
160
+ A standalone link carries no underline, and that is a different case rather than an exception. What the rule protects against is a link that cannot be told from the text around it; a standalone link has no text around it. It sits on its own line, in brand ink, next to a mark — three things that are not colour.
161
+
162
+ ## Rules
163
+
164
+ - **On a phone a section's actions stack and each fills the width, including when there is only one** — On a phone a page's actions stack, and each one fills the width. Not most of it, and not the width its label happens to need — the whole column.
165
+
166
+ Two side by side is what this replaces. On the narrowest screen each gets half a column minus the gap, which is rarely enough for a real label: the words wrap inside the pills, the two buttons come out different heights, and the pair reads as a broken row rather than as a choice. Stacked, each has the whole width and neither has to shorten its words to fit.
167
+
168
+ A single action fills too, and that is the part worth saying, because it is the one that looks unnecessary. A lone button has the room to sit at its natural width and still should not: a full-width control is the phone's convention for the thing the screen is asking you to do, and a pill hugging its label reads as one option among others that are not there. It also makes the target predictable — the whole width, wherever the thumb lands — which a centred pill does not.
169
+
170
+ Filling is the row's job rather than the button's. A button has no width of its own and is not given one; the row it sits in becomes a column and stretches its children, so nothing about the control changes and the same button is full width here and its own size on a desktop.
171
+
172
+ This is the phone's breakpoint, size.breakpoint.md, and not the wider one that decides whether a heading is centred. Those are different questions and they break at different widths: a heading stops being centred when the measure is the screen, while a button stops being full width much sooner than that — stretched across a tablet it is a long way from its own label, and a label centred in a metre of pill is harder to hit than one in a pill the size of the words.
173
+
174
+ What this is not about is every row of controls. A set of filter chips, a pagination strip, a toolbar, a link sitting after a sentence — none of these is the page asking for something, and stacking them to full width would turn a strip the eye skims into a list it has to read. The test is whether the row is the call to action the section was written for.
175
+ Guidance only — cannot be checked automatically.
176
+ - **Never nest one interactive element inside another** — Nested interactive elements produce ambiguous hit targets and an unreachable inner control for keyboard and screen-reader users. This is why the rule cannot live on any single component — it constrains Button, Link, Input and Switch simultaneously.
177
+ Guidance only — cannot be checked automatically.
178
+ - **A section that paints a ground sets the ink to go with it** — A page sits on color.bg.page, and a section that separates itself from it takes one of three grounds. color.bg.subtle is the light one and needs nothing further — the page's own ink still reads on it. The other two are dark and do not: color.bg.brand-strong takes color.fg.on-brand-strong, and color.bg.brand takes color.fg.on-solid. Both are white, and both are written as the role rather than the white they resolve to. Set one of those backgrounds without its ink and the text inherits whatever the page was already using, which is near-black on a dark band — legible to nobody, and invisible to every check here, because each pair passes contrast on its own and nothing can tell whether a section used both.
179
+
180
+ color.bg.brand carries a second limit that is not about forgetting. Its ink measures 3.39:1, which clears the 3:1 a heading needs and misses the 4.5:1 running copy needs. A coral band may carry a headline and a call to action; a paragraph on one is text the reader has to work through at a ratio the waiver on that role does not cover — the waiver says so itself. A section with copy in it takes color.bg.brand-strong, which is near-black and carries white at full contrast.
181
+
182
+ color.bg.strong is not a section ground. It is the inverted fill for an action that has to outrank what surrounds it, and the components that paint it — Button and ButtonIcon in their inverse form — already set both halves in one rule, which is the pattern a hand-painted section has to copy.
183
+ Guidance only — cannot be checked automatically.
184
+ - **Every gap inside a section names the relationship it expresses, and the same relationship keeps its measure when it turns on its side** — A section's spacing is named by the relationship it expresses, not chosen by size. Every gap in a section has a role token, and reaching for a step off the generic scale because it happens to be the right number is how two sections written by two people stop lining up: the numbers agree today and drift the first time one of them is tuned.
185
+
186
+ The heading group is three steps, not one gap. An eyebrow sits nearer its title than the title sits to its description, and the actions sit further from the description than either — space.heading.eyebrow-title, space.heading.title-description, space.heading.description-actions, in that order. A single `gap` on the group cannot say this; it sets all three the same and the block reads as evenly spaced lines rather than as a mark, a name and a paragraph. The eyebrow has to identify itself for this to work, because a group that opens with a title must not give its description the eyebrow's tighter step.
187
+
188
+ The step between a title and its description follows the size of the title, which is why there are two of it. What a reader sees is not the gap but the gap plus the leading above it, and leading scales with the type: under a display title the leading is most of the space, under a card's title it is half as deep. One value for both makes a card look loose at the size that made a section look right. So space.heading.title-description is the display step and space.heading.title-description-compact is the step at a card's size, and the choice is made by how big the title is rather than by what kind of block it sits in.
189
+
190
+ Every one of those steps is smaller than the gap below the group, and that ordering is what holds the group together as one thing. space.heading.content is the step between a heading group and the content it introduces, and it is the widest measure inside a section: the one gap the eye reads as a change of subject rather than as a continuation.
191
+
192
+ That step is the same whether the content is under the heading or beside it. A split is the same relationship turned on its side — a heading group and the content it introduces — so the space between the two halves is space.heading.content, not a gutter. When the split collapses to one column on a phone the gap becomes vertical again, which is where it started, and nothing has to change for that to be right.
193
+
194
+ space.grid.gutter is between two things of the same kind. Two cards in a row are the same kind; the two halves of a split are not, which is why the gutter is the wrong measure there even when the number would have looked acceptable. The gutter runs on both axes, so a grid reads as an even field rather than as rows with a seam down them.
195
+
196
+ space.inset.card is the card's, not the page's. A row of cards padded differently is a row of different cards, and the fill is the only edge they have. A page composing a row does not get to choose it.
197
+
198
+ Column count is not a breakpoint decision. A row holds as many columns as fit before a column would be narrower than size.grid.column-min, and drops one when they would not. Written as a fixed count that collapses at a breakpoint, a four-up row keeps four columns at every width above the phone and sets its copy two or three words to a line through the whole of the tablet range — and on a narrow desktop, which no breakpoint sits on at all. The threshold is a property of the row rather than of a card: a card fills whatever cell it is given.
199
+
200
+ What this does not cover is the space above and below a section, which is space.section.default and space.section.compact, and the page's own side margin, which is space.inset.page. Those are the section's outside; everything here is its inside.
201
+ Guidance only — cannot be checked automatically.
202
+ - **A section's title is centred over stacked content, starts beside content in columns, and starts on a phone** — Two arrangements, and the title's alignment is decided by which one it is introducing rather than chosen per section.
203
+
204
+ Content stacked under the title — a row of cards, an accordion, a set of steps — takes a centred title. The heading group and the block below it share one axis, so a centred title is symmetric with the thing it names, and the eye drops from the middle of the words to the middle of the set. A title starting at the left over a centred or full-width block reads as belonging to the first column rather than to all of them.
205
+
206
+ Content beside the title — a split, a picture in the other half, anything laid out in columns — takes a title that starts where its content starts. The two share a left edge, and that edge is what says they are one thing read across rather than two stacked. Centring the title there breaks the only alignment the reader has to hold the halves together, and it drifts further from its content the wider the page gets.
207
+
208
+ The heading group is what carries this, not the heading alone. An eyebrow, a title and a description are read as one block and align together; aligning the title without them leaves a centred heading over start-aligned copy, which reads as a mistake rather than as a choice.
209
+
210
+ Centred means all of it, not just the words. A badge, a row of actions, a picture — these are flex children, and a flex child is placed by align-items rather than by text-align, so a block that only sets the text leaves everything that is not text at the start. A hero is the case that shows it: its title and copy centred while its badge and its buttons did not.
211
+
212
+ A capped block centres itself as well as its words. A heading group takes size.heading-group.max, and a cap that is not centred leaves the measure at the start of the column with the words centred inside it — composed, and a long way left of the middle it appears to be in.
213
+
214
+ Both arrangements go to the start on a phone. A centred block reverts below the breakpoint, and the reason is the measure: on a phone the measure is the screen, so a centred title wraps to three or four ragged lines and the eye loses the left edge it was tracking — the same symmetry that reads as composure on a desktop is what makes it hard to scan on a phone. Centring there has to be asked for twice, and a section title is not one of the things that asks: it is centred because there is room for it, and on a phone there is not. Going back to the start means all of it too, and a capped block is the one that hides a leftover: its words go to the start while its measure stays in the middle of the column, which reads as a title still centred over a badge and buttons that are not — the box in the middle and the line inside it at the edge.
215
+
216
+ A hero is a section like any other: its badge, title, copy and actions are one stacked block, so it is centred on a desktop and starts on a phone with everything else.
217
+
218
+ What this is not about is a page whose body is a form or a document. A title over a sign-up form or a guide is not introducing a set of content — it is the first line of the thing itself, and it keeps the alignment the body has, which for running text is the start. The distinction is whether the block below is content the title names or content the title is part of.
219
+ Guidance only — cannot be checked automatically.
220
+ - **Anything a pointer has to hit is at least 24px in both directions** — A control sized by its contents is as big as its contents, and a glyph is chosen for how it reads rather than for how easily it is hit. An icon-only button with no padding is a 16px target — smaller than the pad of a finger, and smaller than the tremor of a hand using a mouse.
221
+
222
+ WCAG 2.2 asks for 24 by 24 CSS pixels at AA. The exceptions are narrower than they look: inline targets inside a sentence are exempt, and so is a small target with 24px of clear space around it — but a clear button sits against the field it empties, and a field is itself a target, so the spacing exemption does not apply to the case that keeps arising.
223
+
224
+ The target and the mark are separate decisions, and conflating them is what produces both faults. Growing the glyph to 24px makes it shout; leaving the button at 16px makes it hard to hit. So the glyph keeps the size that reads correctly beside its text, and the box around it declares a minimum of its own — which is what size.target.min is for.
225
+
226
+ Declared rather than emergent. Padding plus contents does clear 24px in several components today, and it is the weaker statement: it is a size nobody wrote down, so it moves when the type scale or the glyph does, and nothing says it was meant to be a target at all.
227
+ Guidance only — cannot be checked automatically.
228
+
229
+ ## Anti-examples
230
+
231
+ ❌ Link for: The destination is the step the page was built to produce
232
+ A link inside a sentence is read at the speed of the sentence, which is the wrong speed for the one thing the page is asking for. The pill is what makes a call to action findable by someone who is scanning rather than reading
233
+ → use `Button` instead.
234
+
235
+ ❌ Link for: Pressing it does something on this page rather than going somewhere
236
+ Nothing here does this. An anchor that does not navigate is a control wearing a link's clothes: it announces itself as a link, offers cmd-click and a status-bar destination, and then does none of it. A marketing page rarely needs one, and the honest answer when it does is a button the page writes itself
237
+ → nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
238
+
239
+ ❌ Link for: The whole card or panel is the target rather than some words in it
240
+ A link inside a card gives a reader a small target inside a large one they can already see is pressable, and two hit areas where the design showed one
241
+ → use `CardButton` instead.
242
+
243
+ ❌ variant=inline + iconLeading is set
244
+ An inline link is part of a sentence and a glyph mid-line breaks the run of words it belongs to. Every mark on this component is a standalone decision — the trailing arrow already refuses to draw inside a sentence, and this is the same rule said in the type rather than in guidance.
245
+
246
+ ## Example
247
+
248
+ ```tsx
249
+ import { Link } from '@deriv-com/dds-marketing'
250
+
251
+ <Link href="/markets">Learn more</Link>
252
+ ```
253
+
254
+ ## In use
255
+
256
+ ### On its own line, and inside one
257
+
258
+ Two positions rather than two volumes. Standalone is the default and carries no underline — the mark and the line of its own tell it apart. Inline is in a sentence, and the underline is what tells it
259
+
260
+ ```tsx
261
+ import { Link } from '@deriv-com/dds-marketing'
262
+
263
+ // standalone — the default, marked
264
+ <Link href="/markets">Learn more</Link>
265
+
266
+ // inline — underlined, because it is in a sentence
267
+ <Link variant="inline" href="/fees">our fee schedule</Link>
268
+ ```
269
+
270
+ ### One of a column
271
+
272
+ A footer sitemap or a navigation menu. The ink is the column's and nothing is marked — except an external link, which is the one arrow in a list where nothing else has one.
273
+
274
+ ```tsx
275
+ import { Link } from '@deriv-com/dds-marketing'
276
+
277
+ // list — takes the column's ink, no mark
278
+ <Link variant="list" href="/forex">Forex</Link>
279
+
280
+ // list, external — the one row that is marked
281
+ <Link variant="list" external href="https://example.com">SmartTrader</Link>
282
+
283
+ // standalone, for contrast — brand ink and an arrow
284
+ <Link href="/markets">See all markets</Link>
285
+ ```
286
+
287
+ ### On a ground that has set its own ink
288
+
289
+ Brand ink is either invisible or wrong on a coral card or a dark band, so inherit leaves the underline to carry the link alone. The line is never optional — colour cannot carry a link by itself.
290
+
291
+ ```tsx
292
+ import { Link } from '@deriv-com/dds-marketing'
293
+
294
+ // brand — the ordinary ground
295
+ <Link href="/terms">the terms that apply</Link>
296
+
297
+ // inherit — a brand or dark card
298
+ <Link tone="inherit" href="/terms">the terms that apply</Link>
299
+ ```
300
+
301
+ ### What decides the mark
302
+
303
+ Unset, the variant answers: a standalone link is marked and an inline one is not. Set, the page has. External marks itself either way, and with a different arrow.
304
+
305
+ ```tsx
306
+ import { Link } from '@deriv-com/dds-marketing'
307
+
308
+ // standalone — marked, unasked
309
+ <Link href="/markets">See all markets</Link>
310
+
311
+ // standalone, opted out — a footer column
312
+ <Link href="/markets" showIcon={false}>See all markets</Link>
313
+
314
+ // inline — bare, unasked
315
+ <Link variant="inline" href="/fees">our fee schedule</Link>
316
+
317
+ // inline, asked — the regular cut, beside body copy
318
+ <Link variant="inline" href="/fees" showIcon>our fee schedule</Link>
319
+
320
+ // external — marked either way, and differently
321
+ <Link external href="https://example.com">our licence (opens in a new tab)</Link>
322
+ ```
323
+
324
+ ### Leaving the site
325
+
326
+ external carries the target, the rel and the mark together. The arrow is decorative and announced as nothing, so the words have to say so too.
327
+
328
+ ```tsx
329
+ import { Link } from '@deriv-com/dds-marketing'
330
+
331
+ // external
332
+ <Link external href="https://example.com/licence">our licence (opens in a new tab)</Link>
333
+
334
+ // internal — no mark
335
+ <Link href="/licence">our licence</Link>
336
+ ```
337
+
338
+ ### A mark before the words
339
+
340
+ Standalone only, and solid like the arrow — every glyph on a standalone link takes the weight of the semibold label beside it. An inline link may not carry one at all; the type refuses it.
341
+
342
+ ```tsx
343
+ import { Link } from '@deriv-com/dds-marketing'
344
+ import { FileShieldSolidIcon, WalletSolidIcon } from '@deriv-com/quill-icons-web'
345
+
346
+ // A destination with a mark of its own
347
+ <Link href="/licence" iconLeading={<FileShieldSolidIcon />}>Read the licence</Link>
348
+
349
+ // Leading and trailing together
350
+ <Link href="/statements" iconLeading={<WalletSolidIcon />}>Download statements</Link>
351
+
352
+ // Words alone, which is most links
353
+ <Link href="/markets">See all markets</Link>
354
+ ```