@deriv-com/dds-marketing 0.2.0 → 1.0.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 (279) hide show
  1. package/.llm/components/accordion.md +8 -0
  2. package/.llm/components/accordionitem.md +8 -0
  3. package/.llm/components/aspectratio.md +8 -0
  4. package/.llm/components/badge.md +8 -0
  5. package/.llm/components/bottomsheet.md +8 -0
  6. package/.llm/components/breadcrumb.md +8 -0
  7. package/.llm/components/breadcrumbitem.md +8 -0
  8. package/.llm/components/button.md +46 -22
  9. package/.llm/components/buttonicon.md +14 -6
  10. package/.llm/components/card.md +15 -1
  11. package/.llm/components/cardbody.md +28 -2
  12. package/.llm/components/cardbutton.md +15 -1
  13. package/.llm/components/checkbox.md +8 -0
  14. package/.llm/components/ctabanner.md +186 -0
  15. package/.llm/components/ctabannerslider.md +204 -0
  16. package/.llm/components/divider.md +8 -0
  17. package/.llm/components/dropdownmenu.md +13 -5
  18. package/.llm/components/faqaccordion.md +217 -0
  19. package/.llm/components/featurebullets.md +254 -0
  20. package/.llm/components/featurecards.md +313 -0
  21. package/.llm/components/featurescroll.md +284 -0
  22. package/.llm/components/featuresplit.md +249 -0
  23. package/.llm/components/filterchip.md +8 -0
  24. package/.llm/components/footer.md +8 -0
  25. package/.llm/components/footergroup.md +8 -0
  26. package/.llm/components/grid.md +8 -0
  27. package/.llm/components/icon.md +8 -0
  28. package/.llm/components/landinghero.md +254 -0
  29. package/.llm/components/link.md +9 -1
  30. package/.llm/components/logocolumns.md +235 -0
  31. package/.llm/components/logorows.md +212 -0
  32. package/.llm/components/menuitem.md +8 -0
  33. package/.llm/components/navbar.md +79 -15
  34. package/.llm/components/navbaritem.md +9 -1
  35. package/.llm/components/navbarmenu.md +8 -0
  36. package/.llm/components/navbarmenugroup.md +8 -0
  37. package/.llm/components/navbarpanel.md +9 -1
  38. package/.llm/components/navbarswitcher.md +9 -1
  39. package/.llm/components/navbarswitcheroption.md +8 -0
  40. package/.llm/components/option.md +8 -0
  41. package/.llm/components/pageheader.md +231 -0
  42. package/.llm/components/pagination.md +26 -89
  43. package/.llm/components/paginationdots.md +215 -0
  44. package/.llm/components/producthero.md +248 -0
  45. package/.llm/components/removablechip.md +8 -0
  46. package/.llm/components/row.md +8 -0
  47. package/.llm/components/scroller.md +8 -0
  48. package/.llm/components/searchinput.md +8 -0
  49. package/.llm/components/segmentedcontrol.md +8 -0
  50. package/.llm/components/segmentedcontrolitem.md +8 -0
  51. package/.llm/components/select.md +8 -0
  52. package/.llm/components/selectchip.md +56 -15
  53. package/.llm/components/spinner.md +8 -0
  54. package/.llm/components/stack.md +8 -0
  55. package/.llm/components/statusdot.md +8 -0
  56. package/.llm/components/subdomainnavbar.md +8 -0
  57. package/.llm/components/tab.md +8 -0
  58. package/.llm/components/table.md +8 -0
  59. package/.llm/components/tablebody.md +8 -0
  60. package/.llm/components/tablecell.md +8 -0
  61. package/.llm/components/tablehead.md +8 -0
  62. package/.llm/components/tableheadercell.md +8 -0
  63. package/.llm/components/tablerow.md +8 -0
  64. package/.llm/components/tablist.md +8 -0
  65. package/.llm/components/testimonialrow.md +235 -0
  66. package/.llm/components/testimonialslider.md +254 -0
  67. package/.llm/components/textarea.md +8 -0
  68. package/.llm/components/textinput.md +8 -0
  69. package/.llm/components/tooltip.md +8 -0
  70. package/.llm/components/typography.md +8 -0
  71. package/.llm/digest/button.md +11 -6
  72. package/.llm/digest/buttonicon.md +2 -2
  73. package/.llm/digest/card.md +1 -0
  74. package/.llm/digest/cardbody.md +3 -1
  75. package/.llm/digest/cardbutton.md +1 -0
  76. package/.llm/digest/ctabanner.md +44 -0
  77. package/.llm/digest/ctabannerslider.md +45 -0
  78. package/.llm/digest/dropdownmenu.md +1 -1
  79. package/.llm/digest/faqaccordion.md +43 -0
  80. package/.llm/digest/featurebullets.md +52 -0
  81. package/.llm/digest/featurecards.md +49 -0
  82. package/.llm/digest/featurescroll.md +52 -0
  83. package/.llm/digest/featuresplit.md +54 -0
  84. package/.llm/digest/landinghero.md +53 -0
  85. package/.llm/digest/logocolumns.md +55 -0
  86. package/.llm/digest/logorows.md +48 -0
  87. package/.llm/digest/navbar.md +18 -3
  88. package/.llm/digest/pageheader.md +49 -0
  89. package/.llm/digest/pagination.md +6 -17
  90. package/.llm/digest/paginationdots.md +43 -0
  91. package/.llm/digest/producthero.md +53 -0
  92. package/.llm/digest/selectchip.md +6 -1
  93. package/.llm/digest/testimonialrow.md +51 -0
  94. package/.llm/digest/testimonialslider.md +51 -0
  95. package/.llm/index.md +24 -3
  96. package/.llm/rules.md +24 -0
  97. package/.llm/tokens.md +56 -12
  98. package/AGENTS.md +28 -3
  99. package/README.md +41 -21
  100. package/dist/components/banner-data.d.ts +38 -0
  101. package/dist/components/banner-data.js +15 -0
  102. package/dist/components/blocks/block-reveal.css +90 -0
  103. package/dist/components/blocks/cta-banner/CtaBanner.css +66 -0
  104. package/dist/components/blocks/cta-banner/CtaBanner.d.ts +22 -0
  105. package/dist/components/blocks/cta-banner/CtaBanner.js +31 -0
  106. package/dist/components/blocks/cta-banner/CtaBanner.types.d.ts +29 -0
  107. package/dist/components/blocks/cta-banner/CtaBanner.types.js +13 -0
  108. package/dist/components/blocks/cta-banner/cta-banner-impl.css +29 -0
  109. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.css +90 -0
  110. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.d.ts +39 -0
  111. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.js +60 -0
  112. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.d.ts +41 -0
  113. package/dist/components/blocks/cta-banner-slider/CtaBannerSlider.types.js +15 -0
  114. package/dist/components/blocks/cta-banner-slider/cta-banner-slider-impl.css +73 -0
  115. package/dist/components/blocks/faq-accordion/FaqAccordion.css +54 -0
  116. package/dist/components/blocks/faq-accordion/FaqAccordion.d.ts +20 -0
  117. package/dist/components/blocks/faq-accordion/FaqAccordion.js +28 -0
  118. package/dist/components/blocks/faq-accordion/FaqAccordion.types.d.ts +25 -0
  119. package/dist/components/blocks/faq-accordion/FaqAccordion.types.js +10 -0
  120. package/dist/components/blocks/faq-accordion/faq-accordion-impl.css +54 -0
  121. package/dist/components/blocks/feature-bullets/FeatureBullets.css +139 -0
  122. package/dist/components/blocks/feature-bullets/FeatureBullets.d.ts +31 -0
  123. package/dist/components/blocks/feature-bullets/FeatureBullets.js +55 -0
  124. package/dist/components/blocks/feature-bullets/FeatureBullets.types.d.ts +39 -0
  125. package/dist/components/blocks/feature-bullets/FeatureBullets.types.js +16 -0
  126. package/dist/components/blocks/feature-bullets/feature-bullets-impl.css +104 -0
  127. package/dist/components/blocks/feature-cards/FeatureCards.css +84 -0
  128. package/dist/components/blocks/feature-cards/FeatureCards.d.ts +24 -0
  129. package/dist/components/blocks/feature-cards/FeatureCards.js +66 -0
  130. package/dist/components/blocks/feature-cards/FeatureCards.types.d.ts +33 -0
  131. package/dist/components/blocks/feature-cards/FeatureCards.types.js +14 -0
  132. package/dist/components/blocks/feature-cards/feature-cards-impl.css +245 -0
  133. package/dist/components/blocks/feature-scroll/FeatureScroll.css +137 -0
  134. package/dist/components/blocks/feature-scroll/FeatureScroll.d.ts +39 -0
  135. package/dist/components/blocks/feature-scroll/FeatureScroll.js +167 -0
  136. package/dist/components/blocks/feature-scroll/FeatureScroll.types.d.ts +40 -0
  137. package/dist/components/blocks/feature-scroll/FeatureScroll.types.js +17 -0
  138. package/dist/components/blocks/feature-scroll/feature-scroll-impl.css +292 -0
  139. package/dist/components/blocks/feature-split/FeatureSplit.css +95 -0
  140. package/dist/components/blocks/feature-split/FeatureSplit.d.ts +30 -0
  141. package/dist/components/blocks/feature-split/FeatureSplit.js +38 -0
  142. package/dist/components/blocks/feature-split/FeatureSplit.types.d.ts +39 -0
  143. package/dist/components/blocks/feature-split/FeatureSplit.types.js +14 -0
  144. package/dist/components/blocks/feature-split/feature-split-impl.css +83 -0
  145. package/dist/components/blocks/landing-hero/LandingHero.css +85 -0
  146. package/dist/components/blocks/landing-hero/LandingHero.d.ts +41 -0
  147. package/dist/components/blocks/landing-hero/LandingHero.js +54 -0
  148. package/dist/components/blocks/landing-hero/LandingHero.types.d.ts +37 -0
  149. package/dist/components/blocks/landing-hero/LandingHero.types.js +15 -0
  150. package/dist/components/blocks/landing-hero/landing-hero-impl.css +355 -0
  151. package/dist/components/blocks/logo-columns/LogoColumns.css +161 -0
  152. package/dist/components/blocks/logo-columns/LogoColumns.d.ts +23 -0
  153. package/dist/components/blocks/logo-columns/LogoColumns.js +46 -0
  154. package/dist/components/blocks/logo-columns/LogoColumns.types.d.ts +46 -0
  155. package/dist/components/blocks/logo-columns/LogoColumns.types.js +18 -0
  156. package/dist/components/blocks/logo-columns/logo-columns-impl.css +188 -0
  157. package/dist/components/blocks/logo-rows/LogoRows.css +122 -0
  158. package/dist/components/blocks/logo-rows/LogoRows.d.ts +20 -0
  159. package/dist/components/blocks/logo-rows/LogoRows.js +43 -0
  160. package/dist/components/blocks/logo-rows/LogoRows.types.d.ts +36 -0
  161. package/dist/components/blocks/logo-rows/LogoRows.types.js +16 -0
  162. package/dist/components/blocks/logo-rows/logo-rows-impl.css +179 -0
  163. package/dist/components/blocks/page-header/PageHeader.css +79 -0
  164. package/dist/components/blocks/page-header/PageHeader.d.ts +34 -0
  165. package/dist/components/blocks/page-header/PageHeader.js +43 -0
  166. package/dist/components/blocks/page-header/PageHeader.types.d.ts +32 -0
  167. package/dist/components/blocks/page-header/PageHeader.types.js +14 -0
  168. package/dist/components/blocks/page-header/page-header-impl.css +176 -0
  169. package/dist/components/blocks/product-hero/ProductHero.css +86 -0
  170. package/dist/components/blocks/product-hero/ProductHero.d.ts +35 -0
  171. package/dist/components/blocks/product-hero/ProductHero.js +48 -0
  172. package/dist/components/blocks/product-hero/ProductHero.types.d.ts +37 -0
  173. package/dist/components/blocks/product-hero/ProductHero.types.js +15 -0
  174. package/dist/components/blocks/product-hero/product-hero-impl.css +354 -0
  175. package/dist/components/blocks/testimonial-row/TestimonialRow.css +245 -0
  176. package/dist/components/blocks/testimonial-row/TestimonialRow.d.ts +20 -0
  177. package/dist/components/blocks/testimonial-row/TestimonialRow.js +128 -0
  178. package/dist/components/blocks/testimonial-row/TestimonialRow.types.d.ts +54 -0
  179. package/dist/components/blocks/testimonial-row/TestimonialRow.types.js +26 -0
  180. package/dist/components/blocks/testimonial-row/testimonial-row-impl.css +195 -0
  181. package/dist/components/blocks/testimonial-slider/TestimonialSlider.css +181 -0
  182. package/dist/components/blocks/testimonial-slider/TestimonialSlider.d.ts +22 -0
  183. package/dist/components/blocks/testimonial-slider/TestimonialSlider.js +36 -0
  184. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.d.ts +49 -0
  185. package/dist/components/blocks/testimonial-slider/TestimonialSlider.types.js +21 -0
  186. package/dist/components/blocks/testimonial-slider/testimonial-slider-impl.css +202 -0
  187. package/dist/components/blocks/use-reveal.d.ts +46 -0
  188. package/dist/components/blocks/use-reveal.js +120 -0
  189. package/dist/components/blocks/use-rotation.d.ts +62 -0
  190. package/dist/components/blocks/use-rotation.js +176 -0
  191. package/dist/components/core/accordion-item/AccordionItem.css +6 -5
  192. package/dist/components/core/bottom-sheet/BottomSheet.css +1 -1
  193. package/dist/components/core/button/Button.css +63 -16
  194. package/dist/components/core/button/Button.d.ts +14 -12
  195. package/dist/components/core/button/Button.js +43 -14
  196. package/dist/components/core/button/Button.types.d.ts +9 -14
  197. package/dist/components/core/button/button-impl.css +25 -0
  198. package/dist/components/core/button-icon/ButtonIcon.css +31 -15
  199. package/dist/components/core/button-icon/ButtonIcon.d.ts +2 -2
  200. package/dist/components/core/button-icon/ButtonIcon.js +2 -2
  201. package/dist/components/core/button-icon/ButtonIcon.types.d.ts +4 -4
  202. package/dist/components/core/card/Card.css +13 -4
  203. package/dist/components/core/card/Card.types.d.ts +2 -1
  204. package/dist/components/core/card-body/CardBody.css +11 -6
  205. package/dist/components/core/card-body/CardBody.d.ts +1 -1
  206. package/dist/components/core/card-body/CardBody.js +2 -2
  207. package/dist/components/core/card-body/CardBody.types.d.ts +4 -1
  208. package/dist/components/core/card-body/CardBody.types.js +1 -0
  209. package/dist/components/core/card-button/CardButton.css +13 -4
  210. package/dist/components/core/card-button/CardButton.types.d.ts +2 -1
  211. package/dist/components/core/checkbox/Checkbox.css +8 -1
  212. package/dist/components/core/dropdown-menu/DropdownMenu.css +13 -12
  213. package/dist/components/core/dropdown-menu/DropdownMenu.d.ts +5 -3
  214. package/dist/components/core/dropdown-menu/DropdownMenu.js +5 -3
  215. package/dist/components/core/filter-chip/FilterChip.css +2 -1
  216. package/dist/components/core/footer/footer-impl.css +1 -1
  217. package/dist/components/core/footer-group/FooterGroup.css +8 -7
  218. package/dist/components/core/icon/Icon.css +1 -1
  219. package/dist/components/core/link/Link.css +1 -1
  220. package/dist/components/core/menu-item/MenuItem.css +1 -1
  221. package/dist/components/core/navbar/Navbar.css +7 -8
  222. package/dist/components/core/navbar/Navbar.d.ts +17 -1
  223. package/dist/components/core/navbar/Navbar.js +139 -12
  224. package/dist/components/core/navbar/Navbar.types.d.ts +23 -4
  225. package/dist/components/core/navbar/Navbar.types.js +1 -1
  226. package/dist/components/core/navbar/navbar-impl.css +10 -3
  227. package/dist/components/core/navbar/navbar-material.css +96 -0
  228. package/dist/components/core/navbar-item/NavbarItem.css +4 -4
  229. package/dist/components/core/navbar-menu/NavbarMenu.css +7 -5
  230. package/dist/components/core/navbar-menu/NavbarMenu.d.ts +1 -0
  231. package/dist/components/core/navbar-menu/NavbarMenu.js +1 -0
  232. package/dist/components/core/navbar-menu/navbar-menu-impl.css +7 -7
  233. package/dist/components/core/navbar-switcher/NavbarSwitcher.css +6 -5
  234. package/dist/components/core/navbar-switcher/NavbarSwitcher.d.ts +1 -0
  235. package/dist/components/core/navbar-switcher/NavbarSwitcher.js +2 -1
  236. package/dist/components/core/option/Option.css +1 -1
  237. package/dist/components/core/pagination/Pagination.css +1 -75
  238. package/dist/components/core/pagination/Pagination.d.ts +4 -4
  239. package/dist/components/core/pagination/Pagination.js +11 -51
  240. package/dist/components/core/pagination/Pagination.types.d.ts +5 -17
  241. package/dist/components/core/pagination/Pagination.types.js +1 -3
  242. package/dist/components/core/pagination-dots/PaginationDots.css +60 -0
  243. package/dist/components/core/pagination-dots/PaginationDots.d.ts +25 -0
  244. package/dist/components/core/pagination-dots/PaginationDots.js +104 -0
  245. package/dist/components/core/pagination-dots/PaginationDots.types.d.ts +38 -0
  246. package/dist/components/core/pagination-dots/PaginationDots.types.js +9 -0
  247. package/dist/components/core/removable-chip/RemovableChip.css +3 -3
  248. package/dist/components/core/search-input/SearchInput.css +1 -1
  249. package/dist/components/core/segmented-control/SegmentedControl.css +1 -1
  250. package/dist/components/core/segmented-control-item/SegmentedControlItem.css +1 -1
  251. package/dist/components/core/select/Select.css +2 -1
  252. package/dist/components/core/select-chip/SelectChip.css +14 -7
  253. package/dist/components/core/select-chip/SelectChip.d.ts +1 -1
  254. package/dist/components/core/select-chip/SelectChip.js +7 -4
  255. package/dist/components/core/select-chip/SelectChip.types.d.ts +7 -1
  256. package/dist/components/core/select-chip/SelectChip.types.js +1 -1
  257. package/dist/components/core/select-chip/select-chip-impl.css +14 -3
  258. package/dist/components/core/status-dot/StatusDot.css +1 -1
  259. package/dist/components/core/subdomain-navbar/SubdomainNavbar.css +3 -3
  260. package/dist/components/core/tab/Tab.css +1 -1
  261. package/dist/components/core/tab-list/TabList.css +1 -1
  262. package/dist/components/core/table/table-impl.css +36 -14
  263. package/dist/components/core/table-header-cell/TableHeaderCell.css +5 -5
  264. package/dist/components/core/text-area/TextArea.css +1 -1
  265. package/dist/components/core/text-input/TextInput.css +1 -1
  266. package/dist/components/core/tooltip/Tooltip.css +1 -1
  267. package/dist/components/core/typography/Typography.css +5 -5
  268. package/dist/components/index.d.ts +35 -0
  269. package/dist/components/index.js +30 -0
  270. package/dist/components/logo-data.d.ts +24 -0
  271. package/dist/components/logo-data.js +11 -0
  272. package/dist/components/scroll-data.d.ts +64 -0
  273. package/dist/components/scroll-data.js +17 -0
  274. package/dist/components/testimonial-row-data.d.ts +51 -0
  275. package/dist/components/testimonial-row-data.js +11 -0
  276. package/dist/components/testimonial-slider-data.d.ts +26 -0
  277. package/dist/components/testimonial-slider-data.js +10 -0
  278. package/dist/marketing.css +385 -14
  279. package/package.json +1 -6
