@threadlabs/looma 0.33.1 → 0.35.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 (215) hide show
  1. package/components/shared/overlay.js +8 -2
  2. package/components/shared/surface-material.js +21 -0
  3. package/components/ui-badge/ui-badge.html +11 -3
  4. package/components/ui-button/ui-button.html +92 -51
  5. package/components/ui-card/ui-card.html +50 -6
  6. package/components/ui-checkbox/ui-checkbox.html +4 -2
  7. package/components/ui-curve-editor/curve.js +10 -0
  8. package/components/ui-curve-editor/ui-curve-editor.html +181 -0
  9. package/components/ui-curve-editor/ui-curve-editor.js +51 -0
  10. package/components/ui-dialog/ui-dialog.html +64 -1
  11. package/components/ui-dialog/ui-dialog.js +9 -1
  12. package/components/ui-icon-button/ui-icon-button.html +97 -31
  13. package/components/ui-input/ui-input.html +2 -1
  14. package/components/ui-input-group/ui-input-group.html +4 -1
  15. package/components/ui-light-editor/ui-light-editor.html +45 -0
  16. package/components/ui-light-editor/ui-light-editor.js +53 -0
  17. package/components/ui-menu/ui-menu.html +62 -0
  18. package/components/ui-menu/ui-menu.js +1 -1
  19. package/components/ui-number-input/arithmetic.js +47 -0
  20. package/components/ui-number-input/ui-number-input.html +63 -0
  21. package/components/ui-number-input/ui-number-input.js +47 -0
  22. package/components/ui-popover/ui-popover.html +66 -1
  23. package/components/ui-popover/ui-popover.js +1 -1
  24. package/components/ui-select/ui-select.html +9 -7
  25. package/components/ui-slider/ui-slider.html +84 -0
  26. package/components/ui-slider/ui-slider.js +29 -0
  27. package/components/ui-switch/ui-switch.html +3 -0
  28. package/components/ui-tabs/ui-tabs.html +6 -1
  29. package/components/ui-text/ui-text.html +31 -6
  30. package/components/ui-textarea/ui-textarea.html +2 -1
  31. package/components/ui-tooltip/ui-tooltip.html +60 -0
  32. package/components/ui-tooltip/ui-tooltip.js +1 -1
  33. package/dist/index.js +47 -43
  34. package/docs/README.md +59 -5
  35. package/docs/card.html +16 -2
  36. package/docs/card.js +17 -2
  37. package/docs/catalog.json +1640 -108
  38. package/docs/customizer-render.mjs +50 -11
  39. package/docs/customizer.js +137 -24
  40. package/docs/documentation.css +9 -1
  41. package/docs/index.d.ts +8 -3
  42. package/docs/index.mjs +1 -1
  43. package/docs/preview.js +2 -0
  44. package/docs/render.mjs +16 -7
  45. package/docs/site.mjs +78 -27
  46. package/docs/theme-session.mjs +53 -0
  47. package/docs/theme.mjs +189 -18
  48. package/docs/value-editors.mjs +33 -0
  49. package/package.json +2 -2
  50. package/styles/ui-badge.css +11 -6
  51. package/styles/ui-button.css +74 -49
  52. package/styles/ui-card.css +51 -4
  53. package/styles/ui-checkbox.css +4 -2
  54. package/styles/ui-curve-editor.css +109 -0
  55. package/styles/ui-dialog.css +136 -0
  56. package/styles/ui-icon-button.css +85 -28
  57. package/styles/ui-input-group.css +4 -1
  58. package/styles/ui-input.css +2 -1
  59. package/styles/ui-light-editor.css +28 -0
  60. package/styles/ui-menu.css +74 -0
  61. package/styles/ui-number-input.css +34 -0
  62. package/styles/ui-popover.css +76 -0
  63. package/styles/ui-select.css +9 -7
  64. package/styles/ui-slider.css +53 -0
  65. package/styles/ui-switch.css +3 -0
  66. package/styles/ui-tabs.css +6 -1
  67. package/styles/ui-text.css +23 -1
  68. package/styles/ui-textarea.css +2 -1
  69. package/styles/ui-tooltip.css +72 -0
  70. package/theme-light.css +1 -0
  71. package/theme-system.css +69 -17
  72. package/tokens.css +12 -2
  73. package/vanilla/UiButton.d.ts +1 -0
  74. package/vanilla/UiButton.js +195 -130
  75. package/vanilla/UiCard.d.ts +1 -0
  76. package/vanilla/UiCard.js +12 -12
  77. package/vanilla/UiCurveEditor.d.ts +28 -0
  78. package/vanilla/UiCurveEditor.js +134 -0
  79. package/vanilla/UiIconButton.d.ts +2 -1
  80. package/vanilla/UiIconButton.js +58 -31
  81. package/vanilla/UiLightEditor.d.ts +29 -0
  82. package/vanilla/UiLightEditor.js +102 -0
  83. package/vanilla/UiNumberInput.d.ts +33 -0
  84. package/vanilla/UiNumberInput.js +86 -0
  85. package/vanilla/UiSlider.d.ts +33 -0
  86. package/vanilla/UiSlider.js +125 -0
  87. package/vanilla/UiText.d.ts +2 -2
  88. package/vanilla/UiText.js +45 -11
  89. package/vanilla/index.js +4 -0
  90. package/vue/UiBadge.vue +29 -4
  91. package/vue/UiButton.d.ts +6 -0
  92. package/vue/UiButton.vue +188 -60
  93. package/vue/UiCard.d.ts +6 -0
  94. package/vue/UiCard.vue +80 -6
  95. package/vue/UiCheckbox.vue +4 -2
  96. package/vue/UiCurveEditor.d.ts +53 -0
  97. package/vue/UiCurveEditor.js +2 -0
  98. package/vue/UiCurveEditor.vue +427 -0
  99. package/vue/UiDialog.vue +181 -1
  100. package/vue/UiIconButton.d.ts +8 -2
  101. package/vue/UiIconButton.vue +190 -45
  102. package/vue/UiInput.vue +2 -1
  103. package/vue/UiInputGroup.vue +4 -1
  104. package/vue/UiLightEditor.d.ts +75 -0
  105. package/vue/UiLightEditor.js +2 -0
  106. package/vue/UiLightEditor.vue +402 -0
  107. package/vue/UiMenu.vue +91 -0
  108. package/vue/UiNumberInput.d.ts +83 -0
  109. package/vue/UiNumberInput.js +2 -0
  110. package/vue/UiNumberInput.vue +399 -0
  111. package/vue/UiPopover.vue +94 -1
  112. package/vue/UiSelect.vue +16 -10
  113. package/vue/UiSlider.d.ts +83 -0
  114. package/vue/UiSlider.js +2 -0
  115. package/vue/UiSlider.vue +412 -0
  116. package/vue/UiSwitch.vue +3 -0
  117. package/vue/UiTabs.vue +6 -1
  118. package/vue/UiText.d.ts +7 -5
  119. package/vue/UiText.vue +104 -22
  120. package/vue/UiTextarea.vue +2 -1
  121. package/vue/UiTooltip.vue +89 -0
  122. package/vue/chunks/UiActionBar.js +1 -1
  123. package/vue/chunks/UiAffordanceScope.js +2 -2
  124. package/vue/chunks/UiAvatar.js +2 -2
  125. package/vue/chunks/UiAvatarGroup.js +2 -2
  126. package/vue/chunks/UiBadge.js +3 -3
  127. package/vue/chunks/UiBreadcrumbItem.js +2 -2
  128. package/vue/chunks/UiBreadcrumbs.js +2 -2
  129. package/vue/chunks/UiButton.js +94 -11
  130. package/vue/chunks/UiCallout.js +2 -2
  131. package/vue/chunks/UiCard.js +34 -5
  132. package/vue/chunks/UiCheckbox.js +3 -3
  133. package/vue/chunks/UiCluster.js +2 -2
  134. package/vue/chunks/UiColorPicker.js +2 -2
  135. package/vue/chunks/UiCombobox.js +2 -2
  136. package/vue/chunks/UiContainer.js +2 -2
  137. package/vue/chunks/UiContextMenu.js +2 -2
  138. package/vue/chunks/UiCover.js +2 -2
  139. package/vue/chunks/UiCurveEditor.js +413 -0
  140. package/vue/chunks/UiDescriptionItem.js +2 -2
  141. package/vue/chunks/UiDescriptionList.js +2 -2
  142. package/vue/chunks/UiDialog.js +4 -4
  143. package/vue/chunks/UiDisclosure.js +2 -2
  144. package/vue/chunks/UiEditable.js +2 -2
  145. package/vue/chunks/UiEditorBlockActions.js +2 -2
  146. package/vue/chunks/UiEditorChipEditor.js +2 -2
  147. package/vue/chunks/UiEditorCodeLanguage.js +2 -2
  148. package/vue/chunks/UiEditorFootnoteEditor.js +2 -2
  149. package/vue/chunks/UiEditorImageToolbar.js +3 -3
  150. package/vue/chunks/UiEditorInsertTableGrid.js +2 -2
  151. package/vue/chunks/UiEditorLinkCard.js +3 -3
  152. package/vue/chunks/UiEditorLinkForm.js +3 -3
  153. package/vue/chunks/UiEditorMentionMenu.js +2 -2
  154. package/vue/chunks/UiEditorMentionMenuItem.js +2 -2
  155. package/vue/chunks/UiEditorSlashMenu.js +2 -2
  156. package/vue/chunks/UiEditorSlashMenuGroup.js +2 -2
  157. package/vue/chunks/UiEditorSlashMenuItem.js +2 -2
  158. package/vue/chunks/UiEditorSurface.js +2 -2
  159. package/vue/chunks/UiEditorTableContextMenu.js +2 -2
  160. package/vue/chunks/UiEditorTableOverlay.js +2 -2
  161. package/vue/chunks/UiEditorTableToolbar.js +2 -2
  162. package/vue/chunks/UiEditorToolbar.js +2 -2
  163. package/vue/chunks/UiFloatingActionButton.js +2 -2
  164. package/vue/chunks/UiFormField.js +2 -2
  165. package/vue/chunks/UiGrid.js +2 -2
  166. package/vue/chunks/UiIcon.js +2 -2
  167. package/vue/chunks/UiIconButton.js +77 -11
  168. package/vue/chunks/UiImage.js +2 -2
  169. package/vue/chunks/UiInput.js +3 -3
  170. package/vue/chunks/UiInputGroup.js +3 -3
  171. package/vue/chunks/UiLightEditor.js +347 -0
  172. package/vue/chunks/UiList.js +2 -2
  173. package/vue/chunks/UiListItem.js +2 -2
  174. package/vue/chunks/UiListbox.js +2 -2
  175. package/vue/chunks/UiMenu.js +3 -3
  176. package/vue/chunks/UiMenuGroup.js +2 -2
  177. package/vue/chunks/UiMenuItem.js +2 -2
  178. package/vue/chunks/UiMeter.js +2 -2
  179. package/vue/chunks/UiNavItem.js +2 -2
  180. package/vue/chunks/UiNumberInput.js +403 -0
  181. package/vue/chunks/UiPageHeader.js +2 -2
  182. package/vue/chunks/UiPopover.js +4 -4
  183. package/vue/chunks/UiRadio.js +2 -2
  184. package/vue/chunks/UiRadioGroup.js +2 -2
  185. package/vue/chunks/UiReel.js +2 -2
  186. package/vue/chunks/UiScrollArea.js +2 -2
  187. package/vue/chunks/UiSearchResultRow.js +2 -2
  188. package/vue/chunks/UiSearchShell.js +2 -2
  189. package/vue/chunks/UiSection.js +2 -2
  190. package/vue/chunks/UiSelect.js +3 -3
  191. package/vue/chunks/UiSeparator.js +2 -2
  192. package/vue/chunks/UiSidebar.js +2 -2
  193. package/vue/chunks/UiSlider.js +396 -0
  194. package/vue/chunks/UiSpinner.js +2 -2
  195. package/vue/chunks/UiStack.js +2 -2
  196. package/vue/chunks/UiStatusMessage.js +2 -2
  197. package/vue/chunks/UiSwatch.js +2 -2
  198. package/vue/chunks/UiSwitch.js +3 -3
  199. package/vue/chunks/UiSwitcher.js +2 -2
  200. package/vue/chunks/UiTable.js +2 -2
  201. package/vue/chunks/UiTabs.js +3 -3
  202. package/vue/chunks/UiText.js +53 -12
  203. package/vue/chunks/UiTextarea.js +3 -3
  204. package/vue/chunks/UiToast.js +2 -2
  205. package/vue/chunks/UiToastRegion.js +2 -2
  206. package/vue/chunks/UiTooltip.js +3 -3
  207. package/vue/chunks/UiTopBar.js +1 -1
  208. package/vue/chunks/UiTree.js +2 -2
  209. package/vue/chunks/UiTreeItem.js +2 -2
  210. package/vue/chunks/_plugin-vue_export-helper.js +68 -2
  211. package/vue/chunks/props.js +24 -1
  212. package/vue/components.css +3391 -2139
  213. package/vue/editor/index.js +623 -211
  214. package/vue/index.d.ts +4 -0
  215. package/vue/index.js +6 -2
