@threadlabs/looma 0.33.0 → 0.34.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 (207) hide show
  1. package/README.md +15 -0
  2. package/bin/looma-docs.mjs +3 -0
  3. package/components/shared/overlay.js +8 -2
  4. package/components/shared/surface-material.js +21 -0
  5. package/components/ui-button/ui-button.html +63 -47
  6. package/components/ui-card/ui-card.html +44 -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 +62 -1
  11. package/components/ui-dialog/ui-dialog.js +9 -1
  12. package/components/ui-icon-button/ui-icon-button.html +75 -23
  13. package/components/ui-menu/ui-menu.html +60 -0
  14. package/components/ui-menu/ui-menu.js +1 -1
  15. package/components/ui-number-input/arithmetic.js +47 -0
  16. package/components/ui-number-input/ui-number-input.html +62 -0
  17. package/components/ui-number-input/ui-number-input.js +44 -0
  18. package/components/ui-popover/ui-popover.html +64 -1
  19. package/components/ui-popover/ui-popover.js +1 -1
  20. package/components/ui-slider/ui-slider.html +84 -0
  21. package/components/ui-slider/ui-slider.js +29 -0
  22. package/components/ui-tabs/ui-tabs.html +6 -1
  23. package/components/ui-text/ui-text.html +31 -6
  24. package/components/ui-tooltip/ui-tooltip.html +60 -0
  25. package/components/ui-tooltip/ui-tooltip.js +1 -1
  26. package/dist/index.js +46 -43
  27. package/docs/README.md +146 -0
  28. package/docs/card.html +77 -0
  29. package/docs/card.js +47 -0
  30. package/docs/catalog-view.js +18 -0
  31. package/docs/catalog-view.mjs +11 -0
  32. package/docs/catalog.json +23984 -0
  33. package/docs/catalog.mjs +131 -0
  34. package/docs/cli.mjs +26 -0
  35. package/docs/commands.mjs +94 -0
  36. package/docs/customizer-render.mjs +66 -0
  37. package/docs/customizer.js +181 -0
  38. package/docs/documentation.css +16 -0
  39. package/docs/examples/ui-action-bar/examples/01-form-footer.behavior.js +7 -0
  40. package/docs/examples/ui-button/examples/08-loading.behavior.js +21 -0
  41. package/docs/examples/ui-checkbox/examples/02-checked-indeterminate-and-disabled.behavior.js +30 -0
  42. package/docs/examples/ui-combobox/examples/06-selected-values.behavior.js +11 -0
  43. package/docs/examples/ui-search-shell/examples/02-label-dismissible-status-and-footer.behavior.js +34 -0
  44. package/docs/examples/ui-toast/examples/01-authored.behavior.js +15 -0
  45. package/docs/examples/ui-toast/examples/02-danger.behavior.js +2 -0
  46. package/docs/examples/ui-tree/examples/03-max-depth-2-and-hover-expand-delay-300.behavior.js +30 -0
  47. package/docs/examples/ui-tree/examples/06-move-without-dragging.behavior.js +2 -0
  48. package/docs/examples/ui-tree/examples/07-multiple-selection.behavior.js +16 -0
  49. package/docs/examples/ui-tree-item/examples/02-container.behavior.js +1 -0
  50. package/docs/index.d.ts +56 -0
  51. package/docs/index.mjs +4 -0
  52. package/docs/local-server.mjs +68 -0
  53. package/docs/preview.js +22 -0
  54. package/docs/reference.html +1 -0
  55. package/docs/reference.js +36 -0
  56. package/docs/render.mjs +93 -0
  57. package/docs/site.mjs +239 -0
  58. package/docs/store.mjs +92 -0
  59. package/docs/theme-session.mjs +51 -0
  60. package/docs/theme.mjs +219 -0
  61. package/docs/value-editors.mjs +33 -0
  62. package/docs/workspace.mjs +32 -0
  63. package/package.json +28 -4
  64. package/styles/ui-button.css +45 -45
  65. package/styles/ui-card.css +47 -0
  66. package/styles/ui-curve-editor.css +109 -0
  67. package/styles/ui-dialog.css +132 -0
  68. package/styles/ui-icon-button.css +63 -20
  69. package/styles/ui-menu.css +72 -0
  70. package/styles/ui-number-input.css +34 -0
  71. package/styles/ui-popover.css +74 -0
  72. package/styles/ui-slider.css +53 -0
  73. package/styles/ui-tabs.css +6 -1
  74. package/styles/ui-text.css +23 -1
  75. package/styles/ui-tooltip.css +72 -0
  76. package/theme-system.css +26 -10
  77. package/tokens.css +8 -2
  78. package/vanilla/UiButton.d.ts +1 -0
  79. package/vanilla/UiButton.js +195 -130
  80. package/vanilla/UiCard.d.ts +1 -1
  81. package/vanilla/UiCard.js +1 -1
  82. package/vanilla/UiCurveEditor.d.ts +28 -0
  83. package/vanilla/UiCurveEditor.js +134 -0
  84. package/vanilla/UiIconButton.d.ts +2 -1
  85. package/vanilla/UiIconButton.js +58 -31
  86. package/vanilla/UiNumberInput.d.ts +33 -0
  87. package/vanilla/UiNumberInput.js +79 -0
  88. package/vanilla/UiSlider.d.ts +33 -0
  89. package/vanilla/UiSlider.js +125 -0
  90. package/vanilla/UiText.d.ts +2 -2
  91. package/vanilla/UiText.js +45 -11
  92. package/vanilla/index.js +3 -0
  93. package/vue/UiButton.d.ts +6 -0
  94. package/vue/UiButton.vue +155 -56
  95. package/vue/UiCard.d.ts +2 -2
  96. package/vue/UiCard.vue +55 -5
  97. package/vue/UiCurveEditor.d.ts +53 -0
  98. package/vue/UiCurveEditor.js +2 -0
  99. package/vue/UiCurveEditor.vue +427 -0
  100. package/vue/UiDialog.vue +177 -1
  101. package/vue/UiIconButton.d.ts +8 -2
  102. package/vue/UiIconButton.vue +164 -34
  103. package/vue/UiMenu.vue +89 -0
  104. package/vue/UiNumberInput.d.ts +83 -0
  105. package/vue/UiNumberInput.js +2 -0
  106. package/vue/UiNumberInput.vue +370 -0
  107. package/vue/UiPopover.vue +92 -1
  108. package/vue/UiSlider.d.ts +83 -0
  109. package/vue/UiSlider.js +2 -0
  110. package/vue/UiSlider.vue +412 -0
  111. package/vue/UiTabs.vue +6 -1
  112. package/vue/UiText.d.ts +7 -5
  113. package/vue/UiText.vue +104 -22
  114. package/vue/UiTooltip.vue +89 -0
  115. package/vue/chunks/UiActionBar.js +1 -1
  116. package/vue/chunks/UiAffordanceScope.js +2 -2
  117. package/vue/chunks/UiAvatar.js +2 -2
  118. package/vue/chunks/UiAvatarGroup.js +2 -2
  119. package/vue/chunks/UiBadge.js +2 -2
  120. package/vue/chunks/UiBreadcrumbItem.js +2 -2
  121. package/vue/chunks/UiBreadcrumbs.js +2 -2
  122. package/vue/chunks/UiButton.js +94 -11
  123. package/vue/chunks/UiCallout.js +2 -2
  124. package/vue/chunks/UiCard.js +6 -5
  125. package/vue/chunks/UiCheckbox.js +2 -2
  126. package/vue/chunks/UiCluster.js +2 -2
  127. package/vue/chunks/UiColorPicker.js +2 -2
  128. package/vue/chunks/UiCombobox.js +2 -2
  129. package/vue/chunks/UiContainer.js +2 -2
  130. package/vue/chunks/UiContextMenu.js +2 -2
  131. package/vue/chunks/UiCover.js +2 -2
  132. package/vue/chunks/UiCurveEditor.js +413 -0
  133. package/vue/chunks/UiDescriptionItem.js +2 -2
  134. package/vue/chunks/UiDescriptionList.js +2 -2
  135. package/vue/chunks/UiDialog.js +4 -4
  136. package/vue/chunks/UiDisclosure.js +2 -2
  137. package/vue/chunks/UiEditable.js +2 -2
  138. package/vue/chunks/UiEditorBlockActions.js +2 -2
  139. package/vue/chunks/UiEditorChipEditor.js +2 -2
  140. package/vue/chunks/UiEditorCodeLanguage.js +2 -2
  141. package/vue/chunks/UiEditorFootnoteEditor.js +2 -2
  142. package/vue/chunks/UiEditorImageToolbar.js +3 -3
  143. package/vue/chunks/UiEditorInsertTableGrid.js +2 -2
  144. package/vue/chunks/UiEditorLinkCard.js +3 -3
  145. package/vue/chunks/UiEditorLinkForm.js +3 -3
  146. package/vue/chunks/UiEditorMentionMenu.js +2 -2
  147. package/vue/chunks/UiEditorMentionMenuItem.js +2 -2
  148. package/vue/chunks/UiEditorSlashMenu.js +2 -2
  149. package/vue/chunks/UiEditorSlashMenuGroup.js +2 -2
  150. package/vue/chunks/UiEditorSlashMenuItem.js +2 -2
  151. package/vue/chunks/UiEditorSurface.js +2 -2
  152. package/vue/chunks/UiEditorTableContextMenu.js +2 -2
  153. package/vue/chunks/UiEditorTableOverlay.js +2 -2
  154. package/vue/chunks/UiEditorTableToolbar.js +2 -2
  155. package/vue/chunks/UiEditorToolbar.js +2 -2
  156. package/vue/chunks/UiFloatingActionButton.js +2 -2
  157. package/vue/chunks/UiFormField.js +2 -2
  158. package/vue/chunks/UiGrid.js +2 -2
  159. package/vue/chunks/UiIcon.js +2 -2
  160. package/vue/chunks/UiIconButton.js +77 -11
  161. package/vue/chunks/UiImage.js +2 -2
  162. package/vue/chunks/UiInput.js +2 -2
  163. package/vue/chunks/UiInputGroup.js +2 -2
  164. package/vue/chunks/UiList.js +2 -2
  165. package/vue/chunks/UiListItem.js +2 -2
  166. package/vue/chunks/UiListbox.js +2 -2
  167. package/vue/chunks/UiMenu.js +3 -3
  168. package/vue/chunks/UiMenuGroup.js +2 -2
  169. package/vue/chunks/UiMenuItem.js +2 -2
  170. package/vue/chunks/UiMeter.js +2 -2
  171. package/vue/chunks/UiNavItem.js +2 -2
  172. package/vue/chunks/UiNumberInput.js +390 -0
  173. package/vue/chunks/UiPageHeader.js +2 -2
  174. package/vue/chunks/UiPopover.js +4 -4
  175. package/vue/chunks/UiRadio.js +2 -2
  176. package/vue/chunks/UiRadioGroup.js +2 -2
  177. package/vue/chunks/UiReel.js +2 -2
  178. package/vue/chunks/UiScrollArea.js +2 -2
  179. package/vue/chunks/UiSearchResultRow.js +2 -2
  180. package/vue/chunks/UiSearchShell.js +2 -2
  181. package/vue/chunks/UiSection.js +2 -2
  182. package/vue/chunks/UiSelect.js +2 -2
  183. package/vue/chunks/UiSeparator.js +2 -2
  184. package/vue/chunks/UiSidebar.js +2 -2
  185. package/vue/chunks/UiSlider.js +396 -0
  186. package/vue/chunks/UiSpinner.js +2 -2
  187. package/vue/chunks/UiStack.js +2 -2
  188. package/vue/chunks/UiStatusMessage.js +2 -2
  189. package/vue/chunks/UiSwatch.js +2 -2
  190. package/vue/chunks/UiSwitch.js +2 -2
  191. package/vue/chunks/UiSwitcher.js +2 -2
  192. package/vue/chunks/UiTable.js +2 -2
  193. package/vue/chunks/UiTabs.js +3 -3
  194. package/vue/chunks/UiText.js +53 -12
  195. package/vue/chunks/UiTextarea.js +2 -2
  196. package/vue/chunks/UiToast.js +2 -2
  197. package/vue/chunks/UiToastRegion.js +2 -2
  198. package/vue/chunks/UiTooltip.js +3 -3
  199. package/vue/chunks/UiTopBar.js +1 -1
  200. package/vue/chunks/UiTree.js +2 -2
  201. package/vue/chunks/UiTreeItem.js +2 -2
  202. package/vue/chunks/_plugin-vue_export-helper.js +68 -2
  203. package/vue/chunks/props.js +24 -1
  204. package/vue/components.css +2215 -1203
  205. package/vue/editor/index.js +623 -211
  206. package/vue/index.d.ts +3 -0
  207. package/vue/index.js +5 -2
@@ -1216,7 +1216,7 @@ svg,.arc {
1216
1216
  flex: none;
1217
1217
  vertical-align: middle;
1218
1218
  }