@@ -55,7 +55,7 @@ Navbar renders 11 elements. A token binding names the part it applies to.
55
55
 
56
56
  Once the page moves it becomes the pill. The shape does not travel between elements and nothing in the markup is rearranged: the row already holds all three ends, so what changes is which of the two boxes paints. That is the whole of the condensed state — the mark and the actions were always inside this box, and at rest it simply drew nothing around them.
57
57
 
58
- The control it reserves is `size.control.lg`, which is what the bar's actions are. Collapsed, the row holds one of them beside the mark and the way in, so reserving anything smaller would let that button set the bar's height and make a page with one taller than a page without.
58
+ The control it reserves is `size.control.md`, which is what the bar's actions are. Collapsed, the row holds one of them beside the mark and the way in, so reserving anything smaller would let that button set the bar's height and make a page with one taller than a page without.
59
59
 
60
60
  The measure it reserves is `size.bar.height`, not a control's. Reserving a control was the near miss: it is a floor, and the action the bar keeps when it collapses is taller than the floor less this row's own air — so that button set the height, the row's contents came out a step shorter than the panel's header, and the mark moved down four pixels at the moment a surface opened over the bar drawing it. Reserving the bar's height instead puts the contents at one measure whatever is in them, which is the thing the panel can then agree with.
61
61
  - `ground` — `<div>`, class `dds-navbar__ground`. The collapsed bar's ground, and an element rather than a binding on the row it paints.
