@mkbabb/glass-ui 3.7.0 → 3.8.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 (213) hide show
  1. package/dist/CardAction-q2qHCJFG.js +157 -0
  2. package/dist/{CommandShortcut-CY0aQTz5.js → CommandShortcut-SzWRhROC.js} +2 -2
  3. package/dist/{ContextMenuSubContent-BeDz7G6f.js → ContextMenuSubContent-Do977Cbf.js} +1 -1
  4. package/dist/{DataTable-gtPOLZvl.js → DataTable-CvlWXz65.js} +3 -3
  5. package/dist/DeckProgress-AVgbIULY.js +23 -0
  6. package/dist/{DialogContent-DG1YMR-P.js → DialogContent-DjZWT3lK.js} +2 -2
  7. package/dist/{DialogFooter-BCIaDP15.js → DialogFooter-Gprw8H_A.js} +1 -1
  8. package/dist/{DiscoGlyph-ZoBYpoxI.js → DiscoGlyph-CG0F410s.js} +1 -1
  9. package/dist/{GlyphFace-Ce_oe3tM.js → GlyphFace-DRjDkB0s.js} +1 -1
  10. package/dist/{HoverPopover-DXpOEw1P.js → HoverPopover-D56O6Ylp.js} +1 -1
  11. package/dist/{IconTooltip-Cu86JR4e.js → IconTooltip-D2T5nYOM.js} +1 -1
  12. package/dist/{MetricBadge-D-bRaQUD.js → MetricBadge-lTc002u2.js} +1 -1
  13. package/dist/{Notification-B5WHP3_1.js → Notification-BxK8LZMw.js} +1 -1
  14. package/dist/{PopoverContent-F1bWnYoh.js → PopoverContent-BId6ggf_.js} +1 -1
  15. package/dist/{Progress-c4vo4ALi.js → Progress-iEuD9pxG.js} +4 -4
  16. package/dist/{ScrollingText-BEp377U5.js → ScrollingText-CVyqxvfv.js} +2 -2
  17. package/dist/{SelectScrollDownButton-DAo5NmY_.js → SelectScrollDownButton-C7TRe-ep.js} +2 -2
  18. package/dist/{ToggleGroupItem-C-AIkBUw.js → ToggleGroupItem-CkXUcBlt.js} +1 -1
  19. package/dist/{UnderlineTabs-D_c1iYo-.js → UnderlineTabs-Uxn-R3MT.js} +2 -2
  20. package/dist/animated-digit.js +2 -2
  21. package/dist/api/index.d.ts +4 -2
  22. package/dist/api.js +1 -1
  23. package/dist/aurora.js +336 -405
  24. package/dist/canvas.d.ts +1 -0
  25. package/dist/canvas.js +3 -0
  26. package/dist/card.js +1 -1
  27. package/dist/carousel.js +105 -104
  28. package/dist/collapsible.js +1 -1
  29. package/dist/{color-DjJCAQ6f.js → color-DMLTunJK.js} +22 -14
  30. package/dist/color.js +2 -2
  31. package/dist/command.js +1 -1
  32. package/dist/compile-BBTRjvQS.js +158 -0
  33. package/dist/components/custom/aurora/composables/atoms.d.ts +90 -25
  34. package/dist/components/custom/aurora/composables/color.d.ts +0 -12
  35. package/dist/components/custom/aurora/composables/uniformBridge.d.ts +34 -23
  36. package/dist/components/custom/aurora/constants/presets.d.ts +10 -7
  37. package/dist/components/custom/aurora/constants/renderMode.d.ts +22 -0
  38. package/dist/components/custom/aurora/constants/shaders/aurora.wgsl.d.ts +1 -1
  39. package/dist/components/custom/aurora/constants/shaders/brush.glsl.d.ts +1 -1
  40. package/dist/components/custom/aurora/constants/shaders/composition.glsl.d.ts +1 -1
  41. package/dist/components/custom/aurora/constants/shaders/mediums.glsl.d.ts +1 -1
  42. package/dist/components/custom/aurora/index.d.ts +3 -3
  43. package/dist/components/custom/constellation/Constellation.vue.d.ts +40 -5
  44. package/dist/components/custom/constellation/constellationField.d.ts +110 -5
  45. package/dist/components/custom/constellation/index.d.ts +2 -2
  46. package/dist/components/custom/dock/GlassDock.vue.d.ts +12 -4
  47. package/dist/components/custom/dock/composables/dockMorphContext.d.ts +57 -0
  48. package/dist/components/custom/dock/composables/index.d.ts +3 -0
  49. package/dist/components/custom/dock/composables/useDockHold.d.ts +61 -0
  50. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +13 -59
  51. package/dist/components/custom/dock/index.d.ts +2 -0
  52. package/dist/components/custom/goo-blob/GooBlob.vue.d.ts +13 -0
  53. package/dist/components/custom/goo-blob/composables/useBlobMood.d.ts +4 -0
  54. package/dist/components/custom/goo-blob/composables/useBlobPointer.d.ts +2 -0
  55. package/dist/components/custom/goo-blob/composables/useBlobSatellites.d.ts +2 -0
  56. package/dist/components/custom/goo-blob/composables/useMetaballRenderer.d.ts +20 -5
  57. package/dist/components/custom/goo-blob/index.d.ts +1 -1
  58. package/dist/components/custom/goo-blob/shaders/sdf-body.glsl.d.ts +1 -1
  59. package/dist/components/custom/goo-blob/shaders/watercolor-edges.glsl.d.ts +2 -2
  60. package/dist/components/custom/goo-blob/types.d.ts +8 -0
  61. package/dist/components/ui/card/Card.vue.d.ts +23 -7
  62. package/dist/components/ui/card/index.d.ts +1 -1
  63. package/dist/components/ui/progress/ProgressDefault.vue.d.ts +14 -4
  64. package/dist/components/ui/slider/Slider.vue.d.ts +3 -1
  65. package/dist/composables/color/index.d.ts +19 -0
  66. package/dist/composables/dom/index.d.ts +1 -1
  67. package/dist/composables/dom/useResolveTokenColor.d.ts +27 -0
  68. package/dist/composables/glass/canvas2d/index.d.ts +2 -1
  69. package/dist/composables/glass/canvas2d/resolveCanvasColor.d.ts +20 -0
  70. package/dist/composables/glass/canvas2d/useCanvas2D.d.ts +15 -1
  71. package/dist/composables/glass/index.d.ts +3 -1
  72. package/dist/composables/glass/useSpecularTracking.d.ts +33 -0
  73. package/dist/composables/glass/webgl/createCanvasLifecycle.d.ts +1 -1
  74. package/dist/composables/glass/webgl/shaders/procedural-color.glsl.d.ts +4 -0
  75. package/dist/composables/glass/webgl/useWebGLCanvas.d.ts +1 -1
  76. package/dist/composables/motion/core/index.d.ts +1 -0
  77. package/dist/configurator.js +1 -1
  78. package/dist/confirm-dialog.js +1 -1
  79. package/dist/constellation.js +144 -75
  80. package/dist/context-menu.js +2 -2
  81. package/dist/controls.js +2 -2
  82. package/dist/dark.js +1 -1
  83. package/dist/data-table.js +1 -1
  84. package/dist/deck-progress.d.ts +1 -0
  85. package/dist/deck-progress.js +2 -0
  86. package/dist/dialog.js +2 -2
  87. package/dist/disco-glyph.js +1 -1
  88. package/dist/dock.js +386 -285
  89. package/dist/{dockContext-DLgrVWsU.js → dockContext-BKeIMmNk.js} +1 -1
  90. package/dist/dom.js +6 -6
  91. package/dist/{dropdown-menu-BWpwutt0.js → dropdown-menu-B_4bWyyG.js} +2 -2
  92. package/dist/dropdown-menu.js +1 -1
  93. package/dist/expandable-container.js +1 -1
  94. package/dist/fonts/README.md +26 -18
  95. package/dist/forms.js +3 -3
  96. package/dist/fourier-field.js +37 -37
  97. package/dist/glass-carousel.js +12 -7
  98. package/dist/glass-panel.js +7 -7
  99. package/dist/glass-ui.css +1 -1
  100. package/dist/glass-ui.js +150 -162
  101. package/dist/glyph-face.js +2 -2
  102. package/dist/goo-blob.js +353 -270
  103. package/dist/header-ribbon.js +1 -1
  104. package/dist/hover-card.js +1 -1
  105. package/dist/hover-popover.js +1 -1
  106. package/dist/icon-tooltip.js +1 -1
  107. package/dist/index.d.ts +1 -0
  108. package/dist/instrument-chassis.js +1 -1
  109. package/dist/instrument-rail.js +1 -1
  110. package/dist/keyboard.js +1 -1
  111. package/dist/{keys-Dyf_uTs5.js → keys-BsYjEFOW.js} +1 -1
  112. package/dist/label.js +1 -1
  113. package/dist/labeled-field.js +6 -6
  114. package/dist/metric-badge.js +1 -1
  115. package/dist/metric-stack.js +1 -1
  116. package/dist/motion-core.js +65 -65
  117. package/dist/motion.js +3 -3
  118. package/dist/notification.js +1 -1
  119. package/dist/paper-backdrop.js +1 -1
  120. package/dist/popover.js +1 -1
  121. package/dist/progress.js +1 -1
  122. package/dist/pulse.js +1 -1
  123. package/dist/reactive.js +2 -2
  124. package/dist/resolveCanvasColor-BBiYfp8g.js +11 -0
  125. package/dist/responsive-tabs.js +2 -2
  126. package/dist/scrolling-text.js +1 -1
  127. package/dist/search.js +7 -7
  128. package/dist/select.js +3 -3
  129. package/dist/separator.js +1 -1
  130. package/dist/{sheet-Cv1uO-Gq.js → sheet-VZEtNFvO.js} +2 -2
  131. package/dist/sheet.js +1 -1
  132. package/dist/slider-D9puf-Ko.js +142 -0
  133. package/dist/slider.js +1 -1
  134. package/dist/sortable-list.js +3 -3
  135. package/dist/styles/components.css +1 -1
  136. package/dist/styles/dock-controls.css +21 -18
  137. package/dist/styles/dock.css +415 -224
  138. package/dist/styles/fonts.css +0 -25
  139. package/dist/styles/glass.css +100 -41
  140. package/dist/styles/theme.css +9 -2
  141. package/dist/styles/tokens.css +139 -32
  142. package/dist/styles/typography.css +52 -69
  143. package/dist/styles/utilities.css +2 -1
  144. package/dist/styles/view-transition.css +12 -40
  145. package/dist/switch.js +1 -1
  146. package/dist/tabs.js +5 -5
  147. package/dist/timeline.js +3 -3
  148. package/dist/toast.js +1 -1
  149. package/dist/toggle-group.js +1 -1
  150. package/dist/tooltip.js +1 -1
  151. package/dist/typewriter.js +1 -1
  152. package/dist/{useAnimatedNumber-C5I3wWd8.js → useAnimatedNumber-C_3wZLx4.js} +1 -1
  153. package/dist/{useCanvas2D-C31yfUGY.js → useCanvas2D-ClrQuZtp.js} +2 -1
  154. package/dist/{useConfiguratorState-B24TcgIn.js → useConfiguratorState-CMff4GzH.js} +3 -3
  155. package/dist/useResolveTokenColor-r9pnNjqK.js +24 -0
  156. package/dist/useSpecularTracking-BVRZsRHA.js +26 -0
  157. package/dist/{useTextHighlight-aMPdEpkq.js → useTextHighlight-9nMW23Qb.js} +1 -1
  158. package/dist/{useTouchGate-YQRwyUGU.js → useTouchGate-WFyJYsth.js} +1 -1
  159. package/dist/vReveal-CqaCz_mC.js +44 -0
  160. package/dist/watercolor-dot.js +2 -2
  161. package/package.json +36 -4
  162. package/src/fonts/README.md +26 -18
  163. package/src/styles/dock-controls.css +21 -18
  164. package/src/styles/dock.css +415 -224
  165. package/src/styles/fonts.css +0 -25
  166. package/src/styles/glass.css +100 -41
  167. package/src/styles/theme.css +9 -2
  168. package/src/styles/tokens.css +139 -32
  169. package/src/styles/typography.css +52 -69
  170. package/src/styles/utilities.css +2 -1
  171. package/src/styles/view-transition.css +12 -40
  172. package/dist/CardAction-D8nSE62a.js +0 -163
  173. package/dist/compile-iM4IUB66.js +0 -158
  174. package/dist/fonts/fraunces/fraunces-latin.woff2 +0 -0
  175. package/dist/slider-BA9wIs5e.js +0 -130
  176. package/dist/useViewTransition-DaN5Zrox.js +0 -21
  177. package/dist/vReveal-BE2TsPoR.js +0 -24
  178. package/src/fonts/fraunces/fraunces-latin.woff2 +0 -0
  179. /package/dist/{CollapsibleContent-D7UNsXQr.js → CollapsibleContent-CP9qF1v4.js} +0 -0
  180. /package/dist/{ContextMenuContent-DGKZX1Du.js → ContextMenuContent-DDa0v27s.js} +0 -0
  181. /package/dist/{HoverCardContent-Bn0UBMY9.js → HoverCardContent-B6CcQ8He.js} +0 -0
  182. /package/dist/{Input-DWQQIOC4.js → Input-DVG_J0ne.js} +0 -0
  183. /package/dist/{InstrumentChassis-BLJBl1BW.js → InstrumentChassis-C2f6cBaQ.js} +0 -0
  184. /package/dist/{InstrumentRail-BElFwKyt.js → InstrumentRail-CUJ05YVG.js} +0 -0
  185. /package/dist/{Label-DBc7bKzZ.js → Label-zRfbQdCn.js} +0 -0
  186. /package/dist/{ModalOverlay-D1VrWyoi.js → ModalOverlay-B1GkAjNb.js} +0 -0
  187. /package/dist/{PaperBackdrop-DCGoGatv.js → PaperBackdrop-CqwjnfLv.js} +0 -0
  188. /package/dist/{SelectGroup-BcaFjvP4.js → SelectGroup-BFiod7X2.js} +0 -0
  189. /package/dist/{SelectSeparator-COFMJGng.js → SelectSeparator-L8pPEn4L.js} +0 -0
  190. /package/dist/{Separator-DZyqsCum.js → Separator-D7sD7RKj.js} +0 -0
  191. /package/dist/{Switch-2rsAtDfA.js → Switch-LDKLmmgx.js} +0 -0
  192. /package/dist/{TabsList-COqIdW7i.js → TabsList-qyHZ2lKY.js} +0 -0
  193. /package/dist/{Toaster-BMaeziJJ.js → Toaster-CabYEEF_.js} +0 -0
  194. /package/dist/{TooltipProvider-CD2IXfRv.js → TooltipProvider-CmZzCuaG.js} +0 -0
  195. /package/dist/{_plugin-vue_export-helper-gLzyemvl.js → _plugin-vue_export-helper-ok8pgSl5.js} +0 -0
  196. /package/dist/composables/{dom → motion}/useTextHighlight.d.ts +0 -0
  197. /package/dist/{constants-CS75AWHG.js → constants-BPOqYJAm.js} +0 -0
  198. /package/dist/{createContext-CvNyBk4o.js → createContext-B44Sah_H.js} +0 -0
  199. /package/dist/{menuItemVariants-B4eFR5Ix.js → menuItemVariants-DKM85SNE.js} +0 -0
  200. /package/dist/{presets-BKVyQfbt.js → presets-D1XPuTj-.js} +0 -0
  201. /package/dist/{prng-wHuHlNHE.js → prng-COGhh02-.js} +0 -0
  202. /package/dist/{useGlassRenderer-HebgSEgN.js → useGlassRenderer-5I0YkI4t.js} +0 -0
  203. /package/dist/{useGlobalDark-yhL4Wp-s.js → useGlobalDark-D3EBWzXK.js} +0 -0
  204. /package/dist/{useIntersectionPause-Cc-H9ees.js → useIntersectionPause-Bj4sPkMh.js} +0 -0
  205. /package/dist/{useInterval-D3USn0yc.js → useInterval-CcLfq2WU.js} +0 -0
  206. /package/dist/{useKeyboardShortcuts-Be3w_Rwk.js → useKeyboardShortcuts-BXWXOZ-9.js} +0 -0
  207. /package/dist/{useResizeObserver-CSyxGxIX.js → useResizeObserver-CWCbk5Px.js} +0 -0
  208. /package/dist/{useScrollProgress-CAH8Ofwt.js → useScrollProgress-C9ysDic5.js} +0 -0
  209. /package/dist/{useSortable-C8ReQ50P.js → useSortable-MGAbCGVJ.js} +0 -0
  210. /package/dist/{useSpringMount-LRZqJTaF.js → useSpringMount-BJSHcLl3.js} +0 -0
  211. /package/dist/{useTimer-DEJonOZa.js → useTimer-3xqf_54b.js} +0 -0
  212. /package/dist/{useUserInvalidAria-CQKjEfwP.js → useUserInvalidAria-DoJKMZ3s.js} +0 -0
  213. /package/dist/{useViewportReady-K96m-Mdv.js → useViewportReady-RIr5Wgkh.js} +0 -0
