@mkbabb/glass-ui 3.10.0 → 3.10.1

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 (269) hide show
  1. package/dist/{CardAction-DuArVky-.js → CardAction-DrAcAV4d.js} +2 -2
  2. package/dist/{CommandShortcut-CefCj5mt.js → CommandShortcut-mV2e1aG6.js} +2 -2
  3. package/dist/{DataTable-CUHMukiQ.js → DataTable-C3E6jZ5B.js} +2 -2
  4. package/dist/{DialogContent-BRkT1cjP.js → DialogContent-BxaaafFi.js} +1 -1
  5. package/dist/{HoverPopover-2LOIW34a.js → HoverPopover-CDA_SaCe.js} +1 -1
  6. package/dist/{MetricBadge-BZVWIxNy.js → MetricBadge-idgrkqoP.js} +5 -7
  7. package/dist/{Notification-DLMhblXR.js → Notification-Cu0nN17_.js} +1 -1
  8. package/dist/{NumberFieldContent-BbLOh8RU.js → NumberFieldContent-CHEWghnY.js} +2 -2
  9. package/dist/{PopoverContent-BId6ggf_.js → PopoverContent-DpUvdYY-.js} +1 -1
  10. package/dist/{Progress-iEuD9pxG.js → Progress-BW-StFw2.js} +1 -1
  11. package/dist/{ScrollingText-BPP84wKo.js → ScrollingText-DruYCni_.js} +1 -1
  12. package/dist/{SelectScrollDownButton-T32cVFeM.js → SelectScrollDownButton-pirzjm--.js} +3 -3
  13. package/dist/{Switch-Ch-k3Rv-.js → Switch-DeAqg6pi.js} +1 -1
  14. package/dist/{TabsList-B8CVOQPC.js → TabsList-BAVzOZpg.js} +2 -2
  15. package/dist/{Toaster-1rYWrmAm.js → Toaster-CvuuW_y9.js} +49 -46
  16. package/dist/{ToggleGroupItem-Cev4pOVK.js → ToggleGroupItem-DtD37b4G.js} +4 -4
  17. package/dist/animated-digit.js +2 -2
  18. package/dist/api/index.d.ts +3 -4
  19. package/dist/api.js +1 -1
  20. package/dist/aurora.js +66 -66
  21. package/dist/{badge-CaoFJzRb.js → badge-NdCQMvvB.js} +1 -1
  22. package/dist/badge.js +1 -1
  23. package/dist/{button-DN39cGqL.js → button-DyiWFAOE.js} +12 -12
  24. package/dist/button.js +1 -1
  25. package/dist/canvas.js +2 -2
  26. package/dist/card.js +1 -1
  27. package/dist/carousel.js +5 -5
  28. package/dist/collapsible.js +1 -1
  29. package/dist/{color-C5ls_QF7.js → color-B65wWyQz.js} +9 -7
  30. package/dist/color.js +1 -1
  31. package/dist/command.js +1 -1
  32. package/dist/components/custom/aurora/constants/shaders/mediums.glsl.d.ts +1 -1
  33. package/dist/components/custom/aurora/constants/shaders/vangogh-medium.glsl.d.ts +1 -0
  34. package/dist/components/custom/constellation/Constellation.vue.d.ts +12 -0
  35. package/dist/components/custom/constellation/composables/createConstellationField.d.ts +35 -0
  36. package/dist/components/custom/constellation/composables/useConstellationPointer.d.ts +35 -0
  37. package/dist/components/custom/constellation/constants.d.ts +36 -0
  38. package/dist/components/custom/constellation/constellationDraw.d.ts +18 -0
  39. package/dist/components/custom/constellation/constellationField.d.ts +10 -151
  40. package/dist/components/custom/constellation/constellationInteraction.d.ts +102 -0
  41. package/dist/components/custom/constellation/index.d.ts +3 -1
  42. package/dist/components/custom/controls/DarkModeToggle.vue.d.ts +11 -0
  43. package/dist/components/custom/dock/DockTabButton.vue.d.ts +3 -4
  44. package/dist/components/custom/dock/GlassDock.vue.d.ts +2 -110
  45. package/dist/components/custom/dock/composables/dockMorphContext.d.ts +36 -0
  46. package/dist/components/custom/dock/composables/useDockMorphWindow.d.ts +15 -0
  47. package/dist/components/custom/dock/composables/useDockShellProps.d.ts +131 -0
  48. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +44 -0
  49. package/dist/components/custom/dock/constants.d.ts +23 -0
  50. package/dist/components/custom/expandable-container/ExpandableContainer.vue.d.ts +0 -29
  51. package/dist/components/custom/fourier-field/index.d.ts +1 -1
  52. package/dist/components/custom/fourier-field/math.d.ts +17 -0
  53. package/dist/components/custom/fourier-field/presets.d.ts +54 -0
  54. package/dist/components/custom/goo-blob/composables/buildMetaballProgram.d.ts +18 -0
  55. package/dist/components/custom/goo-blob/composables/uploadBlobUniforms.d.ts +41 -0
  56. package/dist/components/custom/goo-blob/composables/useBlobPointer.d.ts +4 -3
  57. package/dist/components/custom/goo-blob/composables/useMetaballRenderer.d.ts +11 -8
  58. package/dist/components/custom/goo-blob/constants.d.ts +52 -0
  59. package/dist/components/custom/goo-blob/shaders/metaball-uniforms.glsl.d.ts +1 -0
  60. package/dist/components/custom/instrument-chassis/InstrumentChassis.vue.d.ts +2 -2
  61. package/dist/components/custom/metric-badge/MetricBadge.vue.d.ts +0 -8
  62. package/dist/components/custom/tabs/constants.d.ts +12 -0
  63. package/dist/components/custom/underline/GlassUnderline.vue.d.ts +84 -0
  64. package/dist/components/custom/underline/index.d.ts +2 -0
  65. package/dist/components/custom/underline/types.d.ts +56 -0
  66. package/dist/components/ui/drawer/Drawer.vue.d.ts +1 -0
  67. package/dist/components/ui/dropdown-menu/DropdownMenuSubContent.vue.d.ts +2 -2
  68. package/dist/components/ui/slider/index.d.ts +22 -19
  69. package/dist/components/ui/toast/use-toast.d.ts +2 -2
  70. package/dist/composables/color/index.d.ts +12 -0
  71. package/dist/composables/glass/useSpecularTracking.d.ts +12 -3
  72. package/dist/composables/motion/core/index.d.ts +0 -1
  73. package/dist/composables/motion/curves.d.ts +48 -0
  74. package/dist/composables/motion/index.d.ts +2 -0
  75. package/dist/composables/motion/springPresets.d.ts +33 -0
  76. package/dist/composables/motion/suite.d.ts +2 -0
  77. package/dist/composables/motion/useSpringMount.d.ts +1 -1
  78. package/dist/configurator.js +1 -1
  79. package/dist/confirm-dialog.js +2 -2
  80. package/dist/constellation.js +260 -225
  81. package/dist/controls.js +48 -14
  82. package/dist/dark.js +1 -1
  83. package/dist/data-table.js +1 -1
  84. package/dist/dialog.js +2 -2
  85. package/dist/dock.js +339 -327
  86. package/dist/dockContext-bho8B1A4.js +17 -0
  87. package/dist/{dropdown-menu-D77jX6Df.js → dropdown-menu-DVnQcA0E.js} +7 -4
  88. package/dist/dropdown-menu.js +1 -1
  89. package/dist/expandable-container.js +38 -61
  90. package/dist/forms.js +2 -2
  91. package/dist/fourier-field.js +137 -102
  92. package/dist/fourier-math.js +2 -2
  93. package/dist/glass-ui.css +1 -1
  94. package/dist/glass-ui.js +287 -209
  95. package/dist/goo-blob.js +243 -212
  96. package/dist/hover-popover.js +1 -1
  97. package/dist/icon-tooltip.js +1 -1
  98. package/dist/index.d.ts +0 -3
  99. package/dist/keyboard.js +1 -1
  100. package/dist/labeled-field.js +5 -5
  101. package/dist/{math-DTpRVC0e.js → math-BUU9hHID.js} +18 -2
  102. package/dist/metric-badge.js +1 -1
  103. package/dist/metric-stack.js +1 -1
  104. package/dist/motion-core.js +69 -70
  105. package/dist/motion-curves.d.ts +1 -0
  106. package/dist/motion-curves.js +130 -0
  107. package/dist/motion.js +38 -37
  108. package/dist/notification.js +1 -1
  109. package/dist/number-field.js +1 -1
  110. package/dist/popover.js +1 -1
  111. package/dist/progress.js +1 -1
  112. package/dist/pulse.js +1 -1
  113. package/dist/reactive.js +1 -1
  114. package/dist/scrolling-text.js +1 -1
  115. package/dist/search.js +6 -6
  116. package/dist/select.js +1 -1
  117. package/dist/{sheet-VZEtNFvO.js → sheet-ChSXcJpU.js} +1 -1
  118. package/dist/sheet.js +1 -1
  119. package/dist/{slider-CyzcxBoh.js → slider-sfl8gFDD.js} +4 -4
  120. package/dist/slider.js +1 -1
  121. package/dist/sortable-list.js +2 -2
  122. package/dist/springPresets-aRSm-4_k.js +40 -0
  123. package/dist/stacked-icons.js +6 -6
  124. package/dist/styles/animations.css +18 -74
  125. package/dist/styles/components.css +1 -1
  126. package/dist/styles/dock/layer-group.css +22 -0
  127. package/dist/styles/dock/layers.css +11 -1
  128. package/dist/styles/dock/morph.css +95 -19
  129. package/dist/styles/dock/shell.css +12 -0
  130. package/dist/styles/dock-controls.css +28 -31
  131. package/dist/styles/drawer.css +2 -0
  132. package/dist/styles/floating-panel.css +2 -0
  133. package/dist/styles/glass/a11y-fallback.css +245 -0
  134. package/dist/styles/glass/ladder.css +304 -0
  135. package/dist/styles/glass/material.css +238 -0
  136. package/dist/styles/glass/progress-rail.css +78 -0
  137. package/dist/styles/glass/squircle.css +66 -0
  138. package/dist/styles/glass/surfaces.css +306 -0
  139. package/dist/styles/glass-refract.css +2 -0
  140. package/dist/styles/glass.css +31 -1188
  141. package/dist/styles/hover-popover.css +2 -0
  142. package/dist/styles/index.css +24 -6
  143. package/dist/styles/instrument-chassis.css +4 -0
  144. package/dist/styles/paper.css +2 -68
  145. package/dist/styles/theme.css +13 -20
  146. package/dist/styles/tokens/color-radius.css +250 -0
  147. package/dist/styles/tokens/dark-arm.css +194 -0
  148. package/dist/styles/tokens/glass.css +413 -0
  149. package/dist/styles/tokens/light-dark.css +158 -0
  150. package/dist/styles/tokens/offsets-sizing.css +406 -0
  151. package/dist/styles/tokens/property-regs.css +169 -0
  152. package/dist/styles/tokens/scale-paper.css +361 -0
  153. package/dist/styles/tokens/scheme-motion.css +334 -0
  154. package/dist/styles/tokens/shadow.css +132 -0
  155. package/dist/styles/tokens.css +22 -2355
  156. package/dist/styles/typography.css +18 -6
  157. package/dist/styles/utilities/a11y-overrides.css +140 -0
  158. package/dist/styles/utilities/animate.css +26 -0
  159. package/dist/styles/utilities/base.css +365 -0
  160. package/dist/styles/utilities/btn.css +399 -0
  161. package/dist/styles/utilities/components.css +317 -0
  162. package/dist/styles/utilities.css +19 -1260
  163. package/dist/styles/view-transition.css +0 -51
  164. package/dist/switch.js +1 -1
  165. package/dist/tabs.js +98 -98
  166. package/dist/timeline.js +2 -2
  167. package/dist/toast.js +1 -1
  168. package/dist/toggle-group.js +1 -1
  169. package/dist/typewriter.js +1 -1
  170. package/dist/underline.d.ts +1 -0
  171. package/dist/underline.js +85 -0
  172. package/dist/{useAnimatedNumber-Bcpy5Etf.js → useAnimatedNumber-DfVgP4te.js} +1 -1
  173. package/dist/{useConfiguratorState-DxAqksK6.js → useConfiguratorState-BdQXh9ie.js} +1 -1
  174. package/dist/useSpecularTracking-DFK_fhpG.js +32 -0
  175. package/dist/useSpringMount-DXUzxBjV.js +108 -0
  176. package/dist/vReveal-CqaCz_mC.js +44 -0
  177. package/dist/watercolor-dot.js +2 -2
  178. package/package.json +34 -52
  179. package/src/styles/animations.css +18 -74
  180. package/src/styles/dock/layer-group.css +22 -0
  181. package/src/styles/dock/layers.css +11 -1
  182. package/src/styles/dock/morph.css +95 -19
  183. package/src/styles/dock/shell.css +12 -0
  184. package/src/styles/dock-controls.css +28 -31
  185. package/src/styles/glass/a11y-fallback.css +245 -0
  186. package/src/styles/glass/ladder.css +304 -0
  187. package/src/styles/glass/material.css +238 -0
  188. package/src/styles/glass/progress-rail.css +78 -0
  189. package/src/styles/glass/squircle.css +66 -0
  190. package/src/styles/glass/surfaces.css +306 -0
  191. package/src/styles/glass.css +31 -1188
  192. package/src/styles/index.css +24 -6
  193. package/src/styles/paper.css +2 -68
  194. package/src/styles/theme.css +13 -20
  195. package/src/styles/tokens/color-radius.css +250 -0
  196. package/src/styles/tokens/dark-arm.css +194 -0
  197. package/src/styles/tokens/glass.css +413 -0
  198. package/src/styles/tokens/light-dark.css +158 -0
  199. package/src/styles/tokens/offsets-sizing.css +406 -0
  200. package/src/styles/tokens/property-regs.css +169 -0
  201. package/src/styles/tokens/scale-paper.css +361 -0
  202. package/src/styles/tokens/scheme-motion.css +334 -0
  203. package/src/styles/tokens/shadow.css +132 -0
  204. package/src/styles/tokens.css +22 -2355
  205. package/src/styles/typography.css +18 -6
  206. package/src/styles/utilities/a11y-overrides.css +140 -0
  207. package/src/styles/utilities/animate.css +26 -0
  208. package/src/styles/utilities/base.css +365 -0
  209. package/src/styles/utilities/btn.css +399 -0
  210. package/src/styles/utilities/components.css +317 -0
  211. package/src/styles/utilities.css +19 -1260
  212. package/src/styles/view-transition.css +0 -51
  213. package/dist/DeckProgress-Dmk4_AKN.js +0 -23
  214. package/dist/InstrumentRail-CUJ05YVG.js +0 -44
  215. package/dist/components/custom/deck-progress/DeckProgress.vue.d.ts +0 -27
  216. package/dist/components/custom/deck-progress/index.d.ts +0 -2
  217. package/dist/components/custom/dialog-native/GlassDialogNative.vue.d.ts +0 -57
  218. package/dist/components/custom/dialog-native/index.d.ts +0 -1
  219. package/dist/components/custom/glass-panel/GlassPanel.vue.d.ts +0 -41
  220. package/dist/components/custom/glass-panel/index.d.ts +0 -2
  221. package/dist/components/custom/handmark/HandMark.vue.d.ts +0 -29
  222. package/dist/components/custom/handmark/brush.d.ts +0 -219
  223. package/dist/components/custom/handmark/freehand.d.ts +0 -69
  224. package/dist/components/custom/handmark/geometry.d.ts +0 -32
  225. package/dist/components/custom/handmark/index.d.ts +0 -21
  226. package/dist/components/custom/handmark/ink.d.ts +0 -11
  227. package/dist/components/custom/handmark/texture.d.ts +0 -39
  228. package/dist/components/custom/handmark/types.d.ts +0 -53
  229. package/dist/components/custom/handmark/useHandMark.d.ts +0 -66
  230. package/dist/components/custom/header-ribbon/HeaderRibbon.vue.d.ts +0 -31
  231. package/dist/components/custom/header-ribbon/index.d.ts +0 -2
  232. package/dist/components/custom/header-ribbon/types.d.ts +0 -7
  233. package/dist/components/custom/instrument-rail/InstrumentRail.vue.d.ts +0 -91
  234. package/dist/components/custom/instrument-rail/index.d.ts +0 -2
  235. package/dist/composables/motion/useRouteTransition.d.ts +0 -42
  236. package/dist/deck-progress.d.ts +0 -1
  237. package/dist/deck-progress.js +0 -2
  238. package/dist/dockContext-BKeIMmNk.js +0 -9
  239. package/dist/glass-panel.d.ts +0 -1
  240. package/dist/glass-panel.js +0 -44
  241. package/dist/handmark.d.ts +0 -1
  242. package/dist/handmark.js +0 -609
  243. package/dist/header-ribbon.d.ts +0 -1
  244. package/dist/header-ribbon.js +0 -63
  245. package/dist/instrument-rail.d.ts +0 -1
  246. package/dist/instrument-rail.js +0 -2
  247. package/dist/useGlassRenderer-D7YGOYiM.js +0 -69
  248. package/dist/useSpecularTracking-BVRZsRHA.js +0 -26
  249. package/dist/useSpringMount-BJSHcLl3.js +0 -113
  250. package/dist/useViewTransition-DaN5Zrox.js +0 -21
  251. package/dist/vReveal-zUIQk-rJ.js +0 -53
  252. /package/dist/{CollapsibleContent-CP9qF1v4.js → CollapsibleContent-Drow5WkV.js} +0 -0
  253. /package/dist/{DialogFooter-Gprw8H_A.js → DialogFooter-DufLHi0y.js} +0 -0
  254. /package/dist/{IconTooltip-Cus0fvK0.js → IconTooltip-BrQ5p181.js} +0 -0
  255. /package/dist/{Input-xuDwALQR.js → Input-B-F818RU.js} +0 -0
  256. /package/dist/{_plugin-vue_export-helper-ok8pgSl5.js → _plugin-vue_export-helper-DWghtRt7.js} +0 -0
  257. /package/dist/{compile-BOXjLUxu.js → compile-Ce_V55zi.js} +0 -0
  258. /package/dist/{constants-yKeKnE84.js → constants-C8NMonuo.js} +0 -0
  259. /package/dist/{presets-Dkdv55Gt.js → presets-1OhFpaIC.js} +0 -0
  260. /package/dist/{prng-D27-B3tK.js → prng-CjVgzjQT.js} +0 -0
  261. /package/dist/{resolveCanvasColor-BBiYfp8g.js → resolveCanvasColor-CRvVzOvP.js} +0 -0
  262. /package/dist/{useCanvas2D-ClrQuZtp.js → useCanvas2D-CSeH8h16.js} +0 -0
  263. /package/dist/{useGlobalDark-d6waty-X.js → useGlobalDark-D7R9OypB.js} +0 -0
  264. /package/dist/{useIntersectionPause-Cck5Uxk8.js → useIntersectionPause-DAdVPVp4.js} +0 -0
  265. /package/dist/{useInterval-Dsmqwi03.js → useInterval-D3USn0yc.js} +0 -0
  266. /package/dist/{useKeyboardShortcuts-CyIYrndH.js → useKeyboardShortcuts-i8tHd5WO.js} +0 -0
  267. /package/dist/{useScrollProgress-CffFGLa5.js → useScrollProgress-CcgmgMQt.js} +0 -0
  268. /package/dist/{useSortable-C8ReQ50P.js → useSortable-DnyGXKKY.js} +0 -0
  269. /package/dist/{useTextHighlight-CWEi25hf.js → useTextHighlight-B3b10W6r.js} +0 -0