@@ -77,7 +77,7 @@ Navbar renders 11 elements. A token binding names the part it applies to.
77
77
 
78
78
  It moves. At rest it stands outside the pill at the leading end of the row; once the bar gathers it is rendered inside the pill instead, which is the whole of what the condensed state does. Rendered in one place at a time rather than drawn twice and hidden — two marks in the markup is two things a screen reader has to be kept from announcing, and a hidden one is only ever one stylesheet away from being read out.
79
79
 
80
- It decides how tall the mark is rather than taking whatever it was handed. A slot that let the page set the measure would let the page set the bar's height with it — a logo an inch tall does not overflow, it makes the row an inch tall and every page below it move down. The step is `icon.size.md`, which sits inside the pill with room either side rather than filling it: a mark as tall as the shape around it reads as a label in a box rather than a mark on a bar. Twenty-four in a forty-eight pill leaves twelve either side, and it is the step the subdomain bar was already drawing its mark at — two bars off the same family disagreeing about how tall a logo is was a difference saying nothing.
80
+ It decides how tall the mark is rather than taking whatever it was handed. A slot that let the page set the measure would let the page set the bar's height with it — a logo an inch tall does not overflow, it makes the row an inch tall and every page below it move down. The step is `icon.size.md`, which sits inside the pill with room either side rather than filling it: a mark as tall as the shape around it reads as a label in a box rather than a mark on a bar. Twenty-four in a forty pill leaves eight either side, and it is the step the subdomain bar was already drawing its mark at — two bars off the same family disagreeing about how tall a logo is was a difference saying nothing.
81
81
 