@@ -38,6 +38,7 @@
38
38
  }
39
39
 
40
40
  :scope:where([data-component~="ui-popover"]) {
41
+ --_ui-material-scale: 0.55;
41
42
  --_ui-popover-surface: var(--ui-popover-surface);
42
43
  --_ui-popover-border: var(--ui-popover-border);
43
44
  --_ui-popover-radius: var(--ui-popover-radius);
@@ -70,6 +71,67 @@
70
71
  box-shadow: var(--_ui-popover-shadow, var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg))));
71
72
  }
72
73
 
74
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
75
+ transparency, saturation and edge light belong to the surrounding decorative material. */
76
+ .surface {
77
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
78
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
79
+ --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
80
+ --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.55) * 8px);
81
+ --_ui-material-content-color: var(--_ui-popover-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
82
+ --_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
83
+ background:
84
+ var(--ui-surface-highlight, linear-gradient(transparent, transparent)) padding-box,
85
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
86
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
87
+ var(--_ui-material-content-color) padding-box;
88
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
89
+ border-color: var(
90
+ --_ui-popover-border,
91
+ color-mix(in oklab, var(--ui-overlay-border, var(--ui-border-strong)) calc((1 - var(--_ui-material-active)) * 100%), transparent)
92
+ );
93
+ box-shadow: var(
94
+ --_ui-popover-shadow,
95
+ var(
96
+ --ui-overlay-shadow,
97
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 8px) calc(
98
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 24px
99
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
100
+ var(--ui-material-glow, 0 0 transparent),
101
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
102
+ var(--ui-elevation-overlay, var(--ui-shadow-lg))
103
+ )
104
+ );
105
+ backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 18px))
106
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 0.18));
107
+ -webkit-backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 18px))
108
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 0.18));
109
+ }
110
+
111
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
112
+ .surface {
113
+ background: var(--_ui-material-content-color);
114
+ }
115
+ }
116
+
117
+ @media (prefers-reduced-transparency: reduce) {
118
+ .surface {
119
+ background: var(--_ui-material-content-color);
120
+ backdrop-filter: none;
121
+ -webkit-backdrop-filter: none;
122
+ }
123
+ }
124
+
125
+ @media (forced-colors: active) {
126
+ .surface {
127
+ background: Canvas;
128
+ border-color: CanvasText;
129
+ box-shadow: none;
130
+ backdrop-filter: none;
131
+ -webkit-backdrop-filter: none;
132
+ }
133
+ }
134
+
73
135
  /* A toolbar or card can supply its own surface, including an unclipped shadow. */