1219
- :scope:not([variant="link"]):has(.badge:not(:empty)):where([data-hn-ui-button]) {
1219
+ :scope:not([data-appearance="link"]):has(.badge:not(:empty)):where([data-hn-ui-button]) {
1220
1220
  padding-block: var(--ui-space-0-5) !important;
1221
1221
  }
1222
1222
  .badge:where([data-hn-ui-button]) {
@@ -1253,7 +1253,7 @@ svg,.arc {
1253
1253
  var(--ui-action-inset-lg, var(--ui-space-4)) !important;
1254
1254
  font-size: var(--ui-font-size-md);
1255
1255
  }
1256
- :scope[data-ui-button-state~="variant=card"]:where([data-hn-ui-button]) {
1256
+ :scope[data-appearance="card"]:where([data-hn-ui-button]) {
1257
1257
  display: grid !important;
1258
1258
  grid-template-columns: auto minmax(0, 1fr) auto;
1259
1259
  align-content: center !important;
@@ -1266,10 +1266,10 @@ svg,.arc {
1266
1266
  box-shadow: none;
1267
1267
  background-image: none;
1268
1268
  }
1269
- :scope[data-ui-button-state~="variant=card"][data-ui-button-state~="size=lg"]:where([data-hn-ui-button]) {
1269
+ :scope[data-appearance="card"][size="lg"]:where([data-hn-ui-button]) {
1270
1270
  min-block-size: max(var(--ui-control-min-block-size), var(--ui-control-size-lg));
1271
1271
  }
1272
- :scope[data-ui-button-state~="variant=card"]:has(.card-icon:empty):where([data-hn-ui-button]) {
1272
+ :scope[data-appearance="card"]:has(.card-icon:empty):where([data-hn-ui-button]) {
1273
1273
  grid-template-columns: minmax(0, 1fr) auto;
1274
1274
  }
1275
1275
  .card-icon:where([data-hn-ui-button]) {
@@ -1291,10 +1291,10 @@ svg,.arc {
1291
1291
  border-color: var(--ui-button-hover-border, var(--_tone-hover));
1292
1292
  background-color: var(--ui-button-hover-surface, oklch(from var(--_tone) l c h / 12%));
1293
1293
  }
1294
- :scope[data-ui-button-state~="variant=card"][data-ui-button-state~="tone=neutral"]:where([data-hn-ui-button]) {
1294
+ :scope[data-appearance="card"][data-tone="neutral"]:where([data-hn-ui-button]) {
1295
1295
  border-color: var(--ui-button-border, var(--ui-border));
1296
1296
  }
1297
- :scope[data-ui-button-state~="variant=card"][data-ui-button-state~="tone=neutral"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1297
+ :scope[data-appearance="card"][data-tone="neutral"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1298
1298
  border-color: var(--ui-button-hover-border, var(--ui-border-strong));
1299
1299
  }
1300
1300
  :scope:active:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
@@ -1303,58 +1303,58 @@ svg,.arc {
1303
1303
  background-image: none;
1304
1304
  box-shadow: var(--ui-pressed);
1305
1305
  }
1306
- :scope[data-ui-button-state~="variant=solid"]:where([data-hn-ui-button]),:scope[data-ui-button-state~="variant=danger"]:where([data-hn-ui-button]) {
1306
+ :scope[data-appearance="solid"]:where([data-hn-ui-button]),:scope[data-appearance="danger"]:where([data-hn-ui-button]) {
1307
1307
  border-color: var(--_tone);
1308
1308
  background-color: var(--_tone);
1309
1309
  color: var(--_on-tone);
1310
1310
  box-shadow: var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow)));
1311
1311
  }
1312
- :is(:scope[data-ui-button-state~="variant=solid"], :scope[data-ui-button-state~="variant=danger"]):hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1312
+ :is(:scope[data-appearance="solid"], :scope[data-appearance="danger"]):hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1313
1313
  background-color: var(--_tone-hover);
1314
1314
  border-color: var(--_tone-hover);
1315
1315
  }
1316
- :is(:scope[data-ui-button-state~="variant=solid"], :scope[data-ui-button-state~="variant=danger"]):active:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1316
+ :is(:scope[data-appearance="solid"], :scope[data-appearance="danger"]):active:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1317
1317
  background-color: var(--_tone-active);
1318
1318
  border-color: var(--_tone-active);
1319
1319
  background-image: none;
1320
1320
  box-shadow: var(--ui-pressed);
1321
1321
  }
1322
- :scope[data-ui-button-state~="tone=neutral"]:where([data-hn-ui-button]) {
1322
+ :scope[data-tone="neutral"]:where([data-hn-ui-button]) {
1323
1323
  --_hue: var(--ui-text);
1324
1324
  --_hue-hover: var(--ui-text);
1325
1325
  --_hue-active: var(--ui-text);
1326
1326
  --_hue-text: var(--ui-text);
1327
1327
  --_on-hue: var(--ui-surface);
1328
1328
  }
1329
- :scope[data-ui-button-state~="tone=danger"]:where([data-hn-ui-button]),:scope[data-ui-button-state~="variant=danger"]:where([data-hn-ui-button]) {
1329
+ :scope[data-tone="danger"]:where([data-hn-ui-button]),:scope[data-appearance="danger"]:where([data-hn-ui-button]) {
1330
1330
  --_hue: var(--ui-danger);
1331
1331
  --_hue-hover: var(--ui-danger-hover);
1332
- --_hue-active: var(--ui-danger-hover);
1333
- --_hue-text: var(--ui-danger-hover);
1332
+ --_hue-active: var(--ui-danger-active, var(--ui-danger-hover));
1333
+ --_hue-text: var(--ui-danger-subtle-text);
1334
1334
  --_on-hue: var(--ui-on-danger);
1335
1335
  }
1336
- :scope[data-ui-button-state~="tone=success"]:where([data-hn-ui-button]) {
1336
+ :scope[data-tone="success"]:where([data-hn-ui-button]) {
1337
1337
  --_hue: var(--ui-success);
1338
- --_hue-hover: color-mix(in srgb, var(--ui-success) 85%, #000);
1339
- --_hue-active: color-mix(in srgb, var(--ui-success) 75%, #000);
1340
- --_hue-text: color-mix(in srgb, var(--ui-success) 85%, #000);
1341
- --_on-hue: var(--ui-surface);
1338
+ --_hue-hover: var(--ui-success-hover);
1339
+ --_hue-active: var(--ui-success-active);
1340
+ --_hue-text: var(--ui-success-subtle-text);
1341
+ --_on-hue: var(--ui-success-on-strong);
1342
1342
  }
1343
- :scope[data-ui-button-state~="tone=warning"]:where([data-hn-ui-button]) {
1343
+ :scope[data-tone="warning"]:where([data-hn-ui-button]) {
1344
1344
  --_hue: var(--ui-warning);
1345
- --_hue-hover: color-mix(in srgb, var(--ui-warning) 85%, #000);
1346
- --_hue-active: color-mix(in srgb, var(--ui-warning) 75%, #000);
1347
- --_hue-text: color-mix(in srgb, var(--ui-warning) 85%, #000);
1348
- --_on-hue: var(--ui-surface);
1345
+ --_hue-hover: var(--ui-warning-hover);
1346
+ --_hue-active: var(--ui-warning-active);
1347
+ --_hue-text: var(--ui-warning-subtle-text);
1348
+ --_on-hue: var(--ui-warning-on-strong);
1349
1349
  }
1350
- :scope[data-ui-button-state~="tone=info"]:where([data-hn-ui-button]) {
1350
+ :scope[data-tone="info"]:where([data-hn-ui-button]) {
1351
1351
  --_hue: var(--ui-info);
1352
- --_hue-hover: color-mix(in srgb, var(--ui-info) 85%, #000);
1353
- --_hue-active: color-mix(in srgb, var(--ui-info) 75%, #000);
1354
- --_hue-text: color-mix(in srgb, var(--ui-info) 85%, #000);
1355
- --_on-hue: var(--ui-surface);
1352
+ --_hue-hover: var(--ui-info-hover);
1353
+ --_hue-active: var(--ui-info-active);
1354
+ --_hue-text: var(--ui-info-subtle-text);
1355
+ --_on-hue: var(--ui-info-on-strong);
1356
1356
  }
1357
- :scope[data-ui-button-state~="variant=field"]:where([data-hn-ui-button]) {
1357
+ :scope[data-appearance="field"]:where([data-hn-ui-button]) {
1358
1358
  --_ui-field-shadow: var(--ui-shadow-sm);
1359
1359
  border-color: var(--ui-button-border, var(--ui-control-border, var(--ui-border-strong)));
1360
1360
  border-radius: var(--ui-button-radius, var(--ui-field-radius, var(--ui-radius-md)));
@@ -1366,7 +1366,7 @@ svg,.arc {
1366
1366
  font-weight: var(--ui-font-normal);
1367
1367
  box-shadow: var(--ui-button-shadow, var(--_ui-field-shadow));
1368
1368
  }
1369
- :scope[data-ui-button-state~="variant=field"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1369
+ :scope[data-appearance="field"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1370
1370
  border-color: var(
1371
1371
  --ui-button-hover-border,
1372
1372
  var(--ui-control-border-hover, var(--ui-text-secondary))
@@ -1376,26 +1376,26 @@ svg,.arc {
1376
1376
  var(--ui-control-surface, var(--ui-surface-elevated))
1377
1377
  );
1378
1378
  }
1379
- :scope[data-ui-button-state~="variant=field"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1379
+ :scope[data-appearance="field"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1380
1380
  --_ui-field-shadow: var(--ui-pressed);
1381
1381
  }
1382
- :scope[data-ui-button-state~="variant=field"]:focus-visible:where([data-hn-ui-button]) {
1382
+ :scope[data-appearance="field"]:focus-visible:where([data-hn-ui-button]) {
1383
1383
  border-color: var(--ui-control-focus, var(--ui-accent-solid));
1384
1384
  box-shadow:
1385
1385
  var(--ui-button-shadow, var(--_ui-field-shadow)),
1386
1386
  var(--ui-control-focus-halo-shadow);
1387
1387
  }
1388
- :scope[data-ui-button-state~="variant=ghost"]:where([data-hn-ui-button]) {
1388
+ :scope[data-appearance="ghost"]:where([data-hn-ui-button]) {
1389
1389
  border-color: transparent;
1390
1390
  background: transparent;
1391
1391
  box-shadow: none;
1392
1392
  color: var(--ui-button-ghost-text, var(--_tone-text));
1393
1393
  }
1394
- :scope[data-ui-button-state~="variant=ghost"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1394
+ :scope[data-appearance="ghost"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1395
1395
  background-color: var(--ui-button-ghost-hover-surface, oklch(from var(--_tone) l c h / 10%));
1396
1396
  border-color: transparent;
1397
1397
  }
1398
- :scope[data-ui-button-state~="variant=ghost"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1398
+ :scope[data-appearance="ghost"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1399
1399
  background-color: var(
1400
1400
  --ui-button-ghost-active-surface,
1401
1401
  color-mix(in oklch, var(--ui-surface), var(--_tone) 3%)
@@ -1411,12 +1411,12 @@ svg,.arc {
1411
1411
  var(--ui-button-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
1412
1412
  var(--ui-focus-halo);
1413
1413
  }
1414
- :scope[data-ui-button-state~="variant=solid"]:focus-visible:where([data-hn-ui-button]) {
1414
+ :scope[data-appearance="solid"]:focus-visible:where([data-hn-ui-button]) {
1415
1415
  box-shadow:
1416
1416
  var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
1417
1417
  var(--ui-focus-halo);
1418
1418
  }
1419
- :is(:scope[data-ui-button-state~="variant=ghost"], :scope[data-ui-button-state~="variant=link"], :scope[data-ui-button-state~="variant=card"]):focus-visible:where([data-hn-ui-button]) {
1419
+ :is(:scope[data-appearance="ghost"], :scope[data-appearance="link"], :scope[data-appearance="card"]):focus-visible:where([data-hn-ui-button]) {
1420
1420
  box-shadow: var(--ui-focus-halo);
1421
1421
  }
1422
1422
  :scope:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])):where([data-hn-ui-button]) {
@@ -1432,7 +1432,7 @@ svg,.arc {
1432
1432
  :is(:scope[data-ui-button-state~="loading"], :scope[data-ui-button-state~="pending"]):focus-visible:where([data-hn-ui-button]) {
1433
1433
  box-shadow: var(--ui-focus-halo);
1434
1434
  }
1435
- :scope[data-ui-button-state~="variant=ghost"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])):where([data-hn-ui-button]) {
1435
+ :scope[data-appearance="ghost"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])):where([data-hn-ui-button]) {
1436
1436
  background-color: var(--ui-disabled-surface);
1437
1437
  border-color: transparent;
1438
1438
  }
@@ -1442,12 +1442,12 @@ svg,.arc {
1442
1442
  }
1443
1443
  }
1444
1444
  html[data-ui-input-modality="touch"]
1445
- :scope[data-ui-button-state~="variant=link"]:where([data-hn-ui-button]),html[data-ui-input-modality="touch"]
1445
+ :scope[data-appearance="link"]:where([data-hn-ui-button]),html[data-ui-input-modality="touch"]
1446
1446
  :scope[data-ui-button-state~="size=xs"]:where([data-hn-ui-button]) {
1447
1447
  position: relative;
1448
1448
  }
1449
1449
  html[data-ui-input-modality="touch"]
1450
- :scope[data-ui-button-state~="variant=link"]:where([data-hn-ui-button])::after,html[data-ui-input-modality="touch"]
1450
+ :scope[data-appearance="link"]:where([data-hn-ui-button])::after,html[data-ui-input-modality="touch"]
1451
1451
  :scope[data-ui-button-state~="size=xs"]:where([data-hn-ui-button])::after {
1452
1452
  position: absolute;
1453
1453
  inset: 50% auto auto 50%;
@@ -1456,7 +1456,7 @@ html[data-ui-input-modality="touch"]
1456
1456
  transform: translate(-50%, -50%);
1457
1457
  content: "";
1458
1458
  }
1459
- :scope[data-ui-button-state~="variant=link"]:where([data-hn-ui-button]) {
1459
+ :scope[data-appearance="link"]:where([data-hn-ui-button]) {
1460
1460
  display: inline !important;
1461
1461
  min-block-size: 0;
1462
1462
  padding: 0 !important;
@@ -1474,21 +1474,21 @@ html[data-ui-input-modality="touch"]
1474
1474
  color var(--ui-motion-fast) var(--ui-motion-ease),
1475
1475
  text-decoration-color var(--ui-motion-fast) var(--ui-motion-ease);
1476
1476
  }
1477
- :scope[data-ui-button-state~="variant=link"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1477
+ :scope[data-appearance="link"]:hover:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1478
1478
  color: var(--ui-button-link-hover-text, var(--ui-text-primary));
1479
1479
  text-decoration-color: currentColor;
1480
1480
  background: none;
1481
1481
  transform: none;
1482
1482
  }
1483
- :scope[data-ui-button-state~="variant=link"]:active:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1483
+ :scope[data-appearance="link"]:active:not(:disabled, [aria-disabled="true"]):where([data-hn-ui-button]) {
1484
1484
  background: none;
1485
1485
  transform: none;
1486
1486
  }
1487
- :scope[data-ui-button-state~="variant=link"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])):where([data-hn-ui-button]) {
1487
+ :scope[data-appearance="link"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])):where([data-hn-ui-button]) {
1488
1488
  background: none;
1489
1489
  border-color: transparent;
1490
1490
  }
1491
- :scope[data-ui-button-state~="variant=link"]:focus-visible:where([data-hn-ui-button]) {
1491
+ :scope[data-appearance="link"]:focus-visible:where([data-hn-ui-button]) {
1492
1492
  box-shadow: none;
1493
1493
  /* Fallback keeps the ring if the token is missing: an unresolved var() would void the outline. */
1494
1494
  outline: var(--ui-focus-width) solid var(--ui-focus-ring);
@@ -1717,6 +1717,53 @@ html[data-ui-input-modality="touch"]
1717
1717
  border-color: var(--ui-border-subtle);
1718
1718
  box-shadow: var(--ui-shadow-lg);
1719
1719
  }
1720
+ :scope[data-ui-card-state~="variant=glass"]:where([data-hn-ui-card]) {
1721
+ --_ui-panel-glass: clamp(0, var(--ui-glassiness, 0), 1);
1722
+ --_ui-panel-separation: clamp(0, var(--ui-surface-separation, 0), 1);
1723
+ --_ui-panel-rim: calc(
1724
+ (var(--_ui-panel-separation) + var(--_ui-panel-glass) * 0.25) * 0.65 * 8px
1725
+ );
1726
+ border-width: calc(var(--ui-border-width) + var(--_ui-panel-rim));
1727
+ border-color: transparent;
1728
+ background:
1729
+ linear-gradient(var(--_ui-card-surface), var(--_ui-card-surface)) padding-box,
1730
+ linear-gradient(
1731
+ var(--ui-material-glass, var(--ui-surface-raised)),
1732
+ var(--ui-material-glass, var(--ui-surface-raised))
1733
+ ) border-box,
1734
+ var(--_ui-card-surface) padding-box;
1735
+ box-shadow:
1736
+ var(--ui-shadow-lg),
1737
+ inset 0 0 0 var(--ui-border-width) var(--ui-material-edge, var(--ui-border-strong));
1738
+ backdrop-filter: blur(calc(var(--_ui-panel-glass) * 0.65 * 18px))
1739
+ saturate(calc(1 + var(--_ui-panel-glass) * 0.65 * 0.18));
1740
+ -webkit-backdrop-filter: blur(calc(var(--_ui-panel-glass) * 0.65 * 18px))
1741
+ saturate(calc(1 + var(--_ui-panel-glass) * 0.65 * 0.18));
1742
+ }
1743
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
1744
+ :scope[data-ui-card-state~="variant=glass"]:where([data-hn-ui-card]) {
1745
+ background: var(--_ui-card-surface);
1746
+ }
1747
+ }
1748
+ @media (prefers-reduced-transparency: reduce) {
1749
+ :scope[data-ui-card-state~="variant=glass"]:where([data-hn-ui-card]) {
1750
+ background: var(--_ui-card-surface);
1751
+ border-width: var(--ui-border-width);
1752
+ border-color: var(--ui-border-strong);
1753
+ backdrop-filter: none;
1754
+ -webkit-backdrop-filter: none;
1755
+ }
1756
+ }
1757
+ @media (forced-colors: active) {
1758
+ :scope[data-ui-card-state~="variant=glass"]:where([data-hn-ui-card]) {
1759
+ background: Canvas;
1760
+ color: CanvasText;
1761
+ border: var(--ui-border-width) solid CanvasText;
1762
+ box-shadow: none;
1763
+ backdrop-filter: none;
1764
+ -webkit-backdrop-filter: none;
1765
+ }
1766
+ }
1720
1767
  :scope[data-ui-card-state~="tone=accent"]:where([data-hn-ui-card]) {
1721
1768
  border-color: color-mix(in srgb, var(--ui-accent) 25%, var(--ui-border-default));
1722
1769
  --_ui-card-surface: color-mix(in srgb, var(--ui-accent) 6%, var(--ui-surface-default));
@@ -2439,6 +2486,9 @@ input[type="range"] {
2439
2486
 
2440
2487
  /* The label and the shortcut sit side by side, a gap apart, with the label wrapping on its own. */
2441
2488
 
2489
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
2490
+ transparency, saturation and edge light belong to the surrounding decorative material. */
2491
+
2442
2492
  /* A keyboard shortcut follows the label after a thin divider, smaller and quieter, as menus show
2443
2493
  it. The label stays first in the description, so a screen reader hears the name, then the keys. */
2444
2494
 
@@ -2448,6 +2498,7 @@ input[type="range"] {
2448
2498
  * the surface border line, so the fill covers that stretch of border and the outline runs unbroken. */
2449
2499
  @scope (.ui-tooltip) to ([data-hn]) {
2450
2500
  :scope:where([data-hn-ui-tooltip]) {
2501
+ --_ui-material-scale: 0.08;
2451
2502
  /* Hooks do not inherit, so the parts below read them from the root. */
2452
2503
  --_ui-tooltip-border: var(--ui-tooltip-border);
2453
2504
  --_ui-tooltip-max-inline-size: var(--ui-tooltip-max-inline-size);
@@ -2500,6 +2551,88 @@ input[type="range"] {
2500
2551
  var(--ui-overlay-shadow, var(--ui-elevation-tooltip, var(--ui-shadow-md)))
2501
2552
  );
2502
2553
  }
2554
+ .surface:where([data-hn-ui-tooltip]) {
2555
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
2556
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
2557
+ --_ui-material-active: clamp(
2558
+ 0,
2559
+ calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000),
2560
+ 1
2561
+ );
2562
+ --_ui-material-rim: calc(
2563
+ (
2564
+ var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25
2565
+ ) *
2566
+ var(--_ui-material-scale, 0.08) *
2567
+ 8px
2568
+ );
2569
+ --_ui-material-content-color: var(
2570
+ --_ui-tooltip-surface,
2571
+ var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated)))
2572
+ );
2573
+ --_ui-material-rim-color: color-mix(
2574
+ in srgb,
2575
+ var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%),
2576
+ transparent
2577
+ );
2578
+ background:
2579
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color))
2580
+ padding-box,
2581
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
2582
+ var(--_ui-material-content-color) padding-box;
2583
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
2584
+ border-color: var(
2585
+ --_ui-tooltip-border,
2586
+ color-mix(
2587
+ in oklab,
2588
+ var(--ui-overlay-border, var(--ui-border-strong)) calc(
2589
+ (1 - var(--_ui-material-active)) * 100%
2590
+ ),
2591
+ transparent
2592
+ )
2593
+ );
2594
+ box-shadow: var(
2595
+ --_ui-tooltip-shadow,
2596
+ var(
2597
+ --ui-overlay-shadow,
2598
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.08) * 8px) calc(
2599
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.08) * 24px
2600
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
2601
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(
2602
+ --ui-material-edge,
2603
+ var(--ui-border-strong)
2604
+ ),
2605
+ var(--ui-elevation-tooltip, var(--ui-shadow-md))
2606
+ )
2607
+ );
2608
+ backdrop-filter: blur(
2609
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 18px)
2610
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 0.18));
2611
+ -webkit-backdrop-filter: blur(
2612
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 18px)
2613
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 0.18));
2614
+ }
2615
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
2616
+ .surface:where([data-hn-ui-tooltip]) {
2617
+ background: var(--_ui-material-content-color);
2618
+ }
2619
+ }
2620
+ @media (prefers-reduced-transparency: reduce) {
2621
+ .surface:where([data-hn-ui-tooltip]) {
2622
+ background: var(--_ui-material-content-color);
2623
+ backdrop-filter: none;
2624
+ -webkit-backdrop-filter: none;
2625
+ }
2626
+ }
2627
+ @media (forced-colors: active) {
2628
+ .surface:where([data-hn-ui-tooltip]) {
2629
+ background: Canvas;
2630
+ border-color: CanvasText;
2631
+ box-shadow: none;
2632
+ backdrop-filter: none;
2633
+ -webkit-backdrop-filter: none;
2634
+ }
2635
+ }
2503
2636
  .shortcut:where([data-hn-ui-tooltip]) {
2504
2637
  display: inline-flex !important;
2505
2638
  align-items: center !important;
@@ -3531,215 +3664,847 @@ button:where(:scope, :scope *):where([data-hn-ui-combobox]) {
3531
3664
  }
3532
3665
  }
3533
3666
 
3534
- /* One term and its value in a ui-description-list, laid out by the list's layout. */
3535
-
3536
- /* A component that sets its display still honours the hidden attribute on its root. */
3537
- @scope (.ui-description-item) to ([data-hn]) {
3538
- :scope:where([data-hn-ui-description-item]) {
3539
- display: var(--_ui-description-display, grid) !important;
3540
- grid-column: var(--_ui-description-column, 1 / -1);
3541
- grid-template-columns: subgrid;
3542
- flex-direction: column !important;
3543
- align-items: var(--_ui-description-align, baseline) !important;
3544
- gap: var(--ui-space-1) var(--ui-space-6) !important;
3545
- min-inline-size: 0;
3546
- padding: var(--_ui-description-padding, 0) !important;
3547
- border-width: var(--_ui-description-border-width, 0);
3548
- border-style: solid;
3549
- border-color: var(--_ui-description-border-color, var(--ui-border-default));
3550
- border-radius: var(--ui-radius-md);
3551
- font-size: var(--ui-font-size-sm);
3552
- }
3553
- dt:where([data-hn-ui-description-item]) {
3554
- color: var(--ui-text-muted);
3555
- }
3556
- dd:where([data-hn-ui-description-item]) {
3557
- margin: 0 !important;
3558
- min-inline-size: 0;
3559
- color: var(--ui-text-primary);
3560
- font-weight: var(--ui-font-medium);
3561
- font-size: var(--_ui-description-value-size, inherit);
3562
- text-align: start;
3563
- overflow-wrap: anywhere;
3564
- }
3565
- :scope[hidden]:where([data-hn-ui-description-item]) {
3566
- display: none !important;
3567
- }
3568
- }
3569
-
3570
- /* Named values: a term and what it is, for each item (ui-description-item). */
3571
- /* Rows line every term up in one column and every value in the next, through subgrid. */
3572
-
3573
- /* Stacked, grid, and tiles set each term above its value, passing the shape to the items through
3574
- private properties, which cross into each item. */
3575
-
3576
- /* A column is at least --_min wide; with columns set, at least its share of the width, so no more
3577
- than that many fit. */
3578
-
3579
- /* Compact takes each layout's closer spacing. */
3580
-
3581
- /* A component that sets its display still honours the hidden attribute on its root. */
3582
- @scope (.ui-description-list) to ([data-hn]) {
3583
- :scope:where([data-hn-ui-description-list]) {
3584
- --_gap: var(--ui-space-2);
3585
- --_gap-compact: var(--ui-space-1);
3586
- --_column-gap: var(--ui-space-6);
3587
- --_min: 10rem;
3588
- --_track: var(--_min);
3589
- --_tile-padding: var(--ui-space-3);
3590
- display: grid !important;
3591
- grid-template-columns: minmax(6rem, max-content) minmax(0, 1fr);
3592
- gap: var(--_gap) var(--_column-gap) !important;
3593
- min-inline-size: 0;
3594
- margin: 0 !important;
3595
- }
3596
- :scope[data-ui-description-list-state~="layout=stacked"]:where([data-hn-ui-description-list]),:scope[data-ui-description-list-state~="layout=grid"]:where([data-hn-ui-description-list]),:scope[data-ui-description-list-state~="layout=tiles"]:where([data-hn-ui-description-list]) {
3597
- --_ui-description-display: flex;
3598
- --_ui-description-column: auto;
3599
- --_ui-description-align: stretch;
3600
- --_gap: var(--ui-space-4);
3601
- --_gap-compact: var(--ui-space-2);
3602
- grid-template-columns: minmax(0, 1fr);
3603
- }
3604
- :scope[data-ui-description-list-state~="layout=grid"]:where([data-hn-ui-description-list]),:scope[data-ui-description-list-state~="layout=tiles"]:where([data-hn-ui-description-list]) {
3605
- inline-size: 100%;
3606
- grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--_track)), 1fr));
3607
- }
3608
- :scope[data-ui-description-list-state~="layout=tiles"]:where([data-hn-ui-description-list]) {
3609
- --_ui-description-align: flex-start;
3610
- --_ui-description-value-size: var(--ui-font-size-lg);
3611
- --_ui-description-padding: var(--_tile-padding);
3612
- --_ui-description-border-width: var(--ui-border-width);
3613
- --_ui-description-border-color: var(--ui-border-strong);
3614
- --_gap: var(--ui-space-3);
3615
- --_gap-compact: var(--ui-space-2);
3616
- --_column-gap: var(--_gap);
3617
- }
3618
- :scope[data-ui-description-list-state~="columns=2"]:where([data-hn-ui-description-list]) {
3619
- --_track: max(var(--_min), (100% - var(--_column-gap)) / 2);
3620
- }
3621
- :scope[data-ui-description-list-state~="columns=3"]:where([data-hn-ui-description-list]) {
3622
- --_track: max(var(--_min), (100% - 2 * var(--_column-gap)) / 3);
3623
- }
3624
- :scope[data-ui-description-list-state~="columns=4"]:where([data-hn-ui-description-list]) {
3625
- --_track: max(var(--_min), (100% - 3 * var(--_column-gap)) / 4);
3626
- }
3627
- :scope[data-ui-description-list-state~="density=compact"]:where([data-hn-ui-description-list]) {
3628
- --_gap: var(--_gap-compact);
3629
- --_tile-padding: var(--ui-space-2);
3630
- }
3631
- :scope[hidden]:where([data-hn-ui-description-list]) {
3632
- display: none !important;
3633
- }
3634
- }
3635
-
3636
- /* The controller sets each fade length from overflow and scroll position. The mask blends
3637
- into whatever is behind the area without needing to know its colour. Before upgrade, its
3638
- zero-length defaults leave the authored scroll area fully visible. */
3639
-
3640
- /* Trim projected edges without changing spacing inside an item. */
3641
-
3642
- /* A component that sets its display still honours the hidden attribute on its root. */
3643
- @scope (.ui-scroll-area) to ([data-hn]) {
3644
- :scope[data-ui-scroll-area-state~="fill"]:where([data-hn-ui-scroll-area]) {
3645
- flex: 1;
3646
- }
3647
- :scope:where([data-hn-ui-scroll-area]) {
3648
- display: block !important;
3649
- box-sizing: border-box !important;
3650
- min-block-size: 0;
3651
- min-inline-size: 0;
3652
- overflow-x: hidden;
3653
- overflow-y: auto;
3654
- overscroll-behavior: contain;
3655
- --_ui-scroll-fade-direction: to bottom;
3656
- --_ui-scroll-fade-inline: to right;
3657
- --_ui-scroll-fade-size: var(--ui-scroll-fade-size, 24px);
3658
- mask-image: linear-gradient(
3659
- var(--_ui-scroll-fade-direction),
3660
- transparent,
3661
- #000 var(--_ui-scroll-fade-start),
3662
- #000 calc(100% - var(--_ui-scroll-fade-end)),
3663
- transparent
3664
- );
3665
- }
3666
- .content:where([data-hn-ui-scroll-area]) {
3667
- display: flow-root !important;
3668
- }
3669
- :scope[data-ui-scroll-area-state~="trim"]
3670
- .content
3671
- > :where(:not([data-hn-ui-scroll-area])):is(:first-child) {
3672
- margin-block-start: 0 !important;
3673
- }
3674
- :scope[data-ui-scroll-area-state~="trim"]
3675
- .content
3676
- > :where(:not([data-hn-ui-scroll-area])):is(:last-child) {
3677
- margin-block-end: 0 !important;
3678
- }
3679
- :scope[data-ui-scroll-area-state~="orientation=horizontal"]:where([data-hn-ui-scroll-area]) {
3680
- overflow-x: auto;
3681
- overflow-y: hidden;
3682
- --_ui-scroll-fade-direction: var(--_ui-scroll-fade-inline);
3683
- }
3684
- :scope:dir(rtl):where([data-hn-ui-scroll-area]) {
3685
- --_ui-scroll-fade-inline: to left;
3686
- }
3687
- :scope[data-ui-scroll-area-state~="size=sm"]:where([data-hn-ui-scroll-area]) {
3688
- max-block-size: calc(9.375rem + var(--ui-scroll-fade-size, 24px));
3689
- }
3690
- :scope[data-ui-scroll-area-state~="size=md"]:where([data-hn-ui-scroll-area]) {
3691
- max-block-size: 20rem;
3692
- }
3693
- :scope[data-ui-scroll-area-state~="size=lg"]:where([data-hn-ui-scroll-area]) {
3694
- max-block-size: 30rem;
3695
- }
3696
- :scope[data-ui-scroll-area-state~="padding=xs"]:where([data-hn-ui-scroll-area]) {
3697
- padding: var(--ui-space-2) !important;
3698
- }
3699
- :scope[data-ui-scroll-area-state~="padding=sm"]:where([data-hn-ui-scroll-area]) {
3700
- padding: var(--ui-space-3) !important;
3701
- }
3702
- :scope[data-ui-scroll-area-state~="padding=md"]:where([data-hn-ui-scroll-area]) {
3703
- padding: var(--ui-space-5) !important;
3704
- }
3705
- :scope[data-ui-scroll-area-state~="padding=lg"]:where([data-hn-ui-scroll-area]) {
3706
- padding: var(--ui-space-6) !important;
3667
+ /* This component's hooks style the element they are set on, and never a nested one. */
3668
+ @property --ui-icon-button-active-scale {
3669
+ syntax: "*";
3670
+ inherits: false;
3707
3671
  }
3708
- :scope[hidden]:where([data-hn-ui-scroll-area]) {
3709
- display: none !important;
3672
+ @property --ui-icon-button-active-surface {
3673
+ syntax: "*";
3674
+ inherits: false;
3710
3675
  }
3676
+ @property --ui-icon-button-border {
3677
+ syntax: "*";
3678
+ inherits: false;
3711
3679
  }
3712
-
3713
- /* This component's hooks style the element they are set on, and never a nested one. */
3714
- @property --ui-dialog-duration {
3680
+ @property --ui-icon-button-disabled-filter {
3715
3681
  syntax: "*";
3716
3682
  inherits: false;
3717
3683
  }
3718
- @property --ui-dialog-surface {
3684
+ @property --ui-icon-button-disabled-opacity {
3719
3685
  syntax: "*";
3720
3686
  inherits: false;
3721
3687
  }
3722
- @property --ui-dialog-border {
3688
+ @property --ui-icon-button-hover-border {
3723
3689
  syntax: "*";
3724
3690
  inherits: false;
3725
3691
  }
3726
- @property --ui-dialog-radius {
3692
+ @property --ui-icon-button-hover-surface {
3727
3693
  syntax: "*";
3728
3694
  inherits: false;
3729
3695
  }
3730
- @property --ui-dialog-shadow {
3696
+ @property --ui-icon-button-hover-text {
3731
3697
  syntax: "*";
3732
3698
  inherits: false;
3733
3699
  }
3734
- @property --ui-dialog-max-width {
3700
+ @property --ui-icon-button-icon-size {
3735
3701
  syntax: "*";
3736
3702
  inherits: false;
3737
3703
  }
3738
- @property --ui-dialog-viewport-gap {
3704
+ @property --ui-icon-button-icon-stroke-width {
3739
3705
  syntax: "*";
3740
3706
  inherits: false;
3741
3707
  }
3742
-
3708
+ @property --ui-icon-button-outline-surface {
3709
+ syntax: "*";
3710
+ inherits: false;
3711
+ }
3712
+ @property --ui-icon-button-outline-text {
3713
+ syntax: "*";
3714
+ inherits: false;
3715
+ }
3716
+ @property --ui-icon-button-radius {
3717
+ syntax: "*";
3718
+ inherits: false;
3719
+ }
3720
+ @property --ui-icon-button-size {
3721
+ syntax: "*";
3722
+ inherits: false;
3723
+ }
3724
+ @property --ui-icon-button-solid-hover-surface {
3725
+ syntax: "*";
3726
+ inherits: false;
3727
+ }
3728
+ @property --ui-icon-button-solid-shadow {
3729
+ syntax: "*";
3730
+ inherits: false;
3731
+ }
3732
+ @property --ui-icon-button-solid-surface {
3733
+ syntax: "*";
3734
+ inherits: false;
3735
+ }
3736
+ @property --ui-icon-button-solid-text {
3737
+ syntax: "*";
3738
+ inherits: false;
3739
+ }
3740
+ @property --ui-icon-button-surface {
3741
+ syntax: "*";
3742
+ inherits: false;
3743
+ }
3744
+
3745
+ /* Omitted tone retains the existing accent solid; explicit neutral is additive. */
3746
+
3747
+ /* At rest an anticipatory button shows only its guide dot. The icon grows into place when
3748
+ proximity, hover, or focus reveals it; the button's hit area and guide remain stable. */
3749
+
3750
+ /* A touch target without a bigger button: an invisible hit area, at least the control
3751
+ minimum, centred on the button (::before is the anticipatory guide). */
3752
+
3753
+ /* A text button's companion uses control geometry; compact icon buttons keep their own density. */
3754
+
3755
+ /* Native toggle state persists after pointer release, including during loading. */
3756
+
3757
+ /* Disabled is a flat neutral control, independent of the active variant's tone. */
3758
+
3759
+ /* A component that sets its display still honours the hidden attribute on its root. */
3760
+ @scope (.ui-icon-button) to ([data-hn]) {
3761
+ :scope:where([data-hn-ui-icon-button]) {
3762
+ /* Optional inherited action-group values keep text and icon actions under the same light.
3763
+ One fine top/start highlight follows the bottom/end lowlight at a joined action seam.
3764
+ A single ambient lift avoids stacking a face gradient or another inset bevel. */
3765
+ --_ui-action-start: 1px;
3766
+ --_ui-action-edge: var(
3767
+ --ui-action-edge,
3768
+ inset var(--_ui-action-start) 1px 0 light-dark(
3769
+ rgb(255 255 255 / 0.08),
3770
+ rgb(255 255 255 / 0.06)
3771
+ ),
3772
+ inset calc(-1 * var(--_ui-action-start)) -1px 0 light-dark(
3773
+ rgb(0 0 0 / 0.08),
3774
+ rgb(0 0 0 / 0.08)
3775
+ )
3776
+ );
3777
+ --_ui-action-shadow:
3778
+ var(--_ui-action-edge),
3779
+ 0 1px 2px light-dark(rgb(0 0 0 / 0.10), rgb(0 0 0 / 0.20));
3780
+ /* Hooks do not inherit, so the parts below read them from the root. */
3781
+ --_ui-icon-button-icon-size: var(--ui-icon-button-icon-size);
3782
+ --_ui-icon-button-icon-stroke-width: var(--ui-icon-button-icon-stroke-width);
3783
+
3784
+ display: inline-flex !important;
3785
+ color: var(--ui-text-secondary);
3786
+ }
3787
+ :scope:dir(rtl):where([data-hn-ui-icon-button]) {
3788
+ --_ui-action-start: -1px;
3789
+ }
3790
+ :scope[data-tone="accent"]:where([data-hn-ui-icon-button]) {
3791
+ --_icon-button-border: var(--ui-accent-solid);
3792
+ --_icon-button-hover-border: var(--ui-accent-hover);
3793
+ --_icon-button-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
3794
+ --_icon-button-outline-surface: color-mix(
3795
+ in srgb,
3796
+ var(--ui-accent-solid) 5%,
3797
+ var(--ui-surface-default)
3798
+ );
3799
+ color: var(--_icon-button-text);
3800
+ }
3801
+ :scope[data-tone="danger"]:where([data-hn-ui-icon-button]) {
3802
+ --_icon-button-border: var(--ui-danger);
3803
+ --_icon-button-hover-border: var(--ui-danger-hover);
3804
+ --_icon-button-text: var(--ui-danger-subtle-text);
3805
+ --_icon-button-outline-surface: color-mix(
3806
+ in srgb,
3807
+ var(--ui-danger) 5%,
3808
+ var(--ui-surface-default)
3809
+ );
3810
+ --_icon-button-solid-surface: var(--ui-danger);
3811
+ --_icon-button-solid-hover-surface: var(--ui-danger-hover);
3812
+ --_icon-button-solid-text: var(--ui-danger-on-strong);
3813
+ color: var(--_icon-button-text);
3814
+ }
3815
+ :scope[data-tone="success"]:where([data-hn-ui-icon-button]) {
3816
+ --_icon-button-border: var(--ui-success);
3817
+ --_icon-button-hover-border: var(--ui-success-hover);
3818
+ --_icon-button-text: var(--ui-success-subtle-text);
3819
+ --_icon-button-outline-surface: color-mix(
3820
+ in srgb,
3821
+ var(--ui-success) 5%,
3822
+ var(--ui-surface-default)
3823
+ );
3824
+ --_icon-button-solid-surface: var(--ui-success);
3825
+ --_icon-button-solid-hover-surface: var(--ui-success-hover);
3826
+ --_icon-button-solid-text: var(--ui-success-on-strong);
3827
+ color: var(--_icon-button-text);
3828
+ }
3829
+ :scope[data-tone="warning"]:where([data-hn-ui-icon-button]) {
3830
+ --_icon-button-border: var(--ui-warning);
3831
+ --_icon-button-hover-border: var(--ui-warning-hover);
3832
+ --_icon-button-text: var(--ui-warning-subtle-text);
3833
+ --_icon-button-outline-surface: color-mix(
3834
+ in srgb,
3835
+ var(--ui-warning) 5%,
3836
+ var(--ui-surface-default)
3837
+ );
3838
+ --_icon-button-solid-surface: var(--ui-warning);
3839
+ --_icon-button-solid-hover-surface: var(--ui-warning-hover);
3840
+ --_icon-button-solid-text: var(--ui-warning-on-strong);
3841
+ color: var(--_icon-button-text);
3842
+ }
3843
+ :scope[data-tone="info"]:where([data-hn-ui-icon-button]) {
3844
+ --_icon-button-border: var(--ui-info);
3845
+ --_icon-button-hover-border: var(--ui-info-hover);
3846
+ --_icon-button-text: var(--ui-info-subtle-text);
3847
+ --_icon-button-outline-surface: color-mix(
3848
+ in srgb,
3849
+ var(--ui-info) 5%,
3850
+ var(--ui-surface-default)
3851
+ );
3852
+ --_icon-button-solid-surface: var(--ui-info);
3853
+ --_icon-button-solid-hover-surface: var(--ui-info-hover);
3854
+ --_icon-button-solid-text: var(--ui-info-on-strong);
3855
+ color: var(--_icon-button-text);
3856
+ }
3857
+ :scope[data-tone="neutral"]:where([data-hn-ui-icon-button]) {
3858
+ --_icon-button-solid-surface: var(--ui-text-primary);
3859
+ --_icon-button-solid-hover-surface: var(--ui-text-primary);
3860
+ --_icon-button-solid-text: var(--ui-surface-default);
3861
+ }
3862
+ :scope[data-ui-icon-button-state~="anticipatory"]:where([data-hn-ui-icon-button]) {
3863
+ position: relative;
3864
+ }
3865
+ :scope[data-ui-icon-button-state~="anticipatory"]:where([data-hn-ui-icon-button])::before {
3866
+ content: "";
3867
+ position: absolute;
3868
+ inset: 50% auto auto 50%;
3869
+ z-index: 1;
3870
+ inline-size: var(--ui-affordance-guide-size);
3871
+ block-size: var(--ui-affordance-guide-size);
3872
+ border-radius: var(--ui-radius-round);
3873
+ background: var(--ui-affordance-guide-color, var(--ui-border-strong));
3874
+ opacity: calc(var(--ui-affordance-guide-opacity) * var(--ui-affordance-scope-guide, 1));
3875
+ transform: translate(-50%, -50%);
3876
+ transition: opacity var(--ui-affordance-motion, var(--ui-motion-fast)) var(--ui-motion-ease);
3877
+ pointer-events: none;
3878
+ }
3879
+ :scope[data-ui-icon-button-state~="anticipatory"][data-ui-icon-button-state~="guide=bar"]:where([data-hn-ui-icon-button])::before {
3880
+ inline-size: 2px;
3881
+ block-size: 20px;
3882
+ background: var(--ui-border-strong);
3883
+ opacity: 1;
3884
+ }
3885
+ :scope[data-ui-icon-button-state~="anticipatory"]:disabled:where([data-hn-ui-icon-button])::before {
3886
+ opacity: 0;
3887
+ }
3888
+ :scope[data-ui-icon-button-state~="anticipatory"]
3889
+ .content:where([data-hn-ui-icon-button]) {
3890
+ opacity: 1;
3891
+ transform: scale(1);
3892
+ transition:
3893
+ opacity var(--ui-motion-fast) var(--ui-motion-ease),
3894
+ transform calc(var(--ui-motion-fast) * 2) cubic-bezier(0.2, 1.4, 0.35, 1);
3895
+ }
3896
+ @media (hover: hover) and (pointer: fine) {
3897
+ :scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="revealed"], :scope[data-appearance="solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible):where([data-hn-ui-icon-button]) {
3898
+ border-color: transparent;
3899
+ background-color: transparent;
3900
+ box-shadow: none;
3901
+ }
3902
+ :scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="revealed"], :scope[data-appearance="solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)
3903
+ .content:where([data-hn-ui-icon-button]) {
3904
+ opacity: 0;
3905
+ transform: scale(0.65);
3906
+ transition-duration: var(--ui-motion-fast);
3907
+ }
3908
+ }
3909
+ :scope[data-ui-icon-button-state~="anticipatory"]:is(:scope[data-ui-icon-button-state~="revealed"], :scope[data-appearance="solid"], [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible):where([data-hn-ui-icon-button])::before {
3910
+ opacity: 0;
3911
+ }
3912
+ :scope:where([data-hn-ui-icon-button]) {
3913
+ /* The size prop resolves here; --ui-icon-button-size overrides it on an element. */
3914
+ --_size: 2rem;
3915
+ appearance: none;
3916
+ inline-size: var(--ui-icon-button-size, var(--_size));
3917
+ block-size: var(--ui-icon-button-size, var(--_size));
3918
+ min-inline-size: var(--ui-icon-button-size, var(--_size));
3919
+ min-block-size: var(--ui-icon-button-size, var(--_size));
3920
+ padding: 0 !important;
3921
+ margin: 0 !important;
3922
+ border: var(--ui-border-width) solid transparent;
3923
+ border-radius: var(--ui-icon-button-radius, var(--ui-action-radius, var(--ui-radius-md)));
3924
+ background-color: var(--ui-icon-button-surface, transparent);
3925
+ color: inherit;
3926
+ display: inline-flex !important;
3927
+ align-items: center !important;
3928
+ justify-content: center !important;
3929
+ cursor: pointer;
3930
+ transition:
3931
+ background-color var(--ui-motion-fast) var(--ui-motion-ease),
3932
+ border-color var(--ui-motion-fast) var(--ui-motion-ease),
3933
+ color var(--ui-motion-fast) var(--ui-motion-ease),
3934
+ box-shadow var(--ui-motion-base) var(--ui-motion-ease),
3935
+ scale var(--ui-motion-press, var(--ui-motion-fast)) var(--ui-motion-ease);
3936
+ }
3937
+ @media (hover: none), (pointer: coarse) {
3938
+ :scope[data-ui-icon-button-state~="anticipatory"]:where([data-hn-ui-icon-button])::before {
3939
+ opacity: 0;
3940
+ }
3941
+ }
3942
+ @media (pointer: coarse) {
3943
+ :scope:where([data-hn-ui-icon-button]) {
3944
+ position: relative;
3945
+ }
3946
+ :scope:where([data-hn-ui-icon-button])::after {
3947
+ content: "";
3948
+ position: absolute;
3949
+ inset: 50% auto auto 50%;
3950
+ inline-size: max(100%, var(--ui-control-min-block-size));
3951
+ block-size: max(100%, var(--ui-control-min-block-size));
3952
+ transform: translate(-50%, -50%);
3953
+ }
3954
+ }
3955
+ html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button]) {
3956
+ position: relative;
3957
+ }
3958
+ html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button])::after {
3959
+ content: "";
3960
+ position: absolute;
3961
+ inset: 50% auto auto 50%;
3962
+ inline-size: max(100%, var(--ui-control-min-block-size));
3963
+ block-size: max(100%, var(--ui-control-min-block-size));
3964
+ transform: translate(-50%, -50%);
3965
+ }
3966
+ :scope[data-ui-icon-button-state~="size=sm"]:where([data-hn-ui-icon-button]) {
3967
+ --_size: 1.75rem;
3968
+ inline-size: var(--ui-icon-button-size, var(--_size));
3969
+ block-size: var(--ui-icon-button-size, var(--_size));
3970
+ min-inline-size: var(--ui-icon-button-size, var(--_size));
3971
+ min-block-size: var(--ui-icon-button-size, var(--_size));
3972
+ }
3973
+ :scope[data-ui-icon-button-state~="size=lg"]:where([data-hn-ui-icon-button]) {
3974
+ --_size: 2.5rem;
3975
+ inline-size: var(--ui-icon-button-size, var(--_size));
3976
+ block-size: var(--ui-icon-button-size, var(--_size));
3977
+ min-inline-size: var(--ui-icon-button-size, var(--_size));
3978
+ min-block-size: var(--ui-icon-button-size, var(--_size));
3979
+ }
3980
+ :scope[data-ui-icon-button-state~="matchButton"]:where([data-hn-ui-icon-button]) {
3981
+ --_size: var(--ui-control-size-md);
3982
+ block-size: auto;
3983
+ align-self: stretch;
3984
+ }
3985
+ :scope[data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=sm"]:where([data-hn-ui-icon-button]) {
3986
+ --_size: var(--ui-control-size-sm);
3987
+ }
3988
+ :scope[data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=lg"]:where([data-hn-ui-icon-button]) {
3989
+ --_size: var(--ui-control-size-lg);
3990
+ }
3991
+ @media (pointer: coarse) {
3992
+ :scope[data-ui-icon-button-state~="matchButton"]:where([data-hn-ui-icon-button]) {
3993
+ inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
3994
+ min-inline-size: max(
3995
+ var(--ui-icon-button-size, var(--_size)),
3996
+ var(--ui-control-min-block-size)
3997
+ );
3998
+ min-block-size: max(
3999
+ var(--ui-icon-button-size, var(--_size)),
4000
+ var(--ui-control-min-block-size)
4001
+ );
4002
+ }
4003
+ }
4004
+ :scope[data-ui-icon-button-state~="round"]:where([data-hn-ui-icon-button]) {
4005
+ border-radius: var(--ui-radius-round);
4006
+ }
4007
+ :scope[data-appearance="outline"]:where([data-hn-ui-icon-button]) {
4008
+ border-color: var(
4009
+ --ui-icon-button-border,
4010
+ var(--_icon-button-border, var(--ui-control-border, var(--ui-border-strong)))
4011
+ );
4012
+ background-color: var(
4013
+ --ui-icon-button-outline-surface,
4014
+ var(--_icon-button-outline-surface, var(--ui-surface-default))
4015
+ );
4016
+ background-image: none;
4017
+ color: var(--ui-icon-button-outline-text, var(--_icon-button-text, var(--ui-text-primary)));
4018
+ box-shadow: var(--ui-action-shadow, var(--_ui-action-shadow));
4019
+ }
4020
+ :scope[data-appearance="solid"]:where([data-hn-ui-icon-button]) {
4021
+ background-color: var(
4022
+ --ui-icon-button-solid-surface,
4023
+ var(--_icon-button-solid-surface, var(--ui-accent-solid))
4024
+ );
4025
+ background-image: none;
4026
+ color: var(
4027
+ --ui-icon-button-solid-text,
4028
+ var(--_icon-button-solid-text, var(--ui-text-on-accent))
4029
+ );
4030
+ box-shadow: var(
4031
+ --ui-icon-button-solid-shadow,
4032
+ var(--ui-action-shadow, var(--_ui-action-shadow))
4033
+ );
4034
+ }
4035
+ :scope:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
4036
+ /* Derived from the text colour so the ghost hover shows on any background. */
4037
+ background-color: var(
4038
+ --ui-icon-button-hover-surface,
4039
+ color-mix(in srgb, currentColor 8%, transparent)
4040
+ );
4041
+ color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
4042
+ }
4043
+ :scope[data-appearance="outline"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
4044
+ border-color: var(
4045
+ --ui-icon-button-hover-border,
4046
+ var(--_icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border)))
4047
+ );
4048
+ }
4049
+ :scope[data-appearance="solid"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
4050
+ background-color: var(
4051
+ --ui-icon-button-solid-hover-surface,
4052
+ var(--_icon-button-solid-hover-surface, var(--ui-accent-hover))
4053
+ );
4054
+ }
4055
+ :scope[data-appearance="solid"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
4056
+ color: var(
4057
+ --ui-icon-button-solid-text,
4058
+ var(--_icon-button-solid-text, var(--ui-text-on-accent))
4059
+ );
4060
+ }
4061
+ :scope[data-appearance="ghost"][aria-expanded="true"]:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
4062
+ background-color: var(
4063
+ --ui-icon-button-active-surface,
4064
+ color-mix(in srgb, currentColor 16%, transparent)
4065
+ );
4066
+ color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
4067
+ box-shadow: var(--ui-pressed);
4068
+ }
4069
+ :scope[data-appearance="outline"][aria-pressed="true"]:enabled:where([data-hn-ui-icon-button]) {
4070
+ background-color: var(
4071
+ --ui-icon-button-active-surface,
4072
+ color-mix(in srgb, currentColor 12%, var(--ui-surface-default))
4073
+ );
4074
+ background-image: none;
4075
+ box-shadow: var(--ui-pressed);
4076
+ }
4077
+ :scope:active:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
4078
+ scale: var(--ui-icon-button-active-scale, var(--ui-press-scale, 0.96));
4079
+ }
4080
+ :is(:scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"]):where([data-hn-ui-icon-button]) {
4081
+ cursor: progress;
4082
+ }
4083
+ .content:where([data-hn-ui-icon-button]) {
4084
+ display: inline-flex !important;
4085
+ align-items: center !important;
4086
+ justify-content: center !important;
4087
+ }
4088
+ :is(:scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"])
4089
+ .content:where([data-hn-ui-icon-button]) {
4090
+ display: none !important;
4091
+ }
4092
+ @media (prefers-reduced-motion: reduce) {
4093
+ :scope[data-ui-icon-button-state~="anticipatory"]
4094
+ .content:where([data-hn-ui-icon-button]) {
4095
+ transition: none;
4096
+ }
4097
+ }
4098
+ :scope:focus-visible:where([data-hn-ui-icon-button]) {
4099
+ outline: none;
4100
+ box-shadow: var(--ui-focus-halo);
4101
+ }
4102
+ :scope[data-appearance="outline"]:focus-visible:where([data-hn-ui-icon-button]) {
4103
+ box-shadow:
4104
+ var(--ui-action-shadow, var(--_ui-action-shadow)),
4105
+ var(--ui-focus-halo);
4106
+ }
4107
+ :scope[data-appearance="solid"]:focus-visible:where([data-hn-ui-icon-button]) {
4108
+ box-shadow:
4109
+ var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
4110
+ var(--ui-focus-halo);
4111
+ }
4112
+ :scope:is(:scope[data-appearance="outline"], :scope[data-appearance="solid"]):active:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
4113
+ background-image: none;
4114
+ box-shadow: var(--ui-pressed);
4115
+ }
4116
+ :scope[data-appearance="outline"][aria-pressed="true"]:enabled:focus-visible:where([data-hn-ui-icon-button]) {
4117
+ box-shadow:
4118
+ var(--ui-pressed),
4119
+ var(--ui-focus-halo);
4120
+ }
4121
+ @media (forced-colors: active) {
4122
+ :scope[data-appearance="outline"][aria-pressed="true"]:enabled:where([data-hn-ui-icon-button]) {
4123
+ outline: var(--ui-focus-width) solid Highlight;
4124
+ outline-offset: calc(-2 * var(--ui-focus-width));
4125
+ }
4126
+ :scope[data-appearance="outline"][aria-pressed="true"]:enabled:focus-visible:where([data-hn-ui-icon-button]) {
4127
+ outline-offset: var(--ui-focus-width);
4128
+ }
4129
+ }
4130
+ :scope:disabled:where([data-hn-ui-icon-button]) {
4131
+ border-color: var(--ui-disabled-border);
4132
+ background-color: var(--ui-disabled-surface);
4133
+ color: var(--ui-disabled-text);
4134
+ filter: var(--ui-icon-button-disabled-filter, var(--ui-disabled-filter));
4135
+ opacity: var(--ui-icon-button-disabled-opacity, 1);
4136
+ cursor: not-allowed;
4137
+ box-shadow: none;
4138
+ background-image: none;
4139
+ }
4140
+ :scope[data-appearance="ghost"]:disabled:where([data-hn-ui-icon-button]) {
4141
+ border-color: transparent;
4142
+ }
4143
+ :scope:where([data-hn-ui-icon-button]) {
4144
+ --_icon-button-icon-default: var(--ui-icon-size-md);
4145
+ /* A slotted ui-icon is its own component, out of reach of the svg rule below; these are its
4146
+ defaults, which its own --ui-icon-* hooks still override. */
4147
+ --_ui-default-icon-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
4148
+ --_ui-default-icon-stroke-width: var(--_ui-icon-button-icon-stroke-width, 1.75);
4149
+ }
4150
+ :scope[data-ui-icon-button-state~="size=sm"]:where([data-hn-ui-icon-button]) {
4151
+ --_icon-button-icon-default: var(--ui-icon-size-sm);
4152
+ }
4153
+ :scope[data-ui-icon-button-state~="size=lg"]:where([data-hn-ui-icon-button]) {
4154
+ --_icon-button-icon-default: var(--ui-icon-size-lg);
4155
+ }
4156
+ :where(:not([data-hn-ui-icon-button])):is(svg) {
4157
+ inline-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
4158
+ block-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
4159
+ flex-shrink: 0;
4160
+ stroke-width: var(--_ui-icon-button-icon-stroke-width, 1.75);
4161
+ }
4162
+ :scope[hidden]:where([data-hn-ui-icon-button]) {
4163
+ display: none !important;
4164
+ }
4165
+ }
4166
+
4167
+ @scope (.ui-number-input) to ([data-hn]) {
4168
+ :scope {
4169
+ display: flex !important;
4170
+ align-items: center !important;
4171
+ gap: var(--ui-space-1) !important;
4172
+ margin: 0 !important;
4173
+ padding: 0 !important;
4174
+ min-inline-size: 0;
4175
+ }
4176
+ :scope[hidden] {
4177
+ display: none !important;
4178
+ }
4179
+ }
4180
+ @scope ([data-slotted~="ui-number-input"]:not([data-hn])) to ([data-hn], [data-slotted]) {
4181
+ :where(.ui-number-input):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-number-input"]))) {
4182
+ display: flex !important;
4183
+ align-items: center !important;
4184
+ gap: var(--ui-space-1) !important;
4185
+ margin: 0 !important;
4186
+ padding: 0 !important;
4187
+ min-inline-size: 0;
4188
+ }
4189
+ :where(.ui-number-input)[hidden]:where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-number-input"]))) {
4190
+ display: none !important;
4191
+ }
4192
+ }
4193
+
4194
+ @scope (.ui-curve-editor) to ([data-hn]) {
4195
+ :scope {
4196
+ display: grid !important;
4197
+ gap: var(--ui-space-3) !important;
4198
+ margin: 0 !important;
4199
+ padding: 0 !important;
4200
+ min-inline-size: 0;
4201
+ }
4202
+ .plot-frame {
4203
+ box-sizing: border-box !important;
4204
+ display: block !important;
4205
+ block-size: 12rem;
4206
+ padding: max(var(--ui-space-4), 0.75rem, calc(var(--ui-control-min-block-size) / 2)) !important;
4207
+ margin: 0 !important;
4208
+ border: var(--ui-border-width) solid var(--ui-control-border);
4209
+ border-radius: var(--ui-field-radius, var(--ui-radius-md));
4210
+ background: var(--ui-control-surface, var(--ui-surface));
4211
+ }
4212
+ .plot {
4213
+ position: relative;
4214
+ display: block !important;
4215
+ inline-size: 100%;
4216
+ block-size: 100%;
4217
+ }
4218
+ svg {
4219
+ inline-size: 100%;
4220
+ block-size: 100%;
4221
+ overflow: visible;
4222
+ }
4223
+ path {
4224
+ fill: none;
4225
+ stroke: var(--ui-accent-solid);
4226
+ stroke-width: 2;
4227
+ vector-effect: non-scaling-stroke;
4228
+ }
4229
+ .guide {
4230
+ stroke: var(--ui-control-border);
4231
+ stroke-width: 1;
4232
+ }
4233
+ .handle {
4234
+ position: absolute;
4235
+ left: 25%;
4236
+ top: 63.333%;
4237
+ translate: -50% -50%;
4238
+ inline-size: max(1.5rem, var(--ui-control-min-block-size));
4239
+ block-size: max(1.5rem, var(--ui-control-min-block-size));
4240
+ border: 0;
4241
+ border-radius: 50%;
4242
+ background: transparent;
4243
+ color: var(--ui-text-primary);
4244
+ touch-action: none;
4245
+ cursor: grab;
4246
+ padding: 0 !important;
4247
+ margin: 0 !important;
4248
+ }
4249
+ .second {
4250
+ top: 33.333%;
4251
+ }
4252
+ .handle::after {
4253
+ content: "";
4254
+ position: absolute;
4255
+ inset: 25%;
4256
+ border: var(--ui-border-width) solid var(--ui-accent-solid);
4257
+ background: var(--ui-surface-raised);
4258
+ border-radius: 50%;
4259
+ box-shadow: var(--ui-shadow-xs);
4260
+ }
4261
+ .handle::before {
4262
+ content: "";
4263
+ position: absolute;
4264
+ inset: 40%;
4265
+ background: var(--ui-accent-solid);
4266
+ border-radius: 50%;
4267
+ z-index: 1;
4268
+ }
4269
+ .handle:focus-visible {
4270
+ outline: var(--ui-focus-width) solid var(--ui-control-focus, var(--ui-accent-solid));
4271
+ outline-offset: var(--ui-space-1);
4272
+ }
4273
+ .handle:disabled {
4274
+ cursor: not-allowed;
4275
+ }
4276
+ .coordinates {
4277
+ display: grid !important;
4278
+ grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
4279
+ gap: var(--ui-space-2) !important;
4280
+ }
4281
+ .coordinate {
4282
+ display: grid !important;
4283
+ gap: var(--ui-space-1) !important;
4284
+ font-size: var(--ui-font-size-sm);
4285
+ }
4286
+ output {
4287
+ overflow-wrap: anywhere;
4288
+ font-family: var(--ui-font-mono, monospace);
4289
+ font-size: var(--ui-font-size-sm);
4290
+ }
4291
+ :scope[hidden] {
4292
+ display: none !important;
4293
+ }
4294
+ }
4295
+
4296
+ /* One term and its value in a ui-description-list, laid out by the list's layout. */
4297
+
4298
+ /* A component that sets its display still honours the hidden attribute on its root. */
4299
+ @scope (.ui-description-item) to ([data-hn]) {
4300
+ :scope:where([data-hn-ui-description-item]) {
4301
+ display: var(--_ui-description-display, grid) !important;
4302
+ grid-column: var(--_ui-description-column, 1 / -1);
4303
+ grid-template-columns: subgrid;
4304
+ flex-direction: column !important;
4305
+ align-items: var(--_ui-description-align, baseline) !important;
4306
+ gap: var(--ui-space-1) var(--ui-space-6) !important;
4307
+ min-inline-size: 0;
4308
+ padding: var(--_ui-description-padding, 0) !important;
4309
+ border-width: var(--_ui-description-border-width, 0);
4310
+ border-style: solid;
4311
+ border-color: var(--_ui-description-border-color, var(--ui-border-default));
4312
+ border-radius: var(--ui-radius-md);
4313
+ font-size: var(--ui-font-size-sm);
4314
+ }
4315
+ dt:where([data-hn-ui-description-item]) {
4316
+ color: var(--ui-text-muted);
4317
+ }
4318
+ dd:where([data-hn-ui-description-item]) {
4319
+ margin: 0 !important;
4320
+ min-inline-size: 0;
4321
+ color: var(--ui-text-primary);
4322
+ font-weight: var(--ui-font-medium);
4323
+ font-size: var(--_ui-description-value-size, inherit);
4324
+ text-align: start;
4325
+ overflow-wrap: anywhere;
4326
+ }
4327
+ :scope[hidden]:where([data-hn-ui-description-item]) {
4328
+ display: none !important;
4329
+ }
4330
+ }
4331
+
4332
+ /* Named values: a term and what it is, for each item (ui-description-item). */
4333
+ /* Rows line every term up in one column and every value in the next, through subgrid. */
4334
+
4335
+ /* Stacked, grid, and tiles set each term above its value, passing the shape to the items through
4336
+ private properties, which cross into each item. */
4337
+
4338
+ /* A column is at least --_min wide; with columns set, at least its share of the width, so no more
4339
+ than that many fit. */
4340
+
4341
+ /* Compact takes each layout's closer spacing. */
4342
+
4343
+ /* A component that sets its display still honours the hidden attribute on its root. */
4344
+ @scope (.ui-description-list) to ([data-hn]) {
4345
+ :scope:where([data-hn-ui-description-list]) {
4346
+ --_gap: var(--ui-space-2);
4347
+ --_gap-compact: var(--ui-space-1);
4348
+ --_column-gap: var(--ui-space-6);
4349
+ --_min: 10rem;
4350
+ --_track: var(--_min);
4351
+ --_tile-padding: var(--ui-space-3);
4352
+ display: grid !important;
4353
+ grid-template-columns: minmax(6rem, max-content) minmax(0, 1fr);
4354
+ gap: var(--_gap) var(--_column-gap) !important;
4355
+ min-inline-size: 0;
4356
+ margin: 0 !important;
4357
+ }
4358
+ :scope[data-ui-description-list-state~="layout=stacked"]:where([data-hn-ui-description-list]),:scope[data-ui-description-list-state~="layout=grid"]:where([data-hn-ui-description-list]),:scope[data-ui-description-list-state~="layout=tiles"]:where([data-hn-ui-description-list]) {
4359
+ --_ui-description-display: flex;
4360
+ --_ui-description-column: auto;
4361
+ --_ui-description-align: stretch;
4362
+ --_gap: var(--ui-space-4);
4363
+ --_gap-compact: var(--ui-space-2);
4364
+ grid-template-columns: minmax(0, 1fr);
4365
+ }
4366
+ :scope[data-ui-description-list-state~="layout=grid"]:where([data-hn-ui-description-list]),:scope[data-ui-description-list-state~="layout=tiles"]:where([data-hn-ui-description-list]) {
4367
+ inline-size: 100%;
4368
+ grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--_track)), 1fr));
4369
+ }
4370
+ :scope[data-ui-description-list-state~="layout=tiles"]:where([data-hn-ui-description-list]) {
4371
+ --_ui-description-align: flex-start;
4372
+ --_ui-description-value-size: var(--ui-font-size-lg);
4373
+ --_ui-description-padding: var(--_tile-padding);
4374
+ --_ui-description-border-width: var(--ui-border-width);
4375
+ --_ui-description-border-color: var(--ui-border-strong);
4376
+ --_gap: var(--ui-space-3);
4377
+ --_gap-compact: var(--ui-space-2);
4378
+ --_column-gap: var(--_gap);
4379
+ }
4380
+ :scope[data-ui-description-list-state~="columns=2"]:where([data-hn-ui-description-list]) {
4381
+ --_track: max(var(--_min), (100% - var(--_column-gap)) / 2);
4382
+ }
4383
+ :scope[data-ui-description-list-state~="columns=3"]:where([data-hn-ui-description-list]) {
4384
+ --_track: max(var(--_min), (100% - 2 * var(--_column-gap)) / 3);
4385
+ }
4386
+ :scope[data-ui-description-list-state~="columns=4"]:where([data-hn-ui-description-list]) {
4387
+ --_track: max(var(--_min), (100% - 3 * var(--_column-gap)) / 4);
4388
+ }
4389
+ :scope[data-ui-description-list-state~="density=compact"]:where([data-hn-ui-description-list]) {
4390
+ --_gap: var(--_gap-compact);
4391
+ --_tile-padding: var(--ui-space-2);
4392
+ }
4393
+ :scope[hidden]:where([data-hn-ui-description-list]) {
4394
+ display: none !important;
4395
+ }
4396
+ }
4397
+
4398
+ /* The controller sets each fade length from overflow and scroll position. The mask blends
4399
+ into whatever is behind the area without needing to know its colour. Before upgrade, its
4400
+ zero-length defaults leave the authored scroll area fully visible. */
4401
+
4402
+ /* Trim projected edges without changing spacing inside an item. */
4403
+
4404
+ /* A component that sets its display still honours the hidden attribute on its root. */
4405
+ @scope (.ui-scroll-area) to ([data-hn]) {
4406
+ :scope[data-ui-scroll-area-state~="fill"]:where([data-hn-ui-scroll-area]) {
4407
+ flex: 1;
4408
+ }
4409
+ :scope:where([data-hn-ui-scroll-area]) {
4410
+ display: block !important;
4411
+ box-sizing: border-box !important;
4412
+ min-block-size: 0;
4413
+ min-inline-size: 0;
4414
+ overflow-x: hidden;
4415
+ overflow-y: auto;
4416
+ overscroll-behavior: contain;
4417
+ --_ui-scroll-fade-direction: to bottom;
4418
+ --_ui-scroll-fade-inline: to right;
4419
+ --_ui-scroll-fade-size: var(--ui-scroll-fade-size, 24px);
4420
+ mask-image: linear-gradient(
4421
+ var(--_ui-scroll-fade-direction),
4422
+ transparent,
4423
+ #000 var(--_ui-scroll-fade-start),
4424
+ #000 calc(100% - var(--_ui-scroll-fade-end)),
4425
+ transparent
4426
+ );
4427
+ }
4428
+ .content:where([data-hn-ui-scroll-area]) {
4429
+ display: flow-root !important;
4430
+ }
4431
+ :scope[data-ui-scroll-area-state~="trim"]
4432
+ .content
4433
+ > :where(:not([data-hn-ui-scroll-area])):is(:first-child) {
4434
+ margin-block-start: 0 !important;
4435
+ }
4436
+ :scope[data-ui-scroll-area-state~="trim"]
4437
+ .content
4438
+ > :where(:not([data-hn-ui-scroll-area])):is(:last-child) {
4439
+ margin-block-end: 0 !important;
4440
+ }
4441
+ :scope[data-ui-scroll-area-state~="orientation=horizontal"]:where([data-hn-ui-scroll-area]) {
4442
+ overflow-x: auto;
4443
+ overflow-y: hidden;
4444
+ --_ui-scroll-fade-direction: var(--_ui-scroll-fade-inline);
4445
+ }
4446
+ :scope:dir(rtl):where([data-hn-ui-scroll-area]) {
4447
+ --_ui-scroll-fade-inline: to left;
4448
+ }
4449
+ :scope[data-ui-scroll-area-state~="size=sm"]:where([data-hn-ui-scroll-area]) {
4450
+ max-block-size: calc(9.375rem + var(--ui-scroll-fade-size, 24px));
4451
+ }
4452
+ :scope[data-ui-scroll-area-state~="size=md"]:where([data-hn-ui-scroll-area]) {
4453
+ max-block-size: 20rem;
4454
+ }
4455
+ :scope[data-ui-scroll-area-state~="size=lg"]:where([data-hn-ui-scroll-area]) {
4456
+ max-block-size: 30rem;
4457
+ }
4458
+ :scope[data-ui-scroll-area-state~="padding=xs"]:where([data-hn-ui-scroll-area]) {
4459
+ padding: var(--ui-space-2) !important;
4460
+ }
4461
+ :scope[data-ui-scroll-area-state~="padding=sm"]:where([data-hn-ui-scroll-area]) {
4462
+ padding: var(--ui-space-3) !important;
4463
+ }
4464
+ :scope[data-ui-scroll-area-state~="padding=md"]:where([data-hn-ui-scroll-area]) {
4465
+ padding: var(--ui-space-5) !important;
4466
+ }
4467
+ :scope[data-ui-scroll-area-state~="padding=lg"]:where([data-hn-ui-scroll-area]) {
4468
+ padding: var(--ui-space-6) !important;
4469
+ }
4470
+ :scope[hidden]:where([data-hn-ui-scroll-area]) {
4471
+ display: none !important;
4472
+ }
4473
+ }
4474
+
4475
+ /* This component's hooks style the element they are set on, and never a nested one. */
4476
+ @property --ui-dialog-duration {
4477
+ syntax: "*";
4478
+ inherits: false;
4479
+ }
4480
+ @property --ui-dialog-surface {
4481
+ syntax: "*";
4482
+ inherits: false;
4483
+ }
4484
+ @property --ui-dialog-border {
4485
+ syntax: "*";
4486
+ inherits: false;
4487
+ }
4488
+ @property --ui-dialog-radius {
4489
+ syntax: "*";
4490
+ inherits: false;
4491
+ }
4492
+ @property --ui-dialog-shadow {
4493
+ syntax: "*";
4494
+ inherits: false;
4495
+ }
4496
+ @property --ui-dialog-max-width {
4497
+ syntax: "*";
4498
+ inherits: false;
4499
+ }
4500
+ @property --ui-dialog-viewport-gap {
4501
+ syntax: "*";
4502
+ inherits: false;
4503
+ }
4504
+
4505
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
4506
+ transparency, saturation and edge light belong to the surrounding decorative material. */
4507
+
3743
4508
  /* Own the layout wrapper; nested component roots are outside these scoped rules. */
3744
4509
 
3745
4510
  /* Alerts have no close target to add height above the title. */
@@ -3749,19 +4514,20 @@ dd:where([data-hn-ui-description-item]) {
3749
4514
  /* A CSS-drawn X. */
3750
4515
 
3751
4516
  /* A touch target, like Button on coarse pointers. */
3752
- @keyframes ui-dialog-enter-c23cce38 {
4517
+ @keyframes ui-dialog-enter-ea8be62a {
3753
4518
  from {
3754
4519
  opacity: 0;
3755
4520
  transform: scale(0.96);
3756
4521
  }
3757
4522
  }
3758
- @keyframes ui-dialog-backdrop-enter-c23cce38 {
4523
+ @keyframes ui-dialog-backdrop-enter-ea8be62a {
3759
4524
  from {
3760
4525
  background-color: transparent;
3761
4526
  }
3762
4527
  }
3763
4528
  @scope (.ui-dialog) to ([data-hn]) {
3764
4529
  :scope:where([data-hn-ui-dialog]) {
4530
+ --_ui-material-scale: 1;
3765
4531
  /* Hooks do not inherit, so the parts below read them from the root. */
3766
4532
  --_ui-dialog-duration: var(--ui-dialog-duration);
3767
4533
 
@@ -3797,13 +4563,95 @@ from {
3797
4563
  display var(--ui-dialog-duration, var(--ui-motion-base)) var(--ui-motion-ease) allow-discrete,
3798
4564
  overlay var(--ui-dialog-duration, var(--ui-motion-base)) var(--ui-motion-ease) allow-discrete;
3799
4565
  }
4566
+ :scope:where([data-hn-ui-dialog]) {
4567
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
4568
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
4569
+ --_ui-material-active: clamp(
4570
+ 0,
4571
+ calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000),
4572
+ 1
4573
+ );
4574
+ --_ui-material-rim: calc(
4575
+ (
4576
+ var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25
4577
+ ) *
4578
+ var(--_ui-material-scale, 1) *
4579
+ 8px
4580
+ );
4581
+ --_ui-material-content-color: var(
4582
+ --ui-dialog-surface,
4583
+ var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated)))
4584
+ );
4585
+ --_ui-material-rim-color: color-mix(
4586
+ in srgb,
4587
+ var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%),
4588
+ transparent
4589
+ );
4590
+ background:
4591
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color))
4592
+ padding-box,
4593
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
4594
+ var(--_ui-material-content-color) padding-box;
4595
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
4596
+ border-color: var(
4597
+ --ui-dialog-border,
4598
+ color-mix(
4599
+ in oklab,
4600
+ var(--ui-overlay-border, var(--ui-border-strong)) calc(
4601
+ (1 - var(--_ui-material-active)) * 100%
4602
+ ),
4603
+ transparent
4604
+ )
4605
+ );
4606
+ box-shadow: var(
4607
+ --ui-dialog-shadow,
4608
+ var(
4609
+ --ui-overlay-shadow,
4610
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 8px) calc(
4611
+ var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 24px
4612
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
4613
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(
4614
+ --ui-material-edge,
4615
+ var(--ui-border-strong)
4616
+ ),
4617
+ var(--ui-elevation-dialog, var(--ui-shadow-xl))
4618
+ )
4619
+ );
4620
+ backdrop-filter: blur(
4621
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 18px)
4622
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 0.18));
4623
+ -webkit-backdrop-filter: blur(
4624
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 18px)
4625
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 0.18));
4626
+ }
4627
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
4628
+ :scope:where([data-hn-ui-dialog]) {
4629
+ background: var(--_ui-material-content-color);
4630
+ }
4631
+ }
4632
+ @media (prefers-reduced-transparency: reduce) {
4633
+ :scope:where([data-hn-ui-dialog]) {
4634
+ background: var(--_ui-material-content-color);
4635
+ backdrop-filter: none;
4636
+ -webkit-backdrop-filter: none;
4637
+ }
4638
+ }
4639
+ @media (forced-colors: active) {
4640
+ :scope:where([data-hn-ui-dialog]) {
4641
+ background: Canvas;
4642
+ border-color: CanvasText;
4643
+ box-shadow: none;
4644
+ backdrop-filter: none;
4645
+ -webkit-backdrop-filter: none;
4646
+ }
4647
+ }
3800
4648
  :scope[open]:where([data-hn-ui-dialog]) {
3801
4649
  display: flex !important;
3802
4650
  visibility: visible;
3803
4651
  pointer-events: auto;
3804
4652
  opacity: 1;
3805
4653
  transform: scale(1);
3806
- animation: ui-dialog-enter-c23cce38 var(--ui-dialog-duration, var(--ui-motion-base))
4654
+ animation: ui-dialog-enter-ea8be62a var(--ui-dialog-duration, var(--ui-motion-base))
3807
4655
  var(--ui-motion-ease);
3808
4656
  }