82
82
  It measures border-box, which matters only because it collapses. Both copies of this part go to nothing wide when they are not the live one — and a width set on a content box leaves the padding standing, so the inset this carries would sit in the bar as a strip of nothing: twelve pixels inside the pill, a gutter's worth at the row's edge. Border-box takes the padding with the width, so nothing is what nothing means.
83
83
 
@@ -101,6 +101,8 @@ Navbar renders 11 elements. A token binding names the part it applies to.
101
101
  No gap between the destinations, which is about the pointer rather than about the spacing. Each one pads its own words, so there is a clear step between them either way — what a gap adds is a strip of row belonging to neither, and a section that opens under the pointer treats that strip as having left. Moving from one name to the next, a reader crossed it: the first section armed its close, and if the hand paused in the four pixels between them it fired, so the panel shut and the next one opened rather than the two exchanging places.
102
102
 
103
103
  At nothing the targets touch, and the pointer is over a destination at every moment of the journey. The words stay `space.inset.sm` apart because that is what each of them is padded by — the spacing a reader sees was never the gap.
104
+
105
+ Not positioned, on purpose. A section's panel hangs from the nearest positioned ancestor, and with the landmark out of that chain it is the pill — so every panel centres on the pill rather than on the destinations alone, which sit to one side of it once the language switcher and the theme toggle share it.
104
106
  - `preferences` — `<div>`, class `dds-navbar__preferences`. What a reader sets rather than goes to, kept with the destinations.