@@ -98,6 +98,22 @@
98
98
  display: flex;
99
99
  flex-direction: column;
100
100
  flex-shrink: 0;
101
+ /* AY.W-DOCK-NAV B6 — `align-self: start` (not the group's `stretch`
102
+ default) so the column rail reports its OWN intrinsic content height
103
+ (the stacked tabs) to the group's cross-axis sizing rather than being
104
+ stretched to the group's content-row height. Under `stretch` the rail's
105
+ height resolved to the group height, which was the single content-row
106
+ height — circular: the rail's 3 tall tabs overflowed a 40px rail and the
107
+ lower tabs + the indicator fell below the dock floor (the B6 break). With
108
+ `align-self: start` the rail demands its natural column height, the group
109
+ grows to it, and the dock grows to contain the whole rail. The
110
+ `min-height: max-content` belt makes the demand explicit — a row-flex
111
+ child's cross-size can otherwise resolve to the (smaller) container row
112
+ height even under `align-self: start`; `max-content` floors the rail at
113
+ its stacked-tab content height so the chain (group → pane → dock) grows
114
+ to fit. */
115
+ align-self: start;
116
+ min-height: max-content;
101
117
  gap: var(--dock-layer-rail-gap, 0.125rem);
102
118
  padding: var(--dock-layer-rail-padding, 0.125rem);