74
136
  :scope:where([data-component~="ui-popover"])[data-ui-popover-state~="bare"] .surface {
75
137
  overflow: visible;
@@ -77,6 +139,8 @@
77
139
  border: 0;
78
140
  background: transparent;
79
141
  box-shadow: none;
142
+ backdrop-filter: none;
143
+ -webkit-backdrop-filter: none;
80
144
  }
81
145
 
82
146
  :scope:where([data-component~="ui-popover"]):not([data-ui-popover-state~="internalOpen"]) {
@@ -134,6 +198,18 @@
134
198
  @scope ([data-component~="ui-popover"]) to ([data-component]) {
135
199
  /* This component's hooks style the element they are set on, and never a nested one. */
136
200
 
201
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
202
+ transparency, saturation and edge light belong to the surrounding decorative material. */
203
+
204
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
205
+ }
206
+
207
+ @media (prefers-reduced-transparency: reduce) {
208
+ }
209
+
210
+ @media (forced-colors: active) {
211
+ }
212
+
137
213
  /* A toolbar or card can supply its own surface, including an unclipped shadow. */
138
214
 
139
215
  @starting-style {
@@ -61,7 +61,7 @@
61
61
  border-radius: var(--ui-select-radius, var(--ui-field-radius, var(--ui-radius-md)));
62
62
  background-color: var(--ui-select-surface, var(--ui-control-surface, var(--ui-surface-elevated)));
63
63
  color: var(--ui-text-primary);
64
- color-scheme: light dark;
64
+ color-scheme: inherit;
65
65
  font: inherit;
66
66
  line-height: var(--ui-line-height-tight);
67
67
  box-shadow: var(--ui-select-shadow, var(--ui-shadow-sm));
@@ -74,15 +74,16 @@
74
74
  /* The select draws its own chevron: the native caret cannot be inset or sized consistently.
75
75
  * The root stays a native <s-lect>, so the icon is a background image rather than an element. */
76
76
  :scope:where([data-component~="ui-select"]) {
77
+ --_ui-select-highlight: var(--ui-surface-highlight, linear-gradient(transparent, transparent));
77
78
  appearance: none;
78
79
  padding-inline-end: calc(var(--ui-space-3) + 1.5rem) !important;
79
80
  background-image: var(
80
81
  --ui-select-chevron,
81
82
  url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c5c58' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
82
- );
83
+ ), var(--_ui-select-highlight);
83
84
  background-repeat: no-repeat;
84
- background-position: right var(--ui-space-3) center;
85
- background-size: 1.125rem 1.125rem;
85
+ background-position: right var(--ui-space-3) center, center;
86
+ background-size: 1.125rem 1.125rem, 100% 100%;
86
87
  }
87
88
 
88
89
  :scope:where([data-component~="ui-select"]):hover:not(:focus):not(:disabled):not([aria-invalid="true"]):not(:is(:user-invalid, [data-user-invalid])) {
@@ -114,6 +115,7 @@
114
115
  }
115
116
 
116
117
  :scope:where([data-component~="ui-select"]):disabled {
118
+ --_ui-select-highlight: none;
117
119
  background-color: var(--ui-control-surface-disabled, var(--ui-surface-muted));
118
120
  color: var(--ui-disabled-text);
119
121
  box-shadow: none;
@@ -124,8 +126,8 @@
124
126
  min-block-size: var(--ui-control-size-sm);
125
127
  padding: var(--ui-control-inset-block-sm, var(--ui-space-1)) var(--ui-space-2) !important;
126
128
  padding-inline-end: calc(var(--ui-space-2) + var(--ui-icon-size-sm) + var(--ui-space-1)) !important;
127
- background-position: right var(--ui-space-2) center;
128
- background-size: var(--ui-icon-size-sm) var(--ui-icon-size-sm);
129
+ background-position: right var(--ui-space-2) center, center;
130
+ background-size: var(--ui-icon-size-sm) var(--ui-icon-size-sm), 100% 100%;
129
131
  font-size: var(--ui-font-size-sm);
130
132
  }
131
133
 
@@ -133,7 +135,7 @@
133
135
  min-block-size: var(--ui-control-size-lg);
134
136
  padding: var(--ui-control-inset-block-lg, var(--ui-space-3)) var(--ui-space-4) !important;
135
137
  padding-inline-end: calc(var(--ui-space-4) + 1.5rem) !important;
136
- background-position: right var(--ui-space-4) center;
138
+ background-position: right var(--ui-space-4) center, center;
137
139
  font-size: var(--ui-font-size-md);
138
140
  }