105
107
 
106
108
  Inside the pill and outside the landmark, which is the whole reason it is a part of its own. A language picker is not a place the site has, so it cannot go in `nav` — a reader tabbing the navigation would be offered it as somewhere to go. And it is not a conversion either, so the trailing end is the wrong home: the pill is the set of things the bar is about, and the locale a reader is reading in belongs to that set rather than to the pair of buttons asking them to sign up.
@@ -178,7 +180,7 @@ Apply these classes from the generated `navbarParts` constant rather than writin
178
180
  ### tone — `default` | `inverse` (default `default`)
179
181
 
180
182
  - `default` — The page begins on a light ground, which is most marketing pages. The bar paints in ink and the pill is paper
181
- - `inverse` — The first section of the page paints its own dark ground and the bar stands on it — a dark hero, a photograph, a brand-coloured takeover. The bar's ink runs light, the pill becomes a veil of white rather than a sheet of it, and the collapsed bar takes a solid dark ground of its own
183
+ - `inverse` — The first section of the page paints its own dark ground and the bar stands on it — a dark hero, a photograph, a brand-coloured takeover. The bar's ink runs light, and the pill and the collapsed bar take the dark see-through material — a near-opaque black base, a white tint and a blur — so a light photograph behind cannot wash them out
182
184
 
183
185
  ### label — `string` **Required.**
184
186
 
@@ -203,13 +205,13 @@ Never for: A heading for the page. This is the site's mark, not the page's title
203
205
  ### utilities — `node`
204
206
 
205
207
  Accepts: Button, ButtonIcon, DropdownMenu
206
- Use when: The bar's trailing end has something in it — a language switcher, a theme switcher, a conversion action, or some combination. A switcher is a DropdownMenu with the current choice on its trigger, which is what DropdownMenu's own guidance describes and why it is accepted here alongside the two controls. They are drawn in the row at wide widths and across the foot of the panel once it collapses
207
- Never for: Destinations. Anything that goes to a section of the site belongs in the children, where the navigation landmark announces it as one. The trailing end is for what a reader reaches for, not for the places the bar ran out of room for
208
+ Use when: The bar's trailing end has the site's actions in it: one Button, which is primary, or two — one primary and one secondary, the conversion beside the way back in. A switcher is a DropdownMenu with the current choice on its trigger, which is what DropdownMenu's own guidance describes and why it is accepted here alongside the two controls. They are drawn in the row at wide widths and across the foot of the panel once it collapses. The bar dresses what it is handed: every Button here is drawn at md and takes the tone of the ground the bar is on at that scroll position — inverse on the hero, default once the pill gathers — and a ButtonIcon or a DropdownMenu takes the tone too. That reaches the controls handed in directly, or in a fragment; a control inside a component of the page's own is past it, so a wrapper takes tone and size as props and passes them down
209
+ Never for: More than two Buttons, a lone Button that is not primary, or a pair that is not one primary and one secondary — the bar's actions are a conversion and its alternative, and a third pill or a second of either rank makes the reader choose between things the bar should have ranked. A switcher is not a Button and does not count against the two. Nor destinations: anything that goes to a section of the site belongs in the children, where the navigation landmark announces it as one
208
210
 
209
211
  ### compactAction — `node`
210
212
 
211
213
  Accepts: Button, ButtonIcon
212
- Use when: The one thing a reader should still be able to do once the bar has collapsed and everything else has gone into the panel — a sign-up, usually. Drawn beside the control that opens the panel, and only at the widths where that control is drawn
214
+ Use when: The one thing a reader should still be able to do once the bar has collapsed and everything else has gone into the panel — a sign-up, usually. Drawn beside the control that opens the panel, and only at the widths where that control is drawn. Dressed like utilities: a Button here is drawn at md and takes the bar's tone
213
215
  Never for: The whole of utilities. A phone has room for one action beside a mark and a menu button, and a bar handed two of them either wraps or pushes the mark off its own edge — the rest belong in utilities, which the panel lays out down its foot where there is room for all of them
214
216
 
215
217
  ### preferences — `node`
@@ -218,6 +220,28 @@ Accepts: NavbarSwitcher, DropdownMenu, ButtonIcon
218
220
  Use when: A switcher that belongs with the destinations rather than with the conversion — a language picker, a theme toggle. It is drawn inside the pill, beside the sections, at every scroll position. A NavbarSwitcher is the one built for it: in the pill it is a trigger and a menu, and in the collapsed panel the same element becomes a row that opens a page of its own with a way back, because a dropdown inside a surface already covering the screen is a surface inside a surface
219
221
  Never for: A conversion action. Those belong in utilities, at the trailing end of the bar where a reader looks for them, and drawing one inside the pill would put the thing the page most wants pressed in among the places it goes
220
222
 
