@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,1071 @@
1
+ @layer slotted.components {
2
+ /**
3
+ * ── An ordinal value drawn as a row of symbols ─────────────────────────
4
+ *
5
+ * Three members share this sheet and `data-ui='rating'`:
6
+ *
7
+ * - `rating`, a `div role="radiogroup"` whose items each hold one native
8
+ * radio per value the reader can pick — two when the step is a half —
9
+ * under a star drawn by the `Glyph` element;
10
+ * - `ratingDisplay`, a `div role="img"` with the same items and no radio, a
11
+ * value the page reports; `data-variant='compact'` draws one star;
12
+ * - `ratingSummary`, `data-variant='summary'`, the aggregate of many ratings
13
+ * and the distribution across levels, whose levels may filter a list.
14
+ *
15
+ * How much of a star is lit is `--_fill`, from 0 to 1. The display reads it
16
+ * from `--slotted-rating-fill`, which the binding writes on each item. The
17
+ * input derives it here, from which radio is checked and which one is under
18
+ * the pointer, so the picture is the platform's state.
19
+ */
20
+ [data-ui='rating'][data-part='root'] {
21
+ /**
22
+ * The symbol does not follow density. The selection scale settled the same
23
+ * question for a checkbox: the thing the value is read from keeps its size,
24
+ * and density moves the text beside it. `md` is twenty pixels, the size
25
+ * ReUI, MUI and Mantine draw an input at; `sm` is the sixteen a product
26
+ * card reports with (ReUI `review-3`, `product-card-9`).
27
+ */
28
+ --_symbol: var(--slotted-rating-symbol-size, var(--slotted-space-7, 1.25rem));
29
+ --_font-size: var(--slotted-control-font-size-md, 13px);
30
+ --_gap: var(--slotted-control-gap-md, 8px);
31
+ /**
32
+ * The paint. A lit star is one solid shape in the tone's solid step; an
33
+ * unlit star is the same shape in the neutral ground a secondary control
34
+ * stands on — the Salesforce, Airbnb and Fluent reading, which draws the
35
+ * row as five equal marks of which some are lit, not as outlines beside
36
+ * solids.
37
+ *
38
+ * `--slotted-rating-edge` is the edge both shapes are stroked with:
39
+ * transparent in `light` and `dark`, black in `high-contrast`, where every
40
+ * tone ground is the page's white and the edge is what is left to draw the
41
+ * shape with. Only the theme knows which scheme it is painting, so the
42
+ * edge is a token of the component layer (`docs/token-foundation.md`,
43
+ * Rating edge).
44
+ */
45
+ --_on: var(--slotted-rating-lit-color, var(--slotted-tone-warning-solid));
46
+ --_off: var(--slotted-rating-empty-color, var(--slotted-tone-secondary-surface));
47
+ --_edge: var(--slotted-rating-edge, transparent);
48
+ --_off-edge: var(--_edge);
49
+ --_stroke: 1.5;
50
+ --_halo: var(--slotted-rating-hover-background, var(--slotted-tone-secondary-subtle-hover));
51
+ --_halo-active: var(
52
+ --slotted-rating-active-background,
53
+ var(--slotted-tone-secondary-subtle-active)
54
+ );
55
+
56
+ align-items: center;
57
+ color: var(--slotted-text, CanvasText);
58
+ /* Between the row of symbols, the value and the count; text that wraps
59
+ to a line of its own starts at the line's edge. */
60
+ column-gap: var(--_gap);
61
+ display: inline-flex;
62
+ flex-wrap: wrap;
63
+ /* The text is trimmed to its ink below, so a line it wraps onto needs the
64
+ air the line box used to give it. */
65
+ row-gap: var(--slotted-space-3, 0.375rem);
66
+ font-family: var(--slotted-control-font-family, system-ui, sans-serif);
67
+ font-size: var(--_font-size);
68
+ line-height: var(--slotted-line-height-md, 1.5);
69
+ max-inline-size: 100%;
70
+ vertical-align: middle;
71
+ }
72
+
73
+ /* ── Size ─────────────────────────────────────────────────────────────── */
74
+
75
+ [data-ui='rating'][data-part='root'][data-size='sm'] {
76
+ --_symbol: var(--slotted-rating-symbol-size, var(--slotted-space-6, 1rem));
77
+ --_font-size: var(--slotted-control-font-size-sm, 12px);
78
+ --_gap: var(--slotted-control-gap-sm, 6px);
79
+ }
80
+
81
+ [data-ui='rating'][data-part='root'][data-size='lg'] {
82
+ --_symbol: var(--slotted-rating-symbol-size, var(--slotted-space-8, 1.5rem));
83
+ --_font-size: var(--slotted-control-font-size-lg, 14px);
84
+ --_gap: var(--slotted-control-gap-lg, 8px);
85
+ }
86
+
87
+ /* ── Tone ─────────────────────────────────────────────────────────────── */
88
+
89
+ [data-ui='rating'][data-part='root'][data-tone='accent'] {
90
+ --_on: var(--slotted-rating-lit-color, var(--slotted-tone-accent-solid));
91
+ }
92
+
93
+ [data-ui='rating'][data-part='root'][data-tone='success'] {
94
+ --_on: var(--slotted-rating-lit-color, var(--slotted-tone-success-solid));
95
+ }
96
+
97
+ [data-ui='rating'][data-part='root'][data-tone='danger'] {
98
+ --_on: var(--slotted-rating-lit-color, var(--slotted-tone-danger-solid));
99
+ }
100
+
101
+ /* ── The row of symbols ───────────────────────────────────────────────── */
102
+
103
+ /**
104
+ * The symbols are one row that never breaks: a rating wrapped after its
105
+ * eighth star reads as eight of eight and then two more. When the row is
106
+ * wider than the space it is given it shrinks instead — every item stays
107
+ * square and the star inside it follows — and the text beside it is what
108
+ * moves to a line of its own.
109
+ *
110
+ * The display sets its symbols two pixels apart: Lucide draws the star
111
+ * inside a twenty-four unit box with a unit and a half of air a side, so two
112
+ * pixels between boxes reads as the five ReUI's rows read at.
113
+ */
114
+ [data-ui='rating'] [data-part='symbols'] {
115
+ column-gap: var(--slotted-rating-gap, var(--slotted-space-1, 0.125rem));
116
+ display: flex;
117
+ flex: 0 1 auto;
118
+ min-inline-size: 0;
119
+ }
120
+
121
+ /**
122
+ * The input's targets touch, so the air between two of them is inside them.
123
+ * A finger dragged along the row is the binding's to read, so the row keeps
124
+ * vertical panning for the page and takes the horizontal gesture.
125
+ */
126
+ [data-ui='rating'] [data-part='symbols']:has([data-part='input']) {
127
+ column-gap: 0;
128
+ touch-action: pan-y;
129
+ }
130
+
131
+ [data-ui='rating'] [data-part='item'] {
132
+ --_fill: var(--slotted-rating-fill, 0);
133
+ /*
134
+ * The curve of the next change of the lit share, read at the moment it
135
+ * starts: a rule that lights a symbol states the enter curve, and the rule
136
+ * it falls back to states the exit curve. A transition takes its timing
137
+ * from the state it moves to, so the curve follows the direction without
138
+ * a script telling it which way.
139
+ */
140
+ --_fill-easing: var(--slotted-easing-exit);
141
+ --_box: var(--_symbol);
142
+ --_air: 0px;
143
+
144
+ aspect-ratio: 1;
145
+ /* The star inside reads the item's width, so a shrunk item draws a
146
+ smaller star rather than clipping one. */
147
+ container-type: inline-size;
148
+ display: grid;
149
+ /* Stated, not a flex basis: under inline-size containment an item has no
150
+ width of its own, and a basis alone let the row shrink with room left. */
151
+ flex: 0 1 auto;
152
+ inline-size: var(--_box);
153
+ /* A reported value shrinks to half its size before the row overflows. */
154
+ min-inline-size: calc(var(--_symbol) / 2);
155
+ /* The symbols and the radios are stacked in one cell; the radios sit
156
+ under the symbols and take the pointer through them. */
157
+ isolation: isolate;
158
+ place-items: center;
159
+ position: relative;
160
+ }
161
+
162
+ /**
163
+ * An item of the input is a target, and the WCAG minimum is its floor,
164
+ * shrinking included: at `sm` and `md` the box is twenty-four pixels, at
165
+ * `lg` the symbol plus two pixels of air a side, twenty-eight.
166
+ */
167
+ [data-ui='rating'] [data-part='item']:has(> [data-part='input']) {
168
+ --_air: var(--slotted-space-1, 0.125rem);
169
+ --_box: max(var(--slotted-target-min, 24px), calc(var(--_symbol) + 2 * var(--_air)));
170
+
171
+ min-inline-size: var(--slotted-target-min, 24px);
172
+ }
173
+
174
+ [data-ui='rating'] :is([data-part='symbol'], [data-part='fill']) {
175
+ --_drawn: min(var(--_symbol), 100cqi - 2 * var(--_air));
176
+ --slotted-icon-size: var(--_drawn);
177
+
178
+ block-size: var(--_drawn);
179
+ display: flex;
180
+ grid-area: 1 / 1;
181
+ inline-size: var(--_drawn);
182
+ pointer-events: none;
183
+ transition: scale var(--slotted-duration-short) var(--slotted-easing-standard);
184
+ z-index: 2;
185
+ }
186
+
187
+ [data-ui='rating'] :is([data-part='symbol'], [data-part='fill']) svg {
188
+ stroke-width: var(--_stroke);
189
+ transition:
190
+ fill var(--slotted-control-transition-duration) var(--slotted-control-transition-easing),
191
+ stroke var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
192
+ }
193
+
194
+ [data-ui='rating'] [data-part='symbol'] svg {
195
+ fill: var(--_off);
196
+ stroke: var(--_off-edge);
197
+ }
198
+
199
+ /**
200
+ * The lit star is the same drawing, clipped from the inline-start edge to
201
+ * the share `--_fill` names; the clip moves on the medium step, so a value
202
+ * that changes by three stars is seen travelling rather than swapped.
203
+ */
204
+ [data-ui='rating'] [data-part='fill'] {
205
+ clip-path: inset(0 calc((1 - var(--_fill)) * 100%) 0 0);
206
+ transition:
207
+ scale var(--slotted-duration-short) var(--slotted-easing-standard),
208
+ clip-path var(--slotted-duration-medium) var(--_fill-easing);
209
+ }
210
+
211
+ [data-ui='rating'][data-part='root']:dir(rtl) [data-part='fill'] {
212
+ clip-path: inset(0 0 0 calc((1 - var(--_fill)) * 100%));
213
+ }
214
+
215
+ [data-ui='rating'] [data-part='fill'] svg {
216
+ fill: var(--_on);
217
+ stroke: var(--_edge);
218
+ }
219
+
220
+ /* ── The radios ───────────────────────────────────────────────────────── */
221
+
222
+ /**
223
+ * Each radio is the item's own box, under the symbols: the pointer lands on
224
+ * the native control, so a press checks it and the form sees it. The half
225
+ * radio covers the inline-start half of the box and is stacked above the
226
+ * whole one — it comes first in the DOM, so at the same level the whole
227
+ * radio painted over it and took every press meant for the half.
228
+ *
229
+ * The box is a circle: its ground is the halo the pointer lights, and its
230
+ * edge is where the focus ring is drawn.
231
+ */
232
+ [data-ui='rating'] [data-part='input'] {
233
+ appearance: none;
234
+ background-color: transparent;
235
+ block-size: 100%;
236
+ border: 0;
237
+ border-radius: var(--slotted-radius-full, 9999px);
238
+ cursor: pointer;
239
+ inline-size: 100%;
240
+ inset: 0;
241
+ margin: 0;
242
+ /* The ring is the item's, drawn below; the browser's goes. */
243
+ outline: none;
244
+ position: absolute;
245
+ transition: background-color var(--slotted-control-transition-duration)
246
+ var(--slotted-control-transition-easing);
247
+ z-index: 0;
248
+ }
249
+
250
+ [data-ui='rating'] [data-part='input'][data-half] {
251
+ border-end-end-radius: 0;
252
+ border-start-end-radius: 0;
253
+ inline-size: 50%;
254
+ inset-inline-end: auto;
255
+ z-index: 1;
256
+ }
257
+
258
+ /**
259
+ * What the reader has picked: every symbol before the checked radio's item
260
+ * is lit, and that item is lit whole or by half.
261
+ */
262
+ [data-ui='rating'] [data-part='item']:has(~ [data-part='item'] > [data-part='input']:checked),
263
+ [data-ui='rating'] [data-part='item']:has(> [data-part='input']:not([data-half]):checked) {
264
+ --_fill: 1;
265
+ --_fill-easing: var(--slotted-easing-enter);
266
+ }
267
+
268
+ [data-ui='rating'] [data-part='item']:has(> [data-part='input'][data-half]:checked) {
269
+ --_fill: 0.5;
270
+ --_fill-easing: var(--slotted-easing-enter);
271
+ }
272
+
273
+ /**
274
+ * What the reader is about to pick. While the pointer is over a radio the
275
+ * row shows the value under it instead of the one held, the way every
276
+ * surveyed input previews; nothing is requested until the press.
277
+ */
278
+ [data-ui='rating'][data-part='root']:not([data-readonly], [data-disabled]):has(
279
+ [data-part='input']:hover:not(:disabled)
280
+ )
281
+ [data-part='item'] {
282
+ --_fill: 0;
283
+ --_fill-easing: var(--slotted-easing-exit);
284
+ }
285
+
286
+ [data-ui='rating'][data-part='root']:not([data-readonly], [data-disabled]):has(
287
+ [data-part='input']:hover:not(:disabled)
288
+ )
289
+ [data-part='item']:is(
290
+ :has(~ [data-part='item'] > [data-part='input']:hover:not(:disabled)),
291
+ :has(> [data-part='input']:not([data-half]):hover:not(:disabled))
292
+ ) {
293
+ --_fill: 1;
294
+ --_fill-easing: var(--slotted-easing-enter);
295
+ }
296
+
297
+ [data-ui='rating'][data-part='root']:not([data-readonly], [data-disabled])
298
+ [data-part='item']:has(> [data-part='input'][data-half]:hover:not(:disabled)) {
299
+ --_fill: 0.5;
300
+ --_fill-easing: var(--slotted-easing-enter);
301
+ }
302
+
303
+ /**
304
+ * While a finger drags along the row the binding checks the radio under it
305
+ * and marks the root `data-dragging`; the transitions of the lit share step
306
+ * aside, so the row follows the finger rather than trailing it.
307
+ */
308
+ [data-ui='rating'][data-part='root'][data-dragging] [data-part='fill'] {
309
+ transition-duration: var(--slotted-duration-instant);
310
+ }
311
+
312
+ /* ── States ───────────────────────────────────────────────────────────── */
313
+
314
+ /**
315
+ * Hover is the lit share following the pointer, and a round wash under the
316
+ * symbol in the neutral subtle step, which the theme holds 0.02 in OKLab
317
+ * lightness above every surface. Nothing grows: the row previews the value,
318
+ * and a star that jumps toward the pointer reads as a toy. Press settles the
319
+ * symbol six per cent below its size and darkens the wash, and the release
320
+ * brings both back on the standard curve.
321
+ */
322
+ [data-ui='rating'][data-part='root']:not([data-readonly], [data-disabled])
323
+ [data-part='input']:hover:not(:disabled) {
324
+ background-color: var(--_halo);
325
+ }
326
+
327
+ [data-ui='rating'][data-part='root']:not([data-readonly], [data-disabled])
328
+ [data-part='input']:active:not(:disabled) {
329
+ background-color: var(--_halo-active);
330
+ }
331
+
332
+ [data-ui='rating'][data-part='root']:not([data-readonly], [data-disabled])
333
+ [data-part='item']:has(> [data-part='input']:active:not(:disabled))
334
+ > :is([data-part='symbol'], [data-part='fill']) {
335
+ scale: 0.94;
336
+ }
337
+
338
+ /**
339
+ * The ring is the item's, a circle drawn one width inside its box: the
340
+ * boxes touch, and a ring outside them would draw over the next star. A
341
+ * half radio is half of a star and the ring still encloses the whole star,
342
+ * because the star is what the reader is on.
343
+ */
344
+ [data-ui='rating'] [data-part='item']:has(> [data-part='input']:focus-visible) {
345
+ border-radius: var(--slotted-radius-full, 9999px);
346
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color);
347
+ outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
348
+ }
349
+
350
+ /**
351
+ * Invalid is the empty stars in the danger pair — a ground and the edge
352
+ * that holds the ratio against it — so a required rating left empty is
353
+ * marked on the stars themselves, beside the message `field` writes.
354
+ */
355
+ [data-ui='rating'][data-part='root'][data-invalid] {
356
+ --_off: var(--slotted-rating-invalid-color, var(--slotted-tone-danger-surface));
357
+ --_off-edge: var(--slotted-tone-danger-border);
358
+ --slotted-focus-ring-color: var(--slotted-focus-ring-color-invalid);
359
+ }
360
+
361
+ /*
362
+ * Width as well as colour (WCAG 1.4.1): in `high-contrast` the danger pair is
363
+ * the page's white and the edge's black, which an empty star already wears.
364
+ * The empty star's outline grows by the edge every invalid control adds. A
365
+ * stroke grows about its path inside the drawing's own box, so no star and
366
+ * no label moves.
367
+ */
368
+ [data-ui='rating'][data-part='root'][data-invalid] [data-part='symbol'] svg {
369
+ stroke-width: calc(
370
+ var(--_stroke) * 1px +
371
+ var(--slotted-rating-invalid-edge-width, var(--slotted-control-invalid-edge-width, 1px))
372
+ );
373
+ }
374
+
375
+ [data-ui='rating'][data-part='root'][data-readonly] [data-part='input'] {
376
+ cursor: default;
377
+ }
378
+
379
+ /**
380
+ * Disabled keeps the value readable: the lit shapes stay solid in the
381
+ * disabled ink and the unlit ones stay on the disabled ground, so three of
382
+ * five reads as three of five and not as an absent control.
383
+ */
384
+ [data-ui='rating'][data-part='root'][data-disabled] {
385
+ --_on: var(--slotted-disabled-foreground);
386
+ --_off: var(--slotted-disabled-background);
387
+
388
+ color: var(--slotted-disabled-foreground);
389
+ }
390
+
391
+ [data-ui='rating'][data-part='root'][data-disabled] [data-part='input'] {
392
+ cursor: not-allowed;
393
+ }
394
+
395
+ /* ── Text beside the symbols ──────────────────────────────────────────── */
396
+
397
+ /**
398
+ * The value is the number or the word the symbols stand for; the count is
399
+ * how many readings the number is made of. Figures are tabular, so a row of
400
+ * products lines its numbers up.
401
+ */
402
+ [data-ui='rating'] [data-part='value'] {
403
+ font-variant-numeric: tabular-nums;
404
+ font-weight: var(--slotted-font-weight-semibold, 600);
405
+ white-space: nowrap;
406
+ }
407
+
408
+ [data-ui='rating'] [data-part='count'] {
409
+ color: var(--slotted-text-muted, GrayText);
410
+ font-variant-numeric: tabular-nums;
411
+ white-space: nowrap;
412
+ }
413
+
414
+ /**
415
+ * The input's value names the pick in words — a hint beside the control
416
+ * rather than a figure — so it is set muted, as a description is, and a
417
+ * long one wraps inside the row rather than running past it.
418
+ */
419
+ [data-ui='rating'][data-part='root']:has([data-part='input']) > [data-part='value'] {
420
+ color: var(--slotted-text-muted, GrayText);
421
+ font-weight: var(--slotted-font-weight-regular, 400);
422
+ min-inline-size: 0;
423
+ overflow-wrap: anywhere;
424
+ transition: color var(--slotted-control-transition-duration)
425
+ var(--slotted-control-transition-easing);
426
+ white-space: normal;
427
+ }
428
+
429
+ /* While the pointer previews a value the word names it, and reads as the
430
+ answer to the pointer rather than as a hint. */
431
+ [data-ui='rating'][data-part='root']:not([data-readonly], [data-disabled]):has(
432
+ [data-part='input']:hover:not(:disabled)
433
+ )
434
+ > [data-part='value'] {
435
+ color: var(--slotted-text, CanvasText);
436
+ }
437
+
438
+ [data-ui='rating'][data-part='root'][data-disabled] > [data-part='value'] {
439
+ color: var(--slotted-disabled-foreground);
440
+ }
441
+
442
+ /**
443
+ * The text beside the stars is centred on its ink, not on its line box. A
444
+ * flex row centres the line box, and a line box is not symmetric around the
445
+ * letters: the ascender reaches further above the cap than the descender
446
+ * reaches below the baseline, so every figure sat high beside a star whose
447
+ * drawing is centred in its box. `text-box` trims the box to the cap and the
448
+ * baseline — the decision `badge` measured first — so the capitals and the
449
+ * figures share the star's centre. Each part is a flex or grid item, which is
450
+ * a block container, the condition `text-box-trim` needs; the level's
451
+ * number is its own `span` for the same reason, because the text of an
452
+ * `inline-flex` lives in an anonymous item no selector reaches. A wrapped
453
+ * word keeps its inner lines; only the outer edges are trimmed.
454
+ *
455
+ * The summary's figure, its scale and its count are left as they are: they
456
+ * sit on a shared baseline and above the stars, not beside them, and a
457
+ * trimmed figure pulled the stars up against its baseline.
458
+ */
459
+ @supports (text-box: trim-both cap alphabetic) {
460
+ [data-ui='rating'][data-part='root'] > :is([data-part='value'], [data-part='count']),
461
+ [data-ui='rating'] [data-part='level-count'],
462
+ [data-ui='rating'] [data-part='level-label'] > span:not([data-ui]) {
463
+ text-box: trim-both cap alphabetic;
464
+ }
465
+ }
466
+
467
+ /* ── Compact display ──────────────────────────────────────────────────── */
468
+
469
+ /**
470
+ * One lit star, the figure and the count: the reading a list row or a table
471
+ * cell has room for, and the one Fluent calls `compact`. The star is the
472
+ * mark of the figure, not a share of it, so it is always lit whole.
473
+ */
474
+ [data-ui='rating'][data-part='root'][data-variant='compact'] {
475
+ column-gap: var(--slotted-space-2, 0.25rem);
476
+ }
477
+
478
+ [data-ui='rating'][data-part='root'][data-variant='compact'] [data-part='item'] {
479
+ --_fill: 1;
480
+ }
481
+
482
+ /* ── Summary ──────────────────────────────────────────────────────────── */
483
+
484
+ /**
485
+ * The aggregate beside the distribution: the figure a page leads with,
486
+ * the stars that draw it, and how many readings it is made of; then one
487
+ * bar per level. The two blocks sit side by side while both fit and stack
488
+ * when they do not — a wrap on the flex line rather than a container
489
+ * query, because the break is where the content stops fitting and nowhere
490
+ * else.
491
+ */
492
+ [data-ui='rating'][data-part='root'][data-variant='summary'] {
493
+ --_bar: var(--slotted-rating-bar-size, var(--slotted-space-4, 0.5rem));
494
+
495
+ align-items: start;
496
+ display: flex;
497
+ gap: var(--slotted-space-8, 1.5rem) var(--slotted-space-9, 2rem);
498
+ /* A block of the page, not a run of text: it takes the width it is
499
+ given, which is what lets the two blocks stand side by side. */
500
+ inline-size: 100%;
501
+ }
502
+
503
+ [data-ui='rating'] [data-part='aggregate'] {
504
+ align-content: start;
505
+ column-gap: var(--slotted-space-3, 0.375rem);
506
+ display: grid;
507
+ flex: 0 0 auto;
508
+ grid-template-columns: auto 1fr;
509
+ row-gap: var(--slotted-space-2, 0.25rem);
510
+ }
511
+
512
+ /**
513
+ * The figure is set at the key-figure step `stat-card` reads, on its own
514
+ * line height, and the scale beside it sits on its baseline.
515
+ */
516
+ [data-ui='rating'] [data-part='aggregate'] > [data-part='value'] {
517
+ align-self: baseline;
518
+ font-size: var(--slotted-font-size-4xl, 2rem);
519
+ font-weight: var(--slotted-font-weight-semibold, 600);
520
+ line-height: var(--slotted-line-height-4xl, 1.2);
521
+ }
522
+
523
+ [data-ui='rating'] [data-part='scale'] {
524
+ align-self: baseline;
525
+ color: var(--slotted-text-muted, GrayText);
526
+ }
527
+
528
+ [data-ui='rating'] [data-part='aggregate'] > :not([data-part='value'], [data-part='scale']) {
529
+ grid-column: 1 / -1;
530
+ }
531
+
532
+ [data-ui='rating'] [data-part='aggregate'] > [data-part='count'] {
533
+ white-space: normal;
534
+ }
535
+
536
+ /**
537
+ * The distribution is one grid whose rows are subgrids, so every label,
538
+ * bar and count lines up with the one above it whatever the numbers.
539
+ */
540
+ [data-ui='rating'] [data-part='distribution'] {
541
+ display: grid;
542
+ flex: 1 1 15rem;
543
+ grid-template-columns: auto minmax(4rem, 1fr) auto;
544
+ list-style: none;
545
+ margin: 0;
546
+ min-inline-size: 0;
547
+ padding: 0;
548
+ row-gap: var(--slotted-space-1, 0.125rem);
549
+ }
550
+
551
+ [data-ui='rating'] [data-part='distribution'] > li {
552
+ display: grid;
553
+ grid-column: 1 / -1;
554
+ grid-template-columns: subgrid;
555
+ }
556
+
557
+ [data-ui='rating'] [data-part='level'] {
558
+ align-items: center;
559
+ background-color: transparent;
560
+ border: 0;
561
+ border-radius: var(--slotted-radius-sm, 4px);
562
+ color: inherit;
563
+ column-gap: var(--slotted-space-5, 0.75rem);
564
+ display: grid;
565
+ font: inherit;
566
+ grid-column: 1 / -1;
567
+ grid-template-columns: subgrid;
568
+ margin: 0;
569
+ /* The row is a target: the control height of its size step, whatever the
570
+ bar draws inside it. */
571
+ min-block-size: var(--slotted-control-height-sm, 30px);
572
+ padding-block: 0;
573
+ padding-inline: var(--slotted-space-3, 0.375rem);
574
+ text-align: start;
575
+ transition:
576
+ background-color var(--slotted-control-transition-duration)
577
+ var(--slotted-control-transition-easing),
578
+ box-shadow var(--slotted-control-transition-duration) var(--slotted-control-transition-easing);
579
+ }
580
+
581
+ [data-ui='rating'] button[data-part='level'] {
582
+ cursor: pointer;
583
+ }
584
+
585
+ [data-ui='rating'] button[data-part='level']:hover:not(:disabled) {
586
+ background-color: var(--_halo);
587
+ }
588
+
589
+ [data-ui='rating'] button[data-part='level']:active:not(:disabled) {
590
+ background-color: var(--_halo-active);
591
+ }
592
+
593
+ [data-ui='rating'] button[data-part='level']:focus-visible {
594
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color);
595
+ outline-offset: calc(-1 * var(--slotted-focus-ring-width, 2px));
596
+ }
597
+
598
+ /**
599
+ * A level the reader filters by carries the tone's surface inside a hairline
600
+ * of the tone's border, and its count at full weight; the other levels stay
601
+ * as they are, so the filter reads as one row lit among five rather than
602
+ * four rows dimmed.
603
+ */
604
+ [data-ui='rating'] [data-part='level'][data-pressed] {
605
+ background-color: var(--slotted-tone-warning-surface);
606
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--slotted-tone-warning-border);
607
+ }
608
+
609
+ [data-ui='rating'] [data-part='level'][data-pressed] [data-part='level-count'] {
610
+ color: var(--slotted-text, CanvasText);
611
+ font-weight: var(--slotted-font-weight-semibold, 600);
612
+ }
613
+
614
+ [data-ui='rating'] button[data-part='level']:disabled {
615
+ color: var(--slotted-disabled-foreground);
616
+ cursor: default;
617
+ }
618
+
619
+ [data-ui='rating'] [data-part='level-label'] {
620
+ --slotted-icon-size: var(--slotted-control-icon-size-sm, 14px);
621
+
622
+ align-items: center;
623
+ column-gap: var(--slotted-space-1, 0.125rem);
624
+ display: inline-flex;
625
+ font-variant-numeric: tabular-nums;
626
+ white-space: nowrap;
627
+ }
628
+
629
+ [data-ui='rating'] [data-part='level-label'] svg {
630
+ fill: currentColor;
631
+ stroke-width: var(--_stroke);
632
+ }
633
+
634
+ [data-ui='rating'] [data-part='level-label'] > [data-ui='icon'] {
635
+ color: var(--slotted-text-muted, GrayText);
636
+ }
637
+
638
+ /* The track takes the symbols' edge: nothing in `light` and `dark`, a black
639
+ hairline in `high-contrast`, where its ground is the page's white. */
640
+ [data-ui='rating'] [data-part='track'] {
641
+ background-color: var(--_off);
642
+ block-size: var(--_bar);
643
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--_edge);
644
+ border-radius: var(--slotted-radius-full, 9999px);
645
+ overflow: hidden;
646
+ }
647
+
648
+ /**
649
+ * The bar grows from the inline start to its share on the long step and
650
+ * the enter curve, the first time it is drawn and every time the share
651
+ * changes, so a summary that loads reads as filling rather than popping.
652
+ */
653
+ [data-ui='rating'] [data-part='indicator'] {
654
+ background-color: var(--slotted-rating-bar-color, var(--_on));
655
+ block-size: 100%;
656
+ border-radius: inherit;
657
+ display: block;
658
+ inline-size: calc(var(--slotted-rating-share, 0) * 100%);
659
+ transition: inline-size var(--slotted-duration-long) var(--slotted-easing-enter);
660
+ }
661
+
662
+ @starting-style {
663
+ [data-ui='rating'] [data-part='indicator'] {
664
+ inline-size: 0;
665
+ }
666
+ }
667
+
668
+ [data-ui='rating'] [data-part='level-count'] {
669
+ color: var(--slotted-text-muted, GrayText);
670
+ font-variant-numeric: tabular-nums;
671
+ justify-self: end;
672
+ white-space: nowrap;
673
+ }
674
+
675
+ [data-ui='rating'][data-disabled] [data-part='indicator'],
676
+ [data-ui='rating'] button[data-part='level']:disabled [data-part='indicator'] {
677
+ background-color: var(--slotted-disabled-foreground);
678
+ }
679
+
680
+ /* ── Spectrum ─────────────────────────────────────────────────────────── */
681
+
682
+ /**
683
+ * The second reading of a summary, for a page that has to say more than the
684
+ * mean. The mean hides the shape and the confidence: 3.3 of five may be half
685
+ * ones and half fives, and 4.9 from seven readings is worth less than 4.7
686
+ * from a thousand. So the distribution is drawn as columns on the scale's own
687
+ * axis, the mean is a line at its exact place on that axis, the 95% interval
688
+ * of the mean is a band behind the columns, and one conclusion stands above
689
+ * (`@slotted/core/rating`, `summariseRatings`). Every figure, the interval
690
+ * included, is also written as text.
691
+ */
692
+ [data-ui='rating'][data-part='root'][data-variant='spectrum'] {
693
+ --_g: var(--slotted-space-3, 0.375rem);
694
+ --_plot: var(--slotted-space-12, 4rem);
695
+ --_col: calc((100% - 4 * var(--_g)) / 5);
696
+ --_mean: var(--slotted-rating-mean, 3);
697
+ --_low: var(--slotted-rating-low, var(--_mean));
698
+ --_high: var(--slotted-rating-high, var(--_mean));
699
+
700
+ display: grid;
701
+ gap: var(--slotted-space-6, 1rem);
702
+ inline-size: 100%;
703
+ }
704
+
705
+ [data-ui='rating'][data-variant='spectrum'] > [data-part='aggregate'] {
706
+ align-items: baseline;
707
+ column-gap: var(--slotted-space-3, 0.375rem);
708
+ display: flex;
709
+ flex-wrap: wrap;
710
+ row-gap: var(--slotted-space-2, 0.25rem);
711
+ }
712
+
713
+ [data-ui='rating'][data-variant='spectrum'] > [data-part='aggregate'] > [data-part='count'] {
714
+ color: var(--slotted-text-muted, GrayText);
715
+ flex-basis: 100%;
716
+ }
717
+
718
+ /**
719
+ * The conclusion is a pill in its tone's surface, edge and text roles, the
720
+ * pair a badge reads, pushed to the inline end of the figure's line.
721
+ */
722
+ [data-ui='rating'] [data-part='insight'] {
723
+ align-self: center;
724
+ background-color: var(--_tint-surface);
725
+ border-radius: var(--slotted-radius-full, 9999px);
726
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--_tint-border);
727
+ color: var(--_tint-text);
728
+ font-size: var(--slotted-font-size-xs, 0.75rem);
729
+ font-weight: var(--slotted-font-weight-medium, 500);
730
+ margin-inline-start: auto;
731
+ padding-block: var(--slotted-space-1, 0.125rem);
732
+ padding-inline: var(--slotted-space-4, 0.5rem);
733
+ white-space: nowrap;
734
+ }
735
+
736
+ [data-ui='rating'] :is([data-part='insight'], [data-part='bucket'])[data-tone='success'] {
737
+ --_tint-surface: var(--slotted-tone-success-surface);
738
+ --_tint-border: var(--slotted-tone-success-border);
739
+ --_tint-text: var(--slotted-tone-success-text);
740
+ --_mark: var(--slotted-tone-success-solid);
741
+ }
742
+
743
+ [data-ui='rating'] :is([data-part='insight'], [data-part='bucket'])[data-tone='warning'] {
744
+ --_tint-surface: var(--slotted-tone-warning-surface);
745
+ --_tint-border: var(--slotted-tone-warning-border);
746
+ --_tint-text: var(--slotted-tone-warning-text);
747
+ --_mark: var(--slotted-tone-warning-solid);
748
+ }
749
+
750
+ [data-ui='rating'] :is([data-part='insight'], [data-part='bucket'])[data-tone='secondary'] {
751
+ --_tint-surface: var(--slotted-tone-secondary-surface);
752
+ --_tint-border: var(--slotted-tone-secondary-border);
753
+ --_tint-text: var(--slotted-text-muted, GrayText);
754
+ --_mark: var(--slotted-tone-secondary-border);
755
+ }
756
+
757
+ [data-ui='rating'] :is([data-part='insight'], [data-part='bucket'])[data-tone='danger'] {
758
+ --_tint-surface: var(--slotted-tone-danger-surface);
759
+ --_tint-border: var(--slotted-tone-danger-border);
760
+ --_tint-text: var(--slotted-tone-danger-text);
761
+ --_mark: var(--slotted-tone-danger-solid);
762
+ }
763
+
764
+ [data-ui='rating'] [data-part='plot'] {
765
+ display: grid;
766
+ row-gap: var(--slotted-space-3, 0.375rem);
767
+ }
768
+
769
+ /* The drawing area: its top margin is the room the mean's label stands in. */
770
+ [data-ui='rating'] [data-part='field'] {
771
+ block-size: var(--_plot);
772
+ border-block-end: var(--slotted-border-width-thin, 1px) solid var(--slotted-border-subtle);
773
+ margin-block-start: var(--slotted-space-7, 1.25rem);
774
+ position: relative;
775
+ }
776
+
777
+ [data-ui='rating'] :is([data-part='columns'], [data-part='axis']) {
778
+ column-gap: var(--_g);
779
+ display: grid;
780
+ grid-template-columns: repeat(5, 1fr);
781
+ }
782
+
783
+ [data-ui='rating'] [data-part='columns'] {
784
+ block-size: 100%;
785
+ isolation: isolate;
786
+ position: relative;
787
+ z-index: 1;
788
+ }
789
+
790
+ [data-ui='rating'] [data-part='column'] {
791
+ align-items: end;
792
+ background-color: transparent;
793
+ border: 0;
794
+ border-start-end-radius: var(--slotted-radius-sm, 4px);
795
+ border-start-start-radius: var(--slotted-radius-sm, 4px);
796
+ display: flex;
797
+ justify-content: center;
798
+ margin: 0;
799
+ padding: 0;
800
+ transition: background-color var(--slotted-control-transition-duration)
801
+ var(--slotted-control-transition-easing);
802
+ }
803
+
804
+ [data-ui='rating'] button[data-part='column'] {
805
+ cursor: pointer;
806
+ }
807
+
808
+ [data-ui='rating'] button[data-part='column']:hover:not(:disabled) {
809
+ background-color: var(--_halo);
810
+ }
811
+
812
+ [data-ui='rating'] button[data-part='column']:active:not(:disabled) {
813
+ background-color: var(--_halo-active);
814
+ }
815
+
816
+ [data-ui='rating'] button[data-part='column']:focus-visible {
817
+ outline: var(--slotted-focus-ring-width, 2px) solid var(--slotted-focus-ring-color);
818
+ outline-offset: var(--slotted-focus-ring-offset, 2px);
819
+ }
820
+
821
+ /**
822
+ * A column is a bar at most forty pixels wide, centred, as tall as its
823
+ * level's share of the largest level. A level nobody chose draws nothing;
824
+ * any other is at least two pixels, so one reading is never invisible. It
825
+ * grows from the baseline on the long step and the enter curve.
826
+ */
827
+ [data-ui='rating'] [data-part='column'] > [data-part='bar'] {
828
+ background-color: var(--_on);
829
+ block-size: max(
830
+ min(var(--slotted-space-1, 0.125rem), var(--slotted-rating-share, 0) * 100rem),
831
+ calc(var(--slotted-rating-share, 0) * 100%)
832
+ );
833
+ border-start-end-radius: var(--slotted-radius-sm, 4px);
834
+ border-start-start-radius: var(--slotted-radius-sm, 4px);
835
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--_edge);
836
+ inline-size: min(100%, var(--slotted-space-10, 2.5rem));
837
+ transition:
838
+ block-size var(--slotted-duration-long) var(--slotted-easing-enter),
839
+ background-color var(--slotted-control-transition-duration)
840
+ var(--slotted-control-transition-easing);
841
+ }
842
+
843
+ @starting-style {
844
+ [data-ui='rating'] [data-part='column'] > [data-part='bar'] {
845
+ block-size: 0;
846
+ }
847
+ }
848
+
849
+ [data-ui='rating']
850
+ [data-part='columns']:has([data-pressed])
851
+ [data-part='column']:not([data-pressed])
852
+ > [data-part='bar'] {
853
+ background-color: var(--_off);
854
+ }
855
+
856
+ /**
857
+ * A value on the scale is placed on the columns' axis: the centre of the
858
+ * first column, plus one column and one gap per unit. The interval sits
859
+ * behind the columns and the mean in front of them.
860
+ */
861
+ [data-ui='rating'] :is([data-part='interval'], [data-part='mean']) {
862
+ pointer-events: none;
863
+ position: absolute;
864
+ }
865
+
866
+ [data-ui='rating'] [data-part='interval'] {
867
+ background-color: color-mix(
868
+ in oklab,
869
+ var(--slotted-text) calc(var(--slotted-highlight-tint-opacity, 0.075) * 100%),
870
+ transparent
871
+ );
872
+ border-radius: var(--slotted-radius-sm, 4px);
873
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--_edge);
874
+ inline-size: max(
875
+ var(--slotted-space-1, 0.125rem),
876
+ calc((var(--_high) - var(--_low)) * (var(--_col) + var(--_g)))
877
+ );
878
+ inset-block: 0;
879
+ inset-inline-start: calc(var(--_col) / 2 + (var(--_low) - 1) * (var(--_col) + var(--_g)));
880
+ transition:
881
+ inset-inline-start var(--slotted-duration-long) var(--slotted-easing-standard),
882
+ inline-size var(--slotted-duration-long) var(--slotted-easing-standard);
883
+ z-index: 0;
884
+ }
885
+
886
+ [data-ui='rating'] [data-part='mean'] {
887
+ border-inline-start: var(--slotted-border-width-thick, 2px) solid var(--slotted-text);
888
+ inset-block: calc(-1 * var(--slotted-space-5, 0.75rem)) 0;
889
+ inset-inline-start: calc(
890
+ var(--_col) / 2 + (var(--_mean) - 1) * (var(--_col) + var(--_g)) -
891
+ var(--slotted-border-width-thin, 1px)
892
+ );
893
+ transition: inset-inline-start var(--slotted-duration-long) var(--slotted-easing-standard);
894
+ z-index: 2;
895
+ }
896
+
897
+ [data-ui='rating'] [data-part='mean-label'] {
898
+ background-color: var(--slotted-surface-inverse);
899
+ border-radius: var(--slotted-radius-full, 9999px);
900
+ color: var(--slotted-text-inverse);
901
+ font-size: var(--slotted-font-size-xs, 0.75rem);
902
+ font-variant-numeric: tabular-nums;
903
+ font-weight: var(--slotted-font-weight-semibold, 600);
904
+ inset-block-end: 100%;
905
+ inset-inline-start: 0;
906
+ line-height: var(--slotted-line-height-xs, 1.4);
907
+ padding-inline: var(--slotted-space-3, 0.375rem);
908
+ position: absolute;
909
+ translate: -50% 0;
910
+ white-space: nowrap;
911
+ }
912
+
913
+ [data-ui='rating'][data-part='root']:dir(rtl) [data-part='mean-label'] {
914
+ translate: 50% 0;
915
+ }
916
+
917
+ [data-ui='rating'] [data-part='tick'] {
918
+ display: grid;
919
+ justify-items: center;
920
+ row-gap: var(--slotted-space-1, 0.125rem);
921
+ }
922
+
923
+ [data-ui='rating'] [data-part='tick-label'] {
924
+ --slotted-icon-size: var(--slotted-control-icon-size-sm, 14px);
925
+
926
+ align-items: center;
927
+ column-gap: var(--slotted-space-1, 0.125rem);
928
+ display: inline-flex;
929
+ font-variant-numeric: tabular-nums;
930
+ }
931
+
932
+ [data-ui='rating'] [data-part='tick-label'] svg {
933
+ fill: currentColor;
934
+ stroke-width: var(--_stroke);
935
+ }
936
+
937
+ [data-ui='rating'] [data-part='tick-label'] > [data-ui='icon'] {
938
+ color: var(--slotted-text-muted, GrayText);
939
+ }
940
+
941
+ [data-ui='rating'] [data-part='tick-share'] {
942
+ color: var(--slotted-text-muted, GrayText);
943
+ font-size: var(--slotted-font-size-xs, 0.75rem);
944
+ font-variant-numeric: tabular-nums;
945
+ }
946
+
947
+ /* The executive reading: positive, neutral and negative shares, each with
948
+ its tone's mark, which never carries the meaning alone. */
949
+ [data-ui='rating'] [data-part='sentiment'] {
950
+ color: var(--slotted-text-muted, GrayText);
951
+ column-gap: var(--slotted-space-6, 1rem);
952
+ display: flex;
953
+ flex-wrap: wrap;
954
+ margin: 0;
955
+ row-gap: var(--slotted-space-2, 0.25rem);
956
+ }
957
+
958
+ [data-ui='rating'] [data-part='bucket'] {
959
+ align-items: center;
960
+ column-gap: var(--slotted-space-2, 0.25rem);
961
+ display: inline-flex;
962
+ }
963
+
964
+ [data-ui='rating'] [data-part='bucket'] > strong {
965
+ color: var(--slotted-text, CanvasText);
966
+ font-variant-numeric: tabular-nums;
967
+ font-weight: var(--slotted-font-weight-semibold, 600);
968
+ }
969
+
970
+ [data-ui='rating'] [data-part='swatch'] {
971
+ background-color: var(--_mark);
972
+ block-size: var(--slotted-space-4, 0.5rem);
973
+ border-radius: var(--slotted-radius-full, 9999px);
974
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--_edge);
975
+ flex: none;
976
+ inline-size: var(--slotted-space-4, 0.5rem);
977
+ }
978
+
979
+ /* ── Histogram display ────────────────────────────────────────────────── */
980
+
981
+ /**
982
+ * The display's third reading, for a cell or a list row: one star, the
983
+ * mean, five columns the height of a capital and a half on a baseline, and
984
+ * the count. Two rows at 3.3 stop looking alike when one is split between
985
+ * the ends.
986
+ */
987
+ [data-ui='rating'][data-part='root'][data-variant='histogram'] {
988
+ column-gap: var(--slotted-space-2, 0.25rem);
989
+ }
990
+
991
+ [data-ui='rating'][data-part='root'][data-variant='histogram'] [data-part='item'] {
992
+ --_fill: 1;
993
+ }
994
+
995
+ [data-ui='rating'] [data-part='histogram'] {
996
+ align-items: end;
997
+ block-size: calc(1cap + 0.5em);
998
+ border-block-end: var(--slotted-border-width-thin, 1px) solid var(--slotted-border-strong);
999
+ column-gap: var(--slotted-border-width-thin, 1px);
1000
+ display: inline-grid;
1001
+ grid-template-columns: repeat(5, var(--slotted-space-2, 0.25rem));
1002
+ margin-inline: var(--slotted-space-2, 0.25rem);
1003
+ }
1004
+
1005
+ [data-ui='rating'] [data-part='histogram'] > [data-part='bar'] {
1006
+ background-color: var(--_on);
1007
+ block-size: max(
1008
+ min(var(--slotted-border-width-thin, 1px), var(--slotted-rating-share, 0) * 100rem),
1009
+ calc(var(--slotted-rating-share, 0) * 100%)
1010
+ );
1011
+ border-start-end-radius: var(--slotted-radius-xs, 2px);
1012
+ border-start-start-radius: var(--slotted-radius-xs, 2px);
1013
+ box-shadow: inset 0 0 0 var(--slotted-border-width-thin, 1px) var(--_edge);
1014
+ }
1015
+
1016
+ /**
1017
+ * A coarse pointer grows each target to the comfortable size, as the theme
1018
+ * grows every control; the symbol stays, so the row spreads and nothing
1019
+ * scales.
1020
+ */
1021
+ @media (pointer: coarse) {
1022
+ [data-ui='rating'] [data-part='item']:has(> [data-part='input']) {
1023
+ --_box: max(var(--slotted-target-comfortable, 44px), var(--_symbol));
1024
+ }
1025
+
1026
+ [data-ui='rating'] [data-part='level'] {
1027
+ min-block-size: var(--slotted-target-comfortable, 44px);
1028
+ }
1029
+ }
1030
+
1031
+ /**
1032
+ * Under forced colours every tone becomes a button face, which is the page's
1033
+ * own ground, and a lit star would be indistinguishable from an unlit one.
1034
+ * The lit shape is filled with the text colour and the unlit one outlined in
1035
+ * it — the shape carries the value, as it does in every scheme.
1036
+ */
1037
+ @media (forced-colors: active) {
1038
+ [data-ui='rating'][data-part='root'] {
1039
+ --_on: CanvasText;
1040
+ --_off: Canvas;
1041
+ --_edge: CanvasText;
1042
+ --_off-edge: CanvasText;
1043
+ }
1044
+
1045
+ [data-ui='rating'][data-part='root'][data-disabled] {
1046
+ --_on: GrayText;
1047
+ --_edge: GrayText;
1048
+ --_off-edge: GrayText;
1049
+ }
1050
+
1051
+ [data-ui='rating'] [data-part='track'] {
1052
+ border: var(--slotted-border-width-thin, 1px) solid CanvasText;
1053
+ }
1054
+
1055
+ [data-ui='rating'] :is([data-part='insight'], [data-part='swatch']) {
1056
+ border: var(--slotted-border-width-thin, 1px) solid CanvasText;
1057
+ }
1058
+
1059
+ [data-ui='rating'] [data-part='column'][data-pressed] {
1060
+ outline: var(--slotted-border-width-thick, 2px) solid Highlight;
1061
+ }
1062
+
1063
+ [data-ui='rating'] [data-part='level'][data-pressed] {
1064
+ outline: var(--slotted-border-width-thick, 2px) solid Highlight;
1065
+ }
1066
+
1067
+ [data-ui='rating'] [data-part='item']:has(> [data-part='input']:focus-visible) {
1068
+ outline-color: Highlight;
1069
+ }
1070
+ }
1071
+ }