139
141
 
@@ -0,0 +1,53 @@
1
+ /* Generated by HTML Next 1.0.0-alpha.69. Do not edit. */
2
+ @supports (-moz-appearance: none) {
3
+ :where([data-component], [data-slotted]) { --html-next-scope-owner: boundary; }
4
+ :where([data-slotted]:not([data-component])) { --html-next-scope-owner: projected !important; }
5
+ }
6
+ @supports (-moz-appearance: none) {
7
+ [data-component~="ui-slider"] { --html-next-scope-owner: "ui-slider" !important; }
8
+ }
9
+ @scope ([data-component~="ui-slider"]) to ([data-component], [data-slotted]) {
10
+ :scope:where([data-component~="ui-slider"]) {
11
+ display: grid !important;
12
+ grid-template-columns: minmax(4rem, 1fr) minmax(8rem, 1fr) !important;
13
+ align-items: center !important;
14
+ gap: var(--ui-space-2) !important;
15
+ margin: 0 !important;
16
+ padding: 0 !important;
17
+ min-inline-size: 0;
18
+ }
19
+ input {
20
+ inline-size: 100%;
21
+ min-inline-size: 0;
22
+ min-block-size: var(--ui-control-size-md);
23
+ margin: 0 !important;
24
+ accent-color: var(--ui-accent-solid);
25
+ cursor: pointer;
26
+ }
27
+ :scope:where([data-component~="ui-slider"])[data-ui-slider-state~="size=sm"] input {
28
+ min-block-size: var(--ui-control-size-sm);
29
+ }
30
+ :scope:where([data-component~="ui-slider"])[data-ui-slider-state~="size=lg"] input {
31
+ min-block-size: var(--ui-control-size-lg);
32
+ }
33
+ input:focus-visible {
34
+ outline: var(--ui-focus-width) solid var(--ui-control-focus, var(--ui-accent-solid));
35
+ outline-offset: var(--ui-space-1);
36
+ border-radius: var(--ui-radius-sm);
37
+ }
38
+ input:disabled {
39
+ cursor: not-allowed;
40
+ }
41
+ @media (pointer: coarse) {
42
+ input {
43
+ min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
44
+ }
45
+ }
46
+ :scope:where([data-component~="ui-slider"])[hidden] {
47
+ display: none !important;
48
+ }
49
+ }
50
+ @scope ([data-component~="ui-slider"]) to ([data-component]) {
51
+ @media (pointer: coarse) {
52
+ }
53
+ }
@@ -84,6 +84,7 @@
84
84
  border: var(--ui-border-width) solid var(--ui-control-border, var(--ui-border-strong));
85
85
  border-radius: var(--ui-radius-round);
86
86
  background-color: var(--ui-control-surface, var(--ui-surface-default));
87
+ background-image: var(--ui-surface-highlight, none);
87
88
  box-shadow: var(--ui-control-inset);
88
89
  cursor: pointer;
89
90
  transition: background-color var(--ui-motion-base) var(--ui-motion-ease), border-color var(--ui-motion-base) var(--ui-motion-ease);
@@ -105,6 +106,7 @@
105
106
 
106
107
  input:checked {
107
108
  background-color: var(--ui-accent-solid);
109
+ background-image: var(--ui-accent-highlight, none);
108
110
  border-color: var(--ui-accent-solid);
109
111
  }
110
112
 