223
+ ### showThemeToggle — `boolean` (default `false`)
224
+
225
+ Use when: The site offers light and dark and a reader can choose between them. The bar draws the toggle itself, after whatever preferences holds — a plain ButtonIcon in a pill-height square, a moon on the light page and a sun on the dark one, with no words — so every site's toggle is the same control in the same place. In the collapsed panel it is drawn at the panel's foot beside the other preferences.
226
+ Never for: A site that ships one theme. A toggle that changes nothing is a control that lies about the page.
227
+
228
+ ### theme — `light` | `dark` **Required when showThemeToggle=true.**
229
+
230
+ - `light` — The page is drawn in its light theme, so the toggle offers dark
231
+ - `dark` — The page is drawn in its dark theme, so the toggle offers light
232
+
233
+ Use when: Whenever showThemeToggle is — the theme in force. The page owns it, because what it switches is the page's data-theme rather than anything inside the bar; the bar only draws the toggle and reports presses.
234
+
235
+ ### onThemeChange — `callback` **Required when showThemeToggle=true.**
236
+
237
+ Use when: Whenever showThemeToggle is. Called with the theme a press moves to; the page sets its data-theme from it and hands the new value back as theme.
238
+ Never for: Persisting a preference the page has not decided to keep. Remembering the choice across visits is the site's call, made where it sets data-theme.
239
+
240
+ ### themeToggleLabel — `string` **Required when showThemeToggle=true.**
241
+
242
+ Use when: Whenever showThemeToggle is — the toggle draws a glyph and no words, and this is the only name it has. Name the theme it turns on, not the gesture: 'Dark theme', read with aria-pressed, so a screen reader hears 'Dark theme, not pressed' on the light page and the name stays the same when the state changes.
243
+ Never for: Visible text. Nothing is drawn beside the glyph; a toggle with words is a NavbarSwitcher.
244
+
221
245
  ### menuOpen — `boolean`
222
246
 
223
247
  Use when: The page is holding whether the panel is open, because something else depends on it — a route change that should close it, a surface of its own that must not open at the same time. Passing it makes the bar controlled: it shows what it is told and reports presses through onMenuOpenChange.
@@ -232,6 +256,16 @@ Never for: Navigation. This says whether the panel is showing; a page that also
232
256
 
233
257
  Also accepts everything from `HTMLAttributes<HTMLElement>`.
234
258
 
259
+ ## Choosing a variant
260
+
261
+ Placement in, props out. When one of these describes what you are building, take
262
+ its props — do not re-derive them from the variant descriptions above.
263
+
264
+ - **A site bar with a language picker and a light and dark choice** — `preferences={<NavbarSwitcher>…</NavbarSwitcher>}` `showThemeToggle`
265
+ The language is a choice among many, so it is a NavbarSwitcher — a trigger and a menu in the pill, a page of its own in the collapsed panel. The theme is one of two, so it is a toggle rather than a menu, drawn by the bar after the language: a glyph with no words at the same height as every other item in the pill.
266
+ - **The actions at the bar's trailing end — a sign-up, and a log-in for a reader who already has an account** — `utilities={<Button (primary) + Button (secondary)>…</Button (primary) + Button (secondary)>}`, not `utilities={<three Buttons, or two of one variant>…</three Buttons, or two of one variant>}`
267
+ Two actions, ranked: the conversion is primary and the way back in is secondary. With only one, it is the primary. A third button is a third demand in a row that has room for a pair, and the bar starts to read as a second navigation.
268
+
235
269
  ## Accessibility
236
270
 
237
271
  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.
@@ -314,6 +348,14 @@ The target and the mark are separate decisions, and conflating them is what prod
314
348
 
315
349
  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.
316
350
  Guidance only — cannot be checked automatically.
351
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
352
+
353
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
354
+
355
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
356
+
357
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
358
+ Guidance only — cannot be checked automatically.
317
359
 
318
360
  ## Anti-examples
319
361
 
@@ -328,6 +370,15 @@ Declared rather than emergent. Padding plus contents does clear 24px in several
328
370
  ❌ Navbar for: The navigation runs down the side of an application rather than across the top of a page
329
371
  → nothing in this system does this. Not a gap waiting to be filled — the case belongs outside it.
330
372
 
373
+ ❌ showThemeToggle=true + theme missing or empty
374
+ A toggle that does not know which theme is in force cannot say which one a press moves to, and would draw the wrong glyph half the time.
375
+
376
+ ❌ showThemeToggle=true + onThemeChange missing or empty
377
+ A toggle with nothing to call answers the pointer and changes nothing — the one failure the affordance cannot disclose.
378
+
379
+ ❌ showThemeToggle=true + themeToggleLabel missing or empty
380
+ The toggle draws a glyph and no words, so without this it ships unnamed and a screen reader announces a button and nothing else.
381
+
331
382
  ## Example
332
383
 
333
384
  ```tsx
@@ -390,25 +441,19 @@ import { DerivCoralWordmark } from '@deriv-com/quill-logos-web'
390
441
  <Navbar label="Main" menuLabel="Menu" closeLabel="Close">{navbaritems}</Navbar>
391
442
  ```
392
443
 
393
- ### The two tiers at the trailing end
444
+ ### The action at the trailing end
394
445
 
395
- What decides the tier is not how important the destination feels but how many the bar already has. Primary means something only while it is the one.
446
+ A lone Button is the primary. With two, the other is secondary beside it — never three, never two of one rank. See the navbar-actions-are-a-pair rule.
396
447
 
397
448
  ```tsx
398
449
  import { Button, Navbar, NavbarItem } from '@deriv-com/dds-marketing'
399
450
  import { DerivCoralWordmark } from '@deriv-com/quill-logos-web'
400
451
 
401
- // Primary — the step the site exists to produce
452
+ // Primary — the one action the bar offers
402
453
  <Navbar label="Main" menuLabel="Menu" closeLabel="Close" brand={<DerivCoralWordmark />} utilities={<Button size="md" href="/signup">Open account</Button>}>
403
454
  <NavbarItem href="/trading">Trading</NavbarItem>
404
455
  <NavbarItem href="/platforms">Platforms</NavbarItem>
405
456
  </Navbar>
406
-
407
- // Secondary — the quieter of a pair
408
- <Navbar label="Main" menuLabel="Menu" closeLabel="Close" brand={<DerivCoralWordmark />} utilities={<Button size="md" href="/login" variant="secondary">Log in</Button>}>
409
- <NavbarItem href="/trading">Trading</NavbarItem>
410
- <NavbarItem href="/platforms">Platforms</NavbarItem>
411
- </Navbar>
412
457
  ```