3809
4657
  :scope[data-ui-dialog-state~="size=sm"]:where([data-hn-ui-dialog]) {
@@ -3924,7 +4772,7 @@ footer:empty:where([data-hn-ui-dialog]) {
3924
4772
  }
3925
4773
  :scope[open]:modal:where([data-hn-ui-dialog])::backdrop {
3926
4774
  background-color: var(--ui-overlay-backdrop);
3927
- animation: ui-dialog-backdrop-enter-c23cce38 var(--_ui-dialog-duration, var(--ui-motion-base))
4775
+ animation: ui-dialog-backdrop-enter-ea8be62a var(--_ui-dialog-duration, var(--ui-motion-base))
3928
4776
  var(--ui-motion-ease);
3929
4777
  }
3930
4778
  :scope[open][data-ui-backdrop-hidden]:where([data-hn-ui-dialog])::backdrop {
@@ -3935,6 +4783,7 @@ footer:empty:where([data-hn-ui-dialog]) {
3935
4783
  }
3936
4784
  @scope ([data-slotted~="ui-dialog"]:not([data-hn])) to ([data-hn], [data-slotted]) {
3937
4785
  :where(.ui-dialog):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog]) {
4786
+ --_ui-material-scale: 1;
3938
4787
  /* Hooks do not inherit, so the parts below read them from the root. */
3939
4788
  --_ui-dialog-duration: var(--ui-dialog-duration);
3940
4789
 
@@ -3970,13 +4819,95 @@ footer:empty:where([data-hn-ui-dialog]) {
3970
4819
  display var(--ui-dialog-duration, var(--ui-motion-base)) var(--ui-motion-ease) allow-discrete,
3971
4820
  overlay var(--ui-dialog-duration, var(--ui-motion-base)) var(--ui-motion-ease) allow-discrete;
3972
4821
  }
4822
+ :where(.ui-dialog):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog]) {
4823
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
4824
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
4825
+ --_ui-material-active: clamp(
4826
+ 0,
4827
+ calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000),
4828
+ 1
4829
+ );
4830
+ --_ui-material-rim: calc(
4831
+ (
4832
+ var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25
4833
+ ) *
4834
+ var(--_ui-material-scale, 1) *
4835
+ 8px
4836
+ );
4837
+ --_ui-material-content-color: var(
4838
+ --ui-dialog-surface,
4839
+ var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated)))
4840
+ );
4841
+ --_ui-material-rim-color: color-mix(
4842
+ in srgb,
4843
+ var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%),
4844
+ transparent
4845
+ );
4846
+ background:
4847
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color))
4848
+ padding-box,
4849
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
4850
+ var(--_ui-material-content-color) padding-box;
4851
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
4852
+ border-color: var(
4853
+ --ui-dialog-border,
4854
+ color-mix(
4855
+ in oklab,
4856
+ var(--ui-overlay-border, var(--ui-border-strong)) calc(
4857
+ (1 - var(--_ui-material-active)) * 100%
4858
+ ),
4859
+ transparent
4860
+ )
4861
+ );
4862
+ box-shadow: var(
4863
+ --ui-dialog-shadow,
4864
+ var(
4865
+ --ui-overlay-shadow,
4866
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 8px) calc(
4867
+ var(--_ui-material-separation) * var(--_ui-material-scale, 1) * 24px
4868
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
4869
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(
4870
+ --ui-material-edge,
4871
+ var(--ui-border-strong)
4872
+ ),
4873
+ var(--ui-elevation-dialog, var(--ui-shadow-xl))
4874
+ )
4875
+ );
4876
+ backdrop-filter: blur(
4877
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 18px)
4878
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 0.18));
4879
+ -webkit-backdrop-filter: blur(
4880
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 18px)
4881
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 1) * 0.18));
4882
+ }
4883
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
4884
+ :where(.ui-dialog):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog]) {
4885
+ background: var(--_ui-material-content-color);
4886
+ }
4887
+ }
4888
+ @media (prefers-reduced-transparency: reduce) {
4889
+ :where(.ui-dialog):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog]) {
4890
+ background: var(--_ui-material-content-color);
4891
+ backdrop-filter: none;
4892
+ -webkit-backdrop-filter: none;
4893
+ }
4894
+ }
4895
+ @media (forced-colors: active) {
4896
+ :where(.ui-dialog):where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog]) {
4897
+ background: Canvas;
4898
+ border-color: CanvasText;
4899
+ box-shadow: none;
4900
+ backdrop-filter: none;
4901
+ -webkit-backdrop-filter: none;
4902
+ }
4903
+ }
3973
4904
  :where(.ui-dialog)[open]:where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog]) {
3974
4905
  display: flex !important;
3975
4906
  visibility: visible;
3976
4907
  pointer-events: auto;
3977
4908
  opacity: 1;
3978
4909
  transform: scale(1);
3979
- animation: ui-dialog-enter-c23cce38 var(--ui-dialog-duration, var(--ui-motion-base))
4910
+ animation: ui-dialog-enter-ea8be62a var(--ui-dialog-duration, var(--ui-motion-base))
3980
4911
  var(--ui-motion-ease);
3981
4912
  }