@@ -128,6 +130,7 @@
128
130
  :scope:where([data-component~="ui-switch"])[data-ui-switch-state~="disabled"] input {
129
131
  border-color: var(--ui-disabled-border);
130
132
  background-color: var(--ui-disabled-surface);
133
+ background-image: none;
131
134
  box-shadow: none;
132
135
  cursor: not-allowed;
133
136
  }
@@ -20,6 +20,10 @@
20
20
  syntax: "*";
21
21
  inherits: false;
22
22
  }
23
+ @property --ui-tabs-panel-padding {
24
+ syntax: "*";
25
+ inherits: false;
26
+ }
23
27
 
24
28
  /* Density resolves into the tab row's own values; the public tokens still override them. */
25
29
  :scope:where([data-component~="ui-tabs"]) {
@@ -27,6 +31,7 @@
27
31
  --_ui-tabs-tab-min-block-size: var(--ui-tabs-tab-min-block-size);
28
32
  --_ui-tabs-tab-padding-block: var(--ui-tabs-tab-padding-block);
29
33
  --_ui-tabs-tab-padding-inline: var(--ui-tabs-tab-padding-inline);
34
+ --_ui-tabs-panel-padding: var(--ui-tabs-panel-padding);
30
35
 
31
36
  --_tab-min-block-size: var(--ui-control-size);
32
37
  --_tab-padding-block: var(--ui-space-2);
@@ -157,7 +162,7 @@
157
162
  border-radius: var(--ui-radius-sm);
158
163
  }
159
164
  .panels > :where([data-slotted], [data-slotted] *):is(*) {
160
- padding: var(--ui-space-4) !important;
165
+ padding: var(--_ui-tabs-panel-padding, var(--ui-space-4)) !important;
161
166
  }
162
167
 
163
168
  :scope:where([data-component~="ui-tabs"])[data-ui-tabs-state~="orientation=vertical"] .list button,
@@ -23,7 +23,7 @@
23
23
 
24
24
  /* A heading drops the browser's heading size and weight, so size and weight set it as they set
25
25
  any text, and inherit keeps the text around it. */
26
- :scope:where([data-component~="ui-text"]):is(h2, h3, h4, h5, h6) {
26
+ :scope:where([data-component~="ui-text"]):is(h1, h2, h3, h4, h5, h6) {
27
27
  font-family: var(--ui-font-display, inherit);
28
28
  font-size: inherit;
29
29
  font-weight: inherit;
@@ -86,10 +86,32 @@
86
86
  font-weight: var(--ui-font-semibold);
87
87
  }
88
88
 
89
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=display"], :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=heading"] {
90
+ font-family: var(--ui-font-display, var(--ui-font-family-sans));
91
+ font-weight: var(--ui-font-semibold);
92
+ line-height: var(--ui-line-height-tight);
93
+ }
94
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=display"] {
95
+ font-size: var(--ui-font-size-2xl);
96
+ }
97
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=heading"] {
98
+ font-size: var(--ui-font-size-xl);
99
+ }
100
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=label"] {
101
+ font-size: var(--ui-font-size-sm);
102
+ font-weight: var(--ui-font-medium);
103
+ line-height: var(--ui-line-height);
104
+ }
105
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=caption"] {
106
+ font-size: var(--ui-font-size-sm);
107
+ line-height: var(--ui-line-height);
108
+ }
109
+
89
110
  :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=eyebrow"] {
90
111
  font-size: var(--ui-font-size-xs);
91
112
  font-weight: var(--ui-font-semibold);
92
113
  letter-spacing: 0.06em;
114
+ line-height: var(--ui-line-height);
93
115
  text-transform: uppercase;
94
116
  }
95
117
  :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=code"] {
@@ -72,7 +72,8 @@
72
72
  border: var(--ui-textarea-border-width, var(--_ui-default-textarea-border-width, var(--ui-border-width))) solid
73
73
  var(--ui-textarea-border, var(--_ui-default-textarea-border, var(--ui-control-border, var(--ui-border-strong))));
74
74
  border-radius: var(--ui-textarea-radius, var(--_ui-default-textarea-radius, var(--ui-field-radius, var(--ui-radius-md))));
75
- background: var(--ui-textarea-surface, var(--_ui-default-textarea-surface, var(--ui-control-surface, var(--ui-surface-elevated))));
75
+ background-color: var(--ui-textarea-surface, var(--_ui-default-textarea-surface, var(--ui-control-surface, var(--ui-surface-elevated))));
76
+ background-image: var(--_ui-default-textarea-highlight, var(--ui-surface-highlight, none));
76
77
  color: var(--ui-text-primary);
77
78
  font: inherit;
78
79
  line-height: var(--ui-line-height-md);
@@ -50,6 +50,7 @@
50
50
  }
51
51
 
52
52
  :scope:where([data-component~="ui-tooltip"]) {
53
+ --_ui-material-scale: 0.08;
53
54
  /* Hooks do not inherit, so the parts below read them from the root. */
54
55
  --_ui-tooltip-border: var(--ui-tooltip-border);
55
56
  --_ui-tooltip-max-inline-size: var(--ui-tooltip-max-inline-size);
@@ -102,6 +103,65 @@
102
103
  box-shadow: var(--_ui-tooltip-shadow, var(--ui-overlay-shadow, var(--ui-elevation-tooltip, var(--ui-shadow-md))));
103
104
  }
104
105
 