413
458
 
414
459
  ### Where the reader is
@@ -456,3 +501,22 @@ import { DerivCoralWordmark } from '@deriv-com/quill-logos-web'
456
501
  // With one — the conversion stays reachable
457
502
  <Navbar label="Main" menuLabel="Menu" closeLabel="Close" brand={<DerivCoralWordmark />} utilities={<Button size="md" href="/signup">Open account</Button>} compactAction={<Button size="md" href="/signup">Sign up</Button>}>{navbaritems}</Navbar>
458
503
  ```
504
+
505
+ ### What a reader sets
506
+
507
+ The language is a NavbarSwitcher in preferences. The theme is a toggle the bar draws itself after it with showThemeToggle — a glyph, no words, the height of every item.
508
+
509
+ ```tsx
510
+ import { Button, Navbar, NavbarSwitcher, NavbarSwitcherOption } from '@deriv-com/dds-marketing'
511
+ import { DerivCoralWordmark } from '@deriv-com/quill-logos-web'
512
+ import { GlobeRegularIcon } from '@deriv-com/quill-icons-web'
513
+
514
+ // Language only
515
+ <Navbar label="Main" menuLabel="Menu" closeLabel="Close" brand={<DerivCoralWordmark />} utilities={<Button size="md" href="/signup">Open account</Button>} preferences={<NavbarSwitcher label="EN" menuLabel="Language" backLabel="Back to the menu" icon={<GlobeRegularIcon />} />}>{navbaritems}</Navbar>
516
+
517
+ // Language and the theme toggle
518
+ <Navbar onThemeChange={(theme) => { /* your handler */ }} label="Main" menuLabel="Menu" closeLabel="Close" brand={<DerivCoralWordmark />} utilities={<Button size="md" href="/signup">Open account</Button>} preferences={<NavbarSwitcher label="EN" menuLabel="Language" backLabel="Back to the menu" icon={<GlobeRegularIcon />} />} showThemeToggle theme="light" themeToggleLabel="Dark theme">{navbaritems}</Navbar>
519
+
520
+ // On a dark page — a sun, the theme a press moves to
521
+ <Navbar onThemeChange={(theme) => { /* your handler */ }} label="Main" menuLabel="Menu" closeLabel="Close" brand={<DerivCoralWordmark />} utilities={<Button size="md" href="/signup">Open account</Button>} preferences={<NavbarSwitcher label="EN" menuLabel="Language" backLabel="Back to the menu" icon={<GlobeRegularIcon />} />} showThemeToggle theme="dark" themeToggleLabel="Dark theme">{navbaritems}</Navbar>
522
+ ```
@@ -36,7 +36,7 @@ NavbarItem renders 4 elements. A token binding names the part it applies to.
36
36
 
37
37
  `position: relative`, for the one thing it holds that is not drawn: an external destination's warning in words, clipped out of the page. That recipe is absolutely positioned, so without a positioned ancestor it takes the document as its containing block and adds its offset to the bottom of a long landing page.
38
38
 
39
- It reserves `size.control.lg`, the same height the bar's actions take. A destination is words and a button is a filled shape, so they are never the same object — but they stand in one row, and a row whose items are two heights reads as two rows that failed to line up.
39
+ It reserves `size.control.md`, the same height the bar's actions take. A destination is words and a button is a filled shape, so they are never the same object — but they stand in one row, and a row whose items are two heights reads as two rows that failed to line up.
40
40
 
41
41
  It pads its words by `space.inset.md`. With no gap between the destinations — the row sets none, so their targets touch and a pointer crossing from one to the next is never over neither — this inset is the whole of the space a reader sees between two names, twice over. It is the spacing decision for the row, not a detail of one item.
42
42
  - `icon` — `<span>`, class `dds-navbaritem__icon`. A mark before the words, for a bar that uses them. Optional and uncommon: a marketing site's sections are named in words a reader reads, and a glyph beside every one of them costs width the destinations need.
@@ -167,6 +167,14 @@ The target and the mark are separate decisions, and conflating them is what prod
167
167
 
168
168
  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.
169
169
  Guidance only — cannot be checked automatically.
170
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
171
+
172
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
173
+
174
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
175
+
176
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
177
+ Guidance only — cannot be checked automatically.
170
178
 
171
179
  ## Anti-examples
172
180
 
@@ -237,6 +237,14 @@ The target and the mark are separate decisions, and conflating them is what prod
237
237
 
238
238
  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.
239
239
  Guidance only — cannot be checked automatically.
240
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
241
+
242
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
243
+
244
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
245
+
246
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
247
+ Guidance only — cannot be checked automatically.
240
248
 
241
249
  ## Anti-examples
242
250
 
@@ -137,6 +137,14 @@ The target and the mark are separate decisions, and conflating them is what prod
137
137
 
138
138
  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.
139
139
  Guidance only — cannot be checked automatically.
140
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
141
+
142
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
143
+
144
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
145
+
146
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
147
+ Guidance only — cannot be checked automatically.
140
148
 
141
149
  ## Anti-examples
142
150
 
@@ -38,7 +38,7 @@ NavbarPanel renders 8 elements. A token binding names the part it applies to.
38
38
 
39
39
  It is paper at every tone, including under a bar that is not. An inverse bar is inverse because the section beneath it painted itself dark and the bar is standing on that section — but this covers the page rather than standing on it, so there is no dark ground here to answer to, only the one this surface chooses. It had a tone briefly and it was wrong for the same reason the scrolled bar's was: a treatment that belongs to a ground, carried somewhere the ground is not.
40
40
 
41
- What the page passes still comes out right without being passed twice. The foot holds the bar's own utilities, and a secondary action taking Button's `tone="inherit"` reads the ink of whatever surface it lands on — white against the bar, near-black here.
41
+ What the page passes still comes out right without being passed twice. The foot holds the bar's own utilities, re-dressed at the default tone, so a secondary action the bar turned white is drawn on paper here as the page's own.
42
42
  - `header` — `<div>`, class `dds-navbarpanel__header`. The top: the mark at one end, the way out at the other. The mark is repeated here rather than the panel being drawn beneath the bar, because a panel covering the page has covered the bar too — and a reader who has lost the mark has lost the one thing telling them whose site they are still on.
43
43
 
44
44
  Its height is the bar's row, and stated the same way: `size.control.md`, a control's height, under the same `space.inset.xs` the bar's row takes above it. Both reserve a control because both hold one — the bar keeps an action beside the trigger, this keeps the way out — and a row sized by whatever happens to be in it would put the mark at one height here and another there. Two tokens rather than one measure that happens to equal their sum, so retuning either moves both halves together.
@@ -207,6 +207,14 @@ The target and the mark are separate decisions, and conflating them is what prod
207
207
 
208
208
  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.
209
209
  Guidance only — cannot be checked automatically.
210
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
211
+
212
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
213
+
214
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
215
+
216
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
217
+ Guidance only — cannot be checked automatically.
210
218
 
211
219
  ## Anti-examples
212
220
 
@@ -40,7 +40,7 @@ NavbarSwitcher renders 7 elements. A token binding names the part it applies to.
40
40
  It pads its words by the same step the destinations do, for the same reason: it stands in their row.
41
41
  - `icon` — `<span>`, class `dds-navbarswitcher__icon`. The mark that says which question this answers — a globe for a language, without which the trigger is two letters nobody can place.
42
42
 
43
- It is drawn at the step that sits with the words rather than above them. The trigger is set in `font.label.sm` and `icon.size.xs` is the nearest step to it — a mark a step larger reads as the thing being said and the letters beside it as a note on it, when the sentence is the other way round: the choice is what a reader came for and the globe only says which question it answers. It is also the measure the chevron at the other end takes, so the two marks bracketing the row agree. Rendered only when `icon` is set.
43
+ It is drawn at icon.control.md, the measure a glyph-alone control takes at the bar's md step. A theme toggle beside it is a ButtonIcon at md, whose mark is drawn at that same measure, and a Quill glyph carries its stroke through any scale — so two marks side by side at different sizes draw different stroke weights, and read as two kinds of control when they are the same kind, a thing a reader sets. The chevron at the other end stays at icon.size.xs because it qualifies the row rather than naming it. Rendered only when `icon` is set.
44
44
  - `chevron` — `<span>`, class `dds-navbarswitcher__chevron`. The mark that says this opens. Absent by default, because in a bar this sits among destinations that each carry one and a third would be repetition rather than signal — and present in the panel whatever the page said, because a row in a list gives a reader nothing else to go on. It points along the reading direction there rather than down: what opens is a page beside this one, not a drawer beneath it. Rendered only when `chevron` is set.
45
45
  - `surface` — `<div>`, class `dds-navbarswitcher__surface`. The choices. Floating, it is a panel hanging off the trigger. In the panel it covers the destinations and the switchers below them and stops at the header, so the mark and the way out stay on screen while a reader is two levels in.
46
46
 
@@ -196,6 +196,14 @@ The target and the mark are separate decisions, and conflating them is what prod
196
196
 
197
197
  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.
198
198
  Guidance only — cannot be checked automatically.
199
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
200
+
201
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
202
+
203
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
204
+
205
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
206
+ Guidance only — cannot be checked automatically.
199
207
 
200
208
  ## Anti-examples
201
209
 
@@ -120,6 +120,14 @@ The target and the mark are separate decisions, and conflating them is what prod
120
120
 
121
121
  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.
122
122
  Guidance only — cannot be checked automatically.
123
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
124
+
125
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
126
+
127
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
128
+
129
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
130
+ Guidance only — cannot be checked automatically.
123
131
 
124
132
  ## Anti-examples
125
133
 
@@ -158,6 +158,14 @@ The target and the mark are separate decisions, and conflating them is what prod
158
158
 
159
159
  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.
160
160
  Guidance only — cannot be checked automatically.
161
+ - **A component is written along the reading axis, not along the page's left and right** — Every measure, inset and placement in this package names an axis rather than a side: inline-size and block-size, padding-inline and padding-block, inset-inline-start and inset-block-end, margin-inline: auto, text-align: start. Written that way a component follows whichever direction the page is read in, and a band whose claim ranges to the leading edge with its subject on the trailing one is the same composition in Arabic as in English, mirrored, with nothing restated. Written as left and right it is the same pixels in both, which is a layout nobody designed for the second language.
162
+
163
+ The enum values follow the same rule and for the same reason. A prop that names where a picture sits takes start and end, never left and right — FeatureSplit, FeatureBullets and FeatureScroll all declare mediaPosition that way, and the flex directions they generate flip on their own because row already means the reading order. A value called left would have to be re-read as right by every author working in a mirrored page, which is a translation this system should be doing rather than asking for.
164
+
165
+ The guidance a contract carries is part of the component, so it follows too. Describing a claim as ranging left is describing one of the two languages, and it was written that way here for a while: three of the opening bands said so in their own intent. A reader in a mirrored page meets that sentence and has to decide whether the component is wrong or the sentence is, and neither answer is one documentation should force.
166
+
167
+ Two things genuinely have no logical form and are not covered by this. A CSS gradient takes a physical direction — there is no to inline-end — so a pattern that must mirror has to be stated twice under a direction query, and one that is periodic and centred, like PageHeader's rule grid, does not need to. A glyph that points the way onward is the other: an arrow is a picture of a direction, and mirroring it belongs to the icon set rather than to the component holding it.
168
+ Guidance only — cannot be checked automatically.
161
169
 
162
170
  ## Anti-examples
163
171