@@ -5,6 +5,29 @@
5
5
  * layering tokens live here so consumers have one public CSS path.
6
6
  */
7
7
 
8
+ /* AX.W01 — the SINGLE morph scalar. `useLayerTransition` writes it once per frame
9
+ to the `.glass-dock` root; EVERY morph axis (box size, padding, radius, scale,
10
+ background/border color, child stagger) is a pure `calc()` read off it — one
11
+ driver, one clock, on every engine (the View-Transitions collapse fork is
12
+ retired). `@property`-registered `<number>` so it interpolates COMPOSITED, not
13
+ discretely (an UNregistered custom property jumps + animates on the main
14
+ thread). `initial-value:0` = the collapsed-progress floor.
15
+
16
+ `inherits:true` (NOT false) — the SOTA inheritance-bomb guard is specifically
17
+ "never write the scalar to `:root`" (a whole-document subtree recalc per frame
18
+ over 1300+ elements). The scalar is written LOCALLY on the small `.glass-dock`
19
+ subtree, and its CONSUMERS are DESCENDANTS (`.dock-layers`/`.dock-layer-stack`
20
+ size + the active pane's child stagger) that read it via inheritance, so it MUST
21
+ inherit. Writing one inheriting var over a ~10–20-element dock subtree is the
22
+ exact pattern the prior `--dock-morph-progress` used (on `.dock-layers`); the
23
+ bomb only fires from a `:root` write, which never happens here. The root-chrome
24
+ reads (padding/bg/border) sit on the same element it is written to. */
25
+ @property --dock-morph-t {
26
+ syntax: "<number>";
27
+ inherits: true;
28
+ initial-value: 0;
29
+ }
30
+
8
31
  @layer components {
9
32
  :where(
10
33
  .glass-dock,
@@ -57,15 +80,26 @@
57
80
  scrolls with a mask-fade. Consumers override per-instance by
58
81
  setting `--dock-max-block-size` / `--dock-max-inline-size`
59
82
  on a `.glass-dock` directly. */
60
- --dock-wrap-max-width: calc(100vw - var(--dock-viewport-inline-gutter, 1rem));
61
83
  --dock-separator-height: calc(var(--dock-h, var(--size-icon-btn)) * 0.5);
62
84
  --dock-collapsed-hover-scale: var(--scale-hover-dock);
63
85
  /* AW.W3 — the spring-keyed child stagger knobs. `--dock-stagger-window-size`
64
86
  is the fraction of the morph each child reveals over; `--dock-stagger-rise`
65
87
  is the px the child rises from as it fades in. Consumers retune the
66
- cascade feel per instance. */
88
+ cascade feel per instance.
89
+
90
+ AX.W02 — `--dock-stagger-step` is the per-child onset BEAT: each
91
+ successive control's reveal starts this fraction-of-morph later than the
92
+ one before it, so the row fills outer→in. ONE token × the child index
93
+ replaces the hand-typed 0.08/0.16/0.24/0.32/0.4 onset ladder — the onset
94
+ is `step × (childIndex − 1)`, capped (the cap below). 0.08 = ~5% of the
95
+ ~0.32s morph between items — inside Emil Kowalski's 30–60ms stagger band,
96
+ never the >100ms "slideshow" register. The onset rides the NORMALIZED
97
+ morph progress (`--dock-expand-t`), NOT a wall-clock timer, so a fast
98
+ flick and a slow hover-open both choreograph correctly and an interrupted
99
+ morph orphans no timers. */
67
100
  --dock-stagger-window-size: 0.55;
68
101
  --dock-stagger-rise: 4px;
102
+ --dock-stagger-step: 0.08;
69
103
  /* AW.W3b — big-dock tokens. `--dock-card-radius` is the finite card-shell
70
104
  radius (default --radius-dock-card = --radius-3xl, density-scaled
71
105
  below); `--dock-tile-min` is the grid tile minimum (auto-fill track
@@ -160,6 +194,30 @@
160
194
  overflow: visible;
161
195
  }
162
196
 
197
+ /* AX.W04 F6 — the vertical-dock max-block-size + internal-scroll CONTRACT.
198
+ A vertical rail caps at `--dock-max-block-size` (the `.vertical` rule), but
199
+ at rest the `overflow: visible` above let over-cap content SPILL — forcing a
200
+ consumer (bbnf-buddy ToolsLayer) to hand-anchor a max-height + scroll. Ship
201
+ the contract here: at rest a vertical column scrolls its OWN block axis when
202
+ content exceeds the cap (cross axis stays `visible` for focus rings + grown
203
+ popovers). When content fits under the cap (`height:auto` < cap) nothing
204
+ scrolls — the scroll port only engages on real over-cap content. The
205
+ block-axis morph clip stays `data-morphing`-gated above; this is the
206
+ AT-REST port only. Consumers set `--dock-max-block-size` per-instance to
207
+ anchor the column to the viewport without re-deriving the scroll plumbing. */
208
+ .glass-dock.vertical.always-expanded:not([data-morphing]),
209
+ .glass-dock.vertical.expanded:not([data-morphing]) {
210
+ overflow-x: visible;
211
+ overflow-y: auto;
212
+ scrollbar-width: none;
213
+ overscroll-behavior-y: contain;
214
+ }
215
+
216
+ .glass-dock.vertical.always-expanded:not([data-morphing])::-webkit-scrollbar,
217
+ .glass-dock.vertical.expanded:not([data-morphing])::-webkit-scrollbar {
218
+ display: none;
219
+ }
220
+
163
221
  .glass-dock[data-density="compact"] {
164
222
  --dock-padding-block: var(--dock-density-compact-padding-block, 0.25rem);
165
223
  --dock-padding-inline: var(--dock-density-compact-padding-inline, 0.375rem);
@@ -309,41 +367,99 @@
309
367
  mix-blend-mode: soft-light;
310
368
  }
311
369
 
312
- /* J.W3.A — horizontal docks transition padding/shadow/transform/background/border
313
- only. Width is driven by the inner `.dock-layers` FLIP via
314
- `useLayerTransition`; pinning it here would race the FLIP and
315
- reintroduce the `width: auto` non-interpolation diagnosed in
316
- R1+R6.
317
-
318
- AW.W3 — the collapsed-hover `scale` (the `.collapsed:hover` rule below) +
319
- the press squish (`--scale-press-dock` on the dock controls) ride the
320
- INDIVIDUAL `scale` property, NOT `transform`. Adding `scale
321
- var(--dock-motion-resize)` here unifies the hover scale onto the SAME dock
322
- spring vocabulary as the morph, so a collapsed→hover→expand gesture reads as
323
- ONE continuous spring rather than a `scale`-ease handed off to the
324
- width-spring. Under PRM the global gate strips `scale` from the
325
- transition-property → the hover scale snaps (0 morph frames). */
326
- .glass-dock:not(.vertical) {
327
- transition:
328
- padding var(--dock-motion-resize),
329
- box-shadow var(--dock-motion-standard),
330
- transform var(--dock-motion-resize),
331
- scale var(--dock-motion-resize),
332
- /* AW.W3b — the pill↔card corner radius morphs on the SAME spring the
333
- aperture rides (ONE free interpolation). Without this the
334
- shape-card collapsed↔expanded radius snaps discretely. The list is
335
- shared by ALL horizontal docks — the radius transition also glides
336
- the wrap collapsed↔expanded radius swap (desirable). */
337
- border-radius var(--dock-motion-resize),
338
- background var(--dock-motion-standard),
339
- border-color var(--dock-motion-standard);
340
- }
341
-
342
- /* Vertical rails grow-to-fit + clamp, no scroll: descendants wrap to
343
- multiple rows (opt-in via `overflow="wrap"`) or clamp via
344
- `--dock-max-block-size`; the cap fails visibly rather than masking
345
- overflow as a scroll affordance. No edge-fade mask — a rail that never
346
- scrolls has nothing to feather. */
370
+ /* AX.W01 — the root chrome morphs off the SINGLE `--dock-morph-t` scalar, NOT a
371
+ CSS transition (the prior `padding/scale/radius var(--dock-motion-resize)` +
372
+ `background/border-color var(--dock-motion-standard)` transition list — TWO
373
+ curves on TWO durations — is DELETED). `--dock-expand-t` is the directional
374
+ expanded-ness (0 = collapsed look, 1 = expanded look) derived from the
375
+ per-swap morph scalar + the synchronously-set `.expanded`/`.collapsed` class:
376
+ the box width AND the root padding/radius/color move on ONE clock. The
377
+ per-frame writes drive the registered `<number>` scalar; the `calc()` reads
378
+ below interpolate composited. Under PRM the spring's `respectReducedMotion`
379
+ settles instantly (the scalar jumps 0→1 in one frame → the chrome snaps). */
380
+
381
+ /* `--dock-expand-t` — the directional expanded-ness. `--dock-morph-t` is a
382
+ REGISTERED `@property` (initial-value 0), so it is NEVER guaranteed-invalid:
383
+ `var(--dock-morph-t, 1)` reads 0 at REST (the fallback is DEAD), which would
384
+ resolve every expanded dock to expand-t 0 → the collapsed resting look (the
385
+ pill-radius + collapsed bg/border/padding regression). So the resting value is
386
+ stated STATICALLY per class, and ONLY while a morph is in flight
387
+ (`[data-morphing]` armed on the root by useLayerTransition, cleared on settle)
388
+ does expand-t track the live spring scalar. The class is ALREADY the END state
389
+ during the morph, so the read resolves the correct in-flight blend (collapse
390
+ 1→0 via `1 - t`; expand 0→1 via `t`); on settle `[data-morphing]` clears and
391
+ expand-t snaps to the exact class endpoint. */
392
+ .glass-dock:not(.vertical).expanded,
393
+ .glass-dock:not(.vertical).always-expanded {
394
+ --dock-expand-t: 1;
395
+ }
396
+
397
+ .glass-dock:not(.vertical).collapsed {
398
+ --dock-expand-t: 0;
399
+ }
400
+
401
+ .glass-dock:not(.vertical).expanded[data-morphing],
402
+ .glass-dock:not(.vertical).always-expanded[data-morphing] {
403
+ --dock-expand-t: var(--dock-morph-t);
404
+ }
405
+
406
+ .glass-dock:not(.vertical).collapsed[data-morphing] {
407
+ --dock-expand-t: calc(1 - var(--dock-morph-t));
408
+ }
409
+
410
+ /* The morphing root chrome — background / border-color interpolate between the
411
+ collapsed and expanded endpoints on the ONE `--dock-expand-t` scalar. Scoped
412
+ to the horizontal `variant-dock` (the rail / instrument-strip variants own
413
+ their own surface vocabulary and do not collapse↔expand). The two color axes
414
+ blend in srgb (the house mix the token ladder speaks). The `.collapsed`
415
+ discrete bg/border declarations are RETIRED — this block is the single
416
+ authority, and at rest `--dock-expand-t` resolves to the class endpoint (0
417
+ collapsed / 1 expanded) so the resting look is exact. */
418
+ .glass-dock.variant-dock:not(.vertical) {
419
+ background: color-mix(
420
+ in srgb,
421
+ var(--glass-bg-dock, var(--glass-bg-resting))
422
+ calc(var(--dock-expand-t, 1) * 100%),
423
+ var(--glass-bg-wash)
424
+ );
425
+ border-color: color-mix(
426
+ in srgb,
427
+ var(--glass-border-dock, var(--glass-border-resting))
428
+ calc(var(--dock-expand-t, 1) * 100%),
429
+ var(--glass-border-floating)
430
+ );
431
+ }
432
+
433
+ /* The padding morph is split out + scoped `:not(.dock-overflow-wrap)` so the
434
+ wrap variant's own padding rules (W04 territory — `.dock-overflow-wrap` +
435
+ its `@media` snap-back) are NOT clobbered by this higher-specificity longhand.
436
+ Padding interpolates linearly between the collapsed floor and the expanded
437
+ block/inline padding on the same `--dock-expand-t` scalar. */
438
+ .glass-dock.variant-dock:not(.vertical):not(.dock-overflow-wrap) {
439
+ --dock-pad-collapsed: var(
440
+ --dock-collapsed-padding,
441
+ var(--dock-padding-block, 0.375rem)
442
+ );
443
+ padding-block: calc(
444
+ var(--dock-pad-collapsed) +
445
+ (var(--dock-padding-block, 0.375rem) - var(--dock-pad-collapsed)) *
446
+ var(--dock-expand-t, 1)
447
+ );
448
+ padding-inline: calc(
449
+ var(--dock-pad-collapsed) +
450
+ (var(--dock-padding-inline, 0.5rem) - var(--dock-pad-collapsed)) *
451
+ var(--dock-expand-t, 1)
452
+ );
453
+ }
454
+
455
+ /* Vertical rails grow-to-fit then clamp at `--dock-max-block-size` (the
456
+ AX.W04 F6 contract). At rest a capped column scrolls its OWN block axis
457
+ internally (the `.vertical.always-expanded:not([data-morphing])` port above)
458
+ so a consumer setting `--dock-max-block-size` gets a viewport-anchored
459
+ scrollable tool palette without hand-anchoring it. `overflow="wrap"` is
460
+ horizontal-only (the class is not emitted for a vertical orientation); a
461
+ vertical column's natural overflow story is this cap + internal scroll. No
462
+ edge-fade mask — the scroll is scrollbar-hidden, not feathered. */
347
463
  .glass-dock.vertical {
348
464
  display: inline-flex;
349
465
  flex-direction: column;
@@ -358,19 +474,20 @@
358
474
  shell above; the cross axis stays visible there. */
359
475
  padding: var(--dock-vertical-padding, var(--dock-padding-block, 0.375rem));
360
476
  border-radius: var(--radius-dock);
361
- /* AW.W2 — axis-parity carve: NON-morph properties only. The block-axis
477
+ /* AX.W01 — a vertical rail is ALWAYS-EXPANDED (no collapse↔expand morph),
478
+ so its root padding/background/border-color never morph; the prior
479
+ `padding/background/border-color var(--dock-motion-*)` transition arms
480
+ are DELETED (a residual root CSS-transition on the morph-chrome props is
481
+ the second-clock smell the single-scalar rebuild retires). The block-axis
362
482
  (height) morph is owned by the inner `.dock-layer-stack` / DockLayerGroup
363
- spring (or the VT path); a `height var(--dock-motion-resize)` here would
364
- be a second driver on the same axis (the AV.W9.0 dual-driver race),
365
- and `width` is the cross axis the spring never writes. Matches how
366
- `:not(.vertical)` already excludes `width`. */
483
+ via the `--dock-morph-t` scalar (the size `calc()` above), never a CSS
484
+ transition here. KEPT: the DECORATIVE hover-scale + press-squish (the
485
+ individual `scale`/`transform`) and the box-shadow fade — these are
486
+ interaction polish on the static rail, NOT the morph. */
367
487
  transition:
368
- padding var(--dock-motion-resize),
369
488
  box-shadow var(--dock-motion-standard),
370
489
  transform var(--dock-motion-resize),
371
- scale var(--dock-motion-resize),
372
- background var(--dock-motion-standard),
373
- border-color var(--dock-motion-standard);
490
+ scale var(--dock-motion-resize);
374
491
  }
375
492
 
376
493
  .glass-dock.variant-rail {
@@ -399,14 +516,18 @@
399
516
 
400
517
  /* The big-dock CARD shell — a FINITE concentric radius above 2xl, below pill.
401
518
  It does NOT collapse to a stadium. Collapsed it returns to a pill (the morph
402
- target); the pill↔card swap glides on the `--dock-motion-resize` spring
403
- (`border-radius` is in the `:not(.vertical)` transition list). */
519
+ target); the pill↔card radius now MORPHS on the SAME `--dock-expand-t` scalar
520
+ the box + chrome ride (ONE clock, no discrete snap) — `--radius-pill` at
521
+ expand-t 0 (collapsed), `--dock-card-radius` at expand-t 1 (expanded). The
522
+ prior two discrete `.shape-card` / `.shape-card.collapsed` rules + their
523
+ reliance on the deleted `border-radius var(--dock-motion-resize)` transition
524
+ are RETIRED for this single interpolation. */
404
525
  .glass-dock.variant-dock:not(.vertical).shape-card {
405
- border-radius: var(--dock-card-radius);
406
- }
407
-
408
- .glass-dock.variant-dock:not(.vertical).shape-card.collapsed {
409
- border-radius: var(--radius-pill);
526
+ border-radius: calc(
527
+ var(--radius-pill) +
528
+ (var(--dock-card-radius) - var(--radius-pill)) *
529
+ var(--dock-expand-t, 1)
530
+ );
410
531
  }
411
532
 
412
533
  /* The squircle reads markedly better at the large card radius — an
@@ -480,15 +601,16 @@
480
601
  border-color: var(--surface-tint-6);
481
602
  }
482
603
 
604
+ /* AX.W01 — the collapsed padding / background / border-color are RETIRED here
605
+ (the `--dock-expand-t` morph block above is the single authority for those
606
+ three axes — they interpolate, never snap). `.collapsed` keeps only its
607
+ non-morphing concerns: the pointer affordance, the centred summary layout,
608
+ and the collapsed shadow (box-shadow crossfades discretely — a subtle,
609
+ acceptable swap that a `color-mix` cannot blend across its multi-layer
610
+ value). */
483
611
  .glass-dock.collapsed {
484
612
  cursor: pointer;
485
- padding: var(--dock-collapsed-padding, var(--dock-padding-block, 0.375rem));
486
613
  justify-content: center;
487
- background: var(--glass-bg-wash);
488
- border-color: var(--glass-border-floating);
489
- /* Idiomatic override path: the consumer-supplied
490
- `--shadow-dock-override` variable engages in every dock state
491
- (was: base only, leaking through here in collapsed). */
492
614
  box-shadow: var(--shadow-dock-override, var(--shadow-dock-collapsed));
493
615
  }
494
616
 
@@ -578,7 +700,47 @@
578
700
  .dock-layers {
579
701
  display: grid;
580
702
  min-width: 0;
581
- transition: width var(--dock-motion-resize);
703
+ }
704
+
705
+ /* AX.W01 — the box size morph reads the SAME `--dock-morph-t` scalar as the
706
+ root chrome (ONE clock, co-temporal by construction). `useLayerTransition`
707
+ measures the from→to size ONCE per swap (the allowed one-time FLIP
708
+ measurement) and writes `--dock-morph-from`/`--dock-morph-to` px on the
709
+ morphing element; the live scalar interpolates between them. The size lands
710
+ on the morph AXIS — `inline-size` for a horizontal `.dock-layers` (always
711
+ inline) + a horizontal inner stack, `block-size` for a vertical inner stack.
712
+ Gated on the root `[data-morphing]`, so at REST the intrinsic / `width:100%`
713
+ rules below hold (the morph vars are cleared on settle). Replaces the prior
714
+ `transition: width var(--dock-motion-resize)` inline-FLIP — there is NO CSS
715
+ transition on the size axis; the spring writes the scalar, CSS reads it. The
716
+ active pane is REVEALED through the clip aperture as the box grows (the W2
717
+ clip-reveal contract). */
718
+ .glass-dock[data-morphing] .dock-layers,
719
+ .glass-dock[data-morphing] .dock-layer-stack {
720
+ --dock-morph-size: calc(
721
+ var(--dock-morph-from, 0px) +
722
+ (var(--dock-morph-to, 0px) - var(--dock-morph-from, 0px)) *
723
+ var(--dock-morph-t, 0)
724
+ );
725
+ inline-size: var(--dock-morph-size);
726
+ }
727
+
728
+ /* A vertical inner group morphs the BLOCK axis — the same span lands on
729
+ block-size, and the inline axis stays intrinsic. */
730
+ .glass-dock[data-morphing] .dock-layer-group.vertical .dock-layer-stack {
731
+ inline-size: auto;
732
+ block-size: var(--dock-morph-size);
733
+ }
734
+
735
+ /* The inner DockLayerGroup stack has no collapsed/expanded class, so its
736
+ stagger directional scalar is the per-swap progress directly: `--dock-morph-t`
737
+ reads onto an inheriting `--dock-expand-t` on the morphing stack so the new
738
+ pane's children cascade in as it reveals. The geometry scalar
739
+ (`--dock-morph-t`) stays registered + non-inheriting on the root; this is the
740
+ small-subtree inheriting alias the stagger reads (the inheritance-bomb guard
741
+ only concerns the `:root`-wide write, which never happens). */
742
+ .glass-dock[data-morphing] .dock-layer-stack {
743
+ --dock-expand-t: var(--dock-morph-t, 1);
582
744
  }
583
745
 
584
746
  /* AV.W9.0 — the AU.W8b native container-morph arm (the `@supports` block that
@@ -607,44 +769,39 @@
607
769
  overflow-x: visible;
608
770
  }
609
771
 
610
- /* AU.W8b-visibility-fork — the 3-state active/inactive/leaving visibility
611
- contract below is LOAD-BEARING (the a11y-006 bite-anchor). A later refactor
612
- greps for this marker so the semantics are not collapsed: the inactive layer
613
- leaves the hit-test tree (`visibility:hidden`), the leaving layer stays
614
- painted-but-untouchable through its fade (`visibility:visible` +
615
- `pointer-events:none`), and the active layer shows IMMEDIATELY (`visibility
616
- 0s`, no fade-in delay). The hand-rolled 3-state fork below is now the SOLE
617
- visibility authority on every engine — AV.W9.1 retired the native
618
- discrete-visibility arm that used to second-drive it, so one owner governs
619
- visibility (one owner governs size, one owns opacity). */
620
-
621
- /* ── Layer crossfade + hit-test contract (shared) ──────────────────
622
- Two dock-layer surfaces stack on a 1/1 CSS grid and crossfade:
623
- `.dock-layer` (GlassDock's built-in collapsed↔expanded pair) and
624
- `.dock-layer-item-host` (a DockLayer inside a DockLayerGroup). They
625
- differ only in base layout — the active/inactive/leaving paint +
626
- hit-test semantics are identical, so the contract is expressed ONCE
627
- here over both state vocabularies (`.layer-active` / `.is-active` /
628
- `.is-leaving`) rather than copied per rule-set (Q-coh-5 — `beec35e`
629
- patched the `visibility` fix into two parallel copies).
630
-
631
- An inactive layer must leave the paint AND hit-test tree: `opacity:0`
632
- alone leaves the box answering `elementFromPoint()`, so an inactive
633
- layer's button intercepts clicks meant for the active one.
634
- `visibility:hidden` removes it from both while KEEPING it in layout
635
- flow, so the FLIP width measurement in `useLayerTransition` still
636
- reads its geometry (`display:none` would zero it). The delayed
637
- `visibility` transition holds a leaving layer `visible` for the
638
- length of the opacity crossfade, then flips it `hidden`.
639
-
640
- AU.W2 — the opacity-lockstep fold (slides-F P0, the "not iOS-smooth"
641
- report). The layer fade rides `--dock-motion-resize` (the SAME duration +
642
- spring the container morph runs at, `:189`/`:216`/`:385`) — NOT the faster
643
- `--dock-motion-fast` (0.2s). Before, the host faded in 0.2s while the
644
- container morphed in 0.3s: a 100ms-apart settle (the items appeared to lag
645
- the pill). Now the fade and the morph settle in lockstep. The matched
646
- `visibility` hold extends to `--duration-normal` so the leaving layer stays
647
- paintable for the FULL (now longer) crossfade. */
772
+ /* ── Layer crossfade + hit-test contract (ONE vocabulary) ──────────────
773
+ AX.W02 — the outer `.dock-layer` (GlassDock's built-in collapsed↔expanded
774
+ pair) and the inner `.dock-layer-item-host` (a DockLayer inside a
775
+ DockLayerGroup) now share ONE active-state vocabulary: `.is-active` /
776
+ `.is-leaving`. The prior `.layer-active` / `.is-active` / `.is-leaving`
777
+ TRIPLE collapsed to the pair — both surfaces drive crossfade + hit-test off
778
+ the same two state classes, and the morph orchestrator fold (one engine per
779
+ dock) means the box, both panes, and every child stagger ride one
780
+ `--dock-morph-t` clock. The greppable-sync tombstone that kept the two
781
+ never-merged vocabularies in lockstep is DELETED — there is nothing to keep
782
+ in sync once the vocabulary is one.
783
+
784
+ The 3-state active/inactive/leaving visibility contract here is LOAD-BEARING
785
+ (the a11y-006 anchor): the inactive layer leaves the hit-test tree
786
+ (`visibility:hidden`), the leaving layer stays painted-but-untouchable
787
+ through its fade (`visibility:visible` + `pointer-events:none`), and the
788
+ active layer shows IMMEDIATELY (`visibility 0s`, no fade-in delay). One
789
+ owner governs each concern — size = the spring scalar, opacity = the CSS
790
+ crossfade below, visibility = this 3-state fork.
791
+
792
+ An inactive layer must leave the paint AND hit-test tree: `opacity:0` alone
793
+ leaves the box answering `elementFromPoint()`, so an inactive layer's button
794
+ intercepts clicks meant for the active one. `visibility:hidden` removes it
795
+ from both while KEEPING it in layout flow, so the FLIP measurement still
796
+ reads its geometry (`display:none` would zero it). The delayed `visibility`
797
+ transition holds a leaving layer `visible` for the length of the opacity
798
+ crossfade, then flips it `hidden`.
799
+
800
+ AU.W2 — the opacity-lockstep fold. The layer fade rides `--dock-motion-resize`
801
+ (the SAME duration the container morph runs at) — NOT the faster
802
+ `--dock-motion-fast` (0.2s), so the fade and the morph settle in lockstep.
803
+ The matched `visibility` hold extends to `--duration-normal` so the leaving
804
+ layer stays paintable for the FULL crossfade. */
648
805
  .dock-layer,
649
806
  .dock-layer-item-host {
650
807
  transition:
@@ -652,34 +809,34 @@
652
809
  visibility 0s linear var(--duration-normal);
653
810
  }
654
811
 
655
- .dock-layer:not(.layer-active),
812
+ .dock-layer:not(.is-active):not(.is-leaving),
656
813
  .dock-layer-item-host:not(.is-active):not(.is-leaving) {
657
814
  opacity: 0;
658
815
  visibility: hidden;
659
816
  pointer-events: none;
660
817
  }
661
818
 
662
- .dock-layer.layer-active,
819
+ .dock-layer.is-active,
663
820
  .dock-layer-item-host.is-active {
664
821
  opacity: 1;
665
822
  visibility: visible;
666
823
  pointer-events: auto;
667
824
  /* AW.W2 — the active pane is STATICALLY opacity:1, REVEALED by the clip
668
- aperture (the box is the reveal mechanism), never faded. The prior
669
- `opacity var(--dock-motion-resize)` arm is DELETED: there is ZERO
670
- opacity authority on the active pane now — the aperture uncovers a
671
- layout that is laid out ONCE at natural size behind it. Only `visibility
672
- 0s` survives (the active layer must paint at once, no fade-in delay —
673
- the AU.W2 governing rule). The leaving pane keeps the shared-token
674
- opacity fade below (the ONLY surviving opacity animation, the thin
675
- polish proof:dock-opacity-lockstep names). */
825
+ aperture (the box is the reveal mechanism), never faded. There is ZERO
826
+ opacity authority on the active pane — the aperture uncovers a layout
827
+ that is laid out ONCE at natural size behind it. Only `visibility 0s`
828
+ survives (the active layer must paint at once, no fade-in delay — the
829
+ AU.W2 governing rule). The leaving pane keeps the shared-token opacity
830
+ fade below (the ONLY surviving opacity animation). */
676
831
  transition: visibility 0s;
677
832
  }
678
833
 
679
- /* A leaving layer is inactive for hit-testing but still painted
680
- through its fade-out. (`.dock-layer` has no separate leaving state —
681
- its `:not(.layer-active)` rule above covers the crossfade-out via the
682
- delayed `visibility` transition.) */
834
+ /* A leaving layer is inactive for hit-testing but still painted through its
835
+ fade-out. The outer collapse↔expand pair has no separate leaving marker in
836
+ markup — its `:not(.is-active):not(.is-leaving)` rule above covers the
837
+ crossfade-out via the delayed `visibility` transition; the inner pane swap
838
+ sets `.is-leaving` explicitly during the crossfade. */
839
+ .dock-layer.is-leaving,
683
840
  .dock-layer-item-host.is-leaving {
684
841
  opacity: 0;
685
842
  visibility: visible;
@@ -694,10 +851,10 @@
694
851
  native size arm gone (W9.0), opacity now has ONE owner everywhere: the
695
852
  `opacity var(--dock-motion-resize)` crossfade on `.dock-layer{,-item-host}`
696
853
  (the AU.W2 lockstep token — kept), and visibility has ONE owner: the delayed
697
- `visibility 0s linear var(--duration-normal)` hold of the
698
- `AU.W8b-visibility-fork` 3-state fallback above (the a11y-006 bite-anchor,
699
- LOAD-BEARING). One authority per concern: size = spring/VT, opacity = the
700
- CSS crossfade, visibility = the delayed-hold fork. */
854
+ `visibility 0s linear var(--duration-normal)` hold of the 3-state fork above
855
+ (the a11y-006 anchor, LOAD-BEARING). One authority per concern: size = the
856
+ spring scalar, opacity = the CSS crossfade, visibility = the delayed-hold
857
+ fork. */
701
858
 
702
859
  /* ── Base layout — distinct per surface ─────────────────────────── */
703
860
  .dock-layer {
@@ -719,87 +876,99 @@
719
876
  height: var(--dock-layer-height, 2.5rem);
720
877
  }
721
878
 
722
- .dock-layer.layer-active {
879
+ .dock-layer.is-active {
723
880
  position: relative;
724
881
  }
725
882
 
726
- .dock-layer:not(.layer-active) {
883
+ .dock-layer:not(.is-active) {
727
884
  position: absolute;
728
885
  inset: 0;
729
886
  }
730
887
 
731
- /* AW.W3 — the spring-keyed child stagger. While the size spring drives the
732
- morph, the driver arms the container (`.dock-layers` / `.dock-layer-stack`)
733
- with `data-revealing` and writes the morph's normalized progress to
734
- `--dock-morph-progress` (0 → 1) every frame. Each direct child of the
735
- ACTIVE pane reveals when that progress crosses a per-child onset, so the
736
- controls cascade IN ON the physical morph — a fast flick and a slow
737
- hover-open both choreograph correctly, and an interrupted morph carries the
738
- cascade with it (no orphaned timers). This is a per-CHILD opacity onset; the
739
- active PANE itself stays statically opacity:1 (revealed by the aperture —
740
- the W2 clip-reveal contract is NOT regressed).
741
-
742
- The reveal is a pure `calc` ramp: `opacity = clamp(0, (progress − onset) /
743
- window, 1)`. `--dock-stagger-onset` steps per child (nth-child); the window
744
- is `--dock-stagger-window`. The children also rise a few px on a `translate`
745
- that resolves on the same ramp. ONLY children inside the `[data-revealing]`
746
- active pane are armed — at rest the children carry no opacity authority (the
747
- default cascade leaves them at 1).
748
-
749
- PRM: the driver never arms `data-revealing` on the synchronous PRM swap (the
750
- FLIP fast-path returns before the spring; the spring's `respectReducedMotion`
751
- settles instantly), so the children paint at full opacity at once. The
752
- global PRM gate also strips `translate` from the transition-property — the
753
- rise snaps. The cascade collapses to 0 stagger frames under PRM. */
754
- .dock-layers[data-revealing] .dock-layer--full > *,
755
- .dock-layer-stack[data-revealing] .dock-layer-item-host.is-active > * {
888
+ /* AX.W01 — the spring-keyed child stagger, now off the SINGLE morph scalar.
889
+ The driver writes `--dock-morph-t` to the `.glass-dock` root and arms
890
+ `[data-morphing]` while the spring runs; `--dock-expand-t` (the inheriting
891
+ directional expanded-ness derived above — 0 collapsed, 1 expanded) cascades
892
+ to the active pane's children. Each direct child reveals when `--dock-expand-t`
893
+ crosses its per-child onset, so the controls cascade IN ON the physical morph
894
+ — symmetric in both directions (expand fades them in outer→in, collapse fades
895
+ them back out) and an interrupted morph carries the cascade with it (no
896
+ orphaned timers). The active PANE stays statically opacity:1 (revealed by the
897
+ clip aperture); only its CHILDREN ride this per-child onset (the W2
898
+ clip-reveal contract is NOT regressed).
899
+
900
+ The reveal is a pure `calc` ramp: `opacity = clamp(0, (expand-t − onset) /
901
+ window, 1)`. Gated on the root `[data-morphing]` so at REST the children
902
+ carry no opacity authority (default cascade → 1). Under PRM the spring's
903
+ `respectReducedMotion` jumps `--dock-morph-t` 0→1 in one frame → `--dock-expand-t`
904
+ lands at the endpoint → the cascade collapses to 0 stagger frames; the
905
+ global PRM gate strips `translate` so the rise snaps too. The inner
906
+ DockLayerGroup defines its own `--dock-expand-t` (= the per-swap progress)
907
+ in DockLayerGroup's scope so a pane swap reveals the new pane's children. */
908
+ .glass-dock[data-morphing] .dock-layer.is-active > *,
909
+ .glass-dock[data-morphing] .dock-layer-item-host.is-active > * {
756
910
  --dock-stagger-window: var(--dock-stagger-window-size, 0.55);
757
911
  --dock-stagger-onset: 0;
758
912
  opacity: clamp(
759
913
  0,
760
914
  calc(
761
- (var(--dock-morph-progress, 1) - var(--dock-stagger-onset)) /
915
+ (var(--dock-expand-t, 1) - var(--dock-stagger-onset)) /
762
916
  var(--dock-stagger-window)
763
917
  ),
764
918
  1
765
919
  );
766
920
  translate: 0
767
921
  calc(
768
- (1 - clamp(0, calc((var(--dock-morph-progress, 1) - var(--dock-stagger-onset)) / var(--dock-stagger-window)), 1)) *
922
+ (1 - clamp(0, calc((var(--dock-expand-t, 1) - var(--dock-stagger-onset)) / var(--dock-stagger-window)), 1)) *
769
923
  var(--dock-stagger-rise, 4px)
770
924
  );
771
925
  }
772
926
 
773
- /* Per-child onsets — each successive control starts a beat later, so the row
774
- fills outer→in on expand. The onsets are fractions of the morph progress;
775
- capped so even a long row finishes within the morph window. */
776
- .dock-layers[data-revealing] .dock-layer--full > *:nth-child(2),
777
- .dock-layer-stack[data-revealing] .dock-layer-item-host.is-active > *:nth-child(2) {
778
- --dock-stagger-onset: 0.08;
927
+ /* AX.W02 — per-child onsets off the ONE `--dock-stagger-step` token. Each
928
+ successive control starts `step` later than the one before it (`onset =
929
+ step × (childIndex − 1)`), so the row fills outer→in on expand. The
930
+ hand-typed 0.08/0.16/0.24/0.32/0.4 ladder is RETIRED — the onsets are now
931
+ derived from the single token, so retuning the cascade beat is a one-token
932
+ override. The set is capped at the 6th child (`nth-child(n + 6)` holds at
933
+ `step × 5`) so even a long row finishes within the morph window. ONE rule
934
+ over the unified `.is-active` vocabulary drives both the outer pane and the
935
+ inner pane-stack — no duplicated comma-group. (`sibling-index()` would
936
+ collapse this to a single declaration, but it is not yet Baseline across
937
+ Safari/Firefox — the token-keyed nth-child set is the cross-engine form, and
938
+ the magic ladder is gone either way.) */
939
+ .glass-dock[data-morphing] .dock-layer.is-active > *:nth-child(2),
940
+ .glass-dock[data-morphing] .dock-layer-item-host.is-active > *:nth-child(2) {
941
+ --dock-stagger-onset: calc(var(--dock-stagger-step) * 1);
779
942
  }
780
- .dock-layers[data-revealing] .dock-layer--full > *:nth-child(3),
781
- .dock-layer-stack[data-revealing] .dock-layer-item-host.is-active > *:nth-child(3) {
782
- --dock-stagger-onset: 0.16;
943
+ .glass-dock[data-morphing] .dock-layer.is-active > *:nth-child(3),
944
+ .glass-dock[data-morphing] .dock-layer-item-host.is-active > *:nth-child(3) {
945
+ --dock-stagger-onset: calc(var(--dock-stagger-step) * 2);
783
946
  }
784
- .dock-layers[data-revealing] .dock-layer--full > *:nth-child(4),
785
- .dock-layer-stack[data-revealing] .dock-layer-item-host.is-active > *:nth-child(4) {
786
- --dock-stagger-onset: 0.24;
947
+ .glass-dock[data-morphing] .dock-layer.is-active > *:nth-child(4),
948
+ .glass-dock[data-morphing] .dock-layer-item-host.is-active > *:nth-child(4) {
949
+ --dock-stagger-onset: calc(var(--dock-stagger-step) * 3);
787
950
  }
788
- .dock-layers[data-revealing] .dock-layer--full > *:nth-child(5),
789
- .dock-layer-stack[data-revealing] .dock-layer-item-host.is-active > *:nth-child(5) {
790
- --dock-stagger-onset: 0.32;
951
+ .glass-dock[data-morphing] .dock-layer.is-active > *:nth-child(5),
952
+ .glass-dock[data-morphing] .dock-layer-item-host.is-active > *:nth-child(5) {
953
+ --dock-stagger-onset: calc(var(--dock-stagger-step) * 4);
791
954
  }
792
- .dock-layers[data-revealing] .dock-layer--full > *:nth-child(n + 6),
793
- .dock-layer-stack[data-revealing] .dock-layer-item-host.is-active > *:nth-child(n + 6) {
794
- --dock-stagger-onset: 0.4;
955
+ .glass-dock[data-morphing] .dock-layer.is-active > *:nth-child(n + 6),
956
+ .glass-dock[data-morphing] .dock-layer-item-host.is-active > *:nth-child(n + 6) {
957
+ --dock-stagger-onset: calc(var(--dock-stagger-step) * 5);
795
958
  }
796
959
 
797
960
  /* AW.W2 — the at-rest clip-lift moved to `.expanded:not([data-morphing])` /
798
961
  `.always-expanded:not([data-morphing])` (the clip-shell block at the top).
799
962
  A plain `overflow: visible` here would lift the clip DURING the morph (the
800
963
  load-bearing sequencing gap), so the `overflow` declarations are dropped
801
- from these state rules; they keep only their non-overflow concerns. */
802
- .glass-dock.expanded:not(.fit-content) .dock-layers {
964
+ from these state rules; they keep only their non-overflow concerns.
965
+
966
+ AX.W01 — `:not([data-morphing])` gate: at REST expanded the layers fill the
967
+ box (`width:100%`), but DURING the morph the FLIP from→to px (the
968
+ `--dock-morph-size` calc above) is the SOLE size authority — a `width:100%`
969
+ here would win on specificity and snap the box past the spring. The gate
970
+ hands the size to the scalar for the morph and back to 100% on settle. */
971
+ .glass-dock.expanded:not(.fit-content):not([data-morphing]) .dock-layers {
803
972
  width: 100%;
804
973
  }
805
974
 
@@ -901,19 +1070,70 @@
901
1070
  display: none;
902
1071
  }
903
1072
 
904
- /* ── `overflow="wrap"` recipe (the `.dock-overflow-wrap` hook) ────────
905
- Parallel to the `.dock-scroll-{x,y}` hooks the `overflow="scroll"`
906
- member emits: the `overflow="wrap"` enum member emits this class. (The
907
- prior `wrap` boolean's hook is retired — clean break, no alias.)
908
- Expanded content wraps to multiple rows; the pill narrows to the
909
- viewport gutter and snaps back to a single nowrap row past
910
- `--dock-overflow-bp` (the `@media` at the tail). */
1073
+ /* ── `overflow="wrap"` recipe — CONTENT-DRIVEN intrinsic flex reflow ──
1074
+ (AX.W04 F0). Parallel to the `.dock-scroll-{x,y}` hooks the
1075
+ `overflow="scroll"` member emits, `overflow="wrap"` emits this class.
1076
+ (HORIZONTAL-ONLY — GlassDock.vue guards the emit on
1077
+ `orientation !== 'vertical'`; a vertical rail grows-to-fit + clamps via
1078
+ `--dock-max-block-size`, its own overflow story.)
1079
+
1080
+ The reflow is INTRINSIC: `flex-wrap: wrap` is ALWAYS-ON (no viewport MQ),
1081
+ and the dock shrink-wraps to content with `max-inline-size` capping it at
1082
+ the canonical `--dock-max-inline-size` token (the SAME cap every
1083
+ overflow strategy reads — `min(80vw, 64rem)` default, consumer-overridable
1084
+ per-instance). So the layer wraps to N rows EXACTLY when its intrinsic row
1085
+ exceeds the cap — at ANY viewport width — and collapses to one row when it
1086
+ fits. The magic-640 `@media` snap-back + the `--dock-overflow-bp` token are
1087
+ DELETED (the inherited mobile-responsive debt, origin 078dd79). */
911
1088
  .glass-dock.dock-overflow-wrap {
912
1089
  white-space: normal;
913
- border-radius: var(--radius-2xl);
914
- max-width: var(--dock-wrap-max-width);
1090
+ /* The content-driven cap. The dock ALREADY shrink-wraps to its content's
1091
+ intrinsic width (the base `.glass-dock` rule), so `max-inline-size` caps
1092
+ that intrinsic width at `--dock-max-inline-size`: under the cap the
1093
+ shrink-wrap wins → one row; over the cap the dock holds at the cap and the
1094
+ inner `flex-wrap: wrap` row reflows to N rows. ONE token, no breakpoint.
1095
+ (The `min(max-content, …)` form is INVALID CSS — the math functions reject
1096
+ the `max-content` intrinsic keyword, computing the property to its initial
1097
+ `none` and silently dropping the cap; intrinsic-shrink + this plain cap IS
1098
+ the valid `min(max-content, cap)`.) */
1099
+ max-inline-size: var(--dock-max-inline-size);
915
1100
  padding: var(--dock-wrap-padding-block, var(--dock-padding-block, 0.375rem))
916
1101
  var(--dock-wrap-padding-inline, 0.625rem);
1102
+
1103
+ /* F4 — the pill↔card radius morph. A wrap dock is a FINITE multi-row CARD
1104
+ surface when expanded and a stadium PILL when collapsed — the SAME
1105
+ pill↔card morph the big-dock `shape-card` path rides. The corner glides
1106
+ on the `--dock-expand-t` W01 single-scalar: `--radius-pill` at expand-t 0
1107
+ (collapsed), `--dock-card-radius` at expand-t 1 (expanded — UNIFIED on
1108
+ the SAME finite-radius token the big-dock card uses; the bare 16px
1109
+ `--radius-2xl` literal is DELETED). ONE register, no discrete snap. */
1110
+ border-radius: calc(
1111
+ var(--radius-pill) +
1112
+ (var(--dock-card-radius) - var(--radius-pill)) *
1113
+ var(--dock-expand-t, 1)
1114
+ );
1115
+
1116
+ /* F1 — the card-tier elevation morph ("material thickens as glass flexes
1117
+ larger", WWDC25 §219). The wrap dock lifts from the flat thin-pill
1118
+ `--shadow-dock` glow onto the FLOATING-tier stack (the `--shadow-dock-wrap`
1119
+ token names the canonical composite on `:root`; a consumer retints the
1120
+ whole card shadow by overriding THAT one token per the cartoon-shadow
1121
+ contract). The three floating layers — drop / material-rim / under-cast —
1122
+ fade in driven by the SAME `--dock-expand-t` scalar the radius glides on:
1123
+ `--dock-wrap-elev` is the scalar as a 0→1 percent, so each layer's alpha
1124
+ tracks the corner morph in LOCKSTEP (ONE clock, ONE register). At
1125
+ expand-t 0 (collapsed/pill) the floating layers are 0%-alpha (invisible)
1126
+ → only the base `--shadow-dock` glow shows; at expand-t 1 (expanded/card)
1127
+ the full floating stack grounds the multi-row silhouette. The per-layer
1128
+ recipe mirrors `--shadow-dock-wrap` (= `--shadow-xl` + `--glass-material-rim`
1129
+ + `--glass-under-shadow-vivid`) so the token stays the source-of-record. */
1130
+ --dock-wrap-elev: calc(var(--dock-expand-t, 1) * 100%);
1131
+ box-shadow:
1132
+ var(--glass-edge-light),
1133
+ var(--shadow-dock-override, var(--shadow-dock)),
1134
+ 0 8px 24px color-mix(in srgb, var(--shadow-color) calc(0.14 * var(--dock-wrap-elev)), transparent),
1135
+ 0 0 0 0.5px color-mix(in srgb, var(--shadow-color) calc(0.05 * var(--dock-wrap-elev)), transparent),
1136
+ 0 8px 32px -4px color-mix(in srgb, oklch(0 0 0 / 0.12) var(--dock-wrap-elev), transparent);
917
1137
  }
918
1138
 
919
1139
  .glass-dock.dock-overflow-wrap .dock-layer--full {
@@ -923,15 +1143,12 @@
923
1143
  min-height: var(--dock-wrap-layer-min-height, var(--dock-layer-height, 2rem));
924
1144
  gap: var(--dock-wrap-row-gap, 0.25rem)
925
1145
  var(--dock-wrap-column-gap, var(--dock-layer-gap, 0.375rem));
926
- /* AW.W3b — the graceful wrap-morph. The wrap/unwrap row-reflow flips
927
- `flex-wrap` at the `--dock-overflow-bp` `@media` boundary; without a
928
- transition the rows JUMP-CUT. Sequencing the layer's `min-height`
929
- through the `--dock-motion-resize` spring MORPHS the reflow. The global
930
- PRM gate strips `min-height` from the transition-property under reduce →
931
- the morph snaps (0 morph frames) while the reflow still completes. The
932
- wrap radius swap (`.collapsed` / `@media`) glides too — `border-radius`
933
- is in the shared `:not(.vertical)` transition list (AW.W3b scope 2). */
934
- transition: min-height var(--dock-motion-resize);
1146
+ /* AX.W04 — NO `transition: min-height` JS-morph (the AW.W3b spring-keyed
1147
+ min-height detector is RETIRED — the false `proof:dock-layering-polish`
1148
+ wrap-reflow claim is STRUCK). The reflow is intrinsic flex: rows
1149
+ appear/vanish on the cap crossing with no second clock. The radius +
1150
+ shadow lift ride the `--dock-expand-t` scalar (the W01 single clock),
1151
+ NOT a CSS transition on the retired `--dock-motion-resize` list. */
935
1152
  }
936
1153
 
937
1154
  .glass-dock.dock-overflow-wrap .dock-layer--summary {
@@ -943,10 +1160,15 @@
943
1160
  display: none;
944
1161
  }
945
1162
 
1163
+ /* Collapsed, a wrap dock is the single-row summary PILL. `white-space: nowrap`
1164
+ keeps the summary on one line; the inline cap stays `max-inline-size:
1165
+ var(--dock-max-inline-size)` (inherited from the `.dock-overflow-wrap` rule
1166
+ above) so the collapsed box still shrink-wraps to the small summary's
1167
+ max-content (NOT the full cap). The
1168
+ radius morph resolves to `--radius-pill` at collapsed (--dock-expand-t 0) and
1169
+ the box-shadow to the flat `--shadow-dock` glow (--dock-wrap-elev 0%). */
946
1170
  .glass-dock.dock-overflow-wrap.collapsed {
947
- border-radius: var(--radius-pill);
948
1171
  white-space: nowrap;
949
- max-width: none;
950
1172
  }
951
1173
 
952
1174
  .dock-separator {
@@ -1151,45 +1373,14 @@
1151
1373
  `popover-animate` motion vocabulary. Click-anchored popovers
1152
1374
  (no dock-keep semantics) compose `<Popover>` directly. */
1153
1375
 
1154
- /* The `overflow="wrap"` desktop snap-back. Past the overflow breakpoint a
1155
- wrap-mode dock reverts from the narrow multi-row pill to a single nowrap
1156
- row. The breakpoint is the named token `--dock-overflow-bp` (tokens.css §9
1157
- Layout) — its single source-of-record. A `var()` cannot drive a
1158
- media-query feature in Baseline CSS, so this one `@media` realizes the
1159
- token's value; there is no longer a bare unexplained magic number — the
1160
- threshold lives under one name and is documented at its mint.
1161
- AV.W16 TW3 — KEPT as `@media` (not converted to `@container`): the wrap
1162
- dock is `max-width: calc(100vw - gutter)` — it spans the VIEWPORT by
1163
- contract, so the snap-back is genuinely viewport-semantic. The dock
1164
- establishes its own `dock` container and cannot self-query that
1165
- container for a rule on the dock root; the descendant-readable
1166
- label/density rules above are the container-query candidates. */
1167
- @media (min-width: 640px /* = var(--dock-overflow-bp) */) {
1168
- .glass-dock.dock-overflow-wrap {
1169
- white-space: nowrap;
1170
- border-radius: var(--radius-pill);
1171
- max-width: none;
1172
- padding: var(
1173
- --dock-wrap-desktop-padding-block,
1174
- var(--dock-padding-block, 0.375rem)
1175
- )
1176
- var(--dock-wrap-desktop-padding-inline, 0.75rem);
1177
- }
1178
-
1179
- .glass-dock.dock-overflow-wrap .dock-layer--full {
1180
- flex-wrap: nowrap;
1181
- height: var(--dock-layer-height, 2.5rem);
1182
- gap: var(--dock-wrap-desktop-gap, var(--dock-layer-gap, 0.25rem));
1183
- }
1184
-
1185
- .glass-dock.dock-overflow-wrap .dock-layer--summary {
1186
- height: var(--dock-layer-height, 2.5rem);
1187
- }
1188
-
1189
- .glass-dock.dock-overflow-wrap .dock-separator {
1190
- display: block;
1191
- }
1192
- }
1376
+ /* AX.W04 F0 — the `@media (min-width: 640px)` desktop snap-back + the
1377
+ `--dock-overflow-bp` token are DELETED. The prior viewport breakpoint forced
1378
+ `flex-wrap: nowrap` + `max-width: none` above 640px, so the dock NEVER
1379
+ wrapped on a wide viewport even when its row overflowed (the 800px → 1861px
1380
+ viewport-bleed defect). The wrap is now CONTENT-driven: the always-on
1381
+ `flex-wrap: wrap` + the `max-inline-size: var(--dock-max-inline-size)` cap
1382
+ above (over the base shrink-wrap) reflow to N rows at ANY width on the
1383
+ over-cap crossing — no viewport coupling, no breakpoint. */
1193
1384
 
1194
1385
  /* O.W6 Lane D — Touch-target floor (speedtest AC.W6 F2.AA-03 / WCAG
1195
1386
  2.5.5). On coarse-pointer devices (touch), every dock-control's