106
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
107
+ transparency, saturation and edge light belong to the surrounding decorative material. */
108
+ .surface {
109
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
110
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
111
+ --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
112
+ --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.08) * 8px);
113
+ --_ui-material-content-color: var(--_ui-tooltip-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
114
+ --_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
115
+ background:
116
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
117
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
118
+ var(--_ui-material-content-color) padding-box;
119
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
120
+ border-color: var(
121
+ --_ui-tooltip-border,
122
+ color-mix(in oklab, var(--ui-overlay-border, var(--ui-border-strong)) calc((1 - var(--_ui-material-active)) * 100%), transparent)
123
+ );
124
+ box-shadow: var(
125
+ --_ui-tooltip-shadow,
126
+ var(
127
+ --ui-overlay-shadow,
128
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.08) * 8px) calc(
129
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.08) * 24px
130
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
131
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
132
+ var(--ui-elevation-tooltip, var(--ui-shadow-md))
133
+ )
134
+ );
135
+ backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 18px))
136
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 0.18));
137
+ -webkit-backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 18px))
138
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 0.18));
139
+ }
140
+
141
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
142
+ .surface {
143
+ background: var(--_ui-material-content-color);
144
+ }
145
+ }
146
+
147
+ @media (prefers-reduced-transparency: reduce) {
148
+ .surface {
149
+ background: var(--_ui-material-content-color);
150
+ backdrop-filter: none;
151
+ -webkit-backdrop-filter: none;
152
+ }
153
+ }
154
+
155
+ @media (forced-colors: active) {
156
+ .surface {
157
+ background: Canvas;
158
+ border-color: CanvasText;
159
+ box-shadow: none;
160
+ backdrop-filter: none;
161
+ -webkit-backdrop-filter: none;
162
+ }
163
+ }
164
+
105
165
  /* A keyboard shortcut follows the label after a thin divider, smaller and quieter, as menus show
106
166
  it. The label stays first in the description, so a screen reader hears the name, then the keys. */
107
167
  .shortcut {
@@ -226,6 +286,18 @@
226
286
 
227
287
  /* The label and the shortcut sit side by side, a gap apart, with the label wrapping on its own. */
228
288
 
289
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
290
+ transparency, saturation and edge light belong to the surrounding decorative material. */
291
+
292
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
293
+ }
294
+
295
+ @media (prefers-reduced-transparency: reduce) {
296
+ }
297
+
298
+ @media (forced-colors: active) {
299
+ }
300
+
229
301
  /* A keyboard shortcut follows the label after a thin divider, smaller and quieter, as menus show
230
302
  it. The label stays first in the description, so a screen reader hears the name, then the keys. */
231
303
 
package/theme-light.css CHANGED
@@ -2,6 +2,7 @@
2
2
  :root:not([data-theme], [data-contrast="high"]),
3
3
  [data-theme="light"] {
4
4
  color-scheme: light;
5
+ --ui-select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235c5c58' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
5
6
  /* The seeds, and only the seeds. Neutrals, hovers, tints, and disabled colours are mixed from
6
7
  these in tokens.css, so a product themes Looma by changing these eleven values. */
7
8
  --ui-surface: #ffffff;
package/theme-system.css CHANGED
@@ -1,5 +1,15 @@
1
1
  /* Optional shared recipe. Load after tokens.css and the chosen palette.
2
2
  Existing public roles remain the customization interface; no component selectors. */
3
+ /* Resolve shared geometry once where it is declared, rather than once per consuming
4
+ control's font. Palette roles remain unregistered so light-dark resolves locally. */
5
+ /* Reserve the same order when the remembered theme arrives before baseline CSS. */
6
+ @layer tokens, base, theme, components;
7
+
8
+ @property --ui-font-size { syntax: "<length>"; inherits: true; initial-value: 16px; }
9
+ @property --ui-control-size { syntax: "<length>"; inherits: true; initial-value: 40px; }
10
+ @property --ui-radius-md { syntax: "<length>"; inherits: true; initial-value: 8px; }
11
+ @property --ui-border-width { syntax: "<length>"; inherits: true; initial-value: 1px; }
12
+
3
13
  @layer theme {
4
14
  :root {
5
15
  --ui-density: 1;
@@ -9,6 +19,14 @@
9
19
  --ui-inner-depth: 0.3;
10
20
  --ui-edge-light: 0;
11
21
  --ui-overlay-translucency: 0;
22
+ --ui-glassiness: 0;
23
+ --ui-surface-separation: 0;
24
+ --ui-finish: 0;
25
+ --ui-glow: 0;
26
+ --ui-light-x: 0.5;
27
+ --ui-light-y: 0;
28
+ --ui-light-spread: 0.5;
29
+ --ui-light-strength: 0.65;
12
30
  }
13
31
 
14
32
  :where(:root, [data-theme], [data-contrast]) {
@@ -20,21 +38,23 @@
20
38
  --ui-control-size-sm: calc(var(--ui-control-size) / var(--_ui-theme-ratio));
21
39
  --ui-control-size-md: var(--ui-control-size);
22
40
  --ui-control-size-lg: calc(var(--ui-control-size) * var(--_ui-theme-ratio));
41
+ /* Bend the interior of the family while keeping its endpoints stable. */
23
42
  --ui-space-1: var(--_ui-theme-unit);
24
- --ui-space-2: calc(var(--_ui-theme-unit) * pow(2, var(--_ui-theme-curve)));
25
- --ui-space-3: calc(var(--_ui-theme-unit) * pow(3, var(--_ui-theme-curve)));
26
- --ui-space-4: calc(var(--_ui-theme-unit) * pow(4, var(--_ui-theme-curve)));
43
+ --ui-space-2: calc(var(--_ui-theme-unit) * (1 + 7 * pow(1 / 7, var(--_ui-theme-curve))));
44
+ --ui-space-3: calc(var(--_ui-theme-unit) * (1 + 7 * pow(2 / 7, var(--_ui-theme-curve))));
45
+ --ui-space-4: calc(var(--_ui-theme-unit) * (1 + 7 * pow(3 / 7, var(--_ui-theme-curve))));
27
46
  --ui-space-0-5: calc(var(--ui-space-1) * 0.5);
28
- --ui-space-5: calc(var(--_ui-theme-unit) * pow(6, var(--_ui-theme-curve)));
29
- --ui-space-6: calc(var(--_ui-theme-unit) * pow(8, var(--_ui-theme-curve)));
47
+ --ui-space-5: calc(var(--_ui-theme-unit) * (1 + 7 * pow(5 / 7, var(--_ui-theme-curve))));
48
+ --ui-space-6: calc(var(--_ui-theme-unit) * (1 + 7 * pow(7 / 7, var(--_ui-theme-curve))));
30
49
  /* Vertical editing/action insets fit the shared box instead of growing with the
31
50
  page spacing curve. Multi-line content can still grow intrinsically. */
32
51
  --ui-control-inset-block-sm: max(0px, calc((var(--ui-control-size-sm) - var(--ui-font-size-sm) * var(--ui-line-height-tight) - 2 * var(--ui-border-width)) / 2));
33
52
  --ui-control-inset-block-md: max(0px, calc((var(--ui-control-size-md) - var(--ui-font-size-md) * var(--ui-line-height-tight) - 2 * var(--ui-border-width)) / 2));
34
53
  --ui-control-inset-block-lg: max(0px, calc((var(--ui-control-size-lg) - var(--ui-font-size-md) * var(--ui-line-height-tight) - 2 * var(--ui-border-width)) / 2));
35
- --ui-action-inset-sm: calc(var(--ui-control-size-sm) * 0.625 * var(--ui-density));
36
- --ui-action-inset-md: calc(var(--ui-control-size-md) * 0.625 * var(--ui-density));
37
- --ui-action-inset-lg: calc(var(--ui-control-size-lg) * 0.625 * var(--ui-density));
54
+ --ui-font-size-xs: max(12px, calc(var(--ui-font-size) * 0.75));
55
+ --ui-action-inset-sm: var(--ui-space-2);
56
+ --ui-action-inset-md: var(--ui-space-3);
57
+ --ui-action-inset-lg: var(--ui-space-4);
38
58
 
39
59
  --ui-radius-sm: calc(var(--ui-radius-md) * 0.5);
40
60
  --ui-radius-lg: calc(var(--ui-radius-md) * 1.5);
@@ -47,25 +67,51 @@
47
67
  --_ui-theme-outer: max(0, var(--ui-outer-depth));
48
68
  --_ui-theme-inner: max(0, var(--ui-inner-depth));
49
69
  --_ui-theme-edge: clamp(0, var(--ui-edge-light), 1);
50
- --_ui-theme-edge-paint: inset 1px 1px 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * 0.08)), inset -1px -1px 0 rgb(0 0 0 / calc(var(--_ui-theme-edge) * 0.08));
70
+ --_ui-light-inline: calc((0.5 - var(--ui-light-x)) * 2px);
71
+ --_ui-shadow-x: calc((0.5 - var(--ui-light-x)) * 2);
72
+ --_ui-shadow-y: calc((0.5 - var(--ui-light-y)) * 2);
73
+ --_ui-light-block: calc((0.5 - var(--ui-light-y)) * 2px);
74
+ --_ui-theme-edge-paint: inset var(--_ui-light-inline) var(--_ui-light-block) 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * var(--ui-light-strength) * 0.3)), inset calc(-1 * var(--_ui-light-inline)) calc(-1 * var(--_ui-light-block)) 0 rgb(0 0 0 / calc(var(--_ui-theme-edge) * 0.1));
51
75
  --ui-action-edge: var(--_ui-theme-edge-paint);