103
119
  background: var(--dock-layer-rail-bg, var(--surface-tint-8));
@@ -134,6 +150,12 @@
134
150
  display: inline-flex;
135
151
  align-items: center;
136
152
  justify-content: center;
153
+ /* AY.W-DOCK-NAV B6 — `flex-shrink: 0` so the stacked tabs in the column rail
154
+ hold their full size and the rail demands its natural content height (no
155
+ tab squish). With the rail's `align-self: start` this makes the rail report
156
+ its true column height to the group's cross-axis sizing, growing the dock
157
+ to contain all the tabs + the travelling indicator (the B6 un-clip). */
158
+ flex-shrink: 0;
137
159
  width: var(--dock-layer-tab-size, var(--dock-control-size, 1.75rem));
138
160
  height: var(--dock-layer-tab-size, var(--dock-control-size, 1.75rem));
139
161
  border: 0;
@@ -196,9 +196,19 @@
196
196
  block-axis morph reveals a column) is NOT forced onto one nowrap row — the
197
197
  vertical group's active host block-sizes to `height: max-content` below
198
198
  (the AP.W3 column treatment, KEPT). */
199
+ /* AY.W-DOCK-NAV B6 — the height is a FLOOR (`min-height`), not a fixed lock. A
200
+ single-row content pane's intrinsic height already equals
201
+ `--dock-layer-height` (the controls + line-height sum to it), so `min-height`
202
+ is byte-identical for the common case. But a horizontal dock hosting a COLUMN
203
+ switcher-rail (`<DockLayerGroup>` with `show-rail`) lays the rail out as a
204
+ stack of tabs taller than one row — the prior fixed `height` clipped the
205
+ rail's lower tabs + the active indicator BELOW the dock floor (the B6 "no rail
206
+ line / broken" read, measured: 2 of 3 tabs clipped). The floor lets the pane
207
+ block-size to the rail's natural column height so the dock grows to contain
208
+ the whole rail. The cross axis keeps `nowrap`. */
199
209
  .glass-dock:not(.vertical) .dock-layer {
200
210
  white-space: nowrap;
201
- height: var(--dock-layer-height, 2.5rem);
211
+ min-height: var(--dock-layer-height, 2.5rem);
202
212
  }