3982
4913
  :where(.ui-dialog)[data-ui-dialog-state~="size=sm"]:where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog]) {
@@ -4105,7 +5036,7 @@ footer:empty:where(:scope, :scope *):where([data-hn-ui-dialog]) {
4105
5036
  }
4106
5037
  :where(.ui-dialog)[open]:modal:where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog])::backdrop {
4107
5038
  background-color: var(--ui-overlay-backdrop);
4108
- animation: ui-dialog-backdrop-enter-c23cce38 var(--_ui-dialog-duration, var(--ui-motion-base))
5039
+ animation: ui-dialog-backdrop-enter-ea8be62a var(--_ui-dialog-duration, var(--ui-motion-base))
4109
5040
  var(--ui-motion-ease);
4110
5041
  }
4111
5042
  :where(.ui-dialog)[open][data-ui-backdrop-hidden]:where(:scope, :not([data-hn], [data-slotted]:not([data-slotted~="ui-dialog"]))):where([data-hn-ui-dialog])::backdrop {
@@ -4454,6 +5385,9 @@ footer:empty:where(:scope, :scope *):where([data-hn-ui-dialog]) {
4454
5385
  still win. */
4455
5386
 
4456
5387
  /* Small follows its trigger down: an item's own hooks still win. */
5388
+
5389
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
5390
+ transparency, saturation and edge light belong to the surrounding decorative material. */
4457
5391
  @scope (.ui-menu) to ([data-hn]) {
4458
5392
  :scope[data-ui-menu-state~="density=compact"]:where([data-hn-ui-menu]) {
4459
5393
  --_ui-default-menu-item-padding-block: var(--ui-space-1);
@@ -4478,6 +5412,7 @@ footer:empty:where(:scope, :scope *):where([data-hn-ui-dialog]) {
4478
5412
  --_ui-default-menu-icon-display: inline-flex;
4479
5413
  }
4480
5414
  :scope:where([data-hn-ui-menu]) {
5415
+ --_ui-material-scale: 0.28;
4481
5416
  --_ui-menu-surface: var(--ui-menu-surface);
4482
5417
  --_ui-menu-border: var(--ui-menu-border);
4483
5418
  --_ui-menu-radius: var(--ui-menu-radius);
@@ -4521,6 +5456,88 @@ footer:empty:where(:scope, :scope *):where([data-hn-ui-dialog]) {
4521
5456
  max-block-size: inherit;
4522
5457
  overflow: auto;
4523
5458
  }
5459
+ :scope:not([inline]) .surface:where([data-hn-ui-menu]) {
5460
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
5461
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
5462
+ --_ui-material-active: clamp(
5463
+ 0,
5464
+ calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000),
5465
+ 1
5466
+ );
5467
+ --_ui-material-rim: calc(
5468
+ (
5469
+ var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25
5470
+ ) *
5471
+ var(--_ui-material-scale, 0.28) *
5472
+ 8px
5473
+ );
5474
+ --_ui-material-content-color: var(
5475
+ --_ui-menu-surface,
5476
+ var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated)))
5477
+ );
5478
+ --_ui-material-rim-color: color-mix(
5479
+ in srgb,
5480
+ var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%),
5481
+ transparent
5482
+ );
5483
+ background:
5484
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color))
5485
+ padding-box,
5486
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
5487
+ var(--_ui-material-content-color) padding-box;
5488
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
5489
+ border-color: var(
5490
+ --_ui-menu-border,
5491
+ color-mix(
5492
+ in oklab,
5493
+ var(--ui-overlay-border, var(--ui-border-strong)) calc(
5494
+ (1 - var(--_ui-material-active)) * 100%
5495
+ ),
5496
+ transparent
5497
+ )
5498
+ );
5499
+ box-shadow: var(
5500
+ --_ui-menu-shadow,
5501
+ var(
5502
+ --ui-overlay-shadow,
5503
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.28) * 8px) calc(
5504
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.28) * 24px
5505
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
5506
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(
5507
+ --ui-material-edge,
5508
+ var(--ui-border-strong)
5509
+ ),
5510
+ var(--ui-elevation-overlay, var(--ui-shadow-lg))
5511
+ )
5512
+ );
5513
+ backdrop-filter: blur(
5514
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 18px)
5515
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 0.18));
5516
+ -webkit-backdrop-filter: blur(
5517
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 18px)
5518
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 0.18));
5519
+ }
5520
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
5521
+ :scope:not([inline]) .surface:where([data-hn-ui-menu]) {
5522
+ background: var(--_ui-material-content-color);
5523
+ }
5524
+ }
5525
+ @media (prefers-reduced-transparency: reduce) {
5526
+ :scope:not([inline]) .surface:where([data-hn-ui-menu]) {
5527
+ background: var(--_ui-material-content-color);
5528
+ backdrop-filter: none;
5529
+ -webkit-backdrop-filter: none;
5530
+ }
5531
+ }
5532
+ @media (forced-colors: active) {
5533
+ :scope:not([inline]) .surface:where([data-hn-ui-menu]) {
5534
+ background: Canvas;
5535
+ border-color: CanvasText;
5536
+ box-shadow: none;
5537
+ backdrop-filter: none;
5538
+ -webkit-backdrop-filter: none;
5539
+ }
5540
+ }
4524
5541
  .surface hr:where([data-hn-ui-menu]) {
4525
5542
  align-self: stretch;
4526
5543
  block-size: 0;
@@ -4983,1051 +6000,607 @@ legend.sr-only:where([data-hn-ui-radio-group]) {
4983
6000
  gap: var(--ui-space-1) !important;
4984
6001
  }
4985
6002
  .label-action:where([data-hn-ui-form-field]) {
4986
- display: flex !important;
4987
- align-items: unsafe center !important;
4988
- block-size: 1lh;
4989
- }
4990
- .label-action:not(:has(> *)):where([data-hn-ui-form-field]) {
4991
- display: none !important;
4992
- }
4993
- .help:where([data-hn-ui-form-field]) {
4994
- color: var(--_ui-form-field-help-text, var(--ui-text-muted));
4995
- font-size: var(--_ui-form-field-help-font-size, var(--ui-font-size-sm));
4996
- line-height: var(--ui-line-height-md);
4997
- }
4998
- .help > :where(:not([data-hn-ui-form-field])):is(*) {
4999
- min-block-size: var(--_ui-form-field-help-min-block-size, 0);
5000
- }
5001
- .error:where([data-hn-ui-form-field]) {
5002
- display: none !important;
5003
- }
5004
- :scope[data-ui-form-field-state~="invalid"] .error:where([data-hn-ui-form-field]) {
5005
- display: contents !important;
5006
- }
5007
- .error:where([data-hn-ui-form-field]),:where(:not([data-hn-ui-form-field])):is([role="alert"]) {
5008
- color: var(--_ui-form-field-danger, var(--ui-field-danger, var(--ui-danger)));
5009
- font-size: var(--ui-font-size-sm);
5010
- }
5011
- :scope[hidden]:where([data-hn-ui-form-field]) {
5012
- display: none !important;
5013
- }
5014
- }
5015
-
5016
- @property --ui-input-group-radius {
5017
- syntax: "*";
5018
- inherits: false;
5019
- }
5020
- @property --ui-input-group-invalid-border {
5021
- syntax: "*";
5022
- inherits: false;
5023
- }
5024
- @property --ui-input-group-invalid-focus-shadow {
5025
- syntax: "*";
5026
- inherits: false;
5027
- }
5028
- /* An input with fixed text before or after it, such as a domain after a site's name
5029
- ("acme" + ".example.com") or slashes around a path. The group draws the field's border and
5030
- focus ring around the input and its affixes together; the input inside drops its own through
5031
- its custom properties, so it is still the one ui-input, with its form behaviour intact. The
5032
- affixes are plain text beside the input, so name the input with a label that says what the
5033
- whole value is. The action slot takes one button at the end, inside the border, for the one
5034
- thing the field is for ("Continue" after a site's address), so it reads as the field's action
5035
- and not the form's. */
5036
-
5037
- /* The frame takes its input's size, so a small group lines up with small buttons and fields. */
5038
-
5039
- /* The ring shows when the field's input would show its own: when it is focus-visible, which a
5040
- text input is for a pointer as well as a keyboard. A focused action button draws its own. */
5041
-
5042
- /* Forced colors drop box shadows, so the focus ring becomes an outline. */
5043
-
5044
- /* Fixed text is part of the value, but should not look editable. */
5045
-
5046
- /* Centred rather than padded above and below: the group is exactly a lone Input's height, so a
5047
- small button sits inside it with the difference split evenly, and the field keeps its height. */
5048
-
5049
- /* Multiline text owns the first row; its action remains inside the same frame below it. */
5050
-
5051
- /* The same textarea keeps its full resizeable box. Its text reserves the action's live width,
5052
- so a translated label or pending indicator cannot cover what the person types. */
5053
-
5054
- /* A component that sets its display still honours the hidden attribute on its root. */
5055
- @scope (.ui-input-group) to ([data-hn]) {
5056
- :scope:where([data-hn-ui-input-group]) {
5057
- /* The group's own border and height stand for the input's, so the group is a lone Input's height.
5058
- Hooks do not inherit, so these are defaults for the input; its own hooks still win. */
5059
- --_ui-default-input-border-width: 0;
5060
- --_ui-default-input-min-block-size: 0;
5061
- --_ui-default-input-border: transparent;
5062
- --_ui-default-input-border-hover: transparent;
5063
- --_ui-default-input-focus-border: transparent;
5064
- --_ui-default-input-invalid-border: transparent;
5065
- --_ui-default-input-invalid-focus-shadow: none;
5066
- --_ui-default-input-shadow: none;
5067
- --_ui-default-input-focus-shadow: none;
5068
- --_ui-default-input-focus-outline: none;
5069
- --_ui-default-input-radius: 0;
5070
- --_ui-default-input-surface: transparent;
5071
- --_ui-default-textarea-border-width: 0;
5072
- --_ui-default-textarea-border: transparent;
5073
- --_ui-default-textarea-border-hover: transparent;
5074
- --_ui-default-textarea-focus-border: transparent;
5075
- --_ui-default-textarea-invalid-border: transparent;
5076
- --_ui-default-textarea-invalid-focus-shadow: none;
5077
- --_ui-default-textarea-shadow: none;
5078
- --_ui-default-textarea-focus-shadow: none;
5079
- --_ui-default-textarea-focus-outline: none;
5080
- --_ui-default-textarea-radius: 0;
5081
- --_ui-default-textarea-surface: transparent;
5082
-
5083
- display: flex !important;
5084
- align-items: stretch !important;
5085
- box-sizing: border-box !important;
5086
- inline-size: 100%;
5087
- min-inline-size: 0;
5088
- min-block-size: var(--ui-control-size-md);
5089
- /* The frame reads the shared control tokens with a lone Input's fallbacks, so the two match. */
5090
- border: var(--ui-border-width) solid var(--ui-control-border, var(--ui-border-strong));
5091
- border-radius: var(--ui-input-group-radius, var(--ui-field-radius, var(--ui-radius-md)));
5092
- background: var(--ui-control-surface, var(--ui-surface-elevated));
5093
- box-shadow: var(--ui-control-inset);
5094
- overflow: hidden;
5095
- /* A press anywhere in the frame focuses the input. */
5096
- cursor: text;
5097
- transition:
5098
- border-color var(--ui-motion-fast) var(--ui-motion-ease),
5099
- box-shadow var(--ui-motion-fast) var(--ui-motion-ease);
5100
- }
5101
- :scope[data-ui-input-group-state~="variant=subtle"]:where([data-hn-ui-input-group]) {
5102
- border-color: var(--ui-border);
5103
- background: var(--ui-surface-muted);
5104
- box-shadow: none;
5105
- }
5106
- :scope:has(.field [data-ui-input-state~="size=sm"]):where([data-hn-ui-input-group]) {
5107
- min-block-size: var(--ui-control-size-sm);
5108
- }
5109
- :scope:has(.field [data-ui-input-state~="size=lg"]):where([data-hn-ui-input-group]) {
5110
- min-block-size: var(--ui-control-size-lg);
5111
- }
5112
- @media (pointer: coarse) {
5113
- :scope:where([data-hn-ui-input-group]) {
5114
- min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
5115
- }
5116
- :scope:has(.field [data-ui-input-state~="size=sm"]):where([data-hn-ui-input-group]) {
5117
- min-block-size: var(--ui-control-min-block-size);
5118
- }
5119
- }
5120
- :scope:hover:not(:has(:is(input, textarea):focus, :is(input, textarea):disabled, :is(input, textarea):read-only, [aria-invalid="true"], :is(:user-invalid, [data-user-invalid]))):where([data-hn-ui-input-group]) {
5121
- border-color: var(--ui-control-border-hover, var(--ui-text-secondary));
5122
- }
5123
- :scope:has(.field :is(input, textarea):focus-visible):where([data-hn-ui-input-group]) {
5124
- border-color: var(--ui-control-focus, var(--ui-accent-solid));
5125
- box-shadow:
5126
- var(--ui-control-inset),
5127
- var(--ui-control-focus-halo-shadow);
5128
- }
5129
- :scope:has([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):where([data-hn-ui-input-group]) {
5130
- border-color: var(
5131
- --ui-input-group-invalid-border,
5132
- var(--ui-field-danger, var(--ui-danger-solid))
5133
- );
5134
- }
5135
- :scope:has(:is(input, textarea):is([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):focus-visible):where([data-hn-ui-input-group]) {
5136
- box-shadow: var(
5137
- --ui-input-group-invalid-focus-shadow,
5138
- var(--ui-control-inset),
5139
- 0 0 0 calc(var(--ui-focus-width) * 1.5) color-mix(
5140
- in srgb,
5141
- var(--ui-input-group-invalid-border, var(--ui-field-danger, var(--ui-danger-solid))) 22%,
5142
- transparent
5143
- )
5144
- );
5145
- }
5146
- @media (forced-colors: active) {
5147
- :scope:has(:is(input, textarea):focus-visible):where([data-hn-ui-input-group]) {
5148
- outline: var(--ui-focus-width) solid Highlight;
5149
- outline-offset: var(--ui-border-width);
5150
- }
5151
- }
5152
- :scope[data-ui-input-group-state~="disabled"]:where([data-hn-ui-input-group]),:scope:has(:is(input, textarea):disabled):where([data-hn-ui-input-group]) {
5153
- background: var(--ui-control-surface-disabled, var(--ui-surface-muted));
5154
- box-shadow: none;
5155
- cursor: not-allowed;
5156
- }
5157
- .field:where([data-hn-ui-input-group]) {
5158
- display: flex !important;
5159
- flex: 1;
5160
- min-inline-size: 0;
5161
- }
5162
- .affix:where([data-hn-ui-input-group]) {
5163
- display: inline-flex !important;
5164
- flex: none;
5165
- align-items: center !important;
5166
- padding-inline: var(--ui-space-2) !important;
5167
- color: var(--ui-text-muted);
5168
- font-family: var(--ui-font-family-mono);
5169
- font-size: var(--ui-font-size-sm);
5170
- white-space: nowrap;
5171
- }
5172
- .affix:has([slot="prefix"]):where([data-hn-ui-input-group]),.affix:has([slot="suffix"]):where([data-hn-ui-input-group]) {
5173
- background: var(--ui-surface-muted);
5174
- }
5175
- .affix:has([slot="prefix"]):where([data-hn-ui-input-group]) {
5176
- border-inline-end: var(--ui-border-width) solid var(--ui-border-divider);
5177
- }
5178
- .affix:has([slot="suffix"]):where([data-hn-ui-input-group]) {
5179
- border-inline-start: var(--ui-border-width) solid var(--ui-border-divider);
5180
- }
5181
- :scope[data-ui-input-group-state~="prefixKind=icon"]:where([data-hn-ui-input-group]) {
5182
- --_ui-default-input-padding-inline-start: var(--ui-space-2);
5183
- }
5184
- :scope[data-ui-input-group-state~="prefixKind=icon"]
5185
- .affix:first-child:where([data-hn-ui-input-group]) {
5186
- padding-inline-end: 0 !important;
5187
- border-inline-end: 0;
5188
- background: transparent;
5189
- }
5190
- .action:where([data-hn-ui-input-group]) {
5191
- display: flex !important;
5192
- flex: none;
5193
- align-items: center !important;
5194
- padding-inline: var(--ui-space-1) !important;
5195
- }
5196
- :scope[data-ui-input-group-state~="multiline"]:where([data-hn-ui-input-group]) {
5197
- display: grid !important;
5198
- grid-template-columns: auto minmax(0, 1fr) auto;
5199
- }
5200
- :scope[data-ui-input-group-state~="multiline"] .field:where([data-hn-ui-input-group]) {
5201
- grid-column: 2;
5202
- }
5203
- :scope[data-ui-input-group-state~="multiline"] .action:where([data-hn-ui-input-group]) {
5204
- grid-column: 1 / -1;
5205
- justify-content: end !important;
5206
- padding: var(--ui-space-2) !important;
5207
- padding-block-start: 0 !important;
5208
- }
5209
- :scope[data-ui-input-group-state~="multiline"][data-ui-input-group-state~="actionPosition=top-end"]:where([data-hn-ui-input-group]) {
5210
- --_ui-default-textarea-padding-inline-end: calc(
5211
- var(--_ui-input-group-action-inline-size, 7rem) + var(--ui-space-3)
5212
- );
5213
- }
5214
- :scope[data-ui-input-group-state~="multiline"][data-ui-input-group-state~="actionPosition=top-end"]
5215
- .field:where([data-hn-ui-input-group]) {
5216
- grid-row: 1;
5217
- }
5218
- :scope[data-ui-input-group-state~="multiline"][data-ui-input-group-state~="actionPosition=top-end"]
5219
- .action:where([data-hn-ui-input-group]) {
5220
- grid-column: 2;
5221
- grid-row: 1;
5222
- align-self: start;
5223
- justify-self: end;
5224
- padding: var(--ui-space-2) !important;
5225
- }
5226
- .affix:empty:where([data-hn-ui-input-group]),.action:empty:where([data-hn-ui-input-group]) {
5227
- display: none !important;
5228
- }
5229
- :scope[hidden]:where([data-hn-ui-input-group]) {
5230
- display: none !important;
5231
- }
5232
- }
5233
-
5234
- /* This component's hooks style the element they are set on, and never a nested one. */
5235
- @property --ui-textarea-border-width {
5236
- syntax: "*";
5237
- inherits: false;
6003
+ display: flex !important;
6004
+ align-items: unsafe center !important;
6005
+ block-size: 1lh;
5238
6006
  }
5239
- @property --ui-textarea-border {
5240
- syntax: "*";
5241
- inherits: false;
6007
+ .label-action:not(:has(> *)):where([data-hn-ui-form-field]) {
6008
+ display: none !important;
5242
6009
  }
5243
- @property --ui-textarea-border-hover {
5244
- syntax: "*";
5245
- inherits: false;
6010
+ .help:where([data-hn-ui-form-field]) {
6011
+ color: var(--_ui-form-field-help-text, var(--ui-text-muted));
6012
+ font-size: var(--_ui-form-field-help-font-size, var(--ui-font-size-sm));
6013
+ line-height: var(--ui-line-height-md);
5246
6014
  }
5247
- @property --ui-textarea-focus-border {
5248
- syntax: "*";
5249
- inherits: false;
6015
+ .help > :where(:not([data-hn-ui-form-field])):is(*) {
6016
+ min-block-size: var(--_ui-form-field-help-min-block-size, 0);
5250
6017
  }
5251
- @property --ui-textarea-focus-outline {
5252
- syntax: "*";
5253
- inherits: false;
6018
+ .error:where([data-hn-ui-form-field]) {
6019
+ display: none !important;
5254
6020
  }
5255
- @property --ui-textarea-surface {
5256
- syntax: "*";
5257
- inherits: false;
6021
+ :scope[data-ui-form-field-state~="invalid"] .error:where([data-hn-ui-form-field]) {
6022
+ display: contents !important;
5258
6023
  }
5259
- @property --ui-textarea-focus-shadow {
5260
- syntax: "*";
5261
- inherits: false;
6024
+ .error:where([data-hn-ui-form-field]),:where(:not([data-hn-ui-form-field])):is([role="alert"]) {
6025
+ color: var(--_ui-form-field-danger, var(--ui-field-danger, var(--ui-danger)));
6026
+ font-size: var(--ui-font-size-sm);
5262
6027
  }
5263
- @property --ui-textarea-invalid-border {
5264
- syntax: "*";
5265
- inherits: false;
6028
+ :scope[hidden]:where([data-hn-ui-form-field]) {
6029
+ display: none !important;
5266
6030
  }
5267
- @property --ui-textarea-invalid-focus-shadow {
5268
- syntax: "*";
5269
- inherits: false;
5270
6031
  }
5271
- @property --ui-textarea-radius {
6032
+
6033
+ @property --ui-input-group-radius {
5272
6034
  syntax: "*";
5273
6035
  inherits: false;
5274
6036
  }
5275
- @property --ui-textarea-shadow {
6037
+ @property --ui-input-group-invalid-border {
5276
6038
  syntax: "*";
5277
6039
  inherits: false;
5278
6040
  }
5279
- @property --ui-textarea-padding-inline-end {
6041
+ @property --ui-input-group-invalid-focus-shadow {
5280
6042
  syntax: "*";
5281
6043
  inherits: false;
5282
6044
  }
6045
+ /* An input with fixed text before or after it, such as a domain after a site's name
6046
+ ("acme" + ".example.com") or slashes around a path. The group draws the field's border and
6047
+ focus ring around the input and its affixes together; the input inside drops its own through
6048
+ its custom properties, so it is still the one ui-input, with its form behaviour intact. The
6049
+ affixes are plain text beside the input, so name the input with a label that says what the
6050
+ whole value is. The action slot takes one button at the end, inside the border, for the one
6051
+ thing the field is for ("Continue" after a site's address), so it reads as the field's action
6052
+ and not the form's. */
5283
6053
 
5284
- /* Tabbing into a field selects its text; tint that selection softly instead of the page highlight. */
6054
+ /* The frame takes its input's size, so a small group lines up with small buttons and fields. */
5285
6055
 
5286
- /* The app's invalid flag, or the browser's own verdict once the user has left an invalid field. */
6056
+ /* The ring shows when the field's input would show its own: when it is focus-visible, which a
6057
+ text input is for a pointer as well as a keyboard. A focused action button draws its own. */
5287
6058
 
5288
- /* Below 16px, iOS zooms the page into the focused field, so touch keeps body-size text. */
6059
+ /* Forced colors drop box shadows, so the focus ring becomes an outline. */
6060
+
6061
+ /* Fixed text is part of the value, but should not look editable. */
6062
+
6063
+ /* Centred rather than padded above and below: the group is exactly a lone Input's height, so a
6064
+ small button sits inside it with the difference split evenly, and the field keeps its height. */
6065
+
6066
+ /* Multiline text owns the first row; its action remains inside the same frame below it. */
6067
+
6068
+ /* The same textarea keeps its full resizeable box. Its text reserves the action's live width,
6069
+ so a translated label or pending indicator cannot cover what the person types. */
5289
6070
 
5290
6071
  /* A component that sets its display still honours the hidden attribute on its root. */
5291
- @scope (.ui-textarea) to ([data-hn]) {
5292
- :scope {
6072
+ @scope (.ui-input-group) to ([data-hn]) {
6073
+ :scope:where([data-hn-ui-input-group]) {
6074
+ /* The group's own border and height stand for the input's, so the group is a lone Input's height.
6075
+ Hooks do not inherit, so these are defaults for the input; its own hooks still win. */
6076
+ --_ui-default-input-border-width: 0;
6077
+ --_ui-default-input-min-block-size: 0;
6078
+ --_ui-default-input-border: transparent;
6079
+ --_ui-default-input-border-hover: transparent;
6080
+ --_ui-default-input-focus-border: transparent;
6081
+ --_ui-default-input-invalid-border: transparent;
6082
+ --_ui-default-input-invalid-focus-shadow: none;
6083
+ --_ui-default-input-shadow: none;
6084
+ --_ui-default-input-focus-shadow: none;
6085
+ --_ui-default-input-focus-outline: none;
6086
+ --_ui-default-input-radius: 0;
6087
+ --_ui-default-input-surface: transparent;
6088
+ --_ui-default-textarea-border-width: 0;
6089
+ --_ui-default-textarea-border: transparent;
6090
+ --_ui-default-textarea-border-hover: transparent;
6091
+ --_ui-default-textarea-focus-border: transparent;
6092
+ --_ui-default-textarea-invalid-border: transparent;
6093
+ --_ui-default-textarea-invalid-focus-shadow: none;
6094
+ --_ui-default-textarea-shadow: none;
6095
+ --_ui-default-textarea-focus-shadow: none;
6096
+ --_ui-default-textarea-focus-outline: none;
6097
+ --_ui-default-textarea-radius: 0;
6098
+ --_ui-default-textarea-surface: transparent;
6099
+
6100
+ display: flex !important;
6101
+ align-items: stretch !important;
5293
6102
  box-sizing: border-box !important;
5294
- display: inline-block !important;
5295
6103
  inline-size: 100%;
5296
6104
  min-inline-size: 0;
5297
- min-block-size: calc(3rem * 2);
5298
- margin: 0 !important;
5299
- --_padding-block: var(--ui-space-2);
5300
- padding: var(--ui-space-2) var(--ui-space-3) !important;
5301
- padding-inline-end: var(
5302
- --ui-textarea-padding-inline-end,
5303
- var(--_ui-default-textarea-padding-inline-end, var(--ui-space-3))
5304
- ) !important;
5305
- appearance: none;
5306
- resize: vertical;
5307
- border: var(
5308
- --ui-textarea-border-width,
5309
- var(--_ui-default-textarea-border-width, var(--ui-border-width))
5310
- ) solid
5311
- var(
5312
- --ui-textarea-border,
5313
- var(--_ui-default-textarea-border, var(--ui-control-border, var(--ui-border-strong)))
5314
- );
5315
- border-radius: var(
5316
- --ui-textarea-radius,
5317
- var(--_ui-default-textarea-radius, var(--ui-field-radius, var(--ui-radius-md)))
5318
- );
5319
- background: var(
5320
- --ui-textarea-surface,
5321
- var(--_ui-default-textarea-surface, var(--ui-control-surface, var(--ui-surface-elevated)))
5322
- );
5323
- color: var(--ui-text-primary);
5324
- font: inherit;
5325
- line-height: var(--ui-line-height-md);
5326
- box-shadow: var(
5327
- --ui-textarea-shadow,
5328
- var(--_ui-default-textarea-shadow, var(--ui-control-inset))
5329
- );
6105
+ min-block-size: var(--ui-control-size-md);
6106
+ /* The frame reads the shared control tokens with a lone Input's fallbacks, so the two match. */
6107
+ border: var(--ui-border-width) solid var(--ui-control-border, var(--ui-border-strong));
6108
+ border-radius: var(--ui-input-group-radius, var(--ui-field-radius, var(--ui-radius-md)));
6109
+ background: var(--ui-control-surface, var(--ui-surface-elevated));
6110
+ box-shadow: var(--ui-control-inset);
6111
+ overflow: hidden;
6112
+ /* A press anywhere in the frame focuses the input. */
6113
+ cursor: text;
5330
6114
  transition:
5331
6115
  border-color var(--ui-motion-fast) var(--ui-motion-ease),
5332
- box-shadow var(--ui-motion-fast) var(--ui-motion-ease),
5333
- background-color var(--ui-motion-fast) var(--ui-motion-ease);
5334
- }
5335
- :scope::selection {
5336
- background: color-mix(in srgb, var(--ui-accent-solid) 20%, transparent);
5337
- color: inherit;
5338
- }
5339
- :scope::placeholder {
5340
- color: var(--ui-control-placeholder, var(--ui-text-secondary));
5341
- opacity: 1;
5342
- }
5343
- :scope:hover:not(:focus):not(:disabled):not(:read-only):not([aria-invalid="true"]):not(:is(:user-invalid, [data-user-invalid])) {
5344
- border-color: var(
5345
- --ui-textarea-border-hover,
5346
- var(
5347
- --_ui-default-textarea-border-hover,
5348
- var(--ui-control-border-hover, var(--ui-text-secondary))
5349
- )
5350
- );
5351
- }
5352
- :scope:focus-visible {
5353
- border-color: var(
5354
- --ui-textarea-focus-border,
5355
- var(--_ui-default-textarea-focus-border, var(--ui-control-focus, var(--ui-accent-solid)))
5356
- );
5357
- outline: var(--ui-textarea-focus-outline, var(--_ui-default-textarea-focus-outline, none));
5358
- box-shadow: var(
5359
- --ui-textarea-focus-shadow,
5360
- var(
5361
- --_ui-default-textarea-focus-shadow,
5362
- var(--ui-control-inset),
5363
- var(--ui-control-focus-halo-shadow)
5364
- )
5365
- );
5366
- }
5367
- :scope[aria-invalid="true"],:scope:is(:user-invalid, [data-user-invalid]) {
5368
- border-color: var(
5369
- --ui-textarea-invalid-border,
5370
- var(--_ui-default-textarea-invalid-border, var(--ui-field-danger, var(--ui-danger-solid)))
5371
- );
5372
- }
5373
- :scope:is([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):focus-visible {
5374
- box-shadow: var(
5375
- --ui-textarea-invalid-focus-shadow,
5376
- var(
5377
- --_ui-default-textarea-invalid-focus-shadow,
5378
- var(--ui-control-inset),
5379
- 0 0 0 calc(var(--ui-focus-width) * 1.5) color-mix(
5380
- in srgb,
5381
- var(
5382
- --ui-textarea-invalid-border,
5383
- var(
5384
- --_ui-default-textarea-invalid-border,
5385
- var(--ui-field-danger, var(--ui-danger-solid))
5386
- )
5387
- ) 22%,
5388
- transparent
5389
- )
5390
- )
5391
- );
6116
+ box-shadow var(--ui-motion-fast) var(--ui-motion-ease);
5392
6117
  }
5393
- :scope:disabled {
5394
- background: var(--ui-control-surface-disabled, var(--ui-surface-muted));
5395
- color: var(--ui-disabled-text);
6118
+ :scope[data-ui-input-group-state~="variant=subtle"]:where([data-hn-ui-input-group]) {
6119
+ border-color: var(--ui-border);
6120
+ background: var(--ui-surface-muted);
5396
6121
  box-shadow: none;
5397
- cursor: not-allowed;
5398
- }
5399
- :scope[data-ui-textarea-state~="size=sm"] {
5400
- --_padding-block: var(--ui-space-1);
5401
- padding: var(--ui-space-1) var(--ui-space-2) !important;
5402
- padding-inline-end: var(
5403
- --ui-textarea-padding-inline-end,
5404
- var(--_ui-default-textarea-padding-inline-end, var(--ui-space-2))
5405
- ) !important;
5406
- font-size: var(--ui-font-size-sm);
5407
- }
5408
- :scope[data-ui-textarea-state~="size=lg"] {
5409
- --_padding-block: var(--ui-space-3);
5410
- padding: var(--ui-space-3) var(--ui-space-4) !important;
5411
- padding-inline-end: var(
5412
- --ui-textarea-padding-inline-end,
5413
- var(--_ui-default-textarea-padding-inline-end, var(--ui-space-4))
5414
- ) !important;
5415
- font-size: var(--ui-font-size-md);
5416
- }
5417
- :scope[data-ui-textarea-state~="maxRows"] {
5418
- max-block-size: calc(
5419
- max(var(--_rows), var(--_max-rows)) * 1lh + var(--_padding-block) + var(--_padding-block) +
5420
- 2px
5421
- );
5422
6122
  }
5423
- @supports (field-sizing: content) {
5424
- :scope[data-ui-textarea-state~="autosize"] {
5425
- field-sizing: content;
5426
- min-block-size: calc(
5427
- var(--_rows) * 1lh + var(--_padding-block) + var(--_padding-block) + 2px
5428
- );
6123
+ :scope:has(.field [data-ui-input-state~="size=sm"]):where([data-hn-ui-input-group]) {
6124
+ min-block-size: var(--ui-control-size-sm);
5429
6125
  }
6126
+ :scope:has(.field [data-ui-input-state~="size=lg"]):where([data-hn-ui-input-group]) {
6127
+ min-block-size: var(--ui-control-size-lg);
5430
6128
  }
5431
6129
  @media (pointer: coarse) {
5432
- :scope[data-ui-textarea-state~="size=sm"] {
5433
- font-size: inherit;
6130
+ :scope:where([data-hn-ui-input-group]) {
6131
+ min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
5434
6132
  }
6133
+ :scope:has(.field [data-ui-input-state~="size=sm"]):where([data-hn-ui-input-group]) {
6134
+ min-block-size: var(--ui-control-min-block-size);
5435
6135
  }
5436
- :scope[hidden] {
5437
- display: none !important;
5438
6136
  }
6137
+ :scope:hover:not(:has(:is(input, textarea):focus, :is(input, textarea):disabled, :is(input, textarea):read-only, [aria-invalid="true"], :is(:user-invalid, [data-user-invalid]))):where([data-hn-ui-input-group]) {
6138
+ border-color: var(--ui-control-border-hover, var(--ui-text-secondary));
5439
6139
  }
5440
-
5441
- /* One row, always. When the controls outgrow the space, the row scrolls sideways rather than
5442
- wrapping into several lines, and a fade at each edge that has more to show says so. */
5443
-
5444
- /* The edge fades are the scroll fade every Looma scroller uses (see ui-scroll-area), a mask on the
5445
- strip, so a floating toolbar's border and shadow stay whole. */
5446
-
5447
- /* Inside LoomaEditor's sticky shell, the shell is the sticky surface. */
5448
-
5449
- /* Inside LoomaEditor's mobile shell, the toolbar is a scroll-snapping strip. */
5450
-
5451
- /* A component that sets its display still honours the hidden attribute on its root. */
5452
- @scope (.ui-editor-toolbar) to ([data-hn]) {
5453
- :scope:where([data-hn-ui-editor-toolbar]) {
5454
- position: sticky;
5455
- top: 0;
5456
- z-index: var(--ui-editor-toolbar-z-index, 10);
5457
- display: flex !important;
5458
- align-items: center !important;
5459
- padding: var(--ui-editor-toolbar-padding-block, 6px)
5460
- var(--ui-editor-toolbar-padding-inline, 12px) !important;
5461
- min-height: var(--ui-editor-toolbar-min-height, 48px);
5462
- background: var(--ui-editor-toolbar-surface, var(--ui-surface));
5463
- border-bottom: var(--ui-border-width) solid
5464
- var(--ui-editor-toolbar-border, var(--ui-border-divider));
6140
+ :scope:has(.field :is(input, textarea):focus-visible):where([data-hn-ui-input-group]) {
6141
+ border-color: var(--ui-control-focus, var(--ui-accent-solid));
6142
+ box-shadow:
6143
+ var(--ui-control-inset),
6144
+ var(--ui-control-focus-halo-shadow);
5465
6145
  }
5466
- .strip:where([data-hn-ui-editor-toolbar]) {
5467
- display: flex !important;
5468
- flex: 1 1 auto;
5469
- align-items: center !important;
5470
- justify-content: flex-start !important;
5471
- gap: var(--ui-editor-toolbar-gap, 2px) !important;
5472
- min-width: 0;
5473
- overflow-x: auto;
5474
- overflow-y: hidden;
5475
- overscroll-behavior-inline: contain;
5476
- scrollbar-width: none;
6146
+ :scope:has([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):where([data-hn-ui-input-group]) {
6147
+ border-color: var(
6148
+ --ui-input-group-invalid-border,
6149
+ var(--ui-field-danger, var(--ui-danger-solid))
6150
+ );
5477
6151
  }
5478
- .strip:where([data-hn-ui-editor-toolbar])::-webkit-scrollbar {
5479
- display: none !important;
6152
+ :scope:has(:is(input, textarea):is([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):focus-visible):where([data-hn-ui-input-group]) {
6153
+ box-shadow: var(
6154
+ --ui-input-group-invalid-focus-shadow,
6155
+ var(--ui-control-inset),
6156
+ 0 0 0 calc(var(--ui-focus-width) * 1.5) color-mix(
6157
+ in srgb,
6158
+ var(--ui-input-group-invalid-border, var(--ui-field-danger, var(--ui-danger-solid))) 22%,
6159
+ transparent
6160
+ )
6161
+ );
5480
6162
  }
5481
- .strip > :where(:not([data-hn-ui-editor-toolbar])):is(*) {
5482
- flex: 0 0 auto;
6163
+ @media (forced-colors: active) {
6164
+ :scope:has(:is(input, textarea):focus-visible):where([data-hn-ui-input-group]) {
6165
+ outline: var(--ui-focus-width) solid Highlight;
6166
+ outline-offset: var(--ui-border-width);
5483
6167
  }
5484
- .strip:where([data-hn-ui-editor-toolbar]) {
5485
- --_ui-scroll-fade-direction: to right;
5486
- --_ui-scroll-fade-size: var(--ui-editor-toolbar-fade-size, var(--ui-scroll-fade-size, 24px));
5487
- mask-image: linear-gradient(
5488
- var(--_ui-scroll-fade-direction),
5489
- transparent,
5490
- #000 var(--_ui-scroll-fade-start),
5491
- #000 calc(100% - var(--_ui-scroll-fade-end)),
5492
- transparent
5493
- );
5494
- animation:
5495
- ui-scroll-fade-start linear,
5496
- ui-scroll-fade-start-hold linear,
5497
- ui-scroll-fade-end-hold linear,
5498
- ui-scroll-fade-end linear;
5499
- animation-timeline: scroll(self inline);
5500
- animation-range:
5501
- 0 var(--_ui-scroll-fade-size),
5502
- var(--_ui-scroll-fade-size) calc(100% + 1px),
5503
- -1px calc(100% - var(--_ui-scroll-fade-size)),
5504
- calc(100% - var(--_ui-scroll-fade-size)) 100%;
5505
6168
  }
5506
- :scope:dir(rtl) .strip:where([data-hn-ui-editor-toolbar]) {
5507
- --_ui-scroll-fade-direction: to left;
6169
+ :scope[data-ui-input-group-state~="disabled"]:where([data-hn-ui-input-group]),:scope:has(:is(input, textarea):disabled):where([data-hn-ui-input-group]) {
6170
+ background: var(--ui-control-surface-disabled, var(--ui-surface-muted));
6171
+ box-shadow: none;
6172
+ cursor: not-allowed;
5508
6173
  }
5509
- :where(:not([data-hn-ui-editor-toolbar])):is(.divider) {
5510
- width: 1px;
5511
- height: 20px;
5512
- background: var(--ui-editor-toolbar-divider, var(--ui-border-divider));
5513
- flex-shrink: 0;
5514
- margin: 0 var(--ui-editor-toolbar-divider-margin, 4px) !important;
6174
+ .field:where([data-hn-ui-input-group]) {
6175
+ display: flex !important;
6176
+ flex: 1;
6177
+ min-inline-size: 0;
5515
6178
  }
5516
- :scope[data-ui-editor-toolbar-state~="floating"]:where([data-hn-ui-editor-toolbar]) {
5517
- box-sizing: border-box !important;
5518
- position: relative;
5519
- top: auto;
5520
- width: max-content;
5521
- max-width: min(calc(100vw - 24px), 100%);
5522
- min-height: auto;
5523
- padding: var(--ui-editor-toolbar-floating-padding, 4px) !important;
5524
- background: color-mix(
5525
- in srgb,
5526
- var(--ui-editor-toolbar-surface, var(--ui-surface)) 96%,
5527
- transparent
5528
- );
5529
- border: var(--ui-border-width) solid var(--ui-editor-toolbar-border, var(--ui-border-strong));
5530
- border-radius: var(--ui-editor-toolbar-floating-radius, var(--ui-radius-lg));
5531
- box-shadow: var(
5532
- --ui-editor-toolbar-floating-shadow,
5533
- var(--ui-shadow-lg, 0 10px 24px rgb(0 0 0 / 0.12))
5534
- );
5535
- backdrop-filter: blur(10px);
6179
+ .affix:where([data-hn-ui-input-group]) {
6180
+ display: inline-flex !important;
6181
+ flex: none;
6182
+ align-items: center !important;
6183
+ padding-inline: var(--ui-space-2) !important;
6184
+ color: var(--ui-text-muted);
6185
+ font-family: var(--ui-font-family-mono);
6186
+ font-size: var(--ui-font-size-sm);
6187
+ white-space: nowrap;
5536
6188
  }
5537
- @media (max-width: 767px) {
5538
- :scope:where([data-hn-ui-editor-toolbar]) {
5539
- position: fixed;
5540
- top: auto;
5541
- bottom: env(safe-area-inset-bottom);
5542
- left: 0;
5543
- right: 0;
5544
- min-height: var(--ui-editor-toolbar-mobile-min-height, 56px);
5545
- border-top: var(--ui-border-width) solid
5546
- var(--ui-editor-toolbar-border, var(--ui-border-divider));
5547
- border-bottom: none;
5548
- box-shadow: var(--ui-editor-toolbar-mobile-shadow, 0 -2px 8px rgb(0 0 0 / 0.06));
6189
+ .affix:has([slot="prefix"]):where([data-hn-ui-input-group]),.affix:has([slot="suffix"]):where([data-hn-ui-input-group]) {
6190
+ background: var(--ui-surface-muted);
5549
6191
  }
5550
- :scope[data-ui-editor-toolbar-state~="floating"]:where([data-hn-ui-editor-toolbar]) {
5551
- position: relative;
5552
- inset: auto;
5553
- min-height: auto;
5554
- border: var(--ui-border-width) solid var(--ui-editor-toolbar-border, var(--ui-border-strong));
5555
- border-radius: var(--ui-editor-toolbar-floating-radius, var(--ui-radius-lg));
5556
- box-shadow: var(
5557
- --ui-editor-toolbar-floating-shadow,
5558
- var(--ui-shadow-lg, 0 10px 24px rgb(0 0 0 / 0.12))
5559
- );
6192
+ .affix:has([slot="prefix"]):where([data-hn-ui-input-group]) {
6193
+ border-inline-end: var(--ui-border-width) solid var(--ui-border-divider);
5560
6194
  }
6195
+ .affix:has([slot="suffix"]):where([data-hn-ui-input-group]) {
6196
+ border-inline-start: var(--ui-border-width) solid var(--ui-border-divider);
5561
6197
  }
5562
- .looma-editor__sticky-toolbar-shell :scope:where([data-hn-ui-editor-toolbar]) {
5563
- position: relative;
5564
- min-height: var(--ui-editor-toolbar-min-height, 48px);
5565
- background: transparent;
5566
- border: 0;
5567
- box-shadow: none;
6198
+ :scope[data-ui-input-group-state~="prefixKind=icon"]:where([data-hn-ui-input-group]) {
6199
+ --_ui-default-input-padding-inline-start: var(--ui-space-2);
5568
6200
  }
5569
- .looma-editor__mobile-toolbar-shell
5570
- :scope[data-ui-editor-toolbar-state~="floating"]:where([data-hn-ui-editor-toolbar]) {
5571
- width: 100%;
5572
- max-width: none;
5573
- min-height: 100%;
5574
- padding: 0 !important;
6201
+ :scope[data-ui-input-group-state~="prefixKind=icon"]
6202
+ .affix:first-child:where([data-hn-ui-input-group]) {
6203
+ padding-inline-end: 0 !important;
6204
+ border-inline-end: 0;
5575
6205
  background: transparent;
5576
- border: 0;
5577
- border-radius: 0;
5578
- box-shadow: none;
5579
- backdrop-filter: none;
5580
6206
  }
5581
- .looma-editor__mobile-toolbar-shell
5582
- :scope[data-ui-editor-toolbar-state~="floating"]
5583
- .strip:where([data-hn-ui-editor-toolbar]) {
5584
- scroll-snap-type: x mandatory;
6207
+ .action:where([data-hn-ui-input-group]) {
6208
+ display: flex !important;
6209
+ flex: none;
6210
+ align-items: center !important;
6211
+ padding-inline: var(--ui-space-1) !important;
5585
6212
  }
5586
- :scope[hidden]:where([data-hn-ui-editor-toolbar]) {
5587
- display: none !important;
6213
+ :scope[data-ui-input-group-state~="multiline"]:where([data-hn-ui-input-group]) {
6214
+ display: grid !important;
6215
+ grid-template-columns: auto minmax(0, 1fr) auto;
5588
6216
  }
6217
+ :scope[data-ui-input-group-state~="multiline"] .field:where([data-hn-ui-input-group]) {
6218
+ grid-column: 2;
5589
6219
  }
5590
-
5591
- /* This component's hooks style the element they are set on, and never a nested one. */
5592
- @property --ui-icon-button-active-scale {
5593
- syntax: "*";
5594
- inherits: false;
6220
+ :scope[data-ui-input-group-state~="multiline"] .action:where([data-hn-ui-input-group]) {
6221
+ grid-column: 1 / -1;
6222
+ justify-content: end !important;
6223
+ padding: var(--ui-space-2) !important;
6224
+ padding-block-start: 0 !important;
5595
6225
  }
5596
- @property --ui-icon-button-active-surface {
5597
- syntax: "*";
5598
- inherits: false;
6226
+ :scope[data-ui-input-group-state~="multiline"][data-ui-input-group-state~="actionPosition=top-end"]:where([data-hn-ui-input-group]) {
6227
+ --_ui-default-textarea-padding-inline-end: calc(
6228
+ var(--_ui-input-group-action-inline-size, 7rem) + var(--ui-space-3)
6229
+ );
5599
6230
  }
5600
- @property --ui-icon-button-border {
5601
- syntax: "*";
5602
- inherits: false;
6231
+ :scope[data-ui-input-group-state~="multiline"][data-ui-input-group-state~="actionPosition=top-end"]
6232
+ .field:where([data-hn-ui-input-group]) {
6233
+ grid-row: 1;
5603
6234
  }
5604
- @property --ui-icon-button-disabled-filter {
5605
- syntax: "*";
5606
- inherits: false;
6235
+ :scope[data-ui-input-group-state~="multiline"][data-ui-input-group-state~="actionPosition=top-end"]
6236
+ .action:where([data-hn-ui-input-group]) {
6237
+ grid-column: 2;
6238
+ grid-row: 1;
6239
+ align-self: start;
6240
+ justify-self: end;
6241
+ padding: var(--ui-space-2) !important;
5607
6242
  }
5608
- @property --ui-icon-button-disabled-opacity {
5609
- syntax: "*";
5610
- inherits: false;
6243
+ .affix:empty:where([data-hn-ui-input-group]),.action:empty:where([data-hn-ui-input-group]) {
6244
+ display: none !important;
5611
6245
  }
5612
- @property --ui-icon-button-hover-border {
5613
- syntax: "*";
5614
- inherits: false;
6246
+ :scope[hidden]:where([data-hn-ui-input-group]) {
6247
+ display: none !important;
5615
6248
  }
5616
- @property --ui-icon-button-hover-surface {
5617
- syntax: "*";
5618
- inherits: false;
5619
6249
  }
5620
- @property --ui-icon-button-hover-text {
6250
+
6251
+ /* This component's hooks style the element they are set on, and never a nested one. */
6252
+ @property --ui-textarea-border-width {
5621
6253
  syntax: "*";
5622
6254
  inherits: false;
5623
6255
  }
5624
- @property --ui-icon-button-icon-size {
6256
+ @property --ui-textarea-border {
5625
6257
  syntax: "*";
5626
6258
  inherits: false;
5627
6259
  }
5628
- @property --ui-icon-button-icon-stroke-width {
6260
+ @property --ui-textarea-border-hover {
5629
6261
  syntax: "*";
5630
6262
  inherits: false;
5631
6263
  }
5632
- @property --ui-icon-button-outline-surface {
6264
+ @property --ui-textarea-focus-border {
5633
6265
  syntax: "*";
5634
6266
  inherits: false;
5635
6267
  }
5636
- @property --ui-icon-button-outline-text {
6268
+ @property --ui-textarea-focus-outline {
5637
6269
  syntax: "*";
5638
6270
  inherits: false;
5639
6271
  }
5640
- @property --ui-icon-button-radius {
6272
+ @property --ui-textarea-surface {
5641
6273
  syntax: "*";
5642
6274
  inherits: false;
5643
6275
  }
5644
- @property --ui-icon-button-size {
6276
+ @property --ui-textarea-focus-shadow {
5645
6277
  syntax: "*";
5646
6278
  inherits: false;
5647
6279
  }
5648
- @property --ui-icon-button-solid-hover-surface {
6280
+ @property --ui-textarea-invalid-border {
5649
6281
  syntax: "*";
5650
6282
  inherits: false;
5651
6283
  }
5652
- @property --ui-icon-button-solid-shadow {
6284
+ @property --ui-textarea-invalid-focus-shadow {
5653
6285
  syntax: "*";
5654
6286
  inherits: false;
5655
6287
  }
5656
- @property --ui-icon-button-solid-surface {
6288
+ @property --ui-textarea-radius {
5657
6289
  syntax: "*";
5658
6290
  inherits: false;
5659
6291
  }
5660
- @property --ui-icon-button-solid-text {
6292
+ @property --ui-textarea-shadow {
5661
6293
  syntax: "*";
5662
6294
  inherits: false;
5663
6295
  }
5664
- @property --ui-icon-button-surface {
6296
+ @property --ui-textarea-padding-inline-end {
5665
6297
  syntax: "*";
5666
6298
  inherits: false;
5667
6299
  }
5668
6300
 
5669
- /* Omitted tone retains the existing accent solid; explicit neutral is additive. */
5670
-
5671
- /* At rest an anticipatory button shows only its guide dot. The icon grows into place when
5672
- proximity, hover, or focus reveals it; the button's hit area and guide remain stable. */
5673
-
5674
- /* A touch target without a bigger button: an invisible hit area, at least the control
5675
- minimum, centred on the button (::before is the anticipatory guide). */
5676
-
5677
- /* A text button's companion uses control geometry; compact icon buttons keep their own density. */
6301
+ /* Tabbing into a field selects its text; tint that selection softly instead of the page highlight. */
5678
6302
 
5679
- /* Native toggle state persists after pointer release, including during loading. */
6303
+ /* The app's invalid flag, or the browser's own verdict once the user has left an invalid field. */
5680
6304
 
5681
- /* Disabled is a flat neutral control, independent of the active variant's tone. */
6305
+ /* Below 16px, iOS zooms the page into the focused field, so touch keeps body-size text. */
5682
6306
 
5683
6307
  /* A component that sets its display still honours the hidden attribute on its root. */
5684
- @scope (.ui-icon-button) to ([data-hn]) {
5685
- :scope:where([data-hn-ui-icon-button]) {
5686
- /* Optional inherited action-group values keep text and icon actions under the same light.
5687
- One fine top/start highlight follows the bottom/end lowlight at a joined action seam.
5688
- A single ambient lift avoids stacking a face gradient or another inset bevel. */
5689
- --_ui-action-start: 1px;
5690
- --_ui-action-edge: var(
5691
- --ui-action-edge,
5692
- inset var(--_ui-action-start) 1px 0 light-dark(
5693
- rgb(255 255 255 / 0.08),
5694
- rgb(255 255 255 / 0.06)
5695
- ),
5696
- inset calc(-1 * var(--_ui-action-start)) -1px 0 light-dark(
5697
- rgb(0 0 0 / 0.08),
5698
- rgb(0 0 0 / 0.08)
5699
- )
6308
+ @scope (.ui-textarea) to ([data-hn]) {
6309
+ :scope {
6310
+ box-sizing: border-box !important;
6311
+ display: inline-block !important;
6312
+ inline-size: 100%;
6313
+ min-inline-size: 0;
6314
+ min-block-size: calc(3rem * 2);
6315
+ margin: 0 !important;
6316
+ --_padding-block: var(--ui-space-2);
6317
+ padding: var(--ui-space-2) var(--ui-space-3) !important;
6318
+ padding-inline-end: var(
6319
+ --ui-textarea-padding-inline-end,
6320
+ var(--_ui-default-textarea-padding-inline-end, var(--ui-space-3))
6321
+ ) !important;
6322
+ appearance: none;
6323
+ resize: vertical;
6324
+ border: var(
6325
+ --ui-textarea-border-width,
6326
+ var(--_ui-default-textarea-border-width, var(--ui-border-width))
6327
+ ) solid
6328
+ var(
6329
+ --ui-textarea-border,
6330
+ var(--_ui-default-textarea-border, var(--ui-control-border, var(--ui-border-strong)))
6331
+ );
6332
+ border-radius: var(
6333
+ --ui-textarea-radius,
6334
+ var(--_ui-default-textarea-radius, var(--ui-field-radius, var(--ui-radius-md)))
5700
6335
  );
5701
- --_ui-action-shadow:
5702
- var(--_ui-action-edge),
5703
- 0 1px 2px light-dark(rgb(0 0 0 / 0.10), rgb(0 0 0 / 0.20));
5704
- /* Hooks do not inherit, so the parts below read them from the root. */
5705
- --_ui-icon-button-icon-size: var(--ui-icon-button-icon-size);
5706
- --_ui-icon-button-icon-stroke-width: var(--ui-icon-button-icon-stroke-width);
5707
-
5708
- display: inline-flex !important;
5709
- color: var(--ui-text-secondary);
5710
- }
5711
- :scope:dir(rtl):where([data-hn-ui-icon-button]) {
5712
- --_ui-action-start: -1px;
5713
- }
5714
- :scope[data-ui-icon-button-state~="tone=accent"]:where([data-hn-ui-icon-button]) {
5715
- --_icon-button-border: var(--ui-accent-solid);
5716
- --_icon-button-hover-border: var(--ui-accent-hover);
5717
- --_icon-button-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
5718
- --_icon-button-outline-surface: color-mix(
5719
- in srgb,
5720
- var(--ui-accent-solid) 5%,
5721
- var(--ui-surface-default)
6336
+ background: var(
6337
+ --ui-textarea-surface,
6338
+ var(--_ui-default-textarea-surface, var(--ui-control-surface, var(--ui-surface-elevated)))
6339
+ );
6340
+ color: var(--ui-text-primary);
6341
+ font: inherit;
6342
+ line-height: var(--ui-line-height-md);
6343
+ box-shadow: var(
6344
+ --ui-textarea-shadow,
6345
+ var(--_ui-default-textarea-shadow, var(--ui-control-inset))
5722
6346
  );
5723
- color: var(--_icon-button-text);
5724
- }
5725
- :scope[data-ui-icon-button-state~="tone=neutral"]:where([data-hn-ui-icon-button]) {
5726
- --_icon-button-solid-surface: var(--ui-text-primary);
5727
- --_icon-button-solid-hover-surface: var(--ui-text-primary);
5728
- --_icon-button-solid-text: var(--ui-surface-default);
5729
- }
5730
- :scope[data-ui-icon-button-state~="anticipatory"]:where([data-hn-ui-icon-button]) {
5731
- position: relative;
5732
- }
5733
- :scope[data-ui-icon-button-state~="anticipatory"]:where([data-hn-ui-icon-button])::before {
5734
- content: "";
5735
- position: absolute;
5736
- inset: 50% auto auto 50%;
5737
- z-index: 1;
5738
- inline-size: var(--ui-affordance-guide-size);
5739
- block-size: var(--ui-affordance-guide-size);
5740
- border-radius: var(--ui-radius-round);
5741
- background: var(--ui-affordance-guide-color, var(--ui-border-strong));
5742
- opacity: calc(var(--ui-affordance-guide-opacity) * var(--ui-affordance-scope-guide, 1));
5743
- transform: translate(-50%, -50%);
5744
- transition: opacity var(--ui-affordance-motion, var(--ui-motion-fast)) var(--ui-motion-ease);
5745
- pointer-events: none;
5746
- }
5747
- :scope[data-ui-icon-button-state~="anticipatory"][data-ui-icon-button-state~="guide=bar"]:where([data-hn-ui-icon-button])::before {
5748
- inline-size: 2px;
5749
- block-size: 20px;
5750
- background: var(--ui-border-strong);
5751
- opacity: 1;
5752
- }
5753
- :scope[data-ui-icon-button-state~="anticipatory"]:disabled:where([data-hn-ui-icon-button])::before {
5754
- opacity: 0;
5755
- }
5756
- :scope[data-ui-icon-button-state~="anticipatory"]
5757
- .content:where([data-hn-ui-icon-button]) {
5758
- opacity: 1;
5759
- transform: scale(1);
5760
- transition:
5761
- opacity var(--ui-motion-fast) var(--ui-motion-ease),
5762
- transform calc(var(--ui-motion-fast) * 2) cubic-bezier(0.2, 1.4, 0.35, 1);
5763
- }
5764
- @media (hover: hover) and (pointer: fine) {
5765
- :scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="revealed"], :scope[data-ui-icon-button-state~="variant=solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible):where([data-hn-ui-icon-button]) {
5766
- border-color: transparent;
5767
- background-color: transparent;
5768
- box-shadow: none;
5769
- }
5770
- :scope[data-ui-icon-button-state~="anticipatory"]:not(:scope[data-ui-icon-button-state~="revealed"], :scope[data-ui-icon-button-state~="variant=solid"], :scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)
5771
- .content:where([data-hn-ui-icon-button]) {
5772
- opacity: 0;
5773
- transform: scale(0.65);
5774
- transition-duration: var(--ui-motion-fast);
5775
- }
5776
- }
5777
- :scope[data-ui-icon-button-state~="anticipatory"]:is(:scope[data-ui-icon-button-state~="revealed"], :scope[data-ui-icon-button-state~="variant=solid"], [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible):where([data-hn-ui-icon-button])::before {
5778
- opacity: 0;
5779
- }
5780
- :scope:where([data-hn-ui-icon-button]) {
5781
- /* The size prop resolves here; --ui-icon-button-size overrides it on an element. */
5782
- --_size: 2rem;
5783
- appearance: none;
5784
- inline-size: var(--ui-icon-button-size, var(--_size));
5785
- block-size: var(--ui-icon-button-size, var(--_size));
5786
- min-inline-size: var(--ui-icon-button-size, var(--_size));
5787
- min-block-size: var(--ui-icon-button-size, var(--_size));
5788
- padding: 0 !important;
5789
- margin: 0 !important;
5790
- border: var(--ui-border-width) solid transparent;
5791
- border-radius: var(--ui-icon-button-radius, var(--ui-action-radius, var(--ui-radius-md)));
5792
- background-color: var(--ui-icon-button-surface, transparent);
5793
- color: inherit;
5794
- display: inline-flex !important;
5795
- align-items: center !important;
5796
- justify-content: center !important;
5797
- cursor: pointer;
5798
6347
  transition:
5799
- background-color var(--ui-motion-fast) var(--ui-motion-ease),
5800
6348
  border-color var(--ui-motion-fast) var(--ui-motion-ease),
5801
- color var(--ui-motion-fast) var(--ui-motion-ease),
5802
- box-shadow var(--ui-motion-base) var(--ui-motion-ease),
5803
- scale var(--ui-motion-press, var(--ui-motion-fast)) var(--ui-motion-ease);
5804
- }
5805
- @media (hover: none), (pointer: coarse) {
5806
- :scope[data-ui-icon-button-state~="anticipatory"]:where([data-hn-ui-icon-button])::before {
5807
- opacity: 0;
5808
- }
5809
- }
5810
- @media (pointer: coarse) {
5811
- :scope:where([data-hn-ui-icon-button]) {
5812
- position: relative;
5813
- }
5814
- :scope:where([data-hn-ui-icon-button])::after {
5815
- content: "";
5816
- position: absolute;
5817
- inset: 50% auto auto 50%;
5818
- inline-size: max(100%, var(--ui-control-min-block-size));
5819
- block-size: max(100%, var(--ui-control-min-block-size));
5820
- transform: translate(-50%, -50%);
5821
- }
5822
- }
5823
- html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button]) {
5824
- position: relative;
5825
- }
5826
- html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button])::after {
5827
- content: "";
5828
- position: absolute;
5829
- inset: 50% auto auto 50%;
5830
- inline-size: max(100%, var(--ui-control-min-block-size));
5831
- block-size: max(100%, var(--ui-control-min-block-size));
5832
- transform: translate(-50%, -50%);
5833
- }
5834
- :scope[data-ui-icon-button-state~="size=sm"]:where([data-hn-ui-icon-button]) {
5835
- --_size: 1.75rem;
5836
- inline-size: var(--ui-icon-button-size, var(--_size));
5837
- block-size: var(--ui-icon-button-size, var(--_size));
5838
- min-inline-size: var(--ui-icon-button-size, var(--_size));
5839
- min-block-size: var(--ui-icon-button-size, var(--_size));
5840
- }
5841
- :scope[data-ui-icon-button-state~="size=lg"]:where([data-hn-ui-icon-button]) {
5842
- --_size: 2.5rem;
5843
- inline-size: var(--ui-icon-button-size, var(--_size));
5844
- block-size: var(--ui-icon-button-size, var(--_size));
5845
- min-inline-size: var(--ui-icon-button-size, var(--_size));
5846
- min-block-size: var(--ui-icon-button-size, var(--_size));
5847
- }
5848
- :scope[data-ui-icon-button-state~="matchButton"]:where([data-hn-ui-icon-button]) {
5849
- --_size: var(--ui-control-size-md);
5850
- block-size: auto;
5851
- align-self: stretch;
5852
- }
5853
- :scope[data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=sm"]:where([data-hn-ui-icon-button]) {
5854
- --_size: var(--ui-control-size-sm);
5855
- }
5856
- :scope[data-ui-icon-button-state~="matchButton"][data-ui-icon-button-state~="size=lg"]:where([data-hn-ui-icon-button]) {
5857
- --_size: var(--ui-control-size-lg);
5858
- }
5859
- @media (pointer: coarse) {
5860
- :scope[data-ui-icon-button-state~="matchButton"]:where([data-hn-ui-icon-button]) {
5861
- inline-size: max(var(--ui-icon-button-size, var(--_size)), var(--ui-control-min-block-size));
5862
- min-inline-size: max(
5863
- var(--ui-icon-button-size, var(--_size)),
5864
- var(--ui-control-min-block-size)
5865
- );
5866
- min-block-size: max(
5867
- var(--ui-icon-button-size, var(--_size)),
5868
- var(--ui-control-min-block-size)
5869
- );
6349
+ box-shadow var(--ui-motion-fast) var(--ui-motion-ease),
6350
+ background-color var(--ui-motion-fast) var(--ui-motion-ease);
5870
6351
  }
6352
+ :scope::selection {
6353
+ background: color-mix(in srgb, var(--ui-accent-solid) 20%, transparent);
6354
+ color: inherit;
5871
6355
  }
5872
- :scope[data-ui-icon-button-state~="round"]:where([data-hn-ui-icon-button]) {
5873
- border-radius: var(--ui-radius-round);
6356
+ :scope::placeholder {
6357
+ color: var(--ui-control-placeholder, var(--ui-text-secondary));
6358
+ opacity: 1;
5874
6359
  }
5875
- :scope[data-ui-icon-button-state~="variant=outline"]:where([data-hn-ui-icon-button]) {
6360
+ :scope:hover:not(:focus):not(:disabled):not(:read-only):not([aria-invalid="true"]):not(:is(:user-invalid, [data-user-invalid])) {
5876
6361
  border-color: var(
5877
- --ui-icon-button-border,
5878
- var(--_icon-button-border, var(--ui-control-border, var(--ui-border-strong)))
5879
- );
5880
- background-color: var(
5881
- --ui-icon-button-outline-surface,
5882
- var(--_icon-button-outline-surface, var(--ui-surface-default))
6362
+ --ui-textarea-border-hover,
6363
+ var(
6364
+ --_ui-default-textarea-border-hover,
6365
+ var(--ui-control-border-hover, var(--ui-text-secondary))
6366
+ )
5883
6367
  );
5884
- background-image: none;
5885
- color: var(--ui-icon-button-outline-text, var(--_icon-button-text, var(--ui-text-primary)));
5886
- box-shadow: var(--ui-action-shadow, var(--_ui-action-shadow));
5887
6368
  }
5888
- :scope[data-ui-icon-button-state~="variant=solid"]:where([data-hn-ui-icon-button]) {
5889
- background-color: var(
5890
- --ui-icon-button-solid-surface,
5891
- var(--_icon-button-solid-surface, var(--ui-accent-solid))
5892
- );
5893
- background-image: none;
5894
- color: var(
5895
- --ui-icon-button-solid-text,
5896
- var(--_icon-button-solid-text, var(--ui-text-on-accent))
6369
+ :scope:focus-visible {
6370
+ border-color: var(
6371
+ --ui-textarea-focus-border,
6372
+ var(--_ui-default-textarea-focus-border, var(--ui-control-focus, var(--ui-accent-solid)))
5897
6373
  );
6374
+ outline: var(--ui-textarea-focus-outline, var(--_ui-default-textarea-focus-outline, none));
5898
6375
  box-shadow: var(
5899
- --ui-icon-button-solid-shadow,
5900
- var(--ui-action-shadow, var(--_ui-action-shadow))
5901
- );
5902
- }
5903
- :scope:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
5904
- /* Derived from the text colour so the ghost hover shows on any background. */
5905
- background-color: var(
5906
- --ui-icon-button-hover-surface,
5907
- color-mix(in srgb, currentColor 8%, transparent)
6376
+ --ui-textarea-focus-shadow,
6377
+ var(
6378
+ --_ui-default-textarea-focus-shadow,
6379
+ var(--ui-control-inset),
6380
+ var(--ui-control-focus-halo-shadow)
6381
+ )
5908
6382
  );
5909
- color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
5910
6383
  }
5911
- :scope[data-ui-icon-button-state~="variant=outline"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
6384
+ :scope[aria-invalid="true"],:scope:is(:user-invalid, [data-user-invalid]) {
5912
6385
  border-color: var(
5913
- --ui-icon-button-hover-border,
5914
- var(--_icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border)))
6386
+ --ui-textarea-invalid-border,
6387
+ var(--_ui-default-textarea-invalid-border, var(--ui-field-danger, var(--ui-danger-solid)))
5915
6388
  );
5916
6389
  }
5917
- :scope[data-ui-icon-button-state~="variant=solid"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
5918
- background-color: var(
5919
- --ui-icon-button-solid-hover-surface,
5920
- var(--_icon-button-solid-hover-surface, var(--ui-accent-hover))
6390
+ :scope:is([aria-invalid="true"], :is(:user-invalid, [data-user-invalid])):focus-visible {
6391
+ box-shadow: var(
6392
+ --ui-textarea-invalid-focus-shadow,
6393
+ var(
6394
+ --_ui-default-textarea-invalid-focus-shadow,
6395
+ var(--ui-control-inset),
6396
+ 0 0 0 calc(var(--ui-focus-width) * 1.5) color-mix(
6397
+ in srgb,
6398
+ var(
6399
+ --ui-textarea-invalid-border,
6400
+ var(
6401
+ --_ui-default-textarea-invalid-border,
6402
+ var(--ui-field-danger, var(--ui-danger-solid))
6403
+ )
6404
+ ) 22%,
6405
+ transparent
6406
+ )
6407
+ )
5921
6408
  );
5922
6409
  }
5923
- :scope[data-ui-icon-button-state~="variant=solid"][data-ui-icon-button-state~="tone=accent"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]),:scope[data-ui-icon-button-state~="variant=solid"][data-ui-icon-button-state~="tone=neutral"]:hover:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
5924
- color: var(
5925
- --ui-icon-button-solid-text,
5926
- var(--_icon-button-solid-text, var(--ui-text-on-accent))
5927
- );
6410
+ :scope:disabled {
6411
+ background: var(--ui-control-surface-disabled, var(--ui-surface-muted));
6412
+ color: var(--ui-disabled-text);
6413
+ box-shadow: none;
6414
+ cursor: not-allowed;
5928
6415
  }
5929
- :scope[data-ui-icon-button-state~="variant=ghost"][aria-expanded="true"]:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
5930
- background-color: var(
5931
- --ui-icon-button-active-surface,
5932
- color-mix(in srgb, currentColor 16%, transparent)
5933
- );
5934
- color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
5935
- box-shadow: var(--ui-pressed);
6416
+ :scope[data-ui-textarea-state~="size=sm"] {
6417
+ --_padding-block: var(--ui-space-1);
6418
+ padding: var(--ui-space-1) var(--ui-space-2) !important;
6419
+ padding-inline-end: var(
6420
+ --ui-textarea-padding-inline-end,
6421
+ var(--_ui-default-textarea-padding-inline-end, var(--ui-space-2))
6422
+ ) !important;
6423
+ font-size: var(--ui-font-size-sm);
5936
6424
  }
5937
- :scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:where([data-hn-ui-icon-button]) {
5938
- background-color: var(
5939
- --ui-icon-button-active-surface,
5940
- color-mix(in srgb, currentColor 12%, var(--ui-surface-default))
6425
+ :scope[data-ui-textarea-state~="size=lg"] {
6426
+ --_padding-block: var(--ui-space-3);
6427
+ padding: var(--ui-space-3) var(--ui-space-4) !important;
6428
+ padding-inline-end: var(
6429
+ --ui-textarea-padding-inline-end,
6430
+ var(--_ui-default-textarea-padding-inline-end, var(--ui-space-4))
6431
+ ) !important;
6432
+ font-size: var(--ui-font-size-md);
6433
+ }
6434
+ :scope[data-ui-textarea-state~="maxRows"] {
6435
+ max-block-size: calc(
6436
+ max(var(--_rows), var(--_max-rows)) * 1lh + var(--_padding-block) + var(--_padding-block) +
6437
+ 2px
5941
6438
  );
5942
- background-image: none;
5943
- box-shadow: var(--ui-pressed);
5944
6439
  }
5945
- :scope:active:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
5946
- scale: var(--ui-icon-button-active-scale, var(--ui-press-scale, 0.96));
6440
+ @supports (field-sizing: content) {
6441
+ :scope[data-ui-textarea-state~="autosize"] {
6442
+ field-sizing: content;
6443
+ min-block-size: calc(
6444
+ var(--_rows) * 1lh + var(--_padding-block) + var(--_padding-block) + 2px
6445
+ );
5947
6446
  }
5948
- :is(:scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"]):where([data-hn-ui-icon-button]) {
5949
- cursor: progress;
5950
6447
  }
5951
- .content:where([data-hn-ui-icon-button]) {
5952
- display: inline-flex !important;
5953
- align-items: center !important;
5954
- justify-content: center !important;
6448
+ @media (pointer: coarse) {
6449
+ :scope[data-ui-textarea-state~="size=sm"] {
6450
+ font-size: inherit;
5955
6451
  }
5956
- :is(:scope[data-ui-icon-button-state~="loading"], :scope[data-ui-icon-button-state~="pending"])
5957
- .content:where([data-hn-ui-icon-button]) {
5958
- display: none !important;
5959
6452
  }
5960
- @media (prefers-reduced-motion: reduce) {
5961
- :scope[data-ui-icon-button-state~="anticipatory"]
5962
- .content:where([data-hn-ui-icon-button]) {
5963
- transition: none;
6453
+ :scope[hidden] {
6454
+ display: none !important;
5964
6455
  }
5965
6456
  }
5966
- :scope:focus-visible:where([data-hn-ui-icon-button]) {
5967
- outline: none;
5968
- box-shadow: var(--ui-focus-halo);
6457
+
6458
+ /* One row, always. When the controls outgrow the space, the row scrolls sideways rather than
6459
+ wrapping into several lines, and a fade at each edge that has more to show says so. */
6460
+
6461
+ /* The edge fades are the scroll fade every Looma scroller uses (see ui-scroll-area), a mask on the
6462
+ strip, so a floating toolbar's border and shadow stay whole. */
6463
+
6464
+ /* Inside LoomaEditor's sticky shell, the shell is the sticky surface. */
6465
+
6466
+ /* Inside LoomaEditor's mobile shell, the toolbar is a scroll-snapping strip. */
6467
+
6468
+ /* A component that sets its display still honours the hidden attribute on its root. */
6469
+ @scope (.ui-editor-toolbar) to ([data-hn]) {
6470
+ :scope:where([data-hn-ui-editor-toolbar]) {
6471
+ position: sticky;
6472
+ top: 0;
6473
+ z-index: var(--ui-editor-toolbar-z-index, 10);
6474
+ display: flex !important;
6475
+ align-items: center !important;
6476
+ padding: var(--ui-editor-toolbar-padding-block, 6px)
6477
+ var(--ui-editor-toolbar-padding-inline, 12px) !important;
6478
+ min-height: var(--ui-editor-toolbar-min-height, 48px);
6479
+ background: var(--ui-editor-toolbar-surface, var(--ui-surface));
6480
+ border-bottom: var(--ui-border-width) solid
6481
+ var(--ui-editor-toolbar-border, var(--ui-border-divider));
5969
6482
  }
5970
- :scope[data-ui-icon-button-state~="variant=outline"]:focus-visible:where([data-hn-ui-icon-button]) {
5971
- box-shadow:
5972
- var(--ui-action-shadow, var(--_ui-action-shadow)),
5973
- var(--ui-focus-halo);
6483
+ .strip:where([data-hn-ui-editor-toolbar]) {
6484
+ display: flex !important;
6485
+ flex: 1 1 auto;
6486
+ align-items: center !important;
6487
+ justify-content: flex-start !important;
6488
+ gap: var(--ui-editor-toolbar-gap, 2px) !important;
6489
+ min-width: 0;
6490
+ overflow-x: auto;
6491
+ overflow-y: hidden;
6492
+ overscroll-behavior-inline: contain;
6493
+ scrollbar-width: none;
5974
6494
  }
5975
- :scope[data-ui-icon-button-state~="variant=solid"]:focus-visible:where([data-hn-ui-icon-button]) {
5976
- box-shadow:
5977
- var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
5978
- var(--ui-focus-halo);
6495
+ .strip:where([data-hn-ui-editor-toolbar])::-webkit-scrollbar {
6496
+ display: none !important;
5979
6497
  }
5980
- :scope:is(:scope[data-ui-icon-button-state~="variant=outline"], :scope[data-ui-icon-button-state~="variant=solid"]):active:enabled:not([aria-disabled="true"]):where([data-hn-ui-icon-button]) {
5981
- background-image: none;
5982
- box-shadow: var(--ui-pressed);
6498
+ .strip > :where(:not([data-hn-ui-editor-toolbar])):is(*) {
6499
+ flex: 0 0 auto;
5983
6500
  }
5984
- :scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:focus-visible:where([data-hn-ui-icon-button]) {
5985
- box-shadow:
5986
- var(--ui-pressed),
5987
- var(--ui-focus-halo);
6501
+ .strip:where([data-hn-ui-editor-toolbar]) {
6502
+ --_ui-scroll-fade-direction: to right;
6503
+ --_ui-scroll-fade-size: var(--ui-editor-toolbar-fade-size, var(--ui-scroll-fade-size, 24px));
6504
+ mask-image: linear-gradient(
6505
+ var(--_ui-scroll-fade-direction),
6506
+ transparent,
6507
+ #000 var(--_ui-scroll-fade-start),
6508
+ #000 calc(100% - var(--_ui-scroll-fade-end)),
6509
+ transparent
6510
+ );
6511
+ animation:
6512
+ ui-scroll-fade-start linear,
6513
+ ui-scroll-fade-start-hold linear,
6514
+ ui-scroll-fade-end-hold linear,
6515
+ ui-scroll-fade-end linear;
6516
+ animation-timeline: scroll(self inline);
6517
+ animation-range:
6518
+ 0 var(--_ui-scroll-fade-size),
6519
+ var(--_ui-scroll-fade-size) calc(100% + 1px),
6520
+ -1px calc(100% - var(--_ui-scroll-fade-size)),
6521
+ calc(100% - var(--_ui-scroll-fade-size)) 100%;
5988
6522
  }
5989
- @media (forced-colors: active) {
5990
- :scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:where([data-hn-ui-icon-button]) {
5991
- outline: var(--ui-focus-width) solid Highlight;
5992
- outline-offset: calc(-2 * var(--ui-focus-width));
6523
+ :scope:dir(rtl) .strip:where([data-hn-ui-editor-toolbar]) {
6524
+ --_ui-scroll-fade-direction: to left;
5993
6525
  }
5994
- :scope[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:focus-visible:where([data-hn-ui-icon-button]) {
5995
- outline-offset: var(--ui-focus-width);
6526
+ :where(:not([data-hn-ui-editor-toolbar])):is(.divider) {
6527
+ width: 1px;
6528
+ height: 20px;
6529
+ background: var(--ui-editor-toolbar-divider, var(--ui-border-divider));
6530
+ flex-shrink: 0;
6531
+ margin: 0 var(--ui-editor-toolbar-divider-margin, 4px) !important;
5996
6532
  }
6533
+ :scope[data-ui-editor-toolbar-state~="floating"]:where([data-hn-ui-editor-toolbar]) {
6534
+ box-sizing: border-box !important;
6535
+ position: relative;
6536
+ top: auto;
6537
+ width: max-content;
6538
+ max-width: min(calc(100vw - 24px), 100%);
6539
+ min-height: auto;
6540
+ padding: var(--ui-editor-toolbar-floating-padding, 4px) !important;
6541
+ background: color-mix(
6542
+ in srgb,
6543
+ var(--ui-editor-toolbar-surface, var(--ui-surface)) 96%,
6544
+ transparent
6545
+ );
6546
+ border: var(--ui-border-width) solid var(--ui-editor-toolbar-border, var(--ui-border-strong));
6547
+ border-radius: var(--ui-editor-toolbar-floating-radius, var(--ui-radius-lg));
6548
+ box-shadow: var(
6549
+ --ui-editor-toolbar-floating-shadow,
6550
+ var(--ui-shadow-lg, 0 10px 24px rgb(0 0 0 / 0.12))
6551
+ );
6552
+ backdrop-filter: blur(10px);
5997
6553
  }
5998
- :scope:disabled:where([data-hn-ui-icon-button]) {
5999
- border-color: var(--ui-disabled-border);
6000
- background-color: var(--ui-disabled-surface);
6001
- color: var(--ui-disabled-text);
6002
- filter: var(--ui-icon-button-disabled-filter, var(--ui-disabled-filter));
6003
- opacity: var(--ui-icon-button-disabled-opacity, 1);
6004
- cursor: not-allowed;
6005
- box-shadow: none;
6006
- background-image: none;
6554
+ @media (max-width: 767px) {
6555
+ :scope:where([data-hn-ui-editor-toolbar]) {
6556
+ position: fixed;
6557
+ top: auto;
6558
+ bottom: env(safe-area-inset-bottom);
6559
+ left: 0;
6560
+ right: 0;
6561
+ min-height: var(--ui-editor-toolbar-mobile-min-height, 56px);
6562
+ border-top: var(--ui-border-width) solid
6563
+ var(--ui-editor-toolbar-border, var(--ui-border-divider));
6564
+ border-bottom: none;
6565
+ box-shadow: var(--ui-editor-toolbar-mobile-shadow, 0 -2px 8px rgb(0 0 0 / 0.06));
6007
6566
  }
6008
- :scope[data-ui-icon-button-state~="variant=ghost"]:disabled:where([data-hn-ui-icon-button]) {
6009
- border-color: transparent;
6567
+ :scope[data-ui-editor-toolbar-state~="floating"]:where([data-hn-ui-editor-toolbar]) {
6568
+ position: relative;
6569
+ inset: auto;
6570
+ min-height: auto;
6571
+ border: var(--ui-border-width) solid var(--ui-editor-toolbar-border, var(--ui-border-strong));
6572
+ border-radius: var(--ui-editor-toolbar-floating-radius, var(--ui-radius-lg));
6573
+ box-shadow: var(
6574
+ --ui-editor-toolbar-floating-shadow,
6575
+ var(--ui-shadow-lg, 0 10px 24px rgb(0 0 0 / 0.12))
6576
+ );
6010
6577
  }
6011
- :scope:where([data-hn-ui-icon-button]) {
6012
- --_icon-button-icon-default: var(--ui-icon-size-md);
6013
- /* A slotted ui-icon is its own component, out of reach of the svg rule below; these are its
6014
- defaults, which its own --ui-icon-* hooks still override. */
6015
- --_ui-default-icon-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
6016
- --_ui-default-icon-stroke-width: var(--_ui-icon-button-icon-stroke-width, 1.75);
6017
6578
  }
6018
- :scope[data-ui-icon-button-state~="size=sm"]:where([data-hn-ui-icon-button]) {
6019
- --_icon-button-icon-default: var(--ui-icon-size-sm);
6579
+ .looma-editor__sticky-toolbar-shell :scope:where([data-hn-ui-editor-toolbar]) {
6580
+ position: relative;
6581
+ min-height: var(--ui-editor-toolbar-min-height, 48px);
6582
+ background: transparent;
6583
+ border: 0;
6584
+ box-shadow: none;
6020
6585
  }
6021
- :scope[data-ui-icon-button-state~="size=lg"]:where([data-hn-ui-icon-button]) {
6022
- --_icon-button-icon-default: var(--ui-icon-size-lg);
6586
+ .looma-editor__mobile-toolbar-shell
6587
+ :scope[data-ui-editor-toolbar-state~="floating"]:where([data-hn-ui-editor-toolbar]) {
6588
+ width: 100%;
6589
+ max-width: none;
6590
+ min-height: 100%;
6591
+ padding: 0 !important;
6592
+ background: transparent;
6593
+ border: 0;
6594
+ border-radius: 0;
6595
+ box-shadow: none;
6596
+ backdrop-filter: none;
6023
6597
  }
6024
- :where(:not([data-hn-ui-icon-button])):is(svg) {
6025
- inline-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
6026
- block-size: var(--_ui-icon-button-icon-size, var(--_icon-button-icon-default));
6027
- flex-shrink: 0;
6028
- stroke-width: var(--_ui-icon-button-icon-stroke-width, 1.75);
6598
+ .looma-editor__mobile-toolbar-shell
6599
+ :scope[data-ui-editor-toolbar-state~="floating"]
6600
+ .strip:where([data-hn-ui-editor-toolbar]) {
6601
+ scroll-snap-type: x mandatory;
6029
6602
  }
6030
- :scope[hidden]:where([data-hn-ui-icon-button]) {
6603
+ :scope[hidden]:where([data-hn-ui-editor-toolbar]) {
6031
6604
  display: none !important;
6032
6605
  }
6033
6606
  }
@@ -6062,9 +6635,13 @@ html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button])::aft
6062
6635
  inherits: false;
6063
6636
  }
6064
6637
 
6638
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
6639
+ transparency, saturation and edge light belong to the surrounding decorative material. */
6640
+
6065
6641
  /* A toolbar or card can supply its own surface, including an unclipped shadow. */
6066
6642
  @scope (.ui-popover) to ([data-hn]) {
6067
6643
  :scope:where([data-hn-ui-popover]) {
6644
+ --_ui-material-scale: 0.55;
6068
6645
  --_ui-popover-surface: var(--ui-popover-surface);
6069
6646
  --_ui-popover-border: var(--ui-popover-border);
6070
6647
  --_ui-popover-radius: var(--ui-popover-radius);
@@ -6099,12 +6676,96 @@ html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button])::aft
6099
6676
  var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg)))
6100
6677
  );
6101
6678
  }
6679
+ .surface:where([data-hn-ui-popover]) {
6680
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
6681
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
6682
+ --_ui-material-active: clamp(
6683
+ 0,
6684
+ calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000),
6685
+ 1
6686
+ );
6687
+ --_ui-material-rim: calc(
6688
+ (
6689
+ var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25
6690
+ ) *
6691
+ var(--_ui-material-scale, 0.55) *
6692
+ 8px
6693
+ );
6694
+ --_ui-material-content-color: var(
6695
+ --_ui-popover-surface,
6696
+ var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated)))
6697
+ );
6698
+ --_ui-material-rim-color: color-mix(
6699
+ in srgb,
6700
+ var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%),
6701
+ transparent
6702
+ );
6703
+ background:
6704
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color))
6705
+ padding-box,
6706
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
6707
+ var(--_ui-material-content-color) padding-box;
6708
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
6709
+ border-color: var(
6710
+ --_ui-popover-border,
6711
+ color-mix(
6712
+ in oklab,
6713
+ var(--ui-overlay-border, var(--ui-border-strong)) calc(
6714
+ (1 - var(--_ui-material-active)) * 100%
6715
+ ),
6716
+ transparent
6717
+ )
6718
+ );
6719
+ box-shadow: var(
6720
+ --_ui-popover-shadow,
6721
+ var(
6722
+ --ui-overlay-shadow,
6723
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 8px) calc(
6724
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 24px
6725
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
6726
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(
6727
+ --ui-material-edge,
6728
+ var(--ui-border-strong)
6729
+ ),
6730
+ var(--ui-elevation-overlay, var(--ui-shadow-lg))
6731
+ )
6732
+ );
6733
+ backdrop-filter: blur(
6734
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 18px)
6735
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 0.18));
6736
+ -webkit-backdrop-filter: blur(
6737
+ calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 18px)
6738
+ ) saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 0.18));
6739
+ }
6740
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
6741
+ .surface:where([data-hn-ui-popover]) {
6742
+ background: var(--_ui-material-content-color);
6743
+ }
6744
+ }
6745
+ @media (prefers-reduced-transparency: reduce) {
6746
+ .surface:where([data-hn-ui-popover]) {
6747
+ background: var(--_ui-material-content-color);
6748
+ backdrop-filter: none;
6749
+ -webkit-backdrop-filter: none;
6750
+ }
6751
+ }
6752
+ @media (forced-colors: active) {
6753
+ .surface:where([data-hn-ui-popover]) {
6754
+ background: Canvas;
6755
+ border-color: CanvasText;
6756
+ box-shadow: none;
6757
+ backdrop-filter: none;
6758
+ -webkit-backdrop-filter: none;
6759
+ }
6760
+ }
6102
6761
  :scope[data-ui-popover-state~="bare"] .surface:where([data-hn-ui-popover]) {
6103
6762
  overflow: visible;
6104
6763
  padding: 0 !important;
6105
6764
  border: 0;
6106
6765
  background: transparent;
6107
6766
  box-shadow: none;
6767
+ backdrop-filter: none;
6768
+ -webkit-backdrop-filter: none;
6108
6769
  }
6109
6770
  :scope:not([data-ui-popover-state~="internalOpen"]):where([data-hn-ui-popover]) {
6110
6771
  display: none !important;
@@ -6180,7 +6841,7 @@ html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button])::aft
6180
6841
  color: var(--ui-text-primary);
6181
6842
  text-align: start;
6182
6843
  }
6183
- :scope:is(h2, h3, h4, h5, h6):where([data-hn-ui-text]) {
6844
+ :scope:is(h1, h2, h3, h4, h5, h6):where([data-hn-ui-text]) {
6184
6845
  font-family: var(--ui-font-display, inherit);
6185
6846
  font-size: inherit;
6186
6847
  font-weight: inherit;
@@ -6235,10 +6896,31 @@ html[data-ui-input-modality="touch"] :scope:where([data-hn-ui-icon-button])::aft
6235
6896
  :scope[data-ui-text-state~="weight=semibold"]:where([data-hn-ui-text]) {
6236
6897
  font-weight: var(--ui-font-semibold);
6237
6898
  }
6899
+ :scope[data-ui-text-state~="variant=display"]:where([data-hn-ui-text]),:scope[data-ui-text-state~="variant=heading"]:where([data-hn-ui-text]) {
6900
+ font-family: var(--ui-font-display, var(--ui-font-family-sans));
6901
+ font-weight: var(--ui-font-semibold);
6902
+ line-height: var(--ui-line-height-tight);
6903
+ }
6904
+ :scope[data-ui-text-state~="variant=display"]:where([data-hn-ui-text]) {
6905
+ font-size: var(--ui-font-size-2xl);
6906
+ }
6907
+ :scope[data-ui-text-state~="variant=heading"]:where([data-hn-ui-text]) {
6908
+ font-size: var(--ui-font-size-xl);
6909
+ }
6910
+ :scope[data-ui-text-state~="variant=label"]:where([data-hn-ui-text]) {
6911
+ font-size: var(--ui-font-size-sm);
6912
+ font-weight: var(--ui-font-medium);
6913
+ line-height: var(--ui-line-height);
6914
+ }
6915
+ :scope[data-ui-text-state~="variant=caption"]:where([data-hn-ui-text]) {
6916
+ font-size: var(--ui-font-size-sm);
6917
+ line-height: var(--ui-line-height);
6918
+ }
6238
6919
  :scope[data-ui-text-state~="variant=eyebrow"]:where([data-hn-ui-text]) {
6239
6920
  font-size: var(--ui-font-size-xs);
6240
6921
  font-weight: var(--ui-font-semibold);
6241
6922
  letter-spacing: 0.06em;
6923
+ line-height: var(--ui-line-height);
6242
6924
  text-transform: uppercase;
6243
6925
  }
6244
6926
  :scope[data-ui-text-state~="variant=code"]:where([data-hn-ui-text]) {
@@ -9556,6 +10238,48 @@ dialog:where([data-hn-ui-search-shell]) {
9556
10238
  }
9557
10239
  }
9558
10240
 
10241
+ @scope (.ui-slider) to ([data-hn]) {
10242
+ :scope {
10243
+ display: grid !important;
10244
+ grid-template-columns: minmax(4rem, 1fr) minmax(8rem, 1fr) !important;
10245
+ align-items: center !important;
10246
+ gap: var(--ui-space-2) !important;
10247
+ margin: 0 !important;
10248
+ padding: 0 !important;
10249
+ min-inline-size: 0;
10250
+ }
10251
+ input {
10252
+ inline-size: 100%;
10253
+ min-inline-size: 0;
10254
+ min-block-size: var(--ui-control-size-md);
10255
+ margin: 0 !important;
10256
+ accent-color: var(--ui-accent-solid);
10257
+ cursor: pointer;
10258
+ }
10259
+ :scope[data-ui-slider-state~="size=sm"] input {
10260
+ min-block-size: var(--ui-control-size-sm);
10261
+ }
10262
+ :scope[data-ui-slider-state~="size=lg"] input {
10263
+ min-block-size: var(--ui-control-size-lg);
10264
+ }
10265
+ input:focus-visible {
10266
+ outline: var(--ui-focus-width) solid var(--ui-control-focus, var(--ui-accent-solid));
10267
+ outline-offset: var(--ui-space-1);
10268
+ border-radius: var(--ui-radius-sm);
10269
+ }
10270
+ input:disabled {
10271
+ cursor: not-allowed;
10272
+ }
10273
+ @media (pointer: coarse) {
10274
+ input {
10275
+ min-block-size: max(var(--ui-control-size-md), var(--ui-control-min-block-size));
10276
+ }
10277
+ }
10278
+ :scope[hidden] {
10279
+ display: none !important;
10280
+ }
10281
+ }
10282
+
9559
10283
  /* The one way a view says it is loading, has nothing yet, or failed, with an optional next step.
9560
10284
  Every view says it the same way, in the same place, at the same size. */
9561
10285
 
@@ -9973,6 +10697,10 @@ input:where([data-hn-ui-switch]),input:where([data-hn-ui-switch])::after {
9973
10697
  syntax: "*";
9974
10698
  inherits: false;
9975
10699
  }
10700
+ @property --ui-tabs-panel-padding {
10701
+ syntax: "*";
10702
+ inherits: false;
10703
+ }
9976
10704
 
9977
10705
  /* Density resolves into the tab row's own values; the public tokens still override them. */
9978
10706
 
@@ -9987,6 +10715,7 @@ input:where([data-hn-ui-switch]),input:where([data-hn-ui-switch])::after {
9987
10715
  --_ui-tabs-tab-min-block-size: var(--ui-tabs-tab-min-block-size);
9988
10716
  --_ui-tabs-tab-padding-block: var(--ui-tabs-tab-padding-block);
9989
10717
  --_ui-tabs-tab-padding-inline: var(--ui-tabs-tab-padding-inline);
10718
+ --_ui-tabs-panel-padding: var(--ui-tabs-panel-padding);
9990
10719
 
9991
10720
  --_tab-min-block-size: var(--ui-control-size);
9992
10721
  --_tab-padding-block: var(--ui-space-2);
@@ -10070,7 +10799,7 @@ input:where([data-hn-ui-switch]),input:where([data-hn-ui-switch])::after {
10070
10799
  min-inline-size: 0;
10071
10800
  }
10072
10801
  .panels > :where(:not([data-hn-ui-tabs])):is(*) {
10073
- padding: var(--ui-space-4) !important;
10802
+ padding: var(--_ui-tabs-panel-padding, var(--ui-space-4)) !important;
10074
10803
  }
10075
10804
  :scope[data-ui-tabs-state~="orientation=vertical"]:where([data-hn-ui-tabs]) {
10076
10805
  grid-template-columns: max-content minmax(0, 1fr);
@@ -12689,7 +13418,7 @@ html[data-ui-input-modality="touch"]
12689
13418
 
12690
13419
  /* A count is an adornment, not another line of label text. Keep the standard control height
12691
13420
  with enough inset for a 24px mark; large content can still grow the button naturally. */
12692
- :scope:where([data-component~="ui-button"]):not([variant="link"]):has(.badge:not(:empty)) {
13421
+ :scope:where([data-component~="ui-button"]):not([data-appearance="link"]):has(.badge:not(:empty)) {
12693
13422
  padding-block: var(--ui-space-0-5) !important;
12694
13423
  }
12695
13424
 
@@ -12734,7 +13463,7 @@ html[data-ui-input-modality="touch"]
12734
13463
 
12735
13464
  /* Card actions inherit Button's palette and behavior; only their shared layout changes.
12736
13465
  The icon may contain any decorative composition. Empty icons remove their column. */
12737
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=card"] {
13466
+ :scope:where([data-component~="ui-button"])[data-appearance="card"] {
12738
13467
  display: grid !important;
12739
13468
  grid-template-columns: auto minmax(0, 1fr) auto;
12740
13469
  align-content: center !important;
@@ -12747,10 +13476,10 @@ html[data-ui-input-modality="touch"]
12747
13476
  box-shadow: none;
12748
13477
  background-image: none;
12749
13478
  }
12750
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=card"][data-ui-button-state~="size=lg"] {
13479
+ :scope:where([data-component~="ui-button"])[data-appearance="card"][size="lg"] {
12751
13480
  min-block-size: max(var(--ui-control-min-block-size), var(--ui-control-size-lg));
12752
13481
  }
12753
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=card"]:has(.card-icon:empty) {
13482
+ :scope:where([data-component~="ui-button"])[data-appearance="card"]:has(.card-icon:empty) {
12754
13483
  grid-template-columns: minmax(0, 1fr) auto;
12755
13484
  }
12756
13485
  .card-icon {
@@ -12777,11 +13506,11 @@ html[data-ui-input-modality="touch"]
12777
13506
  }
12778
13507
 
12779
13508
  /* A neutral card encloses content quietly; ordinary outlines keep their action-tone edge. */
12780
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=card"][data-ui-button-state~="tone=neutral"] {
13509
+ :scope:where([data-component~="ui-button"])[data-appearance="card"][data-tone="neutral"] {
12781
13510
  border-color: var(--ui-button-border, var(--ui-border));
12782
13511
  }
12783
13512
 
12784
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=card"][data-ui-button-state~="tone=neutral"]:hover:not(:disabled, [aria-disabled="true"]) {
13513
+ :scope:where([data-component~="ui-button"])[data-appearance="card"][data-tone="neutral"]:hover:not(:disabled, [aria-disabled="true"]) {
12785
13514
  border-color: var(--ui-button-hover-border, var(--ui-border-strong));
12786
13515
  }
12787
13516
 
@@ -12793,19 +13522,19 @@ html[data-ui-input-modality="touch"]
12793
13522
  box-shadow: var(--ui-pressed);
12794
13523
  }
12795
13524
 
12796
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=solid"], :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=danger"] {
13525
+ :scope:where([data-component~="ui-button"])[data-appearance="solid"], :scope:where([data-component~="ui-button"])[data-appearance="danger"] {
12797
13526
  border-color: var(--_tone);
12798
13527
  background-color: var(--_tone);
12799
13528
  color: var(--_on-tone);
12800
13529
  box-shadow: var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow)));
12801
13530
  }
12802
13531
 
12803
- :is(:scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=solid"], :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=danger"]):hover:not(:disabled, [aria-disabled="true"]) {
13532
+ :is(:scope:where([data-component~="ui-button"])[data-appearance="solid"], :scope:where([data-component~="ui-button"])[data-appearance="danger"]):hover:not(:disabled, [aria-disabled="true"]) {
12804
13533
  background-color: var(--_tone-hover);
12805
13534
  border-color: var(--_tone-hover);
12806
13535
  }
12807
13536
 
12808
- :is(:scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=solid"], :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=danger"]):active:not(:disabled, [aria-disabled="true"]) {
13537
+ :is(:scope:where([data-component~="ui-button"])[data-appearance="solid"], :scope:where([data-component~="ui-button"])[data-appearance="danger"]):active:not(:disabled, [aria-disabled="true"]) {
12809
13538
  background-color: var(--_tone-active);
12810
13539
  border-color: var(--_tone-active);
12811
13540
  background-image: none;
@@ -12814,7 +13543,7 @@ html[data-ui-input-modality="touch"]
12814
13543
 
12815
13544
  /* Tone is the colour, variant is the volume. Every pairing works: a danger outline is a
12816
13545
  destructive secondary action, not a special case. */
12817
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="tone=neutral"] {
13546
+ :scope:where([data-component~="ui-button"])[data-tone="neutral"] {
12818
13547
  --_hue: var(--ui-text);
12819
13548
  --_hue-hover: var(--ui-text);
12820
13549
  --_hue-active: var(--ui-text);
@@ -12822,40 +13551,40 @@ html[data-ui-input-modality="touch"]
12822
13551
  --_on-hue: var(--ui-surface);
12823
13552
  }
12824
13553
 
12825
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="tone=danger"], :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=danger"] {
13554
+ :scope:where([data-component~="ui-button"])[data-tone="danger"], :scope:where([data-component~="ui-button"])[data-appearance="danger"] {
12826
13555
  --_hue: var(--ui-danger);
12827
13556
  --_hue-hover: var(--ui-danger-hover);
12828
- --_hue-active: var(--ui-danger-hover);
12829
- --_hue-text: var(--ui-danger-hover);
13557
+ --_hue-active: var(--ui-danger-active, var(--ui-danger-hover));
13558
+ --_hue-text: var(--ui-danger-subtle-text);
12830
13559
  --_on-hue: var(--ui-on-danger);
12831
13560
  }
12832
13561
 
12833
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="tone=success"] {
13562
+ :scope:where([data-component~="ui-button"])[data-tone="success"] {
12834
13563
  --_hue: var(--ui-success);
12835
- --_hue-hover: color-mix(in srgb, var(--ui-success) 85%, #000);
12836
- --_hue-active: color-mix(in srgb, var(--ui-success) 75%, #000);
12837
- --_hue-text: color-mix(in srgb, var(--ui-success) 85%, #000);
12838
- --_on-hue: var(--ui-surface);
13564
+ --_hue-hover: var(--ui-success-hover);
13565
+ --_hue-active: var(--ui-success-active);
13566
+ --_hue-text: var(--ui-success-subtle-text);
13567
+ --_on-hue: var(--ui-success-on-strong);
12839
13568
  }
12840
13569
 
12841
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="tone=warning"] {
13570
+ :scope:where([data-component~="ui-button"])[data-tone="warning"] {
12842
13571
  --_hue: var(--ui-warning);
12843
- --_hue-hover: color-mix(in srgb, var(--ui-warning) 85%, #000);
12844
- --_hue-active: color-mix(in srgb, var(--ui-warning) 75%, #000);
12845
- --_hue-text: color-mix(in srgb, var(--ui-warning) 85%, #000);
12846
- --_on-hue: var(--ui-surface);
13572
+ --_hue-hover: var(--ui-warning-hover);
13573
+ --_hue-active: var(--ui-warning-active);
13574
+ --_hue-text: var(--ui-warning-subtle-text);
13575
+ --_on-hue: var(--ui-warning-on-strong);
12847
13576
  }
12848
13577
 
12849
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="tone=info"] {
13578
+ :scope:where([data-component~="ui-button"])[data-tone="info"] {
12850
13579
  --_hue: var(--ui-info);
12851
- --_hue-hover: color-mix(in srgb, var(--ui-info) 85%, #000);
12852
- --_hue-active: color-mix(in srgb, var(--ui-info) 75%, #000);
12853
- --_hue-text: color-mix(in srgb, var(--ui-info) 85%, #000);
12854
- --_on-hue: var(--ui-surface);
13580
+ --_hue-hover: var(--ui-info-hover);
13581
+ --_hue-active: var(--ui-info-active);
13582
+ --_hue-text: var(--ui-info-subtle-text);
13583
+ --_on-hue: var(--ui-info-on-strong);
12855
13584
  }
12856
13585
 
12857
13586
  /* A value picker is a field, with Select's quiet edge and resting lift. */
12858
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=field"] {
13587
+ :scope:where([data-component~="ui-button"])[data-appearance="field"] {
12859
13588
  --_ui-field-shadow: var(--ui-shadow-sm);
12860
13589
  border-color: var(--ui-button-border, var(--ui-control-border, var(--ui-border-strong)));
12861
13590
  border-radius: var(--ui-button-radius, var(--ui-field-radius, var(--ui-radius-md)));
@@ -12865,23 +13594,23 @@ html[data-ui-input-modality="touch"]
12865
13594
  box-shadow: var(--ui-button-shadow, var(--_ui-field-shadow));
12866
13595
  }
12867
13596
 
12868
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=field"]:hover:not(:disabled, [aria-disabled="true"]) {
13597
+ :scope:where([data-component~="ui-button"])[data-appearance="field"]:hover:not(:disabled, [aria-disabled="true"]) {
12869
13598
  border-color: var(--ui-button-hover-border, var(--ui-control-border-hover, var(--ui-text-secondary)));
12870
13599
  background-color: var(--ui-button-hover-surface, var(--ui-control-surface, var(--ui-surface-elevated)));
12871
13600
  }
12872
13601
 
12873
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=field"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]) {
13602
+ :scope:where([data-component~="ui-button"])[data-appearance="field"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]) {
12874
13603
  --_ui-field-shadow: var(--ui-pressed);
12875
13604
  }
12876
13605
 
12877
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=field"]:focus-visible {
13606
+ :scope:where([data-component~="ui-button"])[data-appearance="field"]:focus-visible {
12878
13607
  border-color: var(--ui-control-focus, var(--ui-accent-solid));
12879
13608
  box-shadow:
12880
13609
  var(--ui-button-shadow, var(--_ui-field-shadow)),
12881
13610
  var(--ui-control-focus-halo-shadow);
12882
13611
  }
12883
13612
 
12884
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=ghost"] {
13613
+ :scope:where([data-component~="ui-button"])[data-appearance="ghost"] {
12885
13614
  border-color: transparent;
12886
13615
  background: transparent;
12887
13616
  box-shadow: none;
@@ -12889,14 +13618,14 @@ html[data-ui-input-modality="touch"]
12889
13618
  }
12890
13619
 
12891
13620
  /* Tints derive from the text colour, not a surface token, so hover and press show on any background. */
12892
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=ghost"]:hover:not(:disabled, [aria-disabled="true"]) {
13621
+ :scope:where([data-component~="ui-button"])[data-appearance="ghost"]:hover:not(:disabled, [aria-disabled="true"]) {
12893
13622
  background-color: var(--ui-button-ghost-hover-surface, oklch(from var(--_tone) l c h / 10%));
12894
13623
  border-color: transparent;
12895
13624
  }
12896
13625
 
12897
13626
  /* Pressed, or holding its menu open, a ghost button sinks slightly: a light surface with a faint
12898
13627
  edge and a soft inner shadow. Lighter than hover, so an open menu's trigger never reads as heavy. */
12899
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=ghost"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]) {
13628
+ :scope:where([data-component~="ui-button"])[data-appearance="ghost"]:is(:active, [aria-expanded="true"]):not(:disabled, [aria-disabled="true"]) {
12900
13629
  background-color: var(--ui-button-ghost-active-surface, color-mix(in oklch, var(--ui-surface), var(--_tone) 3%));
12901
13630
  border-color: transparent;
12902
13631
  box-shadow: inset 0 0 0 1px oklch(from var(--_tone) l c h / 10%), inset 0 1px 2px oklch(from var(--_tone) l c h / 8%);
@@ -12910,13 +13639,13 @@ html[data-ui-input-modality="touch"]
12910
13639
  var(--ui-focus-halo);
12911
13640
  }
12912
13641
 
12913
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=solid"]:focus-visible {
13642
+ :scope:where([data-component~="ui-button"])[data-appearance="solid"]:focus-visible {
12914
13643
  box-shadow:
12915
13644
  var(--ui-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
12916
13645
  var(--ui-focus-halo);
12917
13646
  }
12918
13647
 
12919
- :is(:scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=ghost"], :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"], :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=card"]):focus-visible {
13648
+ :is(:scope:where([data-component~="ui-button"])[data-appearance="ghost"], :scope:where([data-component~="ui-button"])[data-appearance="link"], :scope:where([data-component~="ui-button"])[data-appearance="card"]):focus-visible {
12920
13649
  box-shadow: var(--ui-focus-halo);
12921
13650
  }
12922
13651
 
@@ -12938,7 +13667,7 @@ html[data-ui-input-modality="touch"]
12938
13667
  }
12939
13668
 
12940
13669
  /* Ghost keeps no border, but gains the same neutral surface as other disabled buttons. */
12941
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=ghost"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
13670
+ :scope:where([data-component~="ui-button"])[data-appearance="ghost"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
12942
13671
  background-color: var(--ui-disabled-surface);
12943
13672
  border-color: transparent;
12944
13673
  }
@@ -12955,12 +13684,12 @@ html[data-ui-input-modality="touch"]
12955
13684
  a link-style one keeps its text size, so a standalone one ("See all" under a list) needs the
12956
13685
  area. xs sits inside a line of text the same way, so it keeps its size and gains the area too.
12957
13686
  Only these need it: a hit area on every button would reach over its neighbours. */
12958
- html[data-ui-input-modality="touch"] :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"],
13687
+ html[data-ui-input-modality="touch"] :scope:where([data-component~="ui-button"])[data-appearance="link"],
12959
13688
  html[data-ui-input-modality="touch"] :scope:where([data-component~="ui-button"])[data-ui-button-state~="size=xs"] {
12960
13689
  position: relative;
12961
13690
  }
12962
13691
 
12963
- html[data-ui-input-modality="touch"] :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"]::after,
13692
+ html[data-ui-input-modality="touch"] :scope:where([data-component~="ui-button"])[data-appearance="link"]::after,
12964
13693
  html[data-ui-input-modality="touch"] :scope:where([data-component~="ui-button"])[data-ui-button-state~="size=xs"]::after {
12965
13694
  position: absolute;
12966
13695
  inset: 50% auto auto 50%;
@@ -12972,7 +13701,7 @@ html[data-ui-input-modality="touch"]
12972
13701
 
12973
13702
  /* Link: an inline text action. No box, padding, or minimum height (inline targets are exempt under
12974
13703
  WCAG 2.5.8); the inherited font; an underline that strengthens on hover; a visible focus ring. */
12975
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"] {
13704
+ :scope:where([data-component~="ui-button"])[data-appearance="link"] {
12976
13705
  display: inline !important;
12977
13706
  min-block-size: 0;
12978
13707
  padding: 0 !important;
@@ -12989,24 +13718,24 @@ html[data-ui-input-modality="touch"]
12989
13718
  transition: color var(--ui-motion-fast) var(--ui-motion-ease), text-decoration-color var(--ui-motion-fast) var(--ui-motion-ease);
12990
13719
  }
12991
13720
 
12992
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"]:hover:not(:disabled, [aria-disabled="true"]) {
13721
+ :scope:where([data-component~="ui-button"])[data-appearance="link"]:hover:not(:disabled, [aria-disabled="true"]) {
12993
13722
  color: var(--ui-button-link-hover-text, var(--ui-text-primary));
12994
13723
  text-decoration-color: currentColor;
12995
13724
  background: none;
12996
13725
  transform: none;
12997
13726
  }
12998
13727
 
12999
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"]:active:not(:disabled, [aria-disabled="true"]) {
13728
+ :scope:where([data-component~="ui-button"])[data-appearance="link"]:active:not(:disabled, [aria-disabled="true"]) {
13000
13729
  background: none;
13001
13730
  transform: none;
13002
13731
  }
13003
13732
 
13004
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
13733
+ :scope:where([data-component~="ui-button"])[data-appearance="link"]:is(:disabled, [aria-disabled="true"]:not([aria-busy="true"])) {
13005
13734
  background: none;
13006
13735
  border-color: transparent;
13007
13736
  }
13008
13737
 
13009
- :scope:where([data-component~="ui-button"])[data-ui-button-state~="variant=link"]:focus-visible {
13738
+ :scope:where([data-component~="ui-button"])[data-appearance="link"]:focus-visible {
13010
13739
  box-shadow: none;
13011
13740
  /* Fallback keeps the ring if the token is missing: an unresolved var() would void the outline. */
13012
13741
  outline: var(--ui-focus-width) solid var(--ui-focus-ring);
@@ -13501,7 +14230,7 @@ html[data-ui-input-modality="touch"]
13501
14230
  --_ui-action-start: -1px;
13502
14231
  }
13503
14232
 
13504
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="tone=accent"] {
14233
+ :scope:where([data-component~="ui-icon-button"])[data-tone="accent"] {
13505
14234
  --_icon-button-border: var(--ui-accent-solid);
13506
14235
  --_icon-button-hover-border: var(--ui-accent-hover);
13507
14236
  --_icon-button-text: var(--ui-accent-subtle-text, var(--ui-accent-solid));
@@ -13509,8 +14238,52 @@ html[data-ui-input-modality="touch"]
13509
14238
  color: var(--_icon-button-text);
13510
14239
  }
13511
14240
 
14241
+ :scope:where([data-component~="ui-icon-button"])[data-tone="danger"] {
14242
+ --_icon-button-border: var(--ui-danger);
14243
+ --_icon-button-hover-border: var(--ui-danger-hover);
14244
+ --_icon-button-text: var(--ui-danger-subtle-text);
14245
+ --_icon-button-outline-surface: color-mix(in srgb, var(--ui-danger) 5%, var(--ui-surface-default));
14246
+ --_icon-button-solid-surface: var(--ui-danger);
14247
+ --_icon-button-solid-hover-surface: var(--ui-danger-hover);
14248
+ --_icon-button-solid-text: var(--ui-danger-on-strong);
14249
+ color: var(--_icon-button-text);
14250
+ }
14251
+
14252
+ :scope:where([data-component~="ui-icon-button"])[data-tone="success"] {
14253
+ --_icon-button-border: var(--ui-success);
14254
+ --_icon-button-hover-border: var(--ui-success-hover);
14255
+ --_icon-button-text: var(--ui-success-subtle-text);
14256
+ --_icon-button-outline-surface: color-mix(in srgb, var(--ui-success) 5%, var(--ui-surface-default));
14257
+ --_icon-button-solid-surface: var(--ui-success);
14258
+ --_icon-button-solid-hover-surface: var(--ui-success-hover);
14259
+ --_icon-button-solid-text: var(--ui-success-on-strong);
14260
+ color: var(--_icon-button-text);
14261
+ }
14262
+
14263
+ :scope:where([data-component~="ui-icon-button"])[data-tone="warning"] {
14264
+ --_icon-button-border: var(--ui-warning);
14265
+ --_icon-button-hover-border: var(--ui-warning-hover);
14266
+ --_icon-button-text: var(--ui-warning-subtle-text);
14267
+ --_icon-button-outline-surface: color-mix(in srgb, var(--ui-warning) 5%, var(--ui-surface-default));
14268
+ --_icon-button-solid-surface: var(--ui-warning);
14269
+ --_icon-button-solid-hover-surface: var(--ui-warning-hover);
14270
+ --_icon-button-solid-text: var(--ui-warning-on-strong);
14271
+ color: var(--_icon-button-text);
14272
+ }
14273
+
14274
+ :scope:where([data-component~="ui-icon-button"])[data-tone="info"] {
14275
+ --_icon-button-border: var(--ui-info);
14276
+ --_icon-button-hover-border: var(--ui-info-hover);
14277
+ --_icon-button-text: var(--ui-info-subtle-text);
14278
+ --_icon-button-outline-surface: color-mix(in srgb, var(--ui-info) 5%, var(--ui-surface-default));
14279
+ --_icon-button-solid-surface: var(--ui-info);
14280
+ --_icon-button-solid-hover-surface: var(--ui-info-hover);
14281
+ --_icon-button-solid-text: var(--ui-info-on-strong);
14282
+ color: var(--_icon-button-text);
14283
+ }
14284
+
13512
14285
  /* Omitted tone retains the existing accent solid; explicit neutral is additive. */
13513
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="tone=neutral"] {
14286
+ :scope:where([data-component~="ui-icon-button"])[data-tone="neutral"] {
13514
14287
  --_icon-button-solid-surface: var(--ui-text-primary);
13515
14288
  --_icon-button-solid-hover-surface: var(--ui-text-primary);
13516
14289
  --_icon-button-solid-text: var(--ui-surface-default);
@@ -13555,13 +14328,13 @@ html[data-ui-input-modality="touch"]
13555
14328
  }
13556
14329
 
13557
14330
  @media (hover: hover) and (pointer: fine) {
13558
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="anticipatory"]:not(:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="revealed"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="loading"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible) {
14331
+ :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="anticipatory"]:not(:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="revealed"], :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="loading"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible) {
13559
14332
  border-color: transparent;
13560
14333
  background-color: transparent;
13561
14334
  box-shadow: none;
13562
14335
  }
13563
14336
 
13564
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="anticipatory"]:not(:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="revealed"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="loading"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)
14337
+ :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="anticipatory"]:not(:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="revealed"], :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="loading"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="pending"], :disabled, [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)
13565
14338
  .content {
13566
14339
  opacity: 0;
13567
14340
  transform: scale(0.65);
@@ -13569,7 +14342,7 @@ html[data-ui-input-modality="touch"]
13569
14342
  }
13570
14343
  }
13571
14344
 
13572
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="anticipatory"]:is(:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="revealed"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"], [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)::before {
14345
+ :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="anticipatory"]:is(:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="revealed"], :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"], [aria-pressed="true"], [data-ui-proximity="near"], :hover, :focus-visible)::before {
13573
14346
  opacity: 0;
13574
14347
  }
13575
14348
 
@@ -13678,7 +14451,7 @@ html[data-ui-input-modality="touch"]
13678
14451
  border-radius: var(--ui-radius-round);
13679
14452
  }
13680
14453
 
13681
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"] {
14454
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="outline"] {
13682
14455
  border-color: var(--ui-icon-button-border, var(--_icon-button-border, var(--ui-control-border, var(--ui-border-strong))));
13683
14456
  background-color: var(--ui-icon-button-outline-surface, var(--_icon-button-outline-surface, var(--ui-surface-default)));
13684
14457
  background-image: none;
@@ -13686,7 +14459,7 @@ html[data-ui-input-modality="touch"]
13686
14459
  box-shadow: var(--ui-action-shadow, var(--_ui-action-shadow));
13687
14460
  }
13688
14461
 
13689
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"] {
14462
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"] {
13690
14463
  background-color: var(--ui-icon-button-solid-surface, var(--_icon-button-solid-surface, var(--ui-accent-solid)));
13691
14464
  background-image: none;
13692
14465
  color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
@@ -13699,27 +14472,26 @@ html[data-ui-input-modality="touch"]
13699
14472
  color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
13700
14473
  }
13701
14474
 
13702
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"]:hover:enabled:not([aria-disabled="true"]) {
14475
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="outline"]:hover:enabled:not([aria-disabled="true"]) {
13703
14476
  border-color: var(--ui-icon-button-hover-border, var(--_icon-button-hover-border, var(--ui-control-border-hover, var(--ui-control-border))));
13704
14477
  }
13705
14478
 
13706
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"]:hover:enabled:not([aria-disabled="true"]) {
14479
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"]:hover:enabled:not([aria-disabled="true"]) {
13707
14480
  background-color: var(--ui-icon-button-solid-hover-surface, var(--_icon-button-solid-hover-surface, var(--ui-accent-hover)));
13708
14481
  }
13709
14482
 
13710
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"][data-ui-icon-button-state~="tone=accent"]:hover:enabled:not([aria-disabled="true"]),
13711
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"][data-ui-icon-button-state~="tone=neutral"]:hover:enabled:not([aria-disabled="true"]) {
14483
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"]:hover:enabled:not([aria-disabled="true"]) {
13712
14484
  color: var(--ui-icon-button-solid-text, var(--_icon-button-solid-text, var(--ui-text-on-accent)));
13713
14485
  }
13714
14486
 
13715
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=ghost"][aria-expanded="true"]:enabled:not([aria-disabled="true"]) {
14487
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="ghost"][aria-expanded="true"]:enabled:not([aria-disabled="true"]) {
13716
14488
  background-color: var(--ui-icon-button-active-surface, color-mix(in srgb, currentColor 16%, transparent));
13717
14489
  color: var(--ui-icon-button-hover-text, var(--_icon-button-text, var(--ui-text-primary)));
13718
14490
  box-shadow: var(--ui-pressed);
13719
14491
  }
13720
14492
 
13721
14493
  /* Native toggle state persists after pointer release, including during loading. */
13722
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled {
14494
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="outline"][aria-pressed="true"]:enabled {
13723
14495
  background-color: var(--ui-icon-button-active-surface, color-mix(in srgb, currentColor 12%, var(--ui-surface-default)));
13724
14496
  background-image: none;
13725
14497
  box-shadow: var(--ui-pressed);
@@ -13754,35 +14526,35 @@ html[data-ui-input-modality="touch"]
13754
14526
  box-shadow: var(--ui-focus-halo);
13755
14527
  }
13756
14528
 
13757
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"]:focus-visible {
14529
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="outline"]:focus-visible {
13758
14530
  box-shadow:
13759
14531
  var(--ui-action-shadow, var(--_ui-action-shadow)),
13760
14532
  var(--ui-focus-halo);
13761
14533
  }
13762
14534
 
13763
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"]:focus-visible {
14535
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"]:focus-visible {
13764
14536
  box-shadow:
13765
14537
  var(--ui-icon-button-solid-shadow, var(--ui-action-shadow, var(--_ui-action-shadow))),
13766
14538
  var(--ui-focus-halo);
13767
14539
  }
13768
14540
 
13769
- :scope:where([data-component~="ui-icon-button"]):is(:scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"], :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=solid"]):active:enabled:not([aria-disabled="true"]) {
14541
+ :scope:where([data-component~="ui-icon-button"]):is(:scope:where([data-component~="ui-icon-button"])[data-appearance="outline"], :scope:where([data-component~="ui-icon-button"])[data-appearance="solid"]):active:enabled:not([aria-disabled="true"]) {
13770
14542
  background-image: none;
13771
14543
  box-shadow: var(--ui-pressed);
13772
14544
  }
13773
14545
 
13774
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:focus-visible {
14546
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="outline"][aria-pressed="true"]:enabled:focus-visible {
13775
14547
  box-shadow:
13776
14548
  var(--ui-pressed),
13777
14549
  var(--ui-focus-halo);
13778
14550
  }
13779
14551
 
13780
14552
  @media (forced-colors: active) {
13781
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled {
14553
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="outline"][aria-pressed="true"]:enabled {
13782
14554
  outline: var(--ui-focus-width) solid Highlight;
13783
14555
  outline-offset: calc(-2 * var(--ui-focus-width));
13784
14556
  }
13785
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=outline"][aria-pressed="true"]:enabled:focus-visible {
14557
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="outline"][aria-pressed="true"]:enabled:focus-visible {
13786
14558
  outline-offset: var(--ui-focus-width);
13787
14559
  }
13788
14560
  }
@@ -13799,7 +14571,7 @@ html[data-ui-input-modality="touch"]
13799
14571
  background-image: none;
13800
14572
  }
13801
14573
 
13802
- :scope:where([data-component~="ui-icon-button"])[data-ui-icon-button-state~="variant=ghost"]:disabled {
14574
+ :scope:where([data-component~="ui-icon-button"])[data-appearance="ghost"]:disabled {
13803
14575
  border-color: transparent;
13804
14576
  }
13805
14577
 
@@ -14025,6 +14797,7 @@ html[data-ui-input-modality="touch"]
14025
14797
  }
14026
14798
 
14027
14799
  :scope:where([data-component~="ui-menu"]) {
14800
+ --_ui-material-scale: 0.28;
14028
14801
  --_ui-menu-surface: var(--ui-menu-surface);
14029
14802
  --_ui-menu-border: var(--ui-menu-border);
14030
14803
  --_ui-menu-radius: var(--ui-menu-radius);
@@ -14066,6 +14839,65 @@ html[data-ui-input-modality="touch"]
14066
14839
  overflow: auto;
14067
14840
  }
14068
14841
 
14842
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
14843
+ transparency, saturation and edge light belong to the surrounding decorative material. */
14844
+ :scope:where([data-component~="ui-menu"]):not([inline]) .surface {
14845
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
14846
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
14847
+ --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
14848
+ --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.28) * 8px);
14849
+ --_ui-material-content-color: var(--_ui-menu-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
14850
+ --_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
14851
+ background:
14852
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
14853
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
14854
+ var(--_ui-material-content-color) padding-box;
14855
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
14856
+ border-color: var(
14857
+ --_ui-menu-border,
14858
+ color-mix(in oklab, var(--ui-overlay-border, var(--ui-border-strong)) calc((1 - var(--_ui-material-active)) * 100%), transparent)
14859
+ );
14860
+ box-shadow: var(
14861
+ --_ui-menu-shadow,
14862
+ var(
14863
+ --ui-overlay-shadow,
14864
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.28) * 8px) calc(
14865
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.28) * 24px
14866
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
14867
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
14868
+ var(--ui-elevation-overlay, var(--ui-shadow-lg))
14869
+ )
14870
+ );
14871
+ backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 18px))
14872
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 0.18));
14873
+ -webkit-backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 18px))
14874
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.28) * 0.18));
14875
+ }
14876
+
14877
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
14878
+ :scope:where([data-component~="ui-menu"]):not([inline]) .surface {
14879
+ background: var(--_ui-material-content-color);
14880
+ }
14881
+ }
14882
+
14883
+ @media (prefers-reduced-transparency: reduce) {
14884
+ :scope:where([data-component~="ui-menu"]):not([inline]) .surface {
14885
+ background: var(--_ui-material-content-color);
14886
+ backdrop-filter: none;
14887
+ -webkit-backdrop-filter: none;
14888
+ }
14889
+ }
14890
+
14891
+ @media (forced-colors: active) {
14892
+ :scope:where([data-component~="ui-menu"]):not([inline]) .surface {
14893
+ background: Canvas;
14894
+ border-color: CanvasText;
14895
+ box-shadow: none;
14896
+ backdrop-filter: none;
14897
+ -webkit-backdrop-filter: none;
14898
+ }
14899
+ }
14900
+
14069
14901
  .surface hr {
14070
14902
  align-self: stretch;
14071
14903
  block-size: 0;
@@ -14123,6 +14955,18 @@ html[data-ui-input-modality="touch"]
14123
14955
 
14124
14956
  /* Small follows its trigger down: an item's own hooks still win. */
14125
14957
 
14958
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
14959
+ transparency, saturation and edge light belong to the surrounding decorative material. */
14960
+
14961
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
14962
+ }
14963
+
14964
+ @media (prefers-reduced-transparency: reduce) {
14965
+ }
14966
+
14967
+ @media (forced-colors: active) {
14968
+ }
14969
+
14126
14970
  @starting-style {
14127
14971
  }
14128
14972
 
@@ -14364,6 +15208,7 @@ html[data-ui-input-modality="touch"]
14364
15208
  }
14365
15209
 
14366
15210
  :scope:where([data-component~="ui-popover"]) {
15211
+ --_ui-material-scale: 0.55;
14367
15212
  --_ui-popover-surface: var(--ui-popover-surface);
14368
15213
  --_ui-popover-border: var(--ui-popover-border);
14369
15214
  --_ui-popover-radius: var(--ui-popover-radius);
@@ -14396,6 +15241,65 @@ html[data-ui-input-modality="touch"]
14396
15241
  box-shadow: var(--_ui-popover-shadow, var(--ui-overlay-shadow, var(--ui-elevation-overlay, var(--ui-shadow-lg))));
14397
15242
  }
14398
15243
 
15244
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
15245
+ transparency, saturation and edge light belong to the surrounding decorative material. */
15246
+ .surface {
15247
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
15248
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
15249
+ --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
15250
+ --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.55) * 8px);
15251
+ --_ui-material-content-color: var(--_ui-popover-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
15252
+ --_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
15253
+ background:
15254
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
15255
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
15256
+ var(--_ui-material-content-color) padding-box;
15257
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
15258
+ border-color: var(
15259
+ --_ui-popover-border,
15260
+ color-mix(in oklab, var(--ui-overlay-border, var(--ui-border-strong)) calc((1 - var(--_ui-material-active)) * 100%), transparent)
15261
+ );
15262
+ box-shadow: var(
15263
+ --_ui-popover-shadow,
15264
+ var(
15265
+ --ui-overlay-shadow,
15266
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 8px) calc(
15267
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.55) * 24px
15268
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
15269
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
15270
+ var(--ui-elevation-overlay, var(--ui-shadow-lg))
15271
+ )
15272
+ );
15273
+ backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 18px))
15274
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 0.18));
15275
+ -webkit-backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 18px))
15276
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.55) * 0.18));
15277
+ }
15278
+
15279
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
15280
+ .surface {
15281
+ background: var(--_ui-material-content-color);
15282
+ }
15283
+ }
15284
+
15285
+ @media (prefers-reduced-transparency: reduce) {
15286
+ .surface {
15287
+ background: var(--_ui-material-content-color);
15288
+ backdrop-filter: none;
15289
+ -webkit-backdrop-filter: none;
15290
+ }
15291
+ }
15292
+
15293
+ @media (forced-colors: active) {
15294
+ .surface {
15295
+ background: Canvas;
15296
+ border-color: CanvasText;
15297
+ box-shadow: none;
15298
+ backdrop-filter: none;
15299
+ -webkit-backdrop-filter: none;
15300
+ }
15301
+ }
15302
+
14399
15303
  /* A toolbar or card can supply its own surface, including an unclipped shadow. */
14400
15304
  :scope:where([data-component~="ui-popover"])[data-ui-popover-state~="bare"] .surface {
14401
15305
  overflow: visible;
@@ -14403,6 +15307,8 @@ html[data-ui-input-modality="touch"]
14403
15307
  border: 0;
14404
15308
  background: transparent;
14405
15309
  box-shadow: none;
15310
+ backdrop-filter: none;
15311
+ -webkit-backdrop-filter: none;
14406
15312
  }
14407
15313
 
14408
15314
  :scope:where([data-component~="ui-popover"]):not([data-ui-popover-state~="internalOpen"]) {
@@ -14460,6 +15366,18 @@ html[data-ui-input-modality="touch"]
14460
15366
  @scope ([data-component~="ui-popover"]) to ([data-component]) {
14461
15367
  /* This component's hooks style the element they are set on, and never a nested one. */
14462
15368
 
15369
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
15370
+ transparency, saturation and edge light belong to the surrounding decorative material. */
15371
+
15372
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
15373
+ }
15374
+
15375
+ @media (prefers-reduced-transparency: reduce) {
15376
+ }
15377
+
15378
+ @media (forced-colors: active) {
15379
+ }
15380
+
14463
15381
  /* A toolbar or card can supply its own surface, including an unclipped shadow. */
14464
15382
 
14465
15383
  @starting-style {
@@ -14580,7 +15498,7 @@ html[data-ui-input-modality="touch"]
14580
15498
 
14581
15499
  /* A heading drops the browser's heading size and weight, so size and weight set it as they set
14582
15500
  any text, and inherit keeps the text around it. */
14583
- :scope:where([data-component~="ui-text"]):is(h2, h3, h4, h5, h6) {
15501
+ :scope:where([data-component~="ui-text"]):is(h1, h2, h3, h4, h5, h6) {
14584
15502
  font-family: var(--ui-font-display, inherit);
14585
15503
  font-size: inherit;
14586
15504
  font-weight: inherit;
@@ -14643,10 +15561,32 @@ html[data-ui-input-modality="touch"]
14643
15561
  font-weight: var(--ui-font-semibold);
14644
15562
  }
14645
15563
 
15564
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=display"], :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=heading"] {
15565
+ font-family: var(--ui-font-display, var(--ui-font-family-sans));
15566
+ font-weight: var(--ui-font-semibold);
15567
+ line-height: var(--ui-line-height-tight);
15568
+ }
15569
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=display"] {
15570
+ font-size: var(--ui-font-size-2xl);
15571
+ }
15572
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=heading"] {
15573
+ font-size: var(--ui-font-size-xl);
15574
+ }
15575
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=label"] {
15576
+ font-size: var(--ui-font-size-sm);
15577
+ font-weight: var(--ui-font-medium);
15578
+ line-height: var(--ui-line-height);
15579
+ }
15580
+ :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=caption"] {
15581
+ font-size: var(--ui-font-size-sm);
15582
+ line-height: var(--ui-line-height);
15583
+ }
15584
+
14646
15585
  :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=eyebrow"] {
14647
15586
  font-size: var(--ui-font-size-xs);
14648
15587
  font-weight: var(--ui-font-semibold);
14649
15588
  letter-spacing: 0.06em;
15589
+ line-height: var(--ui-line-height);
14650
15590
  text-transform: uppercase;
14651
15591
  }
14652
15592
  :scope:where([data-component~="ui-text"])[data-ui-text-state~="variant=code"] {
@@ -14762,6 +15702,7 @@ html[data-ui-input-modality="touch"]
14762
15702
  }
14763
15703
 
14764
15704
  :scope:where([data-component~="ui-tooltip"]) {
15705
+ --_ui-material-scale: 0.08;
14765
15706
  /* Hooks do not inherit, so the parts below read them from the root. */
14766
15707
  --_ui-tooltip-border: var(--ui-tooltip-border);
14767
15708
  --_ui-tooltip-max-inline-size: var(--ui-tooltip-max-inline-size);
@@ -14814,6 +15755,65 @@ html[data-ui-input-modality="touch"]
14814
15755
  box-shadow: var(--_ui-tooltip-shadow, var(--ui-overlay-shadow, var(--ui-elevation-tooltip, var(--ui-shadow-md))));
14815
15756
  }
14816
15757
 
15758
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
15759
+ transparency, saturation and edge light belong to the surrounding decorative material. */
15760
+ .surface {
15761
+ --_ui-material-glassiness: clamp(0, var(--ui-glassiness, 0), 1);
15762
+ --_ui-material-separation: clamp(0, var(--ui-surface-separation, 0), 1);
15763
+ --_ui-material-active: clamp(0, calc((var(--_ui-material-glassiness) + var(--_ui-material-separation)) * 100000), 1);
15764
+ --_ui-material-rim: calc((var(--_ui-material-separation) + var(--_ui-material-glassiness) * 0.25) * var(--_ui-material-scale, 0.08) * 8px);
15765
+ --_ui-material-content-color: var(--_ui-tooltip-surface, var(--ui-material-content, var(--ui-overlay-surface, var(--ui-surface-elevated))));
15766
+ --_ui-material-rim-color: color-mix(in srgb, var(--ui-material-glass, var(--ui-surface-elevated)) calc(var(--_ui-material-active) * 100%), transparent);
15767
+ background:
15768
+ linear-gradient(var(--_ui-material-content-color), var(--_ui-material-content-color)) padding-box,
15769
+ linear-gradient(var(--_ui-material-rim-color), var(--_ui-material-rim-color)) border-box,
15770
+ var(--_ui-material-content-color) padding-box;
15771
+ border-width: calc(var(--ui-border-width) + var(--_ui-material-rim));
15772
+ border-color: var(
15773
+ --_ui-tooltip-border,
15774
+ color-mix(in oklab, var(--ui-overlay-border, var(--ui-border-strong)) calc((1 - var(--_ui-material-active)) * 100%), transparent)
15775
+ );
15776
+ box-shadow: var(
15777
+ --_ui-tooltip-shadow,
15778
+ var(
15779
+ --ui-overlay-shadow,
15780
+ 0 calc(var(--_ui-material-separation) * var(--_ui-material-scale, 0.08) * 8px) calc(
15781
+ var(--_ui-material-separation) * var(--_ui-material-scale, 0.08) * 24px
15782
+ ) color-mix(in oklab, var(--ui-text-primary) 15%, transparent),
15783
+ inset 0 0 0 calc(var(--_ui-material-active) * var(--ui-border-width)) var(--ui-material-edge, var(--ui-border-strong)),
15784
+ var(--ui-elevation-tooltip, var(--ui-shadow-md))
15785
+ )
15786
+ );
15787
+ backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 18px))
15788
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 0.18));
15789
+ -webkit-backdrop-filter: blur(calc(var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 18px))
15790
+ saturate(calc(1 + var(--_ui-material-glassiness) * var(--_ui-material-scale, 0.08) * 0.18));
15791
+ }
15792
+
15793
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
15794
+ .surface {
15795
+ background: var(--_ui-material-content-color);
15796
+ }
15797
+ }
15798
+
15799
+ @media (prefers-reduced-transparency: reduce) {
15800
+ .surface {
15801
+ background: var(--_ui-material-content-color);
15802
+ backdrop-filter: none;
15803
+ -webkit-backdrop-filter: none;
15804
+ }
15805
+ }
15806
+
15807
+ @media (forced-colors: active) {
15808
+ .surface {
15809
+ background: Canvas;
15810
+ border-color: CanvasText;
15811
+ box-shadow: none;
15812
+ backdrop-filter: none;
15813
+ -webkit-backdrop-filter: none;
15814
+ }
15815
+ }
15816
+
14817
15817
  /* A keyboard shortcut follows the label after a thin divider, smaller and quieter, as menus show
14818
15818
  it. The label stays first in the description, so a screen reader hears the name, then the keys. */
14819
15819
  .shortcut {
@@ -14938,6 +15938,18 @@ html[data-ui-input-modality="touch"]
14938
15938
 
14939
15939
  /* The label and the shortcut sit side by side, a gap apart, with the label wrapping on its own. */
14940
15940
 
15941
+ /* Purpose and measured size shape one shared separation lever. The content plane stays opaque;
15942
+ transparency, saturation and edge light belong to the surrounding decorative material. */
15943
+
15944
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
15945
+ }
15946
+
15947
+ @media (prefers-reduced-transparency: reduce) {
15948
+ }
15949
+
15950
+ @media (forced-colors: active) {
15951
+ }
15952
+
14941
15953
  /* A keyboard shortcut follows the label after a thin divider, smaller and quieter, as menus show
14942
15954
  it. The label stays first in the description, so a screen reader hears the name, then the keys. */
14943
15955