52
- --ui-shadow-xs: 0 calc(1px * var(--_ui-theme-outer)) calc(2px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.08);
53
- --ui-shadow-sm: 0 calc(1px * var(--_ui-theme-outer)) calc(3px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), 0 calc(4px * var(--_ui-theme-outer)) calc(12px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
76
+ --ui-shadow-xs: calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(2px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.08);
77
+ --ui-shadow-sm: calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(1px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(3px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(12px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
54
78
  --ui-shadow-md: var(--ui-shadow-sm);
55
- --ui-shadow-lg: 0 calc(8px * var(--_ui-theme-outer)) calc(24px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), 0 calc(4px * var(--_ui-theme-outer)) calc(8px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
79
+ --ui-shadow-lg: calc(8px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(8px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(24px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.12), calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-x)) calc(4px * var(--_ui-theme-outer) * var(--_ui-shadow-y)) calc(8px * var(--_ui-theme-outer)) rgb(0 0 0 / 0.06);
56
80
  --ui-shadow-xl: var(--ui-shadow-lg);
57
- --ui-action-shadow: var(--ui-shadow-sm);
81
+ --ui-action-shadow: var(--ui-action-edge), var(--ui-shadow-sm);
58
82
  --ui-raised: var(--ui-shadow-sm);
59
83
  --ui-elevation-tooltip: var(--ui-shadow-sm);
60
84
  --ui-elevation-overlay: var(--ui-shadow-lg);
61
85
  --ui-elevation-dialog: var(--ui-shadow-lg);
62
- --ui-control-inset: inset 0 calc(1px * var(--_ui-theme-inner)) calc(3px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.15), inset 0 -1px 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * 0.18));
63
- --ui-pressed: inset 0 calc(2px * var(--_ui-theme-inner)) calc(4px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.2);
86
+ --ui-control-inset: inset calc(var(--_ui-light-inline) * var(--_ui-theme-inner)) calc(var(--_ui-light-block) * var(--_ui-theme-inner)) calc(3px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.15), inset calc(-1 * var(--_ui-light-inline)) calc(-1 * var(--_ui-light-block)) 0 rgb(255 255 255 / calc(var(--_ui-theme-edge) * var(--ui-light-strength) * 0.18)), var(--ui-material-glow);
87
+ --ui-pressed: inset calc(2 * var(--_ui-light-inline) * var(--_ui-theme-inner)) calc(2 * var(--_ui-light-block) * var(--_ui-theme-inner)) calc(4px * var(--_ui-theme-inner)) rgb(0 0 0 / 0.2);
64
88
  --ui-overlay-surface: color-mix(in srgb, var(--ui-surface-raised) calc((1 - clamp(0, var(--ui-overlay-translucency), 1)) * 100%), transparent);
89
+ /* Decorative outer material is allowed to transmit the scene. Content keeps
90
+ its own opaque plane; changing the scene cannot undermine text contrast. */
91
+ --ui-material-content: var(--ui-surface-raised);
92
+ --ui-material-glass: color-mix(in srgb, var(--ui-surface-raised) calc((1 - clamp(0, var(--ui-overlay-translucency), 1)) * 35%), transparent);
93
+ --ui-material-edge: color-mix(in srgb, var(--ui-surface-raised) 80%, var(--ui-text));
94
+ /* Each role has a bounded reflection colour. Shared source coordinates are
95
+ relative to each surface, so size and position never change the lighting. */
96
+ --ui-surface-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-surface-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
97
+ --ui-neutral-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-neutral-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
98
+ --ui-accent-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-accent-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
99
+ --ui-danger-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-danger-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
100
+ --ui-success-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-success-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
101
+ --ui-warning-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-warning-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
102
+ --ui-info-highlight: radial-gradient(ellipse calc(35% + var(--ui-light-spread) * 165%) calc(55% + var(--ui-light-spread) * 200%) at calc(var(--ui-light-x) * 100%) calc(var(--ui-light-y) * 100%), color-mix(in srgb, var(--ui-info-reflection, var(--ui-surface-raised)) calc(var(--ui-finish) * var(--ui-light-strength) * 100%), transparent), transparent 85%);
103
+ --ui-material-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-accent) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
104
+ --ui-neutral-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-text) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
105
+ --ui-accent-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-accent) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
106
+ --ui-danger-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-danger) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
107
+ --ui-success-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-success) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
108
+ --ui-warning-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-warning) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
109
+ --ui-info-glow: 0 0 calc(18px * var(--ui-glow)) color-mix(in srgb, var(--ui-info) calc(var(--ui-glow) * var(--ui-light-strength) * 18%), transparent);
110
+ --ui-raised-highlight: var(--ui-surface-highlight);
65
111
 