203
213
 
204
214
  .dock-layer.is-active {
@@ -61,9 +61,22 @@
61
61
  authority, and at rest `--dock-expand-t` resolves to the class endpoint (0
62
62
  collapsed / 1 expanded) so the resting look is exact. */
63
63
  .glass-dock.variant-dock:not(.vertical) {
64
+ /* AY.W-A11Y-PERF O-1 — the resting-endpoint dock bg composes the W55 oklab
65
+ adaptive tint so the bright bucket (engaged when a consumer/page marks
66
+ `--glass-backdrop: light` on the dock's ancestor — the @container block
67
+ below + the page-redesign W60 wiring) reaches the LIVE `.variant-dock`
68
+ surface (this 0,3,0 morph interp OVERRIDES the 0,1,0 shell.css bg, so the
69
+ tint must be applied HERE too). The srgb transition mix is preserved between
70
+ the two color endpoints; the adaptive darken rides the resting endpoint
71
+ (`--glass-bg-dock` wrapped in the oklab tint) — at the `0%` rest default the
72
+ inner oklab mix is a no-op so this is byte-identical to today. */
64
73
  background: color-mix(
65
74
  in srgb,
66
- var(--glass-bg-dock, var(--glass-bg-resting))
75
+ color-mix(
76
+ in oklab,
77
+ var(--glass-bg-dock, var(--glass-bg-resting)),
78
+ var(--glass-tint-source) var(--glass-tint-strength)
79
+ )
67
80
  calc(var(--dock-expand-t, 1) * 100%),
68
81
  var(--glass-bg-wash)
69
82
  );
@@ -78,18 +91,40 @@
78
91
  /* The padding morph is split out + scoped `:not(.dock-overflow-wrap)` so the
79
92
  wrap variant's own padding rules (W04 territory — `.dock-overflow-wrap` +
80
93
  its `@media` snap-back) are NOT clobbered by this higher-specificity longhand.
81
- Padding interpolates linearly between the collapsed floor and the expanded
82
- block/inline padding on the same `--dock-expand-t` scalar. */
94
+
95
+ AY.W-DOCK-CHROME §1 — the LAYOUT-ISOLATION fix: the collapse↔expand morph is
96
+ an INLINE-WIDTH aperture by contract ("horizontal docks animate width"), so
97
+ the BLOCK axis MUST be invariant across the morph — otherwise the dock's
98
+ outer height shrinks ~4px on collapse (the collapsed-pad 0.25rem vs the
99
+ expanded pad-block 0.375rem, ×2) and, because a free-floating / inline dock
100
+ sits in normal flow (`display:inline-flex`), that height delta REFLOWS its
101
+ siblings — the page content jumped as the dock animated (the user's 13:27
102
+ audit item 1). The fix holds `padding-block` PINNED at the expanded value in
103
+ BOTH states (no `--dock-expand-t` interpolation on the block axis) so the
104
+ outer block-size is constant; ONLY `padding-inline` morphs to tighten the
105
+ collapsed pill inline. The collapsed circle is unaffected — its diameter is
106
+ owned by the summary pane's own symmetric `block-size` + `aspect-ratio:1`
107
+ (the `.collapsed .dock-layer--summary` rule below), CENTRED on the dock's
108
+ stable-height plate by the root `align-items:center`, not by the root pad. So
109
+ the morph reflows NOTHING vertically: 0px container-height delta. */
83
110
  .glass-dock.variant-dock:not(.vertical):not(.dock-overflow-wrap) {
84
- --dock-pad-collapsed: var(
85
- --dock-collapsed-padding,
86
- var(--dock-padding-block, 0.375rem)
87
- );
88
- padding-block: calc(
89
- var(--dock-pad-collapsed) +
90
- (var(--dock-padding-block, 0.375rem) - var(--dock-pad-collapsed)) *
91
- var(--dock-expand-t, 1)
111
+ /* The collapsed inline-pad endpoint is the EXPANDED block pad (max'd with the
112
+ consumer `--dock-collapsed-padding` handle) so the height-pinned collapsed
113
+ pill is SYMMETRIC → a clean circle at the `--radius-dock` 9999px. The block
114
+ axis is pinned to the expanded pad (below), so matching the inline collapsed
115
+ endpoint to it keeps the box square (the B4 "symmetric collapsed padding
116
+ keeps the pill a circle" intent, preserved through the §1 height-pin). The
117
+ `max()` lets a consumer set `--dock-collapsed-padding` LARGER for a looser
118
+ pill but never SMALLER than the block pad (which would re-introduce the
119
+ narrower-than-tall oval the height-pin would otherwise leave). */
120
+ --dock-pad-collapsed: max(
121
+ var(--dock-padding-block, 0.375rem),
122
+ var(--dock-collapsed-padding, 0px)
92
123
  );
124
+ /* block padding is INVARIANT — the expanded value, both states (the
125
+ layout-isolation contract above): the inline aperture morphs, the block
126
+ axis is pinned so the outer height never changes → 0px container reflow. */
127
+ padding-block: var(--dock-padding-block, 0.375rem);
93
128
  padding-inline: calc(
94
129
  var(--dock-pad-collapsed) +
95
130
  (var(--dock-padding-inline, 0.5rem) - var(--dock-pad-collapsed)) *
@@ -110,14 +145,17 @@
110
145
  box-shadow: var(--shadow-dock-override, var(--shadow-dock-collapsed));
111
146
  }
112
147
 
113
- /* AX.W45-TUNE Q1 — the collapsed summary floors on BOTH axes off the SAME
114
- `--dock-collapsed-summary-min-size` token (now MINTED in tokens.css §10 as a
115
- tight ≈0.7× of the full control height). The prior rule floored ONLY
116
- `min-width` and let the token fall to `--dock-layer-height` (the full control
117
- height) — so the collapsed pill read as a full-row stub, not a proportioned
118
- squircle. Adding the symmetric `min-block-size` makes the collapsed pill a
119
- tight square-ish dot the consumer's glyph sits centred in (the proportioned-
120
- pill target the user's Q1 named). */
148
+
149
+ /* AY.W-DOCK-NAV B4 — the collapsed summary is a PERFECT CIRCLE. The `.dock-layer`
150
+ base rule (`.glass-dock:not(.vertical) .dock-layer`) locks `height:
151
+ var(--dock-layer-height)` (40px) on EVERY layer including the summary; against
152
+ the 0.85× `--dock-collapsed-summary-min-size` min-width that made the pane
153
+ 40h × 30w — an oval (the user's "circle, not oval"). This rule (1) LIFTS the
154
+ height-lock so the summary block-sizes to the SAME token its width floors at,
155
+ and (2) floors both axes to that ONE token, so the collapsed pane is a square
156
+ and the root's symmetric collapsed padding keeps the pill a circle. The glyph
157
+ sits centred on both axes. The `aspect-ratio: 1` belt-and-braces guarantees
158
+ 1:1 even if a consumer's collapsed-slot content is wider than the floor. */
121
159
  .glass-dock.collapsed .dock-layer--summary {
122
160
  min-width: var(
123
161
  --dock-collapsed-summary-min-size,
@@ -127,6 +165,15 @@
127
165
  --dock-collapsed-summary-min-size,
128
166
  var(--dock-layer-height, 2.5rem)
129
167
  );
168
+ block-size: var(
169
+ --dock-collapsed-summary-min-size,
170
+ var(--dock-layer-height, 2.5rem)
171
+ );
172
+ height: var(
173
+ --dock-collapsed-summary-min-size,
174
+ var(--dock-layer-height, 2.5rem)
175
+ );
176
+ aspect-ratio: 1;
130
177
  justify-content: center;
131
178
  }
132
179
 
@@ -146,6 +193,35 @@
146
193
  --dock-expand-t: var(--dock-morph-t);
147
194
  }
148
195
 
196
+ /* AY.W-DOCK-NAV B15 — the EMPTY-collapsed-summary trap. A dock with a
197
+ `#persistent` control but NO `#collapsed` slot (the overview first-section
198
+ dock) still renders a `.dock-layer--summary` pane that floors to the circle
199
+ min-width — so collapsed it read as a WIDE pill: the persistent Home glyph on
200
+ the LEFT + an empty circle of dead space on the RIGHT (the measured 84×50
201
+ oval). Expanding then grew the content INTO that right-side void, so the
202
+ morph read "from the right" not center-out (the user's B15). When the summary
203
+ slot is EMPTY (`:not(:has(*))`), collapse it to zero width + no floor so the
204
+ persistent control stands alone as the collapsed circle, and the morph grows
205
+ symmetrically about the persistent. An empty Vue `#collapsed` slot renders
206
+ ZERO child nodes (no whitespace text node either), so `:empty` matches it
207
+ exactly — and a flat `:empty` avoids the nested-`:has()` form Lightning CSS
208
+ drops. An authored `#collapsed` slot (non-empty summary) keeps its circle
209
+ pill. */
210
+ .glass-dock.collapsed .dock-layer--summary:empty {
211
+ min-width: 0;
212
+ inline-size: 0;
213
+ padding: 0;
214
+ margin: 0;
215
+ border: 0;
216
+ }
217
+
218
+ /* The persistent control IS the collapsed pill in the empty-summary case — drop
219
+ the inter-region gap so the collapsed circle is exactly the persistent box. */
220
+ .glass-dock.collapsed:has(.dock-layer--summary:empty) .dock-persistent
221
+ + .dock-layers {
222
+ margin-inline-start: 0;
223
+ }
224
+
149
225
  /* AW.W3 — the collapsed-hover scale rides the unified dock spring vocabulary.
150
226
  The `scale var(--dock-motion-resize)` arm was added to the `.glass-dock`
151
227
  root transition above, so this hover scale settles on the SAME spring curve
@@ -64,6 +64,18 @@
64
64
  stacking-context guarantee). Covers every dock scale site. */
65
65
  scale: 1;
66
66
  position: relative;
67
+ /* AY.W-A11Y-PERF O-1 — engage the W55 bright-backdrop bucket BY DEFAULT on
68
+ the dock (the surface the user reported unreadable over light content). The
69
+ SELF-engage rule in dock/morph.css darkens the dock's OWN plate toward ink
70
+ unconditionally (a dock floats over arbitrary — frequently light — page
71
+ content). `dark` (the :root default) stays the inherited value a consumer
72
+ re-reads; the descendant/nested-glass reach uses the @container block. */
73
+ --glass-backdrop: light;
74
+ /* AY.W-A11Y-PERF O-4 — paint containment so the maximal-glass nested
75
+ backdrop-filter sample does not escape the dock box (the standard nested-
76
+ backdrop-cost mitigation; the Button-in-glass-in-dock stack re-samples the
77
+ already-blurred buffer at each level without it). */
78
+ contain: paint;
67
79
  display: inline-flex;
68
80
  align-items: center;
69
81
  /* AW.W1 — the dock does NOT establish a default inline-size container.
@@ -225,7 +225,22 @@
225
225
  [data-size="control"]
226
226
  ) {
227
227
  --dark-mode-toggle-size: var(--dock-control-size, var(--size-icon-btn));
228
- --dark-mode-toggle-padding: var(--dock-icon-padding, 0);
228
+ /* AY.W-DOCK-CHROME §2 — the in-dock toggle GLYPH insets to the nav-glyph
229
+ register. The toggle SVG carries `h-full w-full` (the utility layer, which
230
+ BEATS the component-layer `> svg { width: --dock-control-glyph-size }` rule
231
+ below), so the glyph fills whatever the PADDED box leaves. Prior the in-dock
232
+ padding fell to `var(--dock-icon-padding, 0)` (the token is never defined →
233
+ 0 pad → the glyph filled the whole 40px box edge-to-edge, ~2.5× the 16-20px
234
+ nav glyphs — the user's "too large" read). Pad the box by HALF the box↔glyph
235
+ difference so the `h-full` SVG lands at exactly `--dock-icon-glyph` (the
236
+ `--dock-scale`-keyed size the nav icons paint) — optically UNIFORM with the
237
+ nav glyphs through the utility-win path, not fighting it. */
238
+ --dark-mode-toggle-padding: calc(
239
+ (
240
+ var(--dock-control-size, var(--size-icon-btn)) -
241
+ var(--dock-icon-glyph, 1.25rem)
242
+ ) / 2
243
+ );
229
244
  }
230
245
 
231
246
  /* AX.W06 USF-2 — the dock-control optical-size contract. The
@@ -327,28 +342,21 @@
327
342
  /* Tier — primary ────────────────────────────────────────────
328
343
  *
329
344
  * Per W2.7 §9, §12, §13, §17. The primary tier composes three at-rest
330
- * marks (top-highlight, bottom under-shadow, baseline glass) with two
331
- * disco accents on hover (specular swap, disco-grain).
332
- *
333
- * D6.b — the disco-STAR is GONE (the sparkle-sweep sweep is excised from the
334
- * underlying `btn-audacious`, utilities.css). The primary dock button's gold
335
- * identity — the "golden dock button" the user likes — is RE-EXPRESSED sans
336
- * star: a tooled `--gold-rim` gilt edge (the brushed-brass-under-glass read)
337
- * plus the surviving specular catch-light + disco-grain on hover. Three quiet
338
- * golds replacing one loud star.
345
+ * marks (top-highlight, bottom under-shadow, baseline glass) with three
346
+ * disco accents on hover (specular swap, sparkle sweep, disco-grain).
339
347
  *
340
348
  * Reservation: disco fires on hover only. At rest the button reads as
341
- * a Vignelli-restrained composed glass surface with a hairline gilt edge.
342
- * The `--phase-color` cascade (provided by `<InstrumentChassis>` via
343
- * `data-phase`) tints the disco-grain radial only on hover; idle is neutral.
349
+ * a Vignelli-restrained composed glass surface. The `--phase-color`
350
+ * cascade (provided by `<InstrumentChassis>` via `data-phase`) tints
351
+ * the disco-grain radial only on hover; idle is neutral.
344
352
  *
345
- * K.W6 Lane B — the canonical disco-grain + specular recipe lifted to
346
- * `@utility btn-audacious` (utilities.css). The Vue <DockTabButton> attaches
347
- * `btn-audacious` automatically when the consumer passes `data-tier="primary"`.
348
- * The dock-local rules below are STRICTLY the dock extension: structural shell
349
- * (padding, base surface tint, min-height) + the gilt-edge gold identity +
350
- * phase-tint extensions (hover radial uses `--phase-color`, plus the
351
- * `[data-phase]` `::before` halo).
353
+ * K.W6 Lane B — the canonical disco-grain + sparkle-sweep + specular
354
+ * recipe lifted to `@utility btn-audacious` (utilities.css). The Vue
355
+ * <DockTabButton> attaches `btn-audacious` automatically when the
356
+ * consumer passes `data-tier="primary"`. The dock-local rules below
357
+ * are STRICTLY the dock extension: structural shell (padding, base
358
+ * surface tint, min-height) + phase-tint extensions (hover radial
359
+ * uses `--phase-color`, plus the `[data-phase]` `::before` halo).
352
360
  */
353
361
  .dock-tab-button[data-tier="primary"] {
354
362
  --dock-tab-min-height: 4rem;
@@ -356,17 +364,6 @@
356
364
  background: color-mix(in srgb, var(--card) 60%, transparent);
357
365
  color: var(--foreground);
358
366
 
359
- /* D6.b — the gilt edge: a 1px inner `--gold-rim` ring + a faint gold
360
- top-catch, the tooled-brass identity that replaces the excised star.
361
- A box-shadow (no layout, no paint cost), composing UNDER the hover
362
- specular/grain. The gold reads as a bevel light at the edge, never a
363
- fill — the surface still reads as composed glass. Idiom mirrors the
364
- `.glass-gilt` modifier (glass.css region) at the dock-button scale. */
365
- box-shadow:
366
- inset 0 0 0 1px var(--gold-rim),
367
- inset 0 0.5px 0 0
368
- color-mix(in oklab, var(--gold-light) 30%, transparent);
369
-
370
367
  /* Phase-tint hover override — same disco-grain composition as
371
368
  * `btn-audacious`, but the radial uses `--phase-color` (instrument-
372
369
  * cluster axis) instead of the canonical `--primary`. The `--paper-
@@ -49,6 +49,8 @@
49
49
  blur(0) with the rest of the band; the --glass-shadow-overlay ladder rung
50
50
  carries the rim + the --shadow-2xl lift through the ladder. */
51
51
  background: color-mix(in oklab, var(--glass-bg-overlay), var(--glass-tint-source) var(--glass-tint-strength));
52
+ -webkit-backdrop-filter: var(--glass-blur-overlay);
53
+
52
54
  backdrop-filter: var(--glass-blur-overlay);
53
55
  -webkit-backdrop-filter: var(--glass-blur-overlay);
54
56
  border: 1px solid var(--glass-border-overlay);
@@ -7,6 +7,8 @@
7
7
  border-radius: var(--radius-panel);
8
8
  border: 1px solid var(--glass-border-resting);
9
9
  background: var(--glass-bg-resting);
10
+ -webkit-backdrop-filter: var(--glass-blur-resting);
11
+
10
12
  backdrop-filter: var(--glass-blur-resting);
11
13
  color: var(--popover-foreground);
12
14
  box-shadow: var(--glass-shadow-resting);
@@ -0,0 +1,245 @@
1
+ /* glass/a11y-fallback.css
2
+ The accessibility + capability overrides — @media (prefers-reduced-transparency) / (prefers-contrast: more) / (forced-colors: active), the non-backdrop-filter @layer components fallback, and the :has()-less @supports fallback. LAST in cascade (they override the base ladder).
3
+ Carved from the glass.css cascade root; @import-ed by glass.css in cascade
4
+ order, each in its own @layer components (isomorphic to the monolith).
5
+ See docs/precepts/design-idioms.md §cohesion-aware partials. */
6
+ /* ── Accessibility: reduced transparency ──────────
7
+ AX.W54 — the gestalt collapse: ONE `--glass-level: 0` replaces the ten per-rung
8
+ opacity+blur clobbers. The level-0 path resolves solid `--card` + `blur(0)`
9
+ through the SAME machinery (the opacity seam → 1, the blur seam → 0), so every
10
+ glass surface — current and future — flattens with no per-rung enumeration. The
11
+ grain + highlight kills stay (they sit off the level axis). */
12
+ @media (prefers-reduced-transparency: reduce) {
13
+ :root {
14
+ --glass-level: 0;
15
+ --glass-grain-opacity: 0;
16
+ --glass-highlight: 0 0 0 0 transparent;
17
+ }
18
+ }
19
+
20
+ /* ── Accessibility: high contrast ─────────────────
21
+ AX.W54 — a single bounded `--glass-level: 0.3` (mostly-solid, not fully flat)
22
+ replaces the five per-rung opacity clobbers: every rung firms up toward solid
23
+ for AA while keeping a hint of the glass register. ONE knob, every rung.
24
+
25
+ AX.W55 — the Clear↔Tinted user-escape (Apple's iOS-26.2 analog) COORDINATES the
26
+ two axes here: the OPACITY axis rides W54's `--glass-level` (firm up toward solid)
27
+ AND the TINT axis biases toward ink — `--glass-tint-source` → the warm-ink +
28
+ `--glass-tint-strength` → the AA floor, the same darken the automatic bright
29
+ bucket applies, now reached by the explicit "more contrast" user request. The two
30
+ axes stay DISTINCT (level = opacity+blur, tint = darken) but share the bracket so
31
+ a high-contrast user gets BOTH a firmer plate and the ink-tint legibility lift —
32
+ one coordinated escape, not two parallel forks. */
33
+ @media (prefers-contrast: more) {
34
+ :root {
35
+ --glass-level: 0.3;
36
+ --glass-tint-source: var(--glass-tint-ink);
37
+ --glass-tint-strength: var(--glass-tint-strength-aa);
38
+ }
39
+ }
40
+
41
+ /* ── Accessibility: forced-colors (Windows High Contrast) glass-language skin ──
42
+ AX.W36 — when the OS forces a palette (Windows High Contrast), the platform
43
+ strips the whole decorative glass register: `backdrop-filter` is dropped, the
44
+ `--glass-*` inset/box-shadow rungs vanish, and every meaning-bearing chroma
45
+ flattens to one system color. A `.glass-floating` Dialog over a `.glass-resting`
46
+ Card would read as two borderless transparent rectangles with no edge, and a
47
+ green-vs-red StatusDot would resolve to one indistinguishable dot. This skin
48
+ restores the STRUCTURE the glass chrome encoded — it does NOT pin glass-ui's
49
+ brand colours (no `forced-color-adjust: none`); the chrome is decorative and
50
+ YIELDS to the user's forced palette (css forced-colors guidance). Only the
51
+ standard WHC system keywords are used (`Canvas`/`CanvasText`/`Highlight`) — no
52
+ glass-ui token leaks into the WHC arm.
53
+
54
+ COORDINATES WITH W54 — the same `--glass-level: 0` opaque escape the reduced-
55
+ transparency / high-contrast brackets ride. Setting the ONE clarity knob to 0
56
+ collapses the `--glass-bg-*` opacity recipe to solid `--card` + `blur(0)` through
57
+ the SAME machinery (no parallel solid recipe), so the platform sees opaque plates
58
+ it maps to `Canvas`. The grain + highlight kills match the reduce bracket (they
59
+ sit off the level axis). The W55 tint axis is moot under WHC (the user's palette
60
+ supersedes the ink-darken) but harmless — the opaque plate is system-painted. */
61
+ @media (forced-colors: active) {
62
+ :root {
63
+ --glass-level: 0;
64
+ --glass-grain-opacity: 0;
65
+ --glass-highlight: 0 0 0 0 transparent;
66
+ }
67
+
68
+ /* Every glass-material ladder rung relied on `backdrop-filter` + an inset
69
+ `box-shadow` rim for its silhouette — both gone under WHC. Restore a real
70
+ `border` keyed to the system text colour so each tier pane reads as a boxed
71
+ region. The selector group MIRRORS the ladder definition above (one source,
72
+ not a hand-rolled re-list) so a future rung added to the material group
73
+ inherits the WHC edge for free — and any `.glass-material` div picks up the
74
+ edge with no per-component arm. */
75
+ .glass-material,
76
+ .glass-wash,
77
+ .glass-quiet,
78
+ .glass-resting,
79
+ .glass-floating,
80
+ .glass-overlay,
81
+ .glass-card,
82
+ .glass-drawer {
83
+ border: 1px solid CanvasText;
84
+ }
85
+
86
+ /* The floating + overlay rungs (Dialog / Sheet / Popover / DropdownMenu /
87
+ HoverCard compose them) + the Drawer (the overlay-band sheet, drawer.css)
88
+ get the canonical `Canvas` fill so the modal reads as a DISTINCT boxed
89
+ region OVER the page, not a transparent overlap — the hierarchy survives.
90
+ The `CanvasText` edge above already draws the box; this opaque fill
91
+ separates the floating layer from the content beneath it. */
92
+ .glass-floating,
93
+ .glass-overlay,
94
+ .glass-drawer {
95
+ background: Canvas;
96
+ }
97
+
98
+ /* The decorative specular catch-light (`::before`) + grain overlay (`::after`)
99
+ paint nothing meaningful once chroma collapses — yield them entirely (the
100
+ same decorative-chrome cede the `--glass-level: 0` opaque escape performs on
101
+ the body). They are NOT part of the structure the skin restores. */
102
+ .glass-material::before,
103
+ .glass-wash::before,
104
+ .glass-quiet::before,
105
+ .glass-resting::before,
106
+ .glass-floating::before,
107
+ .glass-overlay::before,
108
+ .glass-card::before,
109
+ .glass-drawer::before,
110
+ .glass-wash::after,
111
+ .glass-quiet::after,
112
+ .glass-resting::after,
113
+ .glass-floating::after,
114
+ .glass-overlay::after {
115
+ display: none;
116
+ }
117
+
118
+ /* Meaning-bearing hue identity → a bordered glyph that keeps ok/warn/error
119
+ distinguishable by a WHC-HONORED system color, NOT a glass-ui hue (which WHC
120
+ strips to one fill). StatusDot reflects its variant onto `data-status`
121
+ (StatusDot.vue) and the inner dot carries `.status-dot__dot`; the
122
+ `role="img"` + `aria-label` accessible name already ships, so this is the
123
+ VISUAL differentiation only. A bare bordered dot + the per-status fill triplet
124
+ below means a sighted WHC user can still tell the row apart.
125
+
126
+ `!important` IS load-bearing here: StatusDot paints the dot fill via an INLINE
127
+ `:style="dotStyle"` (`background-color`, specificity 1,0,0,0), which outranks
128
+ any stylesheet selector AND which forced-colors then `forced-color-adjust:
129
+ auto`-remaps to a single Canvas-white — collapsing the row to one indistinct
130
+ dot. The WHC arm must override that inline fill, and inline can only be beaten
131
+ by `!important`; this is the documented forced-colors degradation path (the
132
+ arm only activates under WHC). The component keeps its inline hue in normal
133
+ mode untouched. */
134
+ .status-dot__dot {
135
+ border: 1px solid CanvasText;
136
+ /* The bordered ring alone separates a dot from its surround; the per-status
137
+ fill below adds the WHC-honored distinction. */
138
+ }
139
+ /* The inner painted fill (`.status-dot__fill`, `h-full w-full`) + the pulse ring
140
+ carry the SAME inline glass-ui hue StatusDot paints — under WHC they cover the
141
+ outer `.status-dot__dot` glyph with a `forced-color-adjust`-remapped Canvas
142
+ fill (the row collapses to one white dot even with the outer system color set).
143
+ Yield them so the outer bordered + system-color glyph is the sole visible dot. */
144
+ .status-dot__fill,
145
+ .status-dot__pulse {
146
+ display: none;
147
+ }
148
+ /* The ok/warn/error/idle distinction rides the standard WHC keyword palette:
149
+ active (ok) → Highlight (the affirmative system accent)
150
+ paused (warn) → Mark (the marked/attention system color)
151
+ error → CanvasText (a solid filled dot — the strongest weight)
152
+ idle/custom → Canvas (a hollow dot — only the CanvasText ring reads)
153
+ Each stays distinguishable by the system color the user's palette assigns,
154
+ never glass-ui chroma. The `!important` beats the component's inline fill. */
155
+ .status-dot__dot[data-status="active"] {
156
+ background: Highlight !important;
157
+ }
158
+ .status-dot__dot[data-status="paused"] {
159
+ background: Mark !important;
160
+ }
161
+ .status-dot__dot[data-status="error"] {
162
+ background: CanvasText !important;
163
+ }
164
+ .status-dot__dot[data-status="idle"],
165
+ .status-dot__dot[data-status="custom"] {
166
+ background: Canvas !important;
167
+ }
168
+ }
169
+
170
+ /* ── @supports fallbacks for non-backdrop-filter browsers ── */
171
+ @layer components {
172
+ /* GUARD 1 — the NO-BLUR-AT-ALL engine (supports NEITHER the unprefixed NOR the
173
+ webkit form): paint an opaque-leaning plate so text stays legible without any
174
+ blur. AY.W-A11Y-PERF O-2b note: this is the floor for the theoretical
175
+ neither-supported case. The Safari ≤17 webkit-only trap (supports the `-webkit-`
176
+ form, so this `@supports not (… or …)` is FALSE and the fallback does NOT fire)
177
+ is closed at the SOURCE OF THE PREFIX: O-2a's build pass guarantees the shipped
178
+ dist carries the `-webkit-backdrop-filter:` pair, so a Safari-17 engine renders
179
+ the BLUR off the prefixed rule (it no longer falls through to a transparent
180
+ unprefixed-only surface). The trap closes where the prefix is emitted, not here. */
181
+ @supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
182
+ .glass-wash {
183
+ background: color-mix(in srgb, var(--card) 80%, transparent);
184
+ }
185
+ .glass-quiet {
186
+ background: color-mix(in srgb, var(--card) 88%, transparent);
187
+ }
188
+ .glass-resting {
189
+ background: color-mix(in srgb, var(--card) 94%, transparent);
190
+ }
191
+ .glass-floating {
192
+ background: color-mix(in srgb, var(--card) 98%, transparent);
193
+ }
194
+ .glass-overlay {
195
+ background: var(--card);
196
+ }
197
+ .glass-btn {
198
+ background: color-mix(in srgb, var(--background) 92%, transparent);
199
+ }
200
+ }
201
+
202
+ /* GUARD 2 — the WEBKIT-ONLY engine (supports `-webkit-backdrop-filter` but NOT the
203
+ unprefixed `backdrop-filter` — Safari ≤17). With O-2a's build-emitted prefix the
204
+ shipped rung carries the `-webkit-backdrop-filter:` pair, so this engine PAINTS
205
+ the blur off that prefixed declaration. This guard exists to DOCUMENT-and-confirm
206
+ that path (and would re-assert the translucent glass identity if a future change
207
+ ever stripped the rung bg under this engine) — it re-states the rungs' translucent
208
+ glass-mix so a webkit-only engine that DID get the prefix keeps the glass look,
209
+ never the opaque GUARD-1 plate. The `proof:webkit-backdrop` gate asserts the
210
+ shipped dist carries BOTH guards. */
211
+ @supports ((-webkit-backdrop-filter: blur(1px)) and (not (backdrop-filter: blur(1px)))) {
212
+ .glass-wash {
213
+ background: color-mix(in oklab, var(--glass-bg-wash), var(--glass-tint-source) var(--glass-tint-strength));
214
+ }
215
+ .glass-quiet {
216
+ background: color-mix(in oklab, var(--glass-bg-quiet), var(--glass-tint-source) var(--glass-tint-strength));
217
+ }
218
+ .glass-resting {
219
+ background: color-mix(in oklab, var(--glass-bg-resting), var(--glass-tint-source) var(--glass-tint-strength));
220
+ }
221
+ .glass-floating {
222
+ background: color-mix(in oklab, var(--glass-bg-floating), var(--glass-tint-source) var(--glass-tint-strength));
223
+ }
224
+ .glass-overlay {
225
+ background: color-mix(in oklab, var(--glass-bg-overlay), var(--glass-tint-source) var(--glass-tint-strength));
226
+ }
227
+ .glass-btn {
228
+ background: var(--glass-bg-wash);
229
+ }
230
+ }
231
+ }
232
+
233
+ /* ── :has() focus-elevation fallback (AQ.W3 §W3.1a) ──────────────────────
234
+ SOLE fallback for engines without `:has()`. `.is-focus-within` is toggled
235
+ by a ≤6-LOC focusin/focusout guard in `Card.vue` that runs ONLY when
236
+ `!CSS.supports('selector(:has(*))')` (modern engines run zero JS). The
237
+ class redefines the SAME `--card-focus-*` rungs as the `:has()` rule, so the
238
+ override values have one source. NOT a live+dead alias — `:has()` is the
239
+ enhancement, this the documented degradation path. */
240
+ @supports not selector(:has(*)) {
241
+ .glass-card.is-focus-within {
242
+ --card-focus-shadow: var(--shadow-md);
243
+ --card-focus-border: var(--glass-border-floating);
244
+ }
245
+ }