@slotted/styles 0.0.0-stage → 0.1.0-beta.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 (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/package.json +276 -3
  4. package/src/accordion/accordion.css +96 -0
  5. package/src/accordion/accordion.tokens.json +14 -0
  6. package/src/action-bar/action-bar.css +455 -0
  7. package/src/action-bar/action-bar.tokens.json +50 -0
  8. package/src/action-sheet/action-sheet.css +462 -0
  9. package/src/action-sheet/action-sheet.tokens.json +59 -0
  10. package/src/alert/alert.css +764 -0
  11. package/src/alert/alert.tokens.json +77 -0
  12. package/src/app-shell/app-shell.css +1899 -0
  13. package/src/app-shell/app-shell.tokens.json +88 -0
  14. package/src/aspect-ratio/aspect-ratio.css +131 -0
  15. package/src/aspect-ratio/aspect-ratio.tokens.json +1 -0
  16. package/src/attachment/attachment.css +906 -0
  17. package/src/attachment/attachment.tokens.json +85 -0
  18. package/src/avatar/avatar.css +598 -0
  19. package/src/avatar/avatar.tokens.json +64 -0
  20. package/src/avatar-group/avatar-group.css +268 -0
  21. package/src/avatar-group/avatar-group.tokens.json +16 -0
  22. package/src/badge/badge.css +462 -0
  23. package/src/badge/badge.tokens.json +58 -0
  24. package/src/breadcrumb/breadcrumb.css +441 -0
  25. package/src/breadcrumb/breadcrumb.tokens.json +50 -0
  26. package/src/button/button.css +754 -0
  27. package/src/button/button.tokens.json +72 -0
  28. package/src/button-group/button-group.css +455 -0
  29. package/src/button-group/button-group.tokens.json +11 -0
  30. package/src/calendar/calendar.css +846 -0
  31. package/src/calendar/calendar.tokens.json +67 -0
  32. package/src/card/card.css +602 -0
  33. package/src/card/card.tokens.json +68 -0
  34. package/src/carousel/carousel.css +860 -0
  35. package/src/carousel/carousel.tokens.json +62 -0
  36. package/src/cascader/cascader.css +1320 -0
  37. package/src/cascader/cascader.tokens.json +103 -0
  38. package/src/chart/chart.css +1473 -0
  39. package/src/chart/chart.tokens.json +107 -0
  40. package/src/checkbox/checkbox.css +1011 -0
  41. package/src/checkbox/checkbox.tokens.json +102 -0
  42. package/src/checkbox-group/checkbox-group.css +70 -0
  43. package/src/checkbox-group/checkbox-group.tokens.json +6 -0
  44. package/src/code-block/code-block.css +555 -0
  45. package/src/code-block/code-block.tokens.json +69 -0
  46. package/src/collapsible/collapsible.css +546 -0
  47. package/src/collapsible/collapsible.tokens.json +55 -0
  48. package/src/color-picker/color-picker.css +607 -0
  49. package/src/color-picker/color-picker.tokens.json +58 -0
  50. package/src/column-manager/column-manager.css +452 -0
  51. package/src/column-manager/column-manager.tokens.json +43 -0
  52. package/src/combobox/combobox.css +1048 -0
  53. package/src/combobox/combobox.tokens.json +112 -0
  54. package/src/command-palette/command-palette.css +1000 -0
  55. package/src/command-palette/command-palette.tokens.json +75 -0
  56. package/src/container/container.css +198 -0
  57. package/src/container/container.tokens.json +18 -0
  58. package/src/context-menu/context-menu.css +104 -0
  59. package/src/context-menu/context-menu.tokens.json +11 -0
  60. package/src/currency-field/currency-field.css +787 -0
  61. package/src/currency-field/currency-field.tokens.json +80 -0
  62. package/src/dashboard-grid/dashboard-grid.css +748 -0
  63. package/src/dashboard-grid/dashboard-grid.tokens.json +67 -0
  64. package/src/data-grid/data-grid.css +2484 -0
  65. package/src/data-grid/data-grid.tokens.json +100 -0
  66. package/src/data-list/data-list.css +455 -0
  67. package/src/data-list/data-list.tokens.json +35 -0
  68. package/src/date-field/date-field.css +560 -0
  69. package/src/date-field/date-field.tokens.json +80 -0
  70. package/src/date-picker/date-picker.css +420 -0
  71. package/src/date-picker/date-picker.tokens.json +49 -0
  72. package/src/date-range-picker/date-range-picker.css +983 -0
  73. package/src/date-range-picker/date-range-picker.tokens.json +109 -0
  74. package/src/datetime-field/datetime-field.css +850 -0
  75. package/src/datetime-field/datetime-field.tokens.json +91 -0
  76. package/src/datetime-picker/datetime-picker.css +843 -0
  77. package/src/datetime-picker/datetime-picker.tokens.json +78 -0
  78. package/src/datetime-range-picker/datetime-range-picker.css +1375 -0
  79. package/src/datetime-range-picker/datetime-range-picker.tokens.json +135 -0
  80. package/src/description-list/description-list.css +675 -0
  81. package/src/description-list/description-list.tokens.json +66 -0
  82. package/src/detail-panel/detail-panel.css +329 -0
  83. package/src/detail-panel/detail-panel.tokens.json +33 -0
  84. package/src/dialog/dialog.css +968 -0
  85. package/src/dialog/dialog.tokens.json +66 -0
  86. package/src/divider/divider.css +131 -0
  87. package/src/divider/divider.tokens.json +18 -0
  88. package/src/drawer/drawer.css +1303 -0
  89. package/src/drawer/drawer.tokens.json +75 -0
  90. package/src/entity-picker/entity-picker.css +1367 -0
  91. package/src/entity-picker/entity-picker.tokens.json +118 -0
  92. package/src/event-calendar/event-calendar.css +2148 -0
  93. package/src/event-calendar/event-calendar.tokens.json +87 -0
  94. package/src/field/field.css +707 -0
  95. package/src/field/field.tokens.json +58 -0
  96. package/src/field-group/field-group.css +226 -0
  97. package/src/field-group/field-group.tokens.json +33 -0
  98. package/src/filter-bar/filter-bar.css +1306 -0
  99. package/src/filter-bar/filter-bar.tokens.json +78 -0
  100. package/src/form/form.css +218 -0
  101. package/src/form/form.tokens.json +32 -0
  102. package/src/fullscreen/fullscreen.css +376 -0
  103. package/src/fullscreen/fullscreen.tokens.json +50 -0
  104. package/src/grid/grid.css +173 -0
  105. package/src/grid/grid.tokens.json +20 -0
  106. package/src/highlight/highlight.css +135 -0
  107. package/src/highlight/highlight.tokens.json +16 -0
  108. package/src/hover-card/hover-card.css +93 -0
  109. package/src/hover-card/hover-card.tokens.json +17 -0
  110. package/src/icon/icon.css +136 -0
  111. package/src/icon/icon.tokens.json +14 -0
  112. package/src/image/image.css +449 -0
  113. package/src/image/image.tokens.json +27 -0
  114. package/src/import-export-center/import-export-center.css +1175 -0
  115. package/src/import-export-center/import-export-center.tokens.json +84 -0
  116. package/src/inline/inline.css +149 -0
  117. package/src/inline/inline.tokens.json +14 -0
  118. package/src/inline-message/inline-message.css +396 -0
  119. package/src/inline-message/inline-message.tokens.json +19 -0
  120. package/src/kbd/kbd.css +490 -0
  121. package/src/kbd/kbd.tokens.json +40 -0
  122. package/src/link/link.css +237 -0
  123. package/src/link/link.tokens.json +25 -0
  124. package/src/list/list.css +240 -0
  125. package/src/list/list.tokens.json +42 -0
  126. package/src/list-item/list-item.css +937 -0
  127. package/src/list-item/list-item.tokens.json +114 -0
  128. package/src/listbox/listbox.css +674 -0
  129. package/src/listbox/listbox.tokens.json +72 -0
  130. package/src/loading-overlay/loading-overlay.css +730 -0
  131. package/src/loading-overlay/loading-overlay.tokens.json +48 -0
  132. package/src/markdown/markdown.css +168 -0
  133. package/src/markdown/markdown.tokens.json +18 -0
  134. package/src/menu/menu.css +817 -0
  135. package/src/menu/menu.tokens.json +78 -0
  136. package/src/menubar/menubar.css +170 -0
  137. package/src/menubar/menubar.tokens.json +32 -0
  138. package/src/message/message.css +1453 -0
  139. package/src/message/message.tokens.json +85 -0
  140. package/src/message-scroller/message-scroller.css +371 -0
  141. package/src/message-scroller/message-scroller.tokens.json +47 -0
  142. package/src/multi-select/multi-select.css +1427 -0
  143. package/src/multi-select/multi-select.tokens.json +114 -0
  144. package/src/navigation-menu/navigation-menu.css +1029 -0
  145. package/src/navigation-menu/navigation-menu.tokens.json +70 -0
  146. package/src/notification-center/notification-center.css +856 -0
  147. package/src/notification-center/notification-center.tokens.json +84 -0
  148. package/src/number-field/number-field.css +794 -0
  149. package/src/number-field/number-field.tokens.json +80 -0
  150. package/src/otp-input/otp-input.css +525 -0
  151. package/src/otp-input/otp-input.tokens.json +69 -0
  152. package/src/page/page.css +179 -0
  153. package/src/page/page.tokens.json +20 -0
  154. package/src/page-header/page-header.css +1181 -0
  155. package/src/page-header/page-header.tokens.json +71 -0
  156. package/src/pagination/pagination.css +500 -0
  157. package/src/pagination/pagination.tokens.json +56 -0
  158. package/src/popover/popover.css +526 -0
  159. package/src/popover/popover.tokens.json +60 -0
  160. package/src/progress-indicator/progress-indicator.css +1584 -0
  161. package/src/progress-indicator/progress-indicator.tokens.json +50 -0
  162. package/src/prompt-composer/prompt-composer.css +680 -0
  163. package/src/prompt-composer/prompt-composer.tokens.json +99 -0
  164. package/src/prose/prose.css +733 -0
  165. package/src/prose/prose.tokens.json +79 -0
  166. package/src/radio-group/radio-group.css +778 -0
  167. package/src/radio-group/radio-group.tokens.json +103 -0
  168. package/src/rating/rating.css +1071 -0
  169. package/src/rating/rating.tokens.json +88 -0
  170. package/src/result-state/result-state.css +980 -0
  171. package/src/result-state/result-state.tokens.json +63 -0
  172. package/src/runtime-properties.mjs +321 -0
  173. package/src/saved-views/saved-views.css +394 -0
  174. package/src/saved-views/saved-views.tokens.json +41 -0
  175. package/src/scroll-area/scroll-area.css +481 -0
  176. package/src/scroll-area/scroll-area.tokens.json +15 -0
  177. package/src/section/section.css +177 -0
  178. package/src/section/section.tokens.json +39 -0
  179. package/src/segmented-control/segmented-control.css +564 -0
  180. package/src/segmented-control/segmented-control.tokens.json +67 -0
  181. package/src/select/select.css +1593 -0
  182. package/src/select/select.tokens.json +110 -0
  183. package/src/side-navigation/side-navigation.css +1096 -0
  184. package/src/side-navigation/side-navigation.tokens.json +87 -0
  185. package/src/skeleton/skeleton.css +431 -0
  186. package/src/skeleton/skeleton.tokens.json +29 -0
  187. package/src/slider/slider.css +792 -0
  188. package/src/slider/slider.tokens.json +75 -0
  189. package/src/sparkline/sparkline.css +282 -0
  190. package/src/sparkline/sparkline.tokens.json +45 -0
  191. package/src/spinner/spinner.css +224 -0
  192. package/src/spinner/spinner.tokens.json +8 -0
  193. package/src/split-button/split-button.css +253 -0
  194. package/src/split-button/split-button.tokens.json +12 -0
  195. package/src/splitter/splitter.css +336 -0
  196. package/src/splitter/splitter.tokens.json +24 -0
  197. package/src/stack/stack.css +128 -0
  198. package/src/stack/stack.tokens.json +14 -0
  199. package/src/stat-card/stat-card.css +641 -0
  200. package/src/stat-card/stat-card.tokens.json +95 -0
  201. package/src/status-indicator/status-indicator.css +481 -0
  202. package/src/status-indicator/status-indicator.tokens.json +38 -0
  203. package/src/stepper/stepper.css +629 -0
  204. package/src/stepper/stepper.tokens.json +72 -0
  205. package/src/switch/switch.css +703 -0
  206. package/src/switch/switch.tokens.json +75 -0
  207. package/src/table/table.css +1482 -0
  208. package/src/table/table.tokens.json +69 -0
  209. package/src/table-of-contents/table-of-contents.css +533 -0
  210. package/src/table-of-contents/table-of-contents.tokens.json +53 -0
  211. package/src/tabs/tabs.css +998 -0
  212. package/src/tabs/tabs.tokens.json +82 -0
  213. package/src/tag/tag.css +768 -0
  214. package/src/tag/tag.tokens.json +85 -0
  215. package/src/tags-input/tags-input.css +757 -0
  216. package/src/tags-input/tags-input.tokens.json +84 -0
  217. package/src/text-field/text-field.css +900 -0
  218. package/src/text-field/text-field.tokens.json +87 -0
  219. package/src/textarea/textarea.css +365 -0
  220. package/src/textarea/textarea.tokens.json +59 -0
  221. package/src/time-field/time-field.css +719 -0
  222. package/src/time-field/time-field.tokens.json +86 -0
  223. package/src/time-picker/time-picker.css +665 -0
  224. package/src/time-picker/time-picker.tokens.json +66 -0
  225. package/src/time-range-picker/time-range-picker.css +1287 -0
  226. package/src/time-range-picker/time-range-picker.tokens.json +134 -0
  227. package/src/timeline/timeline.css +1596 -0
  228. package/src/timeline/timeline.tokens.json +96 -0
  229. package/src/toast/toast.css +943 -0
  230. package/src/toast/toast.tokens.json +90 -0
  231. package/src/toggle/toggle.css +290 -0
  232. package/src/toggle/toggle.tokens.json +54 -0
  233. package/src/toggle-group/toggle-group.css +463 -0
  234. package/src/toggle-group/toggle-group.tokens.json +54 -0
  235. package/src/toolbar/toolbar.css +434 -0
  236. package/src/toolbar/toolbar.tokens.json +49 -0
  237. package/src/tooltip/tooltip.css +368 -0
  238. package/src/tooltip/tooltip.tokens.json +39 -0
  239. package/src/top-navigation/top-navigation.css +1287 -0
  240. package/src/top-navigation/top-navigation.tokens.json +91 -0
  241. package/src/tour/tour.css +680 -0
  242. package/src/tour/tour.tokens.json +67 -0
  243. package/src/transfer/transfer.css +571 -0
  244. package/src/transfer/transfer.tokens.json +49 -0
  245. package/src/tree/tree.css +1000 -0
  246. package/src/tree/tree.tokens.json +80 -0
  247. package/src/typography/typography.css +211 -0
  248. package/src/typography/typography.tokens.json +31 -0
  249. package/src/upload/upload.css +1706 -0
  250. package/src/upload/upload.tokens.json +123 -0
  251. package/src/visually-hidden/visually-hidden.css +52 -0
  252. package/src/visually-hidden/visually-hidden.tokens.json +1 -0
  253. package/src/wizard/wizard.css +740 -0
  254. package/src/wizard/wizard.tokens.json +63 -0
@@ -0,0 +1,1287 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * The bar across the top of an application: the mark, what the application
4
+ * is right now, the destinations, the search, and the global actions —
5
+ * reading its own width and folding by priority as the width goes.
6
+ *
7
+ * root ▸ skip · brand ▸ home ▸ mark · name
8
+ * · context
9
+ * · nav ▸ list ▸ item ▸ link | trigger ▸ indicator
10
+ * ▸ item ▸ more
11
+ * · panel ▸ context · panel-list ▸ item… · help
12
+ * · search ▸ … · search-close
13
+ * · actions ▸ search-toggle · help · notifications ▸ count · account
14
+ *
15
+ * ── The bar folds by container query ────────────────────────────────────
16
+ *
17
+ * Three literal steps, declared in the contract as `collapseAt` and compared
18
+ * by `top-navigation.styles.test.mjs`: below 1024 the low-priority items
19
+ * leave the list, below 600 the medium ones, the search becomes its toggle
20
+ * and the context moves to the panel, below 480 the high ones and the help
21
+ * go with them and the name leaves the eye. The stylesheet decides the whole picture from the
22
+ * width; the script that comes later writes `data-collapsed` from the same
23
+ * three numbers, counts what folded onto `more`, and moves the folded parts
24
+ * into the panel while it is open.
25
+ *
26
+ * ── The panel is the same DOM ───────────────────────────────────────────
27
+ *
28
+ * What folds is not rebuilt: the consumer's `li` is moved (Angular) or
29
+ * portalled (React) into `panel-list`, so a trigger keeps the menu wrapped
30
+ * around it and a link keeps the badge inside it. The panel stands inside
31
+ * the root and after `more` in DOM order, which is what lets Tab enter it.
32
+ *
33
+ * ── Geometry is the shell's where the shell is ──────────────────────────
34
+ *
35
+ * `brand` starts on `--slotted-app-shell-row-inset` so the shell's toggle
36
+ * and the mark stand over the marks in the navigation column, and the
37
+ * panel's rows read the row the shell publishes so a folded destination
38
+ * reads as the row it would be in `side-navigation`. Outside the shell the
39
+ * fallbacks are the control scale.
40
+ */
41
+ [data-ui='top-navigation'] {
42
+ --_control-height: var(--slotted-control-height-md, 34px);
43
+ --_control-padding: var(--slotted-control-padding-inline-md, 13px);
44
+ --_control-font-size: var(--slotted-control-font-size-md, 13px);
45
+ --_icon-size: var(--slotted-control-icon-size-md, 16px);
46
+ --_gap: var(--slotted-control-gap-md, 8px);
47
+ --_action-gap: var(--slotted-control-gap-sm, 6px);
48
+ /** The start inset the shell publishes; nothing outside it. */
49
+ --_row-inset: var(--slotted-app-shell-row-inset, 0px);
50
+ --_row-height: var(--slotted-app-shell-row-height, var(--slotted-control-height-md, 34px));
51
+ --_row-font-size: var(
52
+ --slotted-app-shell-row-font-size,
53
+ var(--slotted-font-size-sm, 0.8125rem)
54
+ );
55
+ --_row-line-height: var(
56
+ --slotted-app-shell-row-line-height,
57
+ var(--slotted-line-height-sm, 1.45)
58
+ );
59
+ --_inset: var(--slotted-top-navigation-inset, var(--slotted-space-5, 0.75rem));
60
+ --_block-size: var(
61
+ --slotted-top-navigation-block-size,
62
+ calc(var(--slotted-control-height-lg, 38px) + var(--slotted-space-5, 0.75rem) * 2)
63
+ );
64
+ --_radius: var(--slotted-top-navigation-radius, var(--slotted-control-radius, 4px));
65
+ --_name-font-size: var(
66
+ --slotted-top-navigation-name-font-size,
67
+ var(--slotted-font-size-md, 0.875rem)
68
+ );
69
+ --_name-max: var(--slotted-top-navigation-name-max, 16rem);
70
+ --_search-size: var(--slotted-top-navigation-search-size, 28rem);
71
+ /** The floor a field is still a field at: nine characters and the shortcut. */
72
+ --_search-min: var(--slotted-top-navigation-search-min, 10rem);
73
+ /** The inset a framed bar carries at both ends; nought inside the shell, which insets the banner itself. */
74
+ --_edge: 0px;
75
+ --_panel-size: var(--slotted-top-navigation-panel-size, 20rem);
76
+ --_mark-size: calc(var(--_control-height) - var(--slotted-space-2, 0.25rem) * 2);
77
+
78
+ --_surface: var(--slotted-top-navigation-surface, var(--slotted-surface, Canvas));
79
+ --_color: var(--slotted-top-navigation-color, var(--slotted-text, CanvasText));
80
+ --_muted-color: var(--slotted-top-navigation-muted-color, var(--slotted-text-muted, GrayText));
81
+ --_border-color: var(
82
+ --slotted-top-navigation-border-color,
83
+ var(--slotted-border-subtle, ButtonBorder)
84
+ );
85
+ --_hover-background: var(
86
+ --slotted-top-navigation-hover-background,
87
+ var(--slotted-tone-secondary-subtle-hover)
88
+ );
89
+ --_active-background: var(
90
+ --slotted-top-navigation-active-background,
91
+ var(--slotted-tone-secondary-subtle-active)
92
+ );
93
+ --_current-color: var(--slotted-top-navigation-current-color, var(--slotted-tone-accent-text));
94
+ --_current-background: var(
95
+ --slotted-top-navigation-current-background,
96
+ var(--slotted-tone-accent-surface)
97
+ );
98
+ /**
99
+ * The state is a pair, ground and edge, for the reason `side-navigation`
100
+ * gives: the foundation's `--slotted-current-edge` is transparent where the
101
+ * tone ground says the state and black in `high-contrast`, where every tone
102
+ * ground is the page's white. Drawn as an inset shadow, so nothing moves.
103
+ */
104
+ --_current-edge: var(
105
+ --slotted-top-navigation-current-edge,
106
+ var(--slotted-current-edge, transparent)
107
+ );
108
+ --_count-background: var(
109
+ --slotted-top-navigation-count-background,
110
+ var(--slotted-tone-accent-solid)
111
+ );
112
+ --_count-color: var(--slotted-top-navigation-count-color, var(--slotted-tone-accent-on-solid));
113
+ --_panel-surface: var(
114
+ --slotted-top-navigation-panel-surface,
115
+ var(--slotted-surface-raised, Canvas)
116
+ );
117
+ --_panel-shadow: var(--slotted-top-navigation-panel-shadow, var(--slotted-shadow-md));
118
+ --_panel-radius: var(--slotted-top-navigation-panel-radius, var(--slotted-radius-lg, 8px));
119
+ --_disabled-color: var(--slotted-disabled-foreground, GrayText);
120
+ --_rule-width: var(--slotted-border-width-thin, 1px);
121
+
122
+ --_duration: var(--slotted-control-transition-duration, var(--slotted-duration-short));
123
+ --_easing: var(--slotted-control-transition-easing, var(--slotted-easing-standard));
124
+
125
+ align-items: center;
126
+ box-sizing: border-box;
127
+ color: var(--_color);
128
+ container-name: slotted-top-navigation;
129
+ container-type: inline-size;
130
+ display: flex;
131
+ font-family: var(--slotted-control-font-family, inherit);
132
+ font-size: var(--_control-font-size);
133
+ gap: var(--_gap);
134
+ line-height: var(--slotted-control-line-height, 1);
135
+ min-block-size: var(--_control-height);
136
+ min-inline-size: 0;
137
+ /* The panel's containing block, and a flex item that fills the shell's banner. */
138
+ flex: 1 1 auto;
139
+ position: relative;
140
+ }
141
+
142
+ /**
143
+ * Standing alone the bar paints its own ground, a rule along its end edge
144
+ * and its own inset; inside the shell the banner already does all three,
145
+ * and the bar paints nothing over what the shell painted.
146
+ *
147
+ * The inset is not padding on the root. A container query resolves against
148
+ * the container's content box, and the width gate in the script measures
149
+ * the border box: with twelve pixels of padding a side the stylesheet folded
150
+ * at 1048 and the script at 1024, and a bar in a room of exactly 1024 drew
151
+ * `more` for two items the script said were in the list. So the root's
152
+ * content box is its border box, and the first and last clusters carry the
153
+ * edge — `--_edge`, nought inside the shell — beside the shell's row inset.
154
+ */
155
+ [data-ui='top-navigation'][data-frame] {
156
+ --_edge: var(--_inset);
157
+
158
+ background-color: var(--_surface);
159
+ border-block-end: var(--_rule-width) solid var(--_border-color);
160
+ min-block-size: var(--_block-size);
161
+ }
162
+
163
+ [data-ui='top-navigation'][data-size='sm'] {
164
+ --_control-height: var(--slotted-control-height-sm, 30px);
165
+ --_control-padding: var(--slotted-control-padding-inline-sm, 10px);
166
+ --_control-font-size: var(--slotted-control-font-size-sm, 12px);
167
+ --_icon-size: var(--slotted-control-icon-size-sm, 14px);
168
+ --_gap: var(--slotted-control-gap-sm, 6px);
169
+ --_action-gap: var(--slotted-control-gap-sm, 6px);
170
+ --_row-height: var(--slotted-control-height-sm, 30px);
171
+ --_row-font-size: var(--slotted-font-size-xs, 0.75rem);
172
+ --_row-line-height: var(--slotted-line-height-xs, 1.4);
173
+ --_name-font-size: var(
174
+ --slotted-top-navigation-name-font-size,
175
+ var(--slotted-font-size-sm, 0.8125rem)
176
+ );
177
+ --_block-size: var(
178
+ --slotted-top-navigation-block-size,
179
+ calc(var(--slotted-control-height-md, 34px) + var(--slotted-space-4, 0.5rem) * 2)
180
+ );
181
+ }
182
+
183
+ [data-ui='top-navigation'][data-size='lg'] {
184
+ --_control-height: var(--slotted-control-height-lg, 38px);
185
+ --_control-padding: var(--slotted-control-padding-inline-lg, 16px);
186
+ --_control-font-size: var(--slotted-control-font-size-lg, 14px);
187
+ --_icon-size: var(--slotted-control-icon-size-lg, 18px);
188
+ --_gap: var(--slotted-control-gap-lg, 8px);
189
+ --_action-gap: var(--slotted-control-gap-md, 8px);
190
+ --_row-height: var(--slotted-control-height-lg, 38px);
191
+ --_row-font-size: var(--slotted-font-size-md, 0.875rem);
192
+ --_row-line-height: var(--slotted-line-height-md, 1.5);
193
+ --_name-font-size: var(
194
+ --slotted-top-navigation-name-font-size,
195
+ var(--slotted-font-size-lg, 1rem)
196
+ );
197
+ --_block-size: var(
198
+ --slotted-top-navigation-block-size,
199
+ calc(var(--slotted-control-height-lg, 38px) + var(--slotted-space-6, 1rem) * 2)
200
+ );
201
+ }
202
+
203
+ /* ── The skip link ──────────────────────────────────────────────────────── */
204
+
205
+ /**
206
+ * Out of sight until it holds focus, and then a control at the start of the
207
+ * bar, on the bar's own ground: a reader tabbing into the page sees where
208
+ * they are before they see anything else.
209
+ */
210
+ [data-ui='top-navigation'] > [data-part='skip'] {
211
+ background-color: var(--_surface);
212
+ block-size: var(--_control-height);
213
+ border-radius: var(--_radius);
214
+ box-sizing: border-box;
215
+ clip-path: inset(50%);
216
+ color: var(--_color);
217
+ display: inline-flex;
218
+ align-items: center;
219
+ font-weight: var(--slotted-font-weight-semibold, 600);
220
+ inset-block-start: 50%;
221
+ inset-inline-start: var(--_edge);
222
+ padding-inline: var(--_control-padding);
223
+ position: absolute;
224
+ text-decoration: none;
225
+ translate: 0 -50%;
226
+ white-space: nowrap;
227
+ z-index: 1;
228
+ }
229
+
230
+ [data-ui='top-navigation'] > [data-part='skip']:focus-visible {
231
+ clip-path: none;
232
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
233
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
234
+ }
235
+
236
+ /* ── Brand ──────────────────────────────────────────────────────────────── */
237
+
238
+ /**
239
+ * The root part is named in the selector for one reason: `app-shell` styles
240
+ * its own brand cluster with a descendant selector,
241
+ * `[data-ui='app-shell'] [data-part='brand']`, which reaches this part when
242
+ * the bar stands in the shell's banner and clips `home` to a sliver at 240
243
+ * pixels. Naming the root outranks it. The shell's own reopening narrows
244
+ * that selector to its banner; until then the two declarations it leaks —
245
+ * the inset, and the overflow on every child — are restated here.
246
+ */
247
+ /**
248
+ * No `min-inline-size: 0` here: the cluster's minimum is its automatic one,
249
+ * the marks it holds, which `home` below contributes without the name. At
250
+ * nought it shrank under its own marks on a phone whose actions held seven
251
+ * touch-sized controls, and the marks spilled over the cluster beside it.
252
+ */
253
+ [data-ui='top-navigation'][data-part='root'] > [data-part='brand'] {
254
+ align-items: center;
255
+ display: flex;
256
+ flex: 0 1 auto;
257
+ font-weight: inherit;
258
+ gap: var(--_gap);
259
+ padding-inline-start: calc(var(--_edge) + var(--_row-inset));
260
+ }
261
+
262
+ [data-ui='top-navigation'][data-part='root'] > [data-part='brand'] > [data-part='home'] {
263
+ min-inline-size: var(--_control-height);
264
+ overflow: visible;
265
+ white-space: normal;
266
+ }
267
+
268
+ [data-ui='top-navigation'] [data-part='home'] {
269
+ align-items: center;
270
+ border-radius: var(--_radius);
271
+ color: var(--_color);
272
+ /*
273
+ * A grid of two tracks, the mark's and the name's, rather than a flex row.
274
+ * The name gives way to its ellipsis and, past it, to the mark alone —
275
+ * the mark never does. As a flex row that order could not be stated: a
276
+ * flex item's minimum is its content's contribution, which for a nowrap
277
+ * string is the whole string, so a floor on the name became a floor on
278
+ * the cluster and the bar overflowed at its end. A `minmax(0, 1fr)` track
279
+ * contributes nothing to the grid's min-content size, so the link's
280
+ * minimum is the mark's track and the name still shrinks to its ellipsis
281
+ * inside its own.
282
+ */
283
+ display: inline-grid;
284
+ flex: 0 1 auto;
285
+ gap: var(--_gap);
286
+ grid-template-columns: auto minmax(0, 1fr);
287
+ min-block-size: var(--_control-height);
288
+ /*
289
+ * A bar whose priorities leave it short of room loses the name before it
290
+ * loses a control, which is the order the name's own step at 480 already sets.
291
+ */
292
+ min-inline-size: var(--_control-height);
293
+ text-decoration: none;
294
+ }
295
+
296
+ [data-ui='top-navigation'] [data-part='home']:focus-visible {
297
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
298
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
299
+ }
300
+
301
+ /** A square the mark is centred in, the height of the bar's controls. */
302
+ [data-ui='top-navigation'] [data-part='mark'] {
303
+ align-items: center;
304
+ block-size: var(--_control-height);
305
+ display: inline-flex;
306
+ flex: 0 0 auto;
307
+ inline-size: var(--_control-height);
308
+ justify-content: center;
309
+ }
310
+
311
+ [data-ui='top-navigation'] [data-part='mark'] > :is(svg, img) {
312
+ block-size: var(--_mark-size);
313
+ inline-size: var(--_mark-size);
314
+ }
315
+
316
+ /**
317
+ * One line. It ends in an ellipsis rather than pushing the bar wider than
318
+ * the space there is — the rule `app-shell` states for its own brand.
319
+ */
320
+ [data-ui='top-navigation'] [data-part='name'] {
321
+ font-size: var(--_name-font-size);
322
+ font-weight: var(--slotted-font-weight-semibold, 600);
323
+ max-inline-size: var(--_name-max);
324
+ min-inline-size: 0;
325
+ overflow: hidden;
326
+ text-overflow: ellipsis;
327
+ white-space: nowrap;
328
+ }
329
+
330
+ /* ── Context ────────────────────────────────────────────────────────────── */
331
+
332
+ /**
333
+ * What gives way when the bar is short of room, and in which order: the
334
+ * search shrinks first, to the floor a field is still a field at; then the
335
+ * name, to its ellipsis. The context, the destinations and the actions keep
336
+ * their width — a workspace switcher wrapped one letter per line, which is
337
+ * what a shrinking cluster does to a button — and the steps below are what
338
+ * takes their room back.
339
+ */
340
+ [data-ui='top-navigation'] [data-part='context'] {
341
+ align-items: center;
342
+ display: flex;
343
+ flex: 0 0 auto;
344
+ gap: var(--_action-gap);
345
+ }
346
+
347
+ /* ── Navigation ─────────────────────────────────────────────────────────── */
348
+
349
+ /**
350
+ * The nav part is also a `navigation-menu` root, which declares private
351
+ * variables of the same names on the same element. The bar's own values are
352
+ * inherited back, so the bar's rows and the sections' panels read the bar's
353
+ * tokens — one bar, one set of decisions.
354
+ */
355
+ [data-ui='top-navigation'] [data-part='nav'] {
356
+ --_control-height: inherit;
357
+ --_control-padding: inherit;
358
+ --_control-font-size: inherit;
359
+ --_icon-size: inherit;
360
+ --_gap: inherit;
361
+ --_radius: inherit;
362
+ --_color: inherit;
363
+ --_muted-color: inherit;
364
+ --_hover-background: inherit;
365
+ --_active-background: inherit;
366
+ --_current-color: inherit;
367
+ --_current-background: inherit;
368
+ --_current-edge: inherit;
369
+ --_disabled-color: inherit;
370
+ --_duration: inherit;
371
+ --_easing: inherit;
372
+
373
+ display: flex;
374
+ flex: 0 0 auto;
375
+ }
376
+
377
+ [data-ui='top-navigation'] [data-part='list'] {
378
+ align-items: center;
379
+ display: flex;
380
+ gap: var(--slotted-space-1, 0.125rem);
381
+ list-style: none;
382
+ margin: 0;
383
+ min-inline-size: 0;
384
+ padding: 0;
385
+ }
386
+
387
+ [data-ui='top-navigation'] [data-part='item'] {
388
+ display: flex;
389
+ flex: 0 0 auto;
390
+ min-inline-size: 0;
391
+ }
392
+
393
+ /**
394
+ * A destination and a section share one row: the control's height and
395
+ * inset, the page's ink at rest and a ground under the pointer. The ink is
396
+ * the page's rather than the muted step because a disabled row has to read
397
+ * as one beside its neighbours, and the disabled ink is one step from the
398
+ * muted ink in `light`; the icon-only controls stay muted, the way Carbon's
399
+ * global actions do, because a mark carries less weight than a word.
400
+ */
401
+ [data-ui='top-navigation']
402
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
403
+ > [data-part='item']
404
+ > :is([data-part='link'], [data-part='trigger']) {
405
+ align-items: center;
406
+ appearance: none;
407
+ background-color: transparent;
408
+ border: 0;
409
+ border-radius: var(--_radius);
410
+ box-sizing: border-box;
411
+ color: var(--_color);
412
+ cursor: pointer;
413
+ display: inline-flex;
414
+ font: inherit;
415
+ font-weight: var(--slotted-font-weight-medium, 500);
416
+ gap: var(--_action-gap);
417
+ margin: 0;
418
+ min-block-size: var(--_control-height);
419
+ padding-block: 0;
420
+ padding-inline: var(--_control-padding);
421
+ text-decoration: none;
422
+ transition:
423
+ background-color var(--_duration) var(--_easing),
424
+ color var(--_duration) var(--_easing);
425
+ white-space: nowrap;
426
+ }
427
+
428
+ [data-ui='top-navigation']
429
+ [data-part='item']:not([data-disabled])
430
+ > [data-part='link']:not([data-current], [aria-current='page']):hover,
431
+ [data-ui='top-navigation']
432
+ [data-part='item']:not([data-disabled])
433
+ > [data-part='trigger']:enabled:hover {
434
+ background-color: var(--_hover-background);
435
+ color: var(--_color);
436
+ }
437
+
438
+ [data-ui='top-navigation']
439
+ [data-part='item']:not([data-disabled])
440
+ > [data-part='link']:not([data-current], [aria-current='page']):active,
441
+ [data-ui='top-navigation']
442
+ [data-part='item']:not([data-disabled])
443
+ > [data-part='trigger']:enabled:active {
444
+ background-color: var(--_active-background);
445
+ color: var(--_color);
446
+ transition-duration: var(--slotted-duration-instant);
447
+ }
448
+
449
+ /**
450
+ * A section that is open holds the ground the pointer gave it. `data-open`
451
+ * is written on the trigger by the consumer's `menu`, whose trigger the
452
+ * family's part is rendered as, so the family wires nothing for it.
453
+ */
454
+ [data-ui='top-navigation']
455
+ [data-part='item']:not([data-disabled])
456
+ > [data-part='trigger'][data-open]:enabled {
457
+ background-color: var(--_hover-background);
458
+ color: var(--_color);
459
+ }
460
+
461
+ /**
462
+ * Current by the family's own attribute, or by the `aria-current` a router
463
+ * wrote on the anchor it rendered: React cannot read the DOM back, so a
464
+ * router link rendered through `render` says where the reader is in the one
465
+ * attribute it owns, and the stylesheet reads it as the same state.
466
+ */
467
+ [data-ui='top-navigation']
468
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
469
+ > [data-part='item']
470
+ > [data-part='link']:is([data-current], [aria-current='page']) {
471
+ background-color: var(--_current-background);
472
+ box-shadow: inset 0 0 0 var(--_rule-width) var(--_current-edge);
473
+ color: var(--_current-color);
474
+ font-weight: var(--slotted-font-weight-semibold, 600);
475
+ }
476
+
477
+ [data-ui='top-navigation']
478
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
479
+ > [data-part='item'][data-disabled]
480
+ > [data-part='link'],
481
+ [data-ui='top-navigation']
482
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
483
+ > [data-part='item']
484
+ > [data-part='trigger']:disabled {
485
+ color: var(--_disabled-color);
486
+ cursor: not-allowed;
487
+ }
488
+
489
+ [data-ui='top-navigation']
490
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
491
+ > [data-part='item']
492
+ > :is([data-part='link'], [data-part='trigger']):focus-visible {
493
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
494
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
495
+ }
496
+
497
+ /**
498
+ * The chevron says a section opens below the bar — the promise `select`
499
+ * makes with the same mark — and turns half a turn while it is open. It is
500
+ * the `chevron-down` Glyph element the binding renders in the part. Down is
501
+ * down in both directions, so its box is not `directional`.
502
+ */
503
+ [data-ui='top-navigation']
504
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
505
+ > [data-part='item']
506
+ > [data-part='trigger']
507
+ > [data-part='indicator'] {
508
+ --slotted-icon-size: var(--_icon-size);
509
+
510
+ display: flex;
511
+ flex: 0 0 auto;
512
+ margin-inline-end: calc(-1 * var(--slotted-space-2, 0.25rem));
513
+ }
514
+
515
+ [data-ui='top-navigation']
516
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
517
+ > [data-part='item']
518
+ > [data-part='trigger']
519
+ > [data-part='indicator']
520
+ > [data-ui='icon'] {
521
+ transition: rotate var(--slotted-duration-medium) var(--_easing);
522
+ }
523
+
524
+ [data-ui='top-navigation']
525
+ [data-part='trigger'][data-open]
526
+ > [data-part='indicator']
527
+ > [data-ui='icon'] {
528
+ rotate: 0.5turn;
529
+ }
530
+
531
+ /* ── Icon-only controls ─────────────────────────────────────────────────── */
532
+
533
+ /**
534
+ * One shape for every control the family draws a mark on: a square the
535
+ * control's height, no frame at rest, the ground under the pointer, the
536
+ * mark a Glyph element the binding renders in the control's own ink.
537
+ * `action` is the same shape for a global control the family did not
538
+ * foresee — approvals, tasks — with the consumer's own glyph where the
539
+ * family's would be, so the cluster is one row of equals and not four of
540
+ * the family's beside three of another.
541
+ */
542
+ [data-ui='top-navigation']
543
+ :is(
544
+ [data-part='more'],
545
+ [data-part='search-toggle'],
546
+ [data-part='search-close'],
547
+ [data-part='help'],
548
+ [data-part='notifications'],
549
+ [data-part='account'],
550
+ [data-part='action']
551
+ ) {
552
+ align-items: center;
553
+ appearance: none;
554
+ background-color: transparent;
555
+ border: 0;
556
+ border-radius: var(--_radius);
557
+ box-sizing: border-box;
558
+ color: var(--_muted-color);
559
+ cursor: pointer;
560
+ display: inline-flex;
561
+ flex: 0 0 auto;
562
+ font: inherit;
563
+ font-weight: var(--slotted-font-weight-medium, 500);
564
+ gap: var(--_action-gap);
565
+ justify-content: center;
566
+ margin: 0;
567
+ min-block-size: var(--_control-height);
568
+ min-inline-size: var(--_control-height);
569
+ padding: 0;
570
+ position: relative;
571
+ text-decoration: none;
572
+ transition:
573
+ background-color var(--_duration) var(--_easing),
574
+ color var(--_duration) var(--_easing);
575
+ white-space: nowrap;
576
+ }
577
+
578
+ /**
579
+ * The family's marks — `ellipsis`, `search`, `x`, `circle-question` and
580
+ * `bell` — are sized by the control they stand in.
581
+ */
582
+ [data-ui='top-navigation']
583
+ :is(
584
+ [data-part='more'],
585
+ [data-part='search-toggle'],
586
+ [data-part='search-close'],
587
+ [data-part='help'],
588
+ [data-part='notifications']
589
+ ) {
590
+ --slotted-icon-size: var(--_icon-size);
591
+ }
592
+
593
+ /**
594
+ * The glyph inside an action is the consumer's, and the control sizes it:
595
+ * an icon box reads `--slotted-icon-size` from the control, a bare glyph
596
+ * host such as `ng-icon` reads the font-size the child rule gives it. The
597
+ * count stands out of the flow and is not the glyph.
598
+ */
599
+ [data-ui='top-navigation'] [data-part='action'] {
600
+ --slotted-icon-size: var(--_icon-size);
601
+ }
602
+
603
+ [data-ui='top-navigation'] [data-part='action'] > :not([data-part='count']) {
604
+ block-size: var(--_icon-size);
605
+ flex: 0 0 auto;
606
+ font-size: var(--_icon-size);
607
+ inline-size: var(--_icon-size);
608
+ }
609
+
610
+ [data-ui='top-navigation']
611
+ :is(
612
+ [data-part='more'],
613
+ [data-part='search-toggle'],
614
+ [data-part='search-close'],
615
+ [data-part='notifications'],
616
+ [data-part='account']
617
+ ):enabled:hover,
618
+ [data-ui='top-navigation']
619
+ a:is([data-part='help'], [data-part='action']):not([data-disabled]):hover,
620
+ [data-ui='top-navigation'] button:is([data-part='help'], [data-part='action']):enabled:hover {
621
+ background-color: var(--_hover-background);
622
+ color: var(--_color);
623
+ }
624
+
625
+ [data-ui='top-navigation']
626
+ :is(
627
+ [data-part='more'],
628
+ [data-part='search-toggle'],
629
+ [data-part='search-close'],
630
+ [data-part='notifications'],
631
+ [data-part='account']
632
+ ):enabled:active,
633
+ [data-ui='top-navigation']
634
+ a:is([data-part='help'], [data-part='action']):not([data-disabled]):active,
635
+ [data-ui='top-navigation'] button:is([data-part='help'], [data-part='action']):enabled:active {
636
+ background-color: var(--_active-background);
637
+ color: var(--_color);
638
+ transition-duration: var(--slotted-duration-instant);
639
+ }
640
+
641
+ /** A control whose layer is open holds the ground the pointer gave it. */
642
+ [data-ui='top-navigation']
643
+ :is(
644
+ [data-part='more'],
645
+ [data-part='notifications'],
646
+ [data-part='account'],
647
+ [data-part='help'],
648
+ [data-part='action']
649
+ )[data-open] {
650
+ background-color: var(--_hover-background);
651
+ color: var(--_color);
652
+ }
653
+
654
+ [data-ui='top-navigation']
655
+ :is(
656
+ [data-part='more'],
657
+ [data-part='search-toggle'],
658
+ [data-part='search-close'],
659
+ [data-part='help'],
660
+ [data-part='notifications'],
661
+ [data-part='account'],
662
+ [data-part='action']
663
+ ):focus-visible {
664
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
665
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
666
+ }
667
+
668
+ [data-ui='top-navigation']
669
+ :is(
670
+ [data-part='more'],
671
+ [data-part='search-toggle'],
672
+ [data-part='search-close'],
673
+ [data-part='notifications'],
674
+ [data-part='account']
675
+ ):disabled,
676
+ [data-ui='top-navigation'] button:is([data-part='help'], [data-part='action']):disabled {
677
+ color: var(--_disabled-color);
678
+ cursor: not-allowed;
679
+ }
680
+
681
+ /** The folded destination is where the reader is: `more` says so the way a closed parent does. */
682
+ [data-ui='top-navigation'] [data-part='more'][data-current] {
683
+ color: var(--_current-color);
684
+ }
685
+
686
+ /**
687
+ * The account is a pill: the consumer's avatar inside a halo of one space
688
+ * step, and, when there is room, a name after it. The halo is the space the
689
+ * pointer's ground keeps between the control's edge and the avatar's edge,
690
+ * and the avatar the bar expects is one step under the control — `xs` at
691
+ * `md` — which is what leaves the halo whole inside the control's height.
692
+ */
693
+ [data-ui='top-navigation'] [data-part='account'] {
694
+ border-radius: var(--slotted-radius-full, 9999px);
695
+ gap: var(--slotted-space-3, 0.375rem);
696
+ padding: var(--slotted-space-2, 0.25rem);
697
+ }
698
+
699
+ [data-ui='top-navigation'] [data-part='account'] > :not([data-ui='avatar']) {
700
+ padding-inline-end: var(--slotted-space-3, 0.375rem);
701
+ }
702
+
703
+ /**
704
+ * The count of what is waiting, over the bell's top-end corner: a disc for
705
+ * one digit and a pill from two, knocked out of the bar's ground by a ring
706
+ * so it reads over the bell's edge. It stands out of the flow, so it adds
707
+ * nothing to the control's width — the control is the bell's box, like the
708
+ * boxes beside it — and a third digit grows away from the bell, over the gap,
709
+ * where the control beside it holds no ink. Tabular figures, so a count that
710
+ * goes from 9 to 10 does not shift the ring.
711
+ *
712
+ * The count is type, and it is sized as the type it is, the way `badge`
713
+ * sizes a count: the control scale's small step — which is the step that
714
+ * moves with density — on a disc the height of that type's line, with a
715
+ * space step of inset on either side of the figures. Sized as a fraction of
716
+ * the bell instead, it was 14 pixels holding 10-pixel semibold figures with
717
+ * two pixels of inset, and the figures were crushed against the edge.
718
+ *
719
+ * A block container rather than a flex one: a flex container centres the
720
+ * line box, which is not symmetric around the figures inside it, and the
721
+ * figures sat high. `align-content` centres the one line, and the trim
722
+ * below makes that line the ink.
723
+ */
724
+ [data-ui='top-navigation'] [data-part='count'] {
725
+ --_count-font: var(--slotted-control-font-size-sm, 12px);
726
+ --_count-size: calc(var(--_count-font) * var(--slotted-line-height-xs, 1.4));
727
+ --_count-inset: calc((var(--_control-height) - var(--_icon-size)) / 2);
728
+ align-content: center;
729
+ background-color: var(--_count-background);
730
+ block-size: var(--_count-size);
731
+ border-radius: var(--slotted-radius-full, 9999px);
732
+ box-shadow: 0 0 0 var(--slotted-border-width-thick, 2px) var(--_surface);
733
+ box-sizing: border-box;
734
+ color: var(--_count-color);
735
+ display: block;
736
+ font-size: var(--_count-font);
737
+ font-variant-numeric: tabular-nums;
738
+ font-weight: var(--slotted-font-weight-semibold, 600);
739
+ inset-block-start: calc(var(--_count-inset) - var(--_count-size) / 2);
740
+ /* Its centre on the bell's top-end corner, so the disc covers a corner of the mark and no more; a pill of three ends inside the account's halo. */
741
+ inset-inline-start: calc(100% - var(--_count-inset) - var(--_count-size) / 2);
742
+ line-height: 1;
743
+ min-inline-size: var(--_count-size);
744
+ padding-inline: var(--slotted-space-2, 0.25rem);
745
+ pointer-events: none;
746
+ position: absolute;
747
+ text-align: center;
748
+ white-space: nowrap;
749
+ z-index: 1;
750
+ }
751
+
752
+ /** What is centred is the ink rather than the font's metrics, as `badge` and `avatar` do it. */
753
+ @supports (text-box: trim-both cap alphabetic) {
754
+ [data-ui='top-navigation'] [data-part='count'] {
755
+ text-box: trim-both cap alphabetic;
756
+ }
757
+ }
758
+
759
+ /* ── Search ─────────────────────────────────────────────────────────────── */
760
+
761
+ /**
762
+ * The one thing in the bar that grows: it takes the middle, up to the
763
+ * measure a search field is read at, and gives way before anything else
764
+ * does. What stands inside it is the consumer's field.
765
+ *
766
+ * It stands at the start of the middle, and the free space is between it
767
+ * and the actions. It was centred in that space, and the two end clusters
768
+ * are never the same width, so the field stood off the bar's centre by half
769
+ * their difference — twenty pixels in the first demo capture, aligned with
770
+ * nothing. Centring on the bar itself needs the two clusters laid out as
771
+ * one grid track each, which is not this family's tree; what a field at the
772
+ * start of the middle aligns with is the brand it follows.
773
+ */
774
+ [data-ui='top-navigation'] [data-part='search'] {
775
+ align-items: center;
776
+ display: flex;
777
+ /* A shrink weight far above the brand's, so the field gives way to its
778
+ floor before the name gives up a letter: flex shares a deficit by weight
779
+ and basis, not in order, and the weight is how an order is stated. Four
780
+ orders of magnitude, because the brand's share of a deficit is what is
781
+ left after the weight, and at a hundred it was four tenths of a pixel —
782
+ enough to overflow the name's box and draw an ellipsis over a whole name. */
783
+ flex: 1 10000 var(--_search-size);
784
+ gap: var(--_action-gap);
785
+ margin-inline: 0 auto;
786
+ max-inline-size: var(--_search-size);
787
+ min-inline-size: var(--_search-min);
788
+ }
789
+
790
+ [data-ui='top-navigation'] [data-part='search'] > :not([data-part='search-close']) {
791
+ flex: 1 1 auto;
792
+ min-inline-size: 0;
793
+ }
794
+
795
+ /** The toggle and the close exist for the narrow bar alone. */
796
+ [data-ui='top-navigation'] [data-part='search-toggle'],
797
+ [data-ui='top-navigation'] [data-part='search-close'] {
798
+ display: none;
799
+ }
800
+
801
+ /* ── Actions ────────────────────────────────────────────────────────────── */
802
+
803
+ [data-ui='top-navigation'] [data-part='actions'] {
804
+ align-items: center;
805
+ display: flex;
806
+ flex: 0 0 auto;
807
+ gap: var(--_action-gap);
808
+ margin-inline-start: auto;
809
+ padding-inline-end: calc(var(--_edge) + var(--_row-inset));
810
+ }
811
+
812
+ /* ── More, and the panel ────────────────────────────────────────────────── */
813
+
814
+ /**
815
+ * Hidden while nothing folds. The container queries below show it as soon
816
+ * as the list holds an item of a priority that has folded; the script
817
+ * shows it by the count it writes, which is what a list whose folded items
818
+ * have all moved into the panel is left with.
819
+ */
820
+ [data-ui='top-navigation'] [data-part='item']:has(> [data-part='more']) {
821
+ display: none;
822
+ }
823
+
824
+ [data-ui='top-navigation'] [data-part='item']:has(> [data-part='more'][data-overflow]) {
825
+ display: flex;
826
+ }
827
+
828
+ /**
829
+ * Under the bar's end edge, on a raised ground, the width a column of
830
+ * destinations is read at. It stays in the DOM closed — out of sight and
831
+ * out of the tab order by `visibility` — so opening is a transition from a
832
+ * style the browser has already computed, and closing leaves from wherever
833
+ * the panel is. It arrives from one step above its place (R7).
834
+ */
835
+ [data-ui='top-navigation'] [data-part='panel'] {
836
+ --_enter-distance: var(--slotted-space-2, 0.25rem);
837
+
838
+ background-color: var(--_panel-surface);
839
+ border: var(--_rule-width) solid var(--_border-color);
840
+ border-radius: var(--_panel-radius);
841
+ box-shadow: var(--_panel-shadow);
842
+ box-sizing: border-box;
843
+ color: var(--_color);
844
+ display: flex;
845
+ flex-direction: column;
846
+ gap: var(--slotted-space-2, 0.25rem);
847
+ inline-size: var(--_panel-size);
848
+ inset-block-start: calc(100% + var(--slotted-space-2, 0.25rem));
849
+ inset-inline-end: var(--_edge);
850
+ max-inline-size: 100%;
851
+ opacity: 0;
852
+ padding: var(--slotted-space-2, 0.25rem);
853
+ position: absolute;
854
+ transition:
855
+ opacity var(--slotted-duration-short) var(--slotted-easing-exit),
856
+ translate var(--slotted-duration-short) var(--slotted-easing-exit),
857
+ visibility var(--slotted-duration-short) step-end;
858
+ translate: 0 calc(-1 * var(--_enter-distance));
859
+ visibility: hidden;
860
+ z-index: calc(var(--slotted-z-index-popover, 1100) + var(--slotted-layer-depth, 0));
861
+ }
862
+
863
+ [data-ui='top-navigation'] [data-part='panel'][data-open] {
864
+ opacity: 1;
865
+ transition:
866
+ opacity var(--slotted-duration-medium) var(--slotted-easing-enter),
867
+ translate var(--slotted-duration-medium) var(--slotted-easing-enter),
868
+ visibility var(--slotted-duration-medium) step-start;
869
+ translate: 0 0;
870
+ visibility: visible;
871
+ }
872
+
873
+ [data-ui='top-navigation'] [data-part='panel-list'] {
874
+ display: flex;
875
+ flex-direction: column;
876
+ gap: var(--slotted-space-1, 0.125rem);
877
+ list-style: none;
878
+ margin: 0;
879
+ padding: 0;
880
+ }
881
+
882
+ [data-ui='top-navigation'] [data-part='panel-list']:empty {
883
+ display: none;
884
+ }
885
+
886
+ /**
887
+ * A folded destination is a row of the column: the shell's row height and
888
+ * type, the whole width, the label at the start. A section trigger in the
889
+ * panel keeps its chevron at the end of the row.
890
+ */
891
+ [data-ui='top-navigation'] [data-part='panel'] [data-part='item'] {
892
+ display: flex;
893
+ flex: 0 0 auto;
894
+ }
895
+
896
+ [data-ui='top-navigation']
897
+ [data-part='panel-list']
898
+ > [data-part='item']
899
+ > :is([data-part='link'], [data-part='trigger']),
900
+ [data-ui='top-navigation'] [data-part='panel'] > [data-part='help'] {
901
+ flex: 1 1 auto;
902
+ font-size: var(--_row-font-size);
903
+ justify-content: flex-start;
904
+ line-height: var(--_row-line-height);
905
+ min-block-size: var(--_row-height);
906
+ padding-inline: var(--_control-padding);
907
+ white-space: normal;
908
+ }
909
+
910
+ [data-ui='top-navigation']
911
+ [data-part='panel-list']
912
+ > [data-part='item']
913
+ > [data-part='trigger']
914
+ > [data-part='indicator'] {
915
+ margin-inline-end: 0;
916
+ margin-inline-start: auto;
917
+ }
918
+
919
+ /**
920
+ * A section folded into the panel opens its links in line under its
921
+ * trigger, as a group of the column does: the shared surface belongs to
922
+ * the bar's row, and a panel floating out of a panel is a second layer the
923
+ * reader did not ask for. The rows read the row geometry the folded links
924
+ * already read.
925
+ */
926
+ [data-ui='top-navigation']
927
+ [data-part='panel-list']
928
+ > [data-part='item']:has(> [data-part='content']) {
929
+ align-items: stretch;
930
+ flex-direction: column;
931
+ }
932
+
933
+ [data-ui='top-navigation'] [data-part='panel-list'] > [data-part='item'] > [data-part='content'] {
934
+ display: grid;
935
+ gap: var(--slotted-space-1, 0.125rem);
936
+ padding-block-end: var(--slotted-space-2, 0.25rem);
937
+ padding-inline-start: var(--_control-padding);
938
+ }
939
+
940
+ [data-ui='top-navigation']
941
+ [data-part='panel-list']
942
+ > [data-part='item']
943
+ > [data-part='content'][hidden] {
944
+ display: none;
945
+ }
946
+
947
+ [data-ui='top-navigation'] [data-part='panel-list'] [data-part='content'] [data-part='links'] {
948
+ display: grid;
949
+ gap: var(--slotted-space-1, 0.125rem);
950
+ list-style: none;
951
+ margin: 0;
952
+ padding: 0;
953
+ }
954
+
955
+ [data-ui='top-navigation'] [data-part='panel-list'] [data-part='content'] [data-part='link'] {
956
+ align-content: center;
957
+ border-radius: var(--_radius);
958
+ color: var(--_color);
959
+ column-gap: var(--_action-gap);
960
+ display: grid;
961
+ font-size: var(--_row-font-size);
962
+ grid-template-columns: auto minmax(0, 1fr);
963
+ line-height: var(--_row-line-height);
964
+ min-block-size: var(--_row-height);
965
+ padding-inline: var(--_control-padding);
966
+ text-decoration: none;
967
+ transition: background-color var(--_duration) var(--_easing);
968
+ }
969
+
970
+ [data-ui='top-navigation']
971
+ [data-part='panel-list']
972
+ [data-part='content']
973
+ [data-part='link']:not([data-disabled], [data-current], [aria-current='page']):hover {
974
+ background-color: var(--_hover-background);
975
+ }
976
+
977
+ [data-ui='top-navigation']
978
+ [data-part='panel-list']
979
+ [data-part='content']
980
+ [data-part='link']:not([data-disabled], [data-current], [aria-current='page']):active {
981
+ background-color: var(--_active-background);
982
+ transition-duration: var(--slotted-duration-instant);
983
+ }
984
+
985
+ [data-ui='top-navigation']
986
+ [data-part='panel-list']
987
+ [data-part='content']
988
+ [data-part='link']:is([data-current], [aria-current='page']) {
989
+ background-color: var(--_current-background);
990
+ box-shadow: inset 0 0 0 var(--_rule-width) var(--_current-edge);
991
+ color: var(--_current-color);
992
+ }
993
+
994
+ [data-ui='top-navigation']
995
+ [data-part='panel-list']
996
+ [data-part='content']
997
+ [data-part='link'][data-disabled] {
998
+ color: var(--_disabled-color);
999
+ cursor: not-allowed;
1000
+ }
1001
+
1002
+ [data-ui='top-navigation']
1003
+ [data-part='panel-list']
1004
+ [data-part='content']
1005
+ [data-part='link']:focus-visible {
1006
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color, Highlight);
1007
+ outline-offset: calc(var(--slotted-focus-ring-width, 2px) * -1);
1008
+ }
1009
+
1010
+ /** A link of plain words, or a rich one with no mark, starts its text at the inset. */
1011
+ [data-ui='top-navigation']
1012
+ [data-part='panel-list']
1013
+ [data-part='content']
1014
+ [data-part='link']:not(:has(> [data-part='icon']))
1015
+ > * {
1016
+ grid-column: 1 / -1;
1017
+ }
1018
+
1019
+ [data-ui='top-navigation'] [data-part='panel-list'] [data-part='content'] [data-part='icon'] {
1020
+ --slotted-icon-size: var(--_icon-size);
1021
+
1022
+ color: var(--_muted-color);
1023
+ display: flex;
1024
+ grid-row: 1 / span 2;
1025
+ }
1026
+
1027
+ [data-ui='top-navigation']
1028
+ [data-part='panel-list']
1029
+ [data-part='content']
1030
+ [data-part='description'] {
1031
+ color: var(--_muted-color);
1032
+ font-size: var(--slotted-font-size-xs, 0.75rem);
1033
+ grid-column: 2;
1034
+ }
1035
+
1036
+ [data-ui='top-navigation']
1037
+ [data-part='panel-list']
1038
+ [data-part='content']
1039
+ [data-part='group-label'] {
1040
+ color: var(--_muted-color);
1041
+ font-size: var(--slotted-font-size-xs, 0.75rem);
1042
+ font-weight: var(--slotted-font-weight-semibold, 600);
1043
+ padding-block: var(--slotted-space-2, 0.25rem);
1044
+ padding-inline: var(--_control-padding);
1045
+ }
1046
+
1047
+ [data-ui='top-navigation'] [data-part='panel-list'] [data-part='content'] [data-part='footer'] {
1048
+ align-items: center;
1049
+ border-block-start: var(--_rule-width) solid var(--_border-color);
1050
+ display: flex;
1051
+ gap: var(--_action-gap);
1052
+ justify-content: space-between;
1053
+ padding-block-start: var(--slotted-space-2, 0.25rem);
1054
+ padding-inline: var(--_control-padding);
1055
+ }
1056
+
1057
+ /**
1058
+ * Help's children are its label: pushed out of the box and clipped in the
1059
+ * bar, where the mark stands alone and the tooltip repeats the words, and
1060
+ * shown after the mark in the panel, where it is a row. One accessible name
1061
+ * in both places, from the same text. The words are a text node, which no
1062
+ * child selector reaches, so the box itself does the hiding.
1063
+ */
1064
+ [data-ui='top-navigation'] [data-part='actions'] > [data-part='help'] {
1065
+ gap: var(--_control-height);
1066
+ inline-size: var(--_control-height);
1067
+ justify-content: flex-start;
1068
+ overflow: hidden;
1069
+ padding-inline-start: calc((var(--_control-height) - var(--_icon-size)) / 2);
1070
+ }
1071
+
1072
+ [data-ui='top-navigation'] [data-part='panel'] > [data-part='help'] {
1073
+ gap: var(--_gap);
1074
+ }
1075
+
1076
+ [data-ui='top-navigation'] [data-part='panel'] > [data-part='context'] {
1077
+ padding: var(--slotted-space-2, 0.25rem) var(--slotted-space-3, 0.375rem);
1078
+ }
1079
+
1080
+ /**
1081
+ * The panel reads context, list, help whatever order they arrived in: React
1082
+ * renders each into the panel through a portal in the order the parts mount,
1083
+ * Angular moves them into place. The rules between the three are drawn on
1084
+ * the list and on help, from what the panel holds rather than from what
1085
+ * stands before them, for the same reason.
1086
+ */
1087
+ [data-ui='top-navigation'] [data-part='panel'] > [data-part='context'] {
1088
+ order: -1;
1089
+ }
1090
+
1091
+ [data-ui='top-navigation'] [data-part='panel'] > [data-part='help'] {
1092
+ order: 1;
1093
+ }
1094
+
1095
+ [data-ui='top-navigation']
1096
+ [data-part='panel']:has(> [data-part='context'])
1097
+ > [data-part='panel-list']:not(:empty),
1098
+ [data-ui='top-navigation']
1099
+ [data-part='panel']:has(> [data-part='panel-list']:not(:empty), > [data-part='context'])
1100
+ > [data-part='help'] {
1101
+ border-block-start: var(--_rule-width) solid var(--_border-color);
1102
+ padding-block-start: var(--slotted-space-2, 0.25rem);
1103
+ }
1104
+
1105
+ /* ── The bar folds ──────────────────────────────────────────────────────── */
1106
+
1107
+ /**
1108
+ * An item without a priority is a medium one, so the default folds where
1109
+ * the shell goes to overlay. `more` shows itself as soon as the list holds
1110
+ * an item of the priority that just folded, so a server render at a narrow
1111
+ * width already has the button.
1112
+ */
1113
+ @container slotted-top-navigation (inline-size < 1024px) {
1114
+ [data-ui='top-navigation'] [data-part='list'] > [data-part='item'][data-priority='low'] {
1115
+ display: none;
1116
+ }
1117
+
1118
+ [data-ui='top-navigation']
1119
+ [data-part='list']:has(> [data-part='item'][data-priority='low'])
1120
+ > [data-part='item']:has(> [data-part='more']) {
1121
+ display: flex;
1122
+ }
1123
+ }
1124
+
1125
+ @container slotted-top-navigation (inline-size < 600px) {
1126
+ [data-ui='top-navigation']
1127
+ [data-part='list']
1128
+ > [data-part='item']:not([data-priority='low']):not([data-priority='high']):not(
1129
+ :has(> [data-part='more'])
1130
+ ) {
1131
+ display: none;
1132
+ }
1133
+
1134
+ [data-ui='top-navigation']
1135
+ [data-part='list']:has(
1136
+ > [data-part='item']:not([data-priority='low']):not([data-priority='high']):not(
1137
+ :has(> [data-part='more'])
1138
+ )
1139
+ )
1140
+ > [data-part='item']:has(> [data-part='more']) {
1141
+ display: flex;
1142
+ }
1143
+
1144
+ /* The field gives way to its toggle; open, it takes the whole bar. */
1145
+ [data-ui='top-navigation']:not([data-search-open]) [data-part='search'] {
1146
+ display: none;
1147
+ }
1148
+
1149
+ [data-ui='top-navigation']:not([data-search-open]) [data-part='search-toggle'] {
1150
+ display: inline-flex;
1151
+ }
1152
+
1153
+ [data-ui='top-navigation'][data-search-open] [data-part='search'] {
1154
+ max-inline-size: none;
1155
+ padding-inline: var(--_edge);
1156
+ }
1157
+
1158
+ [data-ui='top-navigation'][data-search-open] [data-part='search-close'] {
1159
+ display: inline-flex;
1160
+ }
1161
+
1162
+ [data-ui='top-navigation'][data-search-open]
1163
+ > :is([data-part='brand'], [data-part='context'], [data-part='nav'], [data-part='actions']) {
1164
+ display: none;
1165
+ }
1166
+
1167
+ /* The account keeps its avatar and gives up the name beside it. */
1168
+ [data-ui='top-navigation'] [data-part='account'] > :not([data-ui='avatar']) {
1169
+ display: none;
1170
+ }
1171
+
1172
+ /* The context moves to the panel; in the bar it leaves, and `more` shows for it. */
1173
+ [data-ui='top-navigation'] > [data-part='context'] {
1174
+ display: none;
1175
+ }
1176
+
1177
+ [data-ui='top-navigation']:has(> [data-part='context'])
1178
+ [data-part='list']
1179
+ > [data-part='item']:has(> [data-part='more']) {
1180
+ display: flex;
1181
+ }
1182
+ }
1183
+
1184
+ @container slotted-top-navigation (inline-size < 480px) {
1185
+ /* Six controls in a row: the air between them is what gives way. */
1186
+ [data-ui='top-navigation'] {
1187
+ --_gap: var(--slotted-space-2, 0.25rem);
1188
+ --_action-gap: var(--slotted-space-2, 0.25rem);
1189
+ }
1190
+
1191
+ [data-ui='top-navigation'] [data-part='list'] > [data-part='item'][data-priority='high'] {
1192
+ display: none;
1193
+ }
1194
+
1195
+ [data-ui='top-navigation']
1196
+ [data-part='list']:has(> [data-part='item'][data-priority='high'])
1197
+ > [data-part='item']:has(> [data-part='more']) {
1198
+ display: flex;
1199
+ }
1200
+
1201
+ /**
1202
+ * With one space step between the controls, a pill of three anchored on
1203
+ * the bell's corner would reach the avatar. Here the count hangs from the
1204
+ * gap's far edge instead and grows toward the bell: the disc still sits on
1205
+ * the corner, and a pill covers the bell's top before it covers a control.
1206
+ */
1207
+ [data-ui='top-navigation'] [data-part='count'] {
1208
+ inset-inline-end: calc(var(--slotted-border-width-thick, 2px) - var(--_action-gap));
1209
+ inset-inline-start: auto;
1210
+ }
1211
+
1212
+ /* The name leaves the eye and not the DOM: `home` keeps its accessible name. */
1213
+ [data-ui='top-navigation'] [data-part='name'] {
1214
+ clip-path: inset(50%);
1215
+ inline-size: 1px;
1216
+ margin: 0;
1217
+ overflow: hidden;
1218
+ position: absolute;
1219
+ white-space: nowrap;
1220
+ }
1221
+
1222
+ /* Out of flow, the name leaves its track empty; one track, or the gap stays. */
1223
+ [data-ui='top-navigation'] [data-part='home'] {
1224
+ grid-template-columns: auto;
1225
+ }
1226
+
1227
+ /* Help moves to the panel; in the bar it leaves, and `more` shows for it. */
1228
+ [data-ui='top-navigation'] [data-part='actions'] > [data-part='help'] {
1229
+ display: none;
1230
+ }
1231
+
1232
+ [data-ui='top-navigation']:has([data-part='actions'] > [data-part='help'])
1233
+ [data-part='list']
1234
+ > [data-part='item']:has(> [data-part='more']) {
1235
+ display: flex;
1236
+ }
1237
+
1238
+ [data-ui='top-navigation'] [data-part='panel'] {
1239
+ inline-size: auto;
1240
+ inset-inline: var(--_edge);
1241
+ }
1242
+ }
1243
+
1244
+ /* ── Stillness ──────────────────────────────────────────────────────────── */
1245
+
1246
+ @media (prefers-reduced-motion: reduce) {
1247
+ [data-ui='top-navigation'] [data-part='panel'],
1248
+ [data-ui='top-navigation'] [data-part='panel'][data-open] {
1249
+ translate: 0 0;
1250
+ }
1251
+ }
1252
+
1253
+ /* ── Forced colours ─────────────────────────────────────────────────────── */
1254
+
1255
+ @media (forced-colors: active) {
1256
+ [data-ui='top-navigation']
1257
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
1258
+ > [data-part='item']
1259
+ > [data-part='link']:is([data-current], [aria-current='page']) {
1260
+ background-color: Highlight;
1261
+ color: HighlightText;
1262
+ forced-color-adjust: none;
1263
+ }
1264
+
1265
+ [data-ui='top-navigation'] [data-part='count'] {
1266
+ background-color: Highlight;
1267
+ color: HighlightText;
1268
+ forced-color-adjust: none;
1269
+ }
1270
+
1271
+ [data-ui='top-navigation']
1272
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
1273
+ > [data-part='item'][data-disabled]
1274
+ > [data-part='link'],
1275
+ [data-ui='top-navigation']
1276
+ :is([data-part='nav'] > [data-part='list'], [data-part='panel-list'])
1277
+ > [data-part='item']
1278
+ > [data-part='trigger']:disabled {
1279
+ color: GrayText;
1280
+ }
1281
+
1282
+ [data-ui='top-navigation'][data-frame],
1283
+ [data-ui='top-navigation'] [data-part='panel'] {
1284
+ border-color: CanvasText;
1285
+ }
1286
+ }
1287
+ }