66
112
  /* Existing timing and easing names stay canonical. */
67
- --ui-motion-press: calc(var(--ui-motion-fast) / 3);
68
- --ui-motion-base: calc(var(--ui-motion-fast) * 1.2);
113
+ --ui-motion-press: var(--ui-motion-fast);
114
+ --ui-motion-base: calc(var(--ui-motion-fast) * 1.5);
69
115
  --ui-motion-ease-out: var(--ui-motion-ease);
70
116
  --ui-press-scale: 0.98;
71
117
  }
@@ -77,4 +123,10 @@
77
123
  --ui-press-scale: 1;
78
124
  }
79
125
  }
126
+ @media (prefers-reduced-transparency: reduce), (forced-colors: active) {
127
+ :where(:root, [data-theme], [data-contrast]) {
128
+ --ui-finish: 0;
129
+ --ui-glow: 0;
130
+ }
131
+ }
80
132
  }
package/tokens.css CHANGED
@@ -85,6 +85,10 @@
85
85
  never has to: these exist so components share one vocabulary, not to be configured. */
86
86
  :root,
87
87
  :where([data-theme], [data-contrast]) {
88
+ /* Neutral is a quiet filled surface, never the text colour inverted. */
89
+ --ui-neutral-surface: color-mix(in srgb, var(--ui-text) 6%, var(--ui-surface-raised));
90
+ --ui-neutral-hover: color-mix(in srgb, var(--ui-text) 10%, var(--ui-surface-raised));
91
+ --ui-neutral-active: color-mix(in srgb, var(--ui-text) 14%, var(--ui-surface-raised));
88
92
  --ui-accent-line-width: var(--ui-border-width);
89
93
 
90
94
  /* Type scale, from the base size. */
@@ -161,6 +165,12 @@
161
165
  --ui-accent-active: color-mix(in oklab, var(--ui-accent) 74%, var(--ui-text));
162
166
  --ui-accent-subtle: color-mix(in oklab, var(--ui-accent) 12%, var(--ui-surface));
163
167
  --ui-danger-hover: color-mix(in oklab, var(--ui-danger) 86%, var(--ui-text));
168
+ --ui-danger-active: color-mix(in oklab, var(--ui-danger) 74%, var(--ui-text));
169
+ --ui-success-active: color-mix(in oklab, var(--ui-success) 74%, var(--ui-text));
170
+ --ui-warning-active: color-mix(in oklab, var(--ui-warning) 74%, var(--ui-text));
171
+ --ui-info-active: color-mix(in oklab, var(--ui-info) 74%, var(--ui-text));
172
+ --ui-warning-hover: color-mix(in oklab, var(--ui-warning) 86%, var(--ui-text));
173
+ --ui-info-hover: color-mix(in oklab, var(--ui-info) 86%, var(--ui-text));
164
174
 
165
175
  /* Disabled is one decision, not a per-component one: the sunken surface and a pale ink, at
166
176
  full opacity, so a disabled control reads as unavailable rather than as a faded variant.
@@ -340,7 +350,7 @@
340
350
 
341
351
  [data-ui-choice-option]:is(:hover, .active) {
342
352
  background: var(--ui-surface-muted);
343
- outline: var(--ui-border-width) solid var(--ui-focus-ring);
353
+ outline: var(--ui-focus-width) solid var(--ui-focus-ring);
344
354
  outline-offset: calc(-1 * var(--ui-border-width));
345
355
  }
346
356
 
@@ -390,7 +400,7 @@
390
400
 
391
401
  @media (forced-colors: active) {
392
402
  [data-ui-choice-option][aria-selected="true"]:not([aria-disabled="true"]):not(.active) {
393
- outline: var(--ui-border-width) solid Highlight;
403
+ outline: var(--ui-focus-width) solid Highlight;
394
404
  outline-offset: calc(-1 * var(--ui-border-width));
395
405
  }
396
406
  }
@@ -16,6 +16,7 @@ export interface UiButtonProps {
16
16
  href?: string | null;
17
17
  loading?: boolean | null;
18
18
  pending?: boolean | null;
19
+ preset?: "none" | "primary" | "standard" | "quiet" | "destructive" | null;
19
20
  rel?: string | null;
20
21
  shape?: "rounded" | "pill" | null;
21
22
  size?: "xs" | "sm" | "md" | "lg" | null;