@mkbabb/glass-ui 3.8.0 → 3.9.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.
- package/README.md +1 -6
- package/dist/{CardAction-q2qHCJFG.js → CardAction-DuArVky-.js} +4 -4
- package/dist/{CommandShortcut-SzWRhROC.js → CommandShortcut-CefCj5mt.js} +7 -7
- package/dist/{ContextMenuSubContent-Do977Cbf.js → ContextMenuSubContent-Bhg4f5jX.js} +3 -3
- package/dist/{DataTable-CvlWXz65.js → DataTable-CUHMukiQ.js} +1 -1
- package/dist/{DialogContent-DjZWT3lK.js → DialogContent-BRkT1cjP.js} +1 -1
- package/dist/{NumberFieldContent-CLNVR1iY.js → NumberFieldContent-BbLOh8RU.js} +2 -2
- package/dist/{SelectScrollDownButton-C7TRe-ep.js → SelectScrollDownButton-T32cVFeM.js} +3 -3
- package/dist/{SelectSeparator-L8pPEn4L.js → SelectSeparator-C4Ql0gzV.js} +1 -1
- package/dist/{TabsList-qyHZ2lKY.js → TabsList-B8CVOQPC.js} +2 -2
- package/dist/{Toaster-CabYEEF_.js → Toaster-1rYWrmAm.js} +1 -1
- package/dist/{ToggleGroupItem-CkXUcBlt.js → ToggleGroupItem-Cev4pOVK.js} +4 -4
- package/dist/animated-digit.js +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api.js +1 -1
- package/dist/aurora.js +10 -10
- package/dist/{badge-DHQrc_GQ.js → badge-BvwvT50i.js} +4 -4
- package/dist/badge.js +1 -1
- package/dist/{button-CAywcrhO.js → button-DN39cGqL.js} +13 -12
- package/dist/button.js +1 -1
- package/dist/card.js +1 -1
- package/dist/carousel.js +1 -1
- package/dist/color.js +1 -1
- package/dist/command.js +1 -1
- package/dist/{compile-BBTRjvQS.js → compile-DAjIoEy2.js} +1 -1
- package/dist/components/custom/configurator/ConfiguratorLayer.vue.d.ts +1 -1
- package/dist/components/custom/dock/DockSeparator.vue.d.ts +3 -0
- package/dist/components/custom/dock/GlassDock.vue.d.ts +45 -63
- package/dist/components/custom/dock/composables/dockContext.d.ts +7 -0
- package/dist/components/custom/dock/index.d.ts +2 -1
- package/dist/components/custom/goo-blob/composables/useBlobMood.d.ts +19 -5
- package/dist/components/custom/tabs/SegmentedTabs.vue.d.ts +92 -0
- package/dist/components/custom/tabs/composables/useTabIndicator.d.ts +49 -0
- package/dist/components/custom/tabs/index.d.ts +2 -5
- package/dist/components/ui/button/index.d.ts +1 -1
- package/dist/components/ui/card/Card.vue.d.ts +5 -3
- package/dist/components/ui/carousel/CarouselNext.vue.d.ts +1 -1
- package/dist/components/ui/carousel/CarouselPrevious.vue.d.ts +1 -1
- package/dist/components/ui/carousel/GlassCarouselPager.vue.d.ts +3 -4
- package/dist/components/ui/slider/index.d.ts +14 -7
- package/dist/components/ui/tabs/TabsList.vue.d.ts +1 -1
- package/dist/composables/context/createContext.d.ts +1 -1
- package/dist/configurator.js +1 -1
- package/dist/confirm-dialog.js +1 -1
- package/dist/constellation.js +1 -1
- package/dist/context-menu.js +1 -1
- package/dist/controls.js +1 -1
- package/dist/dark.js +1 -1
- package/dist/data-table.js +1 -1
- package/dist/deck-progress.js +1 -1
- package/dist/dialog.js +1 -1
- package/dist/dock.js +256 -243
- package/dist/{dropdown-menu-B_4bWyyG.js → dropdown-menu-D77jX6Df.js} +3 -3
- package/dist/dropdown-menu.js +1 -1
- package/dist/expandable-container.js +1 -1
- package/dist/forms.js +5 -5
- package/dist/fourier-field.js +3 -3
- package/dist/glass-ui.css +1 -1
- package/dist/glass-ui.js +101 -104
- package/dist/goo-blob.js +36 -32
- package/dist/hover-popover.js +1 -1
- package/dist/icon-tooltip.js +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/keyboard.js +1 -1
- package/dist/labeled-field.js +4 -4
- package/dist/{menuItemVariants-DKM85SNE.js → menuItemVariants-CCoBNkU5.js} +1 -1
- package/dist/motion-core.js +4 -4
- package/dist/motion.js +2 -2
- package/dist/number-field.js +1 -1
- package/dist/pulse.js +1 -1
- package/dist/reactive.js +1 -1
- package/dist/scrolling-text.js +1 -1
- package/dist/search.js +4 -4
- package/dist/select.js +2 -2
- package/dist/{slider-D9puf-Ko.js → slider-DC2mwuoe.js} +1 -1
- package/dist/slider.js +1 -1
- package/dist/sortable-list.js +1 -1
- package/dist/status-dot.js +17 -16
- package/dist/styles/animations.css +6 -2
- package/dist/styles/components.css +1 -1
- package/dist/styles/dock/density.css +230 -0
- package/dist/styles/dock/layer-group.css +263 -0
- package/dist/styles/dock/layers.css +355 -0
- package/dist/styles/dock/morph.css +244 -0
- package/dist/styles/dock/overflow.css +201 -0
- package/dist/styles/dock/shell.css +457 -0
- package/dist/styles/dock-controls.css +166 -32
- package/dist/styles/dock.css +42 -1349
- package/dist/styles/glass.css +396 -75
- package/dist/styles/index.css +12 -11
- package/dist/styles/theme.css +51 -0
- package/dist/styles/tokens.css +501 -55
- package/dist/styles/utilities.css +89 -39
- package/dist/tabs.js +182 -151
- package/dist/timeline.js +1 -1
- package/dist/toast.js +1 -1
- package/dist/toggle-group.js +1 -1
- package/dist/{useAnimatedNumber-C_3wZLx4.js → useAnimatedNumber-C5I3wWd8.js} +1 -1
- package/dist/{useConfiguratorState-CMff4GzH.js → useConfiguratorState-DxAqksK6.js} +21 -10
- package/dist/watercolor-dot.js +1 -1
- package/package.json +32 -33
- package/src/styles/animations.css +6 -2
- package/src/styles/dock/density.css +230 -0
- package/src/styles/dock/layer-group.css +263 -0
- package/src/styles/dock/layers.css +355 -0
- package/src/styles/dock/morph.css +244 -0
- package/src/styles/dock/overflow.css +201 -0
- package/src/styles/dock/shell.css +457 -0
- package/src/styles/dock-controls.css +166 -32
- package/src/styles/dock.css +42 -1349
- package/src/styles/glass.css +396 -75
- package/src/styles/index.css +12 -11
- package/src/styles/theme.css +51 -0
- package/src/styles/tokens.css +501 -55
- package/src/styles/utilities.css +89 -39
- package/dist/DiscoGlyph-CG0F410s.js +0 -132
- package/dist/GlyphFace-DRjDkB0s.js +0 -51
- package/dist/UnderlineTabs-Uxn-R3MT.js +0 -39
- package/dist/components/custom/aurora/constants/shaders/painterly.wgsl.d.ts +0 -7
- package/dist/components/custom/aurora/constants/shaders/wake.wgsl.d.ts +0 -4
- package/dist/components/custom/disco-glyph/DiscoGlyph.vue.d.ts +0 -58
- package/dist/components/custom/disco-glyph/index.d.ts +0 -1
- package/dist/components/custom/glass-carousel/GlassCarousel.vue.d.ts +0 -36
- package/dist/components/custom/glass-carousel/GlassCarouselItem.vue.d.ts +0 -28
- package/dist/components/custom/glass-carousel/index.d.ts +0 -4
- package/dist/components/custom/glass-carousel/useGlassCarousel.d.ts +0 -30
- package/dist/components/custom/glyph-face/GlyphFace.vue.d.ts +0 -64
- package/dist/components/custom/glyph-face/index.d.ts +0 -2
- package/dist/components/custom/glyph-face/keys.d.ts +0 -9
- package/dist/components/custom/responsive-tabs/ResponsiveTabs.vue.d.ts +0 -73
- package/dist/components/custom/responsive-tabs/index.d.ts +0 -2
- package/dist/components/custom/tabs/BouncyTabs.vue.d.ts +0 -27
- package/dist/components/custom/tabs/BouncyToggle.vue.d.ts +0 -60
- package/dist/components/custom/tabs/UnderlineTabs.vue.d.ts +0 -20
- package/dist/components/custom/tabs/composables/useBouncySlider.d.ts +0 -39
- package/dist/disco-glyph.d.ts +0 -1
- package/dist/disco-glyph.js +0 -2
- package/dist/glass-carousel.d.ts +0 -1
- package/dist/glass-carousel.js +0 -219
- package/dist/glyph-face.d.ts +0 -1
- package/dist/glyph-face.js +0 -3
- package/dist/keys-BsYjEFOW.js +0 -9
- package/dist/responsive-tabs.d.ts +0 -1
- package/dist/responsive-tabs.js +0 -95
- package/dist/styles/disco-glyph.css +0 -26
- package/dist/styles/glyph-face.css +0 -92
- package/src/styles/disco-glyph.css +0 -26
- package/src/styles/glyph-face.css +0 -92
- /package/dist/{DeckProgress-AVgbIULY.js → DeckProgress-Dmk4_AKN.js} +0 -0
- /package/dist/{HoverPopover-D56O6Ylp.js → HoverPopover-2LOIW34a.js} +0 -0
- /package/dist/{IconTooltip-D2T5nYOM.js → IconTooltip-yefK7cJc.js} +0 -0
- /package/dist/{Input-DVG_J0ne.js → Input-DWQQIOC4.js} +0 -0
- /package/dist/{ScrollingText-CVyqxvfv.js → ScrollingText-BPP84wKo.js} +0 -0
- /package/dist/{color-DMLTunJK.js → color-8jBjWiJ6.js} +0 -0
- /package/dist/{constants-BPOqYJAm.js → constants-CS75AWHG.js} +0 -0
- /package/dist/{presets-D1XPuTj-.js → presets-BKVyQfbt.js} +0 -0
- /package/dist/{prng-COGhh02-.js → prng-wHuHlNHE.js} +0 -0
- /package/dist/{useGlobalDark-D3EBWzXK.js → useGlobalDark-yhL4Wp-s.js} +0 -0
- /package/dist/{useIntersectionPause-Bj4sPkMh.js → useIntersectionPause-Cc-H9ees.js} +0 -0
- /package/dist/{useInterval-CcLfq2WU.js → useInterval-Dsmqwi03.js} +0 -0
- /package/dist/{useKeyboardShortcuts-BXWXOZ-9.js → useKeyboardShortcuts-Be3w_Rwk.js} +0 -0
- /package/dist/{useScrollProgress-C9ysDic5.js → useScrollProgress-CAH8Ofwt.js} +0 -0
- /package/dist/{useSortable-MGAbCGVJ.js → useSortable-C8ReQ50P.js} +0 -0
- /package/dist/{useTextHighlight-9nMW23Qb.js → useTextHighlight-DON84L8w.js} +0 -0
package/src/styles/dock.css
CHANGED
|
@@ -1,9 +1,45 @@
|
|
|
1
1
|
/* Dock primitives exported through @mkbabb/glass-ui/styles.
|
|
2
2
|
*
|
|
3
|
-
* This file is the
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
|
|
3
|
+
* This file is the CORE of the dock component family — the `@property
|
|
4
|
+
* --dock-morph-t` registration, the @layer-components OPEN, the SHARED
|
|
5
|
+
* cross-control four-state contract (the :focus-visible / :disabled comma-groups
|
|
6
|
+
* + the motion-token :where() group — they reference every control selector but
|
|
7
|
+
* are shared, so they live at the import root, not per-control), and the
|
|
8
|
+
* `@import`s of the cohesive `dock/*.css` partials.
|
|
9
|
+
*
|
|
10
|
+
* AX.W06 — the 1762-line dock.css god-module (slice 25) was CARVED into
|
|
11
|
+
* src/styles/dock/ cohesive single-axis partials, each under the 500-line bound,
|
|
12
|
+
* @import-ed below in cascade order into the SAME `@layer components` so the
|
|
13
|
+
* carve is isomorphic (same layer, same source order → ZERO visual delta):
|
|
14
|
+
* - dock/shell.css — the `.glass-dock` structural skeleton (root, W02
|
|
15
|
+
* morph-clip aperture, grain, vertical-root, shape /
|
|
16
|
+
* variant plates, position, W45 #persistent + vertical
|
|
17
|
+
* three-region body).
|
|
18
|
+
* - dock/morph.css — the W01 single-scalar morph chrome + state response
|
|
19
|
+
* (--dock-expand-t interp, collapsed/summary, held /
|
|
20
|
+
* open, the W55 adaptive-legibility bucket).
|
|
21
|
+
* - dock/density.css — the W45 density × --dock-scale cascade.
|
|
22
|
+
* - dock/layers.css — the `.dock-layer` crossfade + hit-test + reveal-
|
|
23
|
+
* stagger contract + the `layout="grid"` tile grid.
|
|
24
|
+
* - dock/layer-group.css — `.dock-layer-group` / layer-switcher rail / stack.
|
|
25
|
+
* - dock/overflow.css — the `overflow=` scroll/wrap strategies + the coarse
|
|
26
|
+
* multiplier.
|
|
27
|
+
*
|
|
28
|
+
* The FIVE interactive control families stay in dock-controls.css (the AU.W8b.3
|
|
29
|
+
* carve, @import-ed by index.css directly after this file). The Vue SFCs own
|
|
30
|
+
* structure + runtime behavior; selectors, motion, glass, and layering tokens
|
|
31
|
+
* live here + in the partials so consumers have one public CSS path. */
|
|
32
|
+
|
|
33
|
+
/* CSS `@import` rules must precede every other rule (a `@property`/`@layer`
|
|
34
|
+
block after an `@import` would render it invalid + dropped). The six partials
|
|
35
|
+
@import in cascade order; each opens its own `@layer components` so the layered
|
|
36
|
+
cascade is preserved bit-for-bit (the carve-isomorphism gate is the witness). */
|
|
37
|
+
@import "./dock/shell.css";
|
|
38
|
+
@import "./dock/morph.css";
|
|
39
|
+
@import "./dock/density.css";
|
|
40
|
+
@import "./dock/layers.css";
|
|
41
|
+
@import "./dock/layer-group.css";
|
|
42
|
+
@import "./dock/overflow.css";
|
|
7
43
|
|
|
8
44
|
/* AX.W01 — the SINGLE morph scalar. `useLayerTransition` writes it once per frame
|
|
9
45
|
to the `.glass-dock` root; EVERY morph axis (box size, padding, radius, scale,
|
|
@@ -55,7 +91,8 @@
|
|
|
55
91
|
group keeps full class+pseudo specificity (NOT `:where()`, which would
|
|
56
92
|
zero the class and let a per-control :hover box-shadow override the focus
|
|
57
93
|
ring). Per-control transition extensions (the box-shadow fade on
|
|
58
|
-
focus-visible) stay with their own selectors
|
|
94
|
+
focus-visible) stay with their own selectors in dock-controls.css where
|
|
95
|
+
they differ. */
|
|
59
96
|
.dock-icon-button:focus-visible,
|
|
60
97
|
.dock-tab-button:focus-visible,
|
|
61
98
|
.dock-select-trigger:focus-visible,
|
|
@@ -71,1348 +108,4 @@
|
|
|
71
108
|
opacity: var(--opacity-disabled);
|
|
72
109
|
cursor: not-allowed;
|
|
73
110
|
}
|
|
74
|
-
|
|
75
|
-
.glass-dock {
|
|
76
|
-
--dock-surface-blur: var(--glass-blur-dock, var(--glass-blur-wash));
|
|
77
|
-
/* J.W3.C — vertical-rail max-block + horizontal max-inline caps
|
|
78
|
-
live as semantic tokens (defaults in `tokens.css`). When
|
|
79
|
-
content exceeds the cap, the appropriate axis container
|
|
80
|
-
scrolls with a mask-fade. Consumers override per-instance by
|
|
81
|
-
setting `--dock-max-block-size` / `--dock-max-inline-size`
|
|
82
|
-
on a `.glass-dock` directly. */
|
|
83
|
-
--dock-separator-height: calc(var(--dock-h, var(--size-icon-btn)) * 0.5);
|
|
84
|
-
--dock-collapsed-hover-scale: var(--scale-hover-dock);
|
|
85
|
-
/* AW.W3 — the spring-keyed child stagger knobs. `--dock-stagger-window-size`
|
|
86
|
-
is the fraction of the morph each child reveals over; `--dock-stagger-rise`
|
|
87
|
-
is the px the child rises from as it fades in. Consumers retune the
|
|
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. */
|
|
100
|
-
--dock-stagger-window-size: 0.55;
|
|
101
|
-
--dock-stagger-rise: 4px;
|
|
102
|
-
--dock-stagger-step: 0.08;
|
|
103
|
-
/* AW.W3b — big-dock tokens. `--dock-card-radius` is the finite card-shell
|
|
104
|
-
radius (default --radius-dock-card = --radius-3xl, density-scaled
|
|
105
|
-
below); `--dock-tile-min` is the grid tile minimum (auto-fill track
|
|
106
|
-
floor). Both are density-scaled (compact tighter, spacious looser) — the
|
|
107
|
-
card radius + tile size ride the density cascade, never magic numbers. */
|
|
108
|
-
--dock-card-radius: var(--radius-dock-card);
|
|
109
|
-
--dock-tile-min: 4.5rem;
|
|
110
|
-
/* Individual-transform identity base (AQ.W3 §W3.2). `scale: 1` at rest
|
|
111
|
-
mints the stacking context once so a portaled popover over `--z-dock`
|
|
112
|
-
stays above the dock during a hover scale (the load-bearing
|
|
113
|
-
stacking-context guarantee). Covers every dock scale site. */
|
|
114
|
-
scale: 1;
|
|
115
|
-
position: relative;
|
|
116
|
-
display: inline-flex;
|
|
117
|
-
align-items: center;
|
|
118
|
-
/* AW.W1 — the dock does NOT establish a default inline-size container.
|
|
119
|
-
`container-type: inline-size` applies `contain: inline-size`, which
|
|
120
|
-
makes an element's inline size INDEPENDENT of its contents — fatally
|
|
121
|
-
incompatible with a shrink-to-fit pill: under it `.glass-dock` cannot
|
|
122
|
-
size to its content and collapses to its padding floor (~19px) with the
|
|
123
|
-
active layer overflowing (the 3.3.0 regression — every horizontal dock,
|
|
124
|
-
collapsed AND always-expanded, rendered as a sliver). The `dock`-named
|
|
125
|
-
container is now OPT-IN via the `containerName` prop: a consumer
|
|
126
|
-
embedding the dock in a width-CONSTRAINED host (a 320px sidebar) sets
|
|
127
|
-
`containerName="dock"` to get the descendant container-query reads (the
|
|
128
|
-
audacious-label compression below), trading shrink-to-fit for the
|
|
129
|
-
host-constrained width it already has there. The default free-floating
|
|
130
|
-
dock shrink-wraps to its content (AV.W16 TW3 made this a default and
|
|
131
|
-
silently broke dock sizing for the common case). */
|
|
132
|
-
border-radius: var(--radius-dock);
|
|
133
|
-
white-space: nowrap;
|
|
134
|
-
max-inline-size: var(--dock-max-inline-size);
|
|
135
|
-
padding: var(--dock-padding-block, 0.375rem) var(--dock-padding-inline, 0.5rem);
|
|
136
|
-
background: var(--glass-bg-dock, var(--glass-bg-resting));
|
|
137
|
-
backdrop-filter: var(--dock-surface-blur);
|
|
138
|
-
border: 1.5px solid var(--glass-border-dock, var(--glass-border-resting));
|
|
139
|
-
/* AV.W15 M3 — the full-perimeter `--glass-edge-light` rim rides as the
|
|
140
|
-
leading inset layer of the dock shadow stack (the navigation-band
|
|
141
|
-
silhouette catch-light, distinct from the top-only highlight). */
|
|
142
|
-
box-shadow: var(--glass-edge-light), var(--shadow-dock-override, var(--shadow-dock));
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/* AW.W2 — the box IS the reveal aperture (clip-reveal one-clock morph).
|
|
146
|
-
Migrated from `overflow: hidden` to a SINGLE-AXIS `overflow: clip` on the
|
|
147
|
-
MORPH axis (horizontal clips X / visible Y; vertical clips Y / visible X),
|
|
148
|
-
gated on a `data-morphing` attribute the driver owns (set at gesture START,
|
|
149
|
-
cleared on SETTLE). The clip PERSISTS through the morph — content is laid
|
|
150
|
-
out ONCE at its natural size behind the aperture and the growing/shrinking
|
|
151
|
-
box uncovers it, never spills it — and lifts to `visible` only at REST
|
|
152
|
-
expanded (so grown content + the focus ring paint past the box). The
|
|
153
|
-
prior `.expanded { overflow: visible }` (bound synchronously to
|
|
154
|
-
`visualExpanded`) lifted the clip at frame 0, leaving no aperture to reveal
|
|
155
|
-
through; the `:not([data-morphing])` guard holds the clip for the whole
|
|
156
|
-
gesture and lifts it on the final paint.
|
|
157
|
-
|
|
158
|
-
`overflow: clip` is PAINT-ONLY (not a scroll container): it never
|
|
159
|
-
participates in `scrollIntoView`/scroll-anchoring, cannot be a
|
|
160
|
-
scroll-driven-animation `scroller`, and drops the `min-width:0` scroll-box
|
|
161
|
-
dance for the non-scroll shell. The cross axis is ALWAYS explicitly
|
|
162
|
-
`visible` (the MDN single-axis-clip-degrades-to-hidden caveat). The
|
|
163
|
-
legitimate scroll ports (`.dock-scroll-{x,y}`, `overflow: auto`) STAY
|
|
164
|
-
`auto` — they are NOT migrated. AT.W7-dock-a's orthogonality holds: the
|
|
165
|
-
`containerName` opt-in does not touch the clip. */
|
|
166
|
-
.glass-dock:not(.vertical) {
|
|
167
|
-
overflow-x: clip;
|
|
168
|
-
overflow-y: visible;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
.glass-dock.vertical {
|
|
172
|
-
overflow-x: visible;
|
|
173
|
-
overflow-y: clip;
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
/* DURING a morph the clip is the aperture — keyed off `data-morphing`, NOT
|
|
177
|
-
off `.expanded`, so it survives the whole gesture and the box reveals its
|
|
178
|
-
content rather than letting it spill. */
|
|
179
|
-
.glass-dock[data-morphing]:not(.vertical) {
|
|
180
|
-
overflow-x: clip;
|
|
181
|
-
overflow-y: visible;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
.glass-dock[data-morphing].vertical {
|
|
185
|
-
overflow-x: visible;
|
|
186
|
-
overflow-y: clip;
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/* AT REST EXPANDED — lift the morph-axis clip (grown content + focus ring
|
|
190
|
-
paint past the box). Fires ONLY when NOT morphing; the [data-morphing]
|
|
191
|
-
rules above win during the gesture by being more specific + later. */
|
|
192
|
-
.glass-dock.expanded:not([data-morphing]),
|
|
193
|
-
.glass-dock.always-expanded:not([data-morphing]) {
|
|
194
|
-
overflow: visible;
|
|
195
|
-
}
|
|
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
|
-
|
|
221
|
-
.glass-dock[data-density="compact"] {
|
|
222
|
-
--dock-padding-block: var(--dock-density-compact-padding-block, 0.25rem);
|
|
223
|
-
--dock-padding-inline: var(--dock-density-compact-padding-inline, 0.375rem);
|
|
224
|
-
--dock-control-size: var(--dock-density-compact-control-size, 2rem);
|
|
225
|
-
--dock-layer-height: var(--dock-density-compact-layer-height, 2rem);
|
|
226
|
-
--dock-layer-gap: var(--dock-density-compact-gap, 0.25rem);
|
|
227
|
-
--dock-trigger-padding-block: var(
|
|
228
|
-
--dock-density-compact-trigger-padding-block,
|
|
229
|
-
0.1875rem
|
|
230
|
-
);
|
|
231
|
-
--dock-trigger-padding-inline: var(
|
|
232
|
-
--dock-density-compact-trigger-padding-inline,
|
|
233
|
-
0.4375rem
|
|
234
|
-
);
|
|
235
|
-
--dock-tab-padding-block: var(
|
|
236
|
-
--dock-density-compact-tab-padding-block,
|
|
237
|
-
0.3125rem
|
|
238
|
-
);
|
|
239
|
-
--dock-tab-padding-inline: var(
|
|
240
|
-
--dock-density-compact-tab-padding-inline,
|
|
241
|
-
0.625rem
|
|
242
|
-
);
|
|
243
|
-
--dock-tab-h: 32px;
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
/* Comfortable density — the GlassDock default. Sits between compact
|
|
247
|
-
and spacious. */
|
|
248
|
-
.glass-dock[data-density="comfortable"] {
|
|
249
|
-
--dock-padding-block: var(--dock-density-comfortable-padding-block, 0.375rem);
|
|
250
|
-
--dock-padding-inline: var(--dock-density-comfortable-padding-inline, 0.5rem);
|
|
251
|
-
--dock-control-size: var(--dock-density-comfortable-control-size, 2.5rem);
|
|
252
|
-
--dock-layer-height: var(--dock-density-comfortable-layer-height, 2.5rem);
|
|
253
|
-
--dock-layer-gap: var(--dock-density-comfortable-gap, 0.375rem);
|
|
254
|
-
--dock-trigger-padding-block: var(
|
|
255
|
-
--dock-density-comfortable-trigger-padding-block,
|
|
256
|
-
0.25rem
|
|
257
|
-
);
|
|
258
|
-
--dock-trigger-padding-inline: var(
|
|
259
|
-
--dock-density-comfortable-trigger-padding-inline,
|
|
260
|
-
0.5rem
|
|
261
|
-
);
|
|
262
|
-
--dock-tab-padding-block: var(
|
|
263
|
-
--dock-density-comfortable-tab-padding-block,
|
|
264
|
-
0.4375rem
|
|
265
|
-
);
|
|
266
|
-
--dock-tab-padding-inline: var(
|
|
267
|
-
--dock-density-comfortable-tab-padding-inline,
|
|
268
|
-
0.75rem
|
|
269
|
-
);
|
|
270
|
-
--dock-tab-h: 38px;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
.glass-dock[data-density="spacious"] {
|
|
274
|
-
--dock-padding-block: var(--dock-density-spacious-padding-block, 0.5rem);
|
|
275
|
-
--dock-padding-inline: var(--dock-density-spacious-padding-inline, 0.75rem);
|
|
276
|
-
--dock-control-size: var(--dock-density-spacious-control-size, 2.75rem);
|
|
277
|
-
--dock-layer-height: var(--dock-density-spacious-layer-height, 2.75rem);
|
|
278
|
-
--dock-layer-gap: var(--dock-density-spacious-gap, 0.5rem);
|
|
279
|
-
--dock-trigger-padding-block: var(
|
|
280
|
-
--dock-density-spacious-trigger-padding-block,
|
|
281
|
-
0.375rem
|
|
282
|
-
);
|
|
283
|
-
--dock-trigger-padding-inline: var(
|
|
284
|
-
--dock-density-spacious-trigger-padding-inline,
|
|
285
|
-
0.625rem
|
|
286
|
-
);
|
|
287
|
-
--dock-tab-padding-block: var(
|
|
288
|
-
--dock-density-spacious-tab-padding-block,
|
|
289
|
-
0.5rem
|
|
290
|
-
);
|
|
291
|
-
--dock-tab-padding-inline: var(
|
|
292
|
-
--dock-density-spacious-tab-padding-inline,
|
|
293
|
-
0.875rem
|
|
294
|
-
);
|
|
295
|
-
--dock-tab-h: 44px;
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
/* Audacious density — typography-forward chrome where the dock reads as
|
|
299
|
-
a primary surface, not a tray. Tab buttons set their own min-height so
|
|
300
|
-
consumer-bumped fonts no longer drift the button height — the
|
|
301
|
-
`--dock-tab-min-height` token reserves the row regardless of glyph rise. */
|
|
302
|
-
.glass-dock[data-density="audacious"] {
|
|
303
|
-
--dock-padding-block: var(--dock-density-audacious-padding-block, 0.5rem);
|
|
304
|
-
--dock-padding-inline: var(--dock-density-audacious-padding-inline, 0.875rem);
|
|
305
|
-
--dock-control-size: var(--dock-density-audacious-control-size, 4rem);
|
|
306
|
-
--dock-layer-height: var(--dock-density-audacious-layer-height, 4rem);
|
|
307
|
-
--dock-layer-gap: var(--dock-density-audacious-gap, 0.875rem);
|
|
308
|
-
--dock-trigger-padding-block: var(
|
|
309
|
-
--dock-density-audacious-trigger-padding-block,
|
|
310
|
-
0.625rem
|
|
311
|
-
);
|
|
312
|
-
--dock-trigger-padding-inline: var(
|
|
313
|
-
--dock-density-audacious-trigger-padding-inline,
|
|
314
|
-
1rem
|
|
315
|
-
);
|
|
316
|
-
--dock-tab-padding-block: var(
|
|
317
|
-
--dock-density-audacious-tab-padding-block,
|
|
318
|
-
0.5rem
|
|
319
|
-
);
|
|
320
|
-
--dock-tab-padding-inline: var(
|
|
321
|
-
--dock-density-audacious-tab-padding-inline,
|
|
322
|
-
1.5rem
|
|
323
|
-
);
|
|
324
|
-
--dock-tab-min-height: var(--dock-density-audacious-tab-min-height, 3.5rem);
|
|
325
|
-
--dock-tab-h: var(--dock-density-audacious-tab-min-height, 3.5rem);
|
|
326
|
-
}
|
|
327
|
-
|
|
328
|
-
/* Density-audacious narrow-box carve (AV.W16 TW3) — when the dock's OWN
|
|
329
|
-
box is narrow the audacious-dock label glyphs compress so the chrome
|
|
330
|
-
doesn't overflow its host (≤14px below 30rem, 15px 30–45rem). Keyed off
|
|
331
|
-
the dock's `dock` inline-size container — now OPT-IN via the
|
|
332
|
-
`containerName="dock"` prop (AW.W1 removed the always-on default that
|
|
333
|
-
broke shrink-to-fit), so it fires only for a dock the consumer has
|
|
334
|
-
width-CONSTRAINED into a host (the 320px sidebar case) where the
|
|
335
|
-
compression is meaningful and the containment does not collapse the box.
|
|
336
|
-
A free-floating dock shrink-wraps (box == content) so there is nothing to
|
|
337
|
-
compress. The var
|
|
338
|
-
is set on the `.dock-label` descendant (which reads it via
|
|
339
|
-
`font-size: var(--dock-label-size)`, typography.css). Thresholds keep
|
|
340
|
-
the prior 479/719px viewport cadence as box widths (30rem ≈ 480px,
|
|
341
|
-
45rem ≈ 720px at the 16px root). */
|
|
342
|
-
@container dock (max-width: 29.9375rem) {
|
|
343
|
-
.glass-dock[data-density="audacious"] .dock-label {
|
|
344
|
-
--dock-label-size: 14px;
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
@container dock (min-width: 30rem) and (max-width: 44.9375rem) {
|
|
348
|
-
.glass-dock[data-density="audacious"] .dock-label {
|
|
349
|
-
--dock-label-size: 15px;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
.glass-dock::after {
|
|
354
|
-
content: "";
|
|
355
|
-
position: absolute;
|
|
356
|
-
inset: 0;
|
|
357
|
-
border-radius: inherit;
|
|
358
|
-
background: var(--paper-clean-texture);
|
|
359
|
-
background-repeat: repeat;
|
|
360
|
-
background-size: var(--paper-texture-size);
|
|
361
|
-
opacity: var(--glass-grain-opacity);
|
|
362
|
-
pointer-events: none;
|
|
363
|
-
mix-blend-mode: overlay;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
.dark .glass-dock::after {
|
|
367
|
-
mix-blend-mode: soft-light;
|
|
368
|
-
}
|
|
369
|
-
|
|
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. */
|
|
463
|
-
.glass-dock.vertical {
|
|
464
|
-
display: inline-flex;
|
|
465
|
-
flex-direction: column;
|
|
466
|
-
align-items: stretch;
|
|
467
|
-
justify-content: flex-start;
|
|
468
|
-
gap: 0.25rem;
|
|
469
|
-
white-space: normal;
|
|
470
|
-
width: auto;
|
|
471
|
-
height: auto;
|
|
472
|
-
max-block-size: var(--dock-max-block-size);
|
|
473
|
-
/* overflow on the block (morph) axis is the data-morphing-gated clip
|
|
474
|
-
shell above; the cross axis stays visible there. */
|
|
475
|
-
padding: var(--dock-vertical-padding, var(--dock-padding-block, 0.375rem));
|
|
476
|
-
border-radius: var(--radius-dock);
|
|
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
|
|
482
|
-
(height) morph is owned by the inner `.dock-layer-stack` / DockLayerGroup
|
|
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. */
|
|
487
|
-
transition:
|
|
488
|
-
box-shadow var(--dock-motion-standard),
|
|
489
|
-
transform var(--dock-motion-resize),
|
|
490
|
-
scale var(--dock-motion-resize);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
.glass-dock.variant-rail {
|
|
494
|
-
padding: var(--dock-rail-padding, var(--dock-padding-inline, 0.5rem));
|
|
495
|
-
background: var(--glass-bg-dock, var(--glass-bg-wash));
|
|
496
|
-
border-color: var(--glass-border-dock, var(--glass-border-wash));
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
.glass-dock.variant-rail.shape-pill {
|
|
500
|
-
border-radius: var(--radius-pill);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
.glass-dock.variant-rail.shape-rounded {
|
|
504
|
-
border-radius: var(--radius-xl);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
/* AW.W3b — horizontal-root shape rules. The `shape-*` class previously bound
|
|
508
|
-
ONLY under `.variant-rail`; on a horizontal `variant-dock` the prop silently
|
|
509
|
-
no-op'd (the root hardwired `--radius-dock` = `--radius-pill`). These rules
|
|
510
|
-
close that documented-but-dead prop — `shape="rounded"` / `shape="card"` now
|
|
511
|
-
paint on a horizontal dock. Scoped to `variant-dock:not(.vertical)` so the
|
|
512
|
-
rail + instrument-strip variants (which own their own radius) are untouched. */
|
|
513
|
-
.glass-dock.variant-dock:not(.vertical).shape-rounded {
|
|
514
|
-
border-radius: var(--radius-xl);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/* The big-dock CARD shell — a FINITE concentric radius above 2xl, below pill.
|
|
518
|
-
It does NOT collapse to a stadium. Collapsed it returns to a pill (the morph
|
|
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. */
|
|
525
|
-
.glass-dock.variant-dock:not(.vertical).shape-card {
|
|
526
|
-
border-radius: calc(
|
|
527
|
-
var(--radius-pill) +
|
|
528
|
-
(var(--dock-card-radius) - var(--radius-pill)) *
|
|
529
|
-
var(--dock-expand-t, 1)
|
|
530
|
-
);
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
/* The squircle reads markedly better at the large card radius — an
|
|
534
|
-
`@supports`-gated ENHANCEMENT only (Chrome 139+, no FF/Safari 2026). The
|
|
535
|
-
border-radius arc is the CONTRACT; the squircle is the better tier (the
|
|
536
|
-
baseline arc is the acceptable contract, NOT a degraded fallback). */
|
|
537
|
-
@supports (corner-shape: squircle) {
|
|
538
|
-
.glass-dock.variant-dock:not(.vertical).shape-card {
|
|
539
|
-
corner-shape: squircle;
|
|
540
|
-
}
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
/* AJ-W1-δ — `instrument-strip` variant (per G-AJ-D7 Path 1).
|
|
544
|
-
*
|
|
545
|
-
* The speedtest survey cockpit's vertical rail needs chassis-strip
|
|
546
|
-
* aesthetics, not the dock-rail's stadium-pill chrome. Adopts the
|
|
547
|
-
* surface vocabulary of the `<InstrumentChassis>` family so the
|
|
548
|
-
* strip reads as a journey-station slot — the same surface the
|
|
549
|
-
* speedtest + complete + thankyou stations ride.
|
|
550
|
-
*
|
|
551
|
-
* The variant intentionally inherits the rail variant's vertical
|
|
552
|
-
* layout (orientation: vertical; flex-direction: column) — the
|
|
553
|
-
* orientation + fitContent computeds in GlassDock.vue branch on
|
|
554
|
-
* `variant === "instrument-strip"` alongside the existing rail
|
|
555
|
-
* branch. Only the surface vocabulary changes vs the rail:
|
|
556
|
-
* - Border-radius drops from `--radius-pill` to `--radius-card`
|
|
557
|
-
* (matches `<InstrumentChassis> { border-radius: var(--radius-card) }`).
|
|
558
|
-
* - Background plate routes through `--glass-bg-chassis` (0.28α
|
|
559
|
-
* per tokens.css §V) instead of `--glass-bg-wash`.
|
|
560
|
-
* - Border routes through `--glass-border-quiet` to match the
|
|
561
|
-
* chassis primitive's at-rest stroke.
|
|
562
|
-
* - Box-shadow routes through `--glass-shadow-quiet` plus the
|
|
563
|
-
* inset-bottom hairline matching the chassis primitive
|
|
564
|
-
* (instrument-chassis.css:42-45).
|
|
565
|
-
*
|
|
566
|
-
* The `.shape-pill` / `.shape-rounded` class hooks are still emitted
|
|
567
|
-
* by the template but no rule binds them under
|
|
568
|
-
* `.variant-instrument-strip` — chassis-strip carries ONE canonical
|
|
569
|
-
* border-radius (`--radius-card`), per the chassis family. */
|
|
570
|
-
.glass-dock.variant-instrument-strip {
|
|
571
|
-
padding: var(
|
|
572
|
-
--dock-instrument-strip-padding,
|
|
573
|
-
var(--dock-padding-inline, 0.75rem)
|
|
574
|
-
);
|
|
575
|
-
background: var(--glass-bg-chassis, var(--glass-bg-wash));
|
|
576
|
-
border: 1px solid var(--glass-border-quiet, var(--glass-border-resting));
|
|
577
|
-
border-radius: var(--radius-card);
|
|
578
|
-
box-shadow:
|
|
579
|
-
var(--glass-shadow-quiet, var(--shadow-dock)),
|
|
580
|
-
inset 0 -0.5px 0 0 rgb(0 0 0 / 0.06);
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
/* Engraved-bezel inner stroke — matches `<InstrumentChassis>::before`
|
|
584
|
-
* (instrument-chassis.css:85-93). The chassis-strip silhouette without
|
|
585
|
-
* this stroke reads as a flat plate; with it the strip reads as the
|
|
586
|
-
* polished sleeve of an instrument-panel module. The `::before`
|
|
587
|
-
* z-index sits above the chassis backdrop but below the slotted
|
|
588
|
-
* content (the MetricBadge stack), matching the chassis primitive's
|
|
589
|
-
* z-order. The host `.glass-dock` is already `position: relative`. */
|
|
590
|
-
.glass-dock.variant-instrument-strip::before {
|
|
591
|
-
content: "";
|
|
592
|
-
position: absolute;
|
|
593
|
-
inset: 0.5px;
|
|
594
|
-
border-radius: calc(var(--radius-card) - 0.5px);
|
|
595
|
-
border: 1px solid var(--surface-tint-4);
|
|
596
|
-
pointer-events: none;
|
|
597
|
-
z-index: 1;
|
|
598
|
-
}
|
|
599
|
-
|
|
600
|
-
.dark .glass-dock.variant-instrument-strip::before {
|
|
601
|
-
border-color: var(--surface-tint-6);
|
|
602
|
-
}
|
|
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). */
|
|
611
|
-
.glass-dock.collapsed {
|
|
612
|
-
cursor: pointer;
|
|
613
|
-
justify-content: center;
|
|
614
|
-
box-shadow: var(--shadow-dock-override, var(--shadow-dock-collapsed));
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
.glass-dock.collapsed .dock-layer--summary {
|
|
618
|
-
min-width: var(
|
|
619
|
-
--dock-collapsed-summary-min-size,
|
|
620
|
-
var(--dock-layer-height, 2.5rem)
|
|
621
|
-
);
|
|
622
|
-
justify-content: center;
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
/* AW.W3 — the collapsed-hover scale rides the unified dock spring vocabulary.
|
|
626
|
-
The `scale var(--dock-motion-resize)` arm was added to the `.glass-dock`
|
|
627
|
-
root transition above, so this hover scale settles on the SAME spring curve
|
|
628
|
-
the expand morph uses — a collapsed→hover→expand gesture is one continuous
|
|
629
|
-
spring, not a `scale`-ease handed off to the width-spring. The hover scale
|
|
630
|
-
and the press squish (`--scale-press-dock`) are now one register on the dock
|
|
631
|
-
surface. */
|
|
632
|
-
.glass-dock.collapsed:hover {
|
|
633
|
-
background: var(--glass-bg-wash);
|
|
634
|
-
border-color: var(--glass-border-floating);
|
|
635
|
-
box-shadow: var(--shadow-dock-override, var(--shadow-dock));
|
|
636
|
-
scale: var(--dock-collapsed-hover-scale);
|
|
637
|
-
}
|
|
638
|
-
|
|
639
|
-
/* J.W5.C — held-state substrate response.
|
|
640
|
-
*
|
|
641
|
-
* When a descendant signals `dockKeepOpen` (e.g. an active slider drag),
|
|
642
|
-
* `useDockState.isHeld` flips true and the root carries `data-held`.
|
|
643
|
-
* The dock background lifts a tier (resting → floating-equivalent) and
|
|
644
|
-
* the border quiets to the floating ring; the change tracks pointer
|
|
645
|
-
* movement on `--duration-fast` so it reads as a held-cursor cue, not
|
|
646
|
-
* a state change. The same flag is consumed by descendants (Slider
|
|
647
|
-
* thumb halo) via `useOptionalDockContext().held` for cross-substrate
|
|
648
|
-
* coordination (typed-key canonical shape; O.W2 invariant 25).
|
|
649
|
-
*/
|
|
650
|
-
.glass-dock[data-held] {
|
|
651
|
-
background: var(--glass-bg-floating, var(--glass-bg-resting));
|
|
652
|
-
border-color: var(--glass-border-floating, var(--glass-border-resting));
|
|
653
|
-
transition:
|
|
654
|
-
background var(--duration-fast) var(--ease-standard),
|
|
655
|
-
border-color var(--duration-fast) var(--ease-standard),
|
|
656
|
-
box-shadow var(--duration-fast) var(--ease-standard);
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
/* AQ.W3 §W3.1b — open-descendant surface response. When a dock-hosted
|
|
660
|
-
trigger (`[data-state="open"]`) is open, the dock root holds its elevated
|
|
661
|
-
read natively (no consumer JS). Idempotent with `[data-held]` above (same
|
|
662
|
-
floating paint, different trigger). Decorative; `:has()` Baseline Widely. */
|
|
663
|
-
.glass-dock:has([data-state="open"]) {
|
|
664
|
-
background: var(--glass-bg-floating, var(--glass-bg-resting));
|
|
665
|
-
border-color: var(--glass-border-floating, var(--glass-border-resting));
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
.glass-dock:where(.fixed) {
|
|
669
|
-
z-index: var(--z-dock);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
.dock-inline {
|
|
673
|
-
margin: 0 auto;
|
|
674
|
-
}
|
|
675
|
-
|
|
676
|
-
.dock-sticky {
|
|
677
|
-
position: sticky;
|
|
678
|
-
top: 0;
|
|
679
|
-
z-index: var(--z-dock);
|
|
680
|
-
margin: 0 auto;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
/* J.W3.A — outer collapsed↔expanded pair drives width via FLIP.
|
|
684
|
-
`useLayerTransition` measures the natural width before/after the
|
|
685
|
-
slot swap and animates `width` between fixed pixel values via
|
|
686
|
-
the `--dock-motion-resize` spring; this eliminates the
|
|
687
|
-
`width: auto` non-interpolation diagnosed in R1+R6. The two
|
|
688
|
-
layers stack on a CSS grid (1/1 area) and crossfade opacity
|
|
689
|
-
in step with the FLIP. Spatial motion (width) is automatically
|
|
690
|
-
suppressed by the global `prefers-reduced-motion` gate in
|
|
691
|
-
`utilities.css` (which strips width from transition-property).
|
|
692
|
-
Opacity transitions remain — the 0.1s shortened cadence in PRM
|
|
693
|
-
still reads as a snap.
|
|
694
|
-
|
|
695
|
-
J.W3.C — when the active layer's natural width exceeds
|
|
696
|
-
`--dock-max-inline-size`, the dock root clips and the layer
|
|
697
|
-
scrolls horizontally with a mask-fade. `min-width: 0` lets the
|
|
698
|
-
grid item shrink under the cap (default min-content is the
|
|
699
|
-
child's intrinsic width which would prevent the clamp). */
|
|
700
|
-
.dock-layers {
|
|
701
|
-
display: grid;
|
|
702
|
-
min-width: 0;
|
|
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);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
/* AV.W9.0 — the AU.W8b native container-morph arm (the `@supports` block that
|
|
747
|
-
opted the subtree into auto-to-length width interpolation and declared the
|
|
748
|
-
active layer's destination width as intrinsic) is RETIRED. It was never made
|
|
749
|
-
mutually exclusive with the `SpringProgress` FLIP driver in
|
|
750
|
-
`useLayerTransition.ts`: on Chrome 129+ the native arm interpolated
|
|
751
|
-
`.dock-layers` width on the browser's own clock WHILE the spring wrote inline
|
|
752
|
-
`width` per frame — a dual-driver race over the SAME property that cancelled
|
|
753
|
-
the morph and froze the dock at runtime (born-RED under
|
|
754
|
-
`proof:dock-animation-live`). One authority per concern: the size morph now
|
|
755
|
-
has exactly ONE driver on every engine — the `SpringProgress` FLIP path above
|
|
756
|
-
(`:382`), or the orthogonal View-Transitions path inside
|
|
757
|
-
`startViewTransition` (which owns size + crossfade as a single browser-side
|
|
758
|
-
mutation and never touches inline width). Neither coexists with a CSS-native
|
|
759
|
-
intrinsic-width destination, so the race is gone. This re-expresses the
|
|
760
|
-
`e8380d7` "one driver owns the morph" invariant on the modern
|
|
761
|
-
FLIP+spring(+VT) architecture. */
|
|
762
|
-
|
|
763
|
-
/* Horizontal dock content grows visibly when the active layer's natural
|
|
764
|
-
width exceeds the content area (grow-to-fit; consumers needing wrap opt
|
|
765
|
-
into `overflow="wrap"`). No edge-fade mask — content never clips or scrolls,
|
|
766
|
-
so a feather has nothing to feather and only bleeds a stray ramp onto
|
|
767
|
-
the edge controls. */
|
|
768
|
-
.glass-dock.expanded:not(.dock-overflow-wrap) > .dock-layers {
|
|
769
|
-
overflow-x: visible;
|
|
770
|
-
}
|
|
771
|
-
|
|
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. */
|
|
805
|
-
.dock-layer,
|
|
806
|
-
.dock-layer-item-host {
|
|
807
|
-
transition:
|
|
808
|
-
opacity var(--dock-motion-resize),
|
|
809
|
-
visibility 0s linear var(--duration-normal);
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
.dock-layer:not(.is-active):not(.is-leaving),
|
|
813
|
-
.dock-layer-item-host:not(.is-active):not(.is-leaving) {
|
|
814
|
-
opacity: 0;
|
|
815
|
-
visibility: hidden;
|
|
816
|
-
pointer-events: none;
|
|
817
|
-
}
|
|
818
|
-
|
|
819
|
-
.dock-layer.is-active,
|
|
820
|
-
.dock-layer-item-host.is-active {
|
|
821
|
-
opacity: 1;
|
|
822
|
-
visibility: visible;
|
|
823
|
-
pointer-events: auto;
|
|
824
|
-
/* AW.W2 — the active pane is STATICALLY opacity:1, REVEALED by the clip
|
|
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). */
|
|
831
|
-
transition: visibility 0s;
|
|
832
|
-
}
|
|
833
|
-
|
|
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,
|
|
840
|
-
.dock-layer-item-host.is-leaving {
|
|
841
|
-
opacity: 0;
|
|
842
|
-
visibility: visible;
|
|
843
|
-
pointer-events: none;
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
/* AV.W9.1 — the AU.W8b native discrete-visibility arm (the second `@supports`
|
|
847
|
-
block that expressed the 3-state contract as one discrete transition over
|
|
848
|
-
opacity + visibility with a `@starting-style` entry anchor) is RETIRED. It
|
|
849
|
-
was a THIRD opacity/visibility authority overlapping the hand-rolled 3-state
|
|
850
|
-
fork above and the spring's settle — three owners for one concern. With the
|
|
851
|
-
native size arm gone (W9.0), opacity now has ONE owner everywhere: the
|
|
852
|
-
`opacity var(--dock-motion-resize)` crossfade on `.dock-layer{,-item-host}`
|
|
853
|
-
(the AU.W2 lockstep token — kept), and visibility has ONE owner: the delayed
|
|
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. */
|
|
858
|
-
|
|
859
|
-
/* ── Base layout — distinct per surface ─────────────────────────── */
|
|
860
|
-
.dock-layer {
|
|
861
|
-
display: flex;
|
|
862
|
-
align-items: center;
|
|
863
|
-
grid-area: 1 / 1;
|
|
864
|
-
gap: var(--dock-layer-gap, 0.375rem);
|
|
865
|
-
}
|
|
866
|
-
|
|
867
|
-
/* AW.W2 — content-intrinsic axis follows the MORPH axis. A horizontal dock
|
|
868
|
-
lays its inline content out ONCE at `width: max-content` (nowrap) so the
|
|
869
|
-
width aperture uncovers a static row; the fixed `height` keeps the row a
|
|
870
|
-
single line. Scoped to `:not(.vertical)` so a vertical rail (whose
|
|
871
|
-
block-axis morph reveals a column) is NOT forced onto one nowrap row — the
|
|
872
|
-
vertical group's active host block-sizes to `height: max-content` below
|
|
873
|
-
(the AP.W3 column treatment, KEPT). */
|
|
874
|
-
.glass-dock:not(.vertical) .dock-layer {
|
|
875
|
-
white-space: nowrap;
|
|
876
|
-
height: var(--dock-layer-height, 2.5rem);
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
.dock-layer.is-active {
|
|
880
|
-
position: relative;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
.dock-layer:not(.is-active) {
|
|
884
|
-
position: absolute;
|
|
885
|
-
inset: 0;
|
|
886
|
-
}
|
|
887
|
-
|
|
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 > * {
|
|
910
|
-
--dock-stagger-window: var(--dock-stagger-window-size, 0.55);
|
|
911
|
-
--dock-stagger-onset: 0;
|
|
912
|
-
opacity: clamp(
|
|
913
|
-
0,
|
|
914
|
-
calc(
|
|
915
|
-
(var(--dock-expand-t, 1) - var(--dock-stagger-onset)) /
|
|
916
|
-
var(--dock-stagger-window)
|
|
917
|
-
),
|
|
918
|
-
1
|
|
919
|
-
);
|
|
920
|
-
translate: 0
|
|
921
|
-
calc(
|
|
922
|
-
(1 - clamp(0, calc((var(--dock-expand-t, 1) - var(--dock-stagger-onset)) / var(--dock-stagger-window)), 1)) *
|
|
923
|
-
var(--dock-stagger-rise, 4px)
|
|
924
|
-
);
|
|
925
|
-
}
|
|
926
|
-
|
|
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);
|
|
942
|
-
}
|
|
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);
|
|
946
|
-
}
|
|
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);
|
|
950
|
-
}
|
|
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);
|
|
954
|
-
}
|
|
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);
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
/* AW.W2 — the at-rest clip-lift moved to `.expanded:not([data-morphing])` /
|
|
961
|
-
`.always-expanded:not([data-morphing])` (the clip-shell block at the top).
|
|
962
|
-
A plain `overflow: visible` here would lift the clip DURING the morph (the
|
|
963
|
-
load-bearing sequencing gap), so the `overflow` declarations are dropped
|
|
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 {
|
|
972
|
-
width: 100%;
|
|
973
|
-
}
|
|
974
|
-
|
|
975
|
-
.glass-dock.expanded:not(.fit-content) .dock-layer--full {
|
|
976
|
-
width: 100%;
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
.glass-dock.always-expanded {
|
|
980
|
-
cursor: default;
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
/* ── AW.W3b — `layout="grid"` the 2D auto-grid big dock ──────────────
|
|
984
|
-
The active layer becomes a self-wrapping tile grid (Launchpad / Stage-Manager
|
|
985
|
-
track symmetry — `auto-fill` columns floored at `--dock-tile-min`, explicit
|
|
986
|
-
`grid-auto-rows` so the concentric look holds). DISTINCT from
|
|
987
|
-
`overflow="wrap"`'s content-ordered flex-wrap. A `layout="grid"` dock is
|
|
988
|
-
`alwaysExpanded` by contract (GlassDock.vue), so there is NO width morph and
|
|
989
|
-
hence NO per-frame grid-column reflow. `white-space: normal` releases the
|
|
990
|
-
single-row nowrap so the tiles wrap. */
|
|
991
|
-
.glass-dock.layout-grid {
|
|
992
|
-
white-space: normal;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
.glass-dock.layout-grid .dock-layer--full {
|
|
996
|
-
display: grid;
|
|
997
|
-
grid-template-columns: repeat(
|
|
998
|
-
auto-fill,
|
|
999
|
-
minmax(var(--dock-tile-min, 4.5rem), 1fr)
|
|
1000
|
-
);
|
|
1001
|
-
grid-auto-rows: var(--dock-tile-min, 4.5rem);
|
|
1002
|
-
gap: var(--dock-layer-gap, 0.375rem);
|
|
1003
|
-
width: 100%;
|
|
1004
|
-
height: auto;
|
|
1005
|
-
white-space: normal;
|
|
1006
|
-
}
|
|
1007
|
-
|
|
1008
|
-
/* A grid dock fills the inline cap; the active layer is the panel body, not a
|
|
1009
|
-
shrink-to-fit row. The cap is the `--dock-max-inline-size` clamp (KEPT). */
|
|
1010
|
-
.glass-dock.layout-grid .dock-layers {
|
|
1011
|
-
width: 100%;
|
|
1012
|
-
}
|
|
1013
|
-
|
|
1014
|
-
/* CONCENTRIC inner tiles — inner radius = outer card radius − padding (the
|
|
1015
|
-
universal macOS / visionOS / Raycast rule). NEVER nest two pills
|
|
1016
|
-
(stadium-in-stadium); a finite outer + a stepped-down inner. */
|
|
1017
|
-
.glass-dock.layout-grid.shape-card .dock-layer--full > * {
|
|
1018
|
-
border-radius: calc(
|
|
1019
|
-
var(--dock-card-radius) - var(--dock-padding-inline, 0.5rem)
|
|
1020
|
-
);
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
/* ── Scroll-on-overflow opt-in (GlassDock `overflow="scroll"`) ───────
|
|
1024
|
-
The default contract grows-to-fit then overflows visibly past the
|
|
1025
|
-
axis cap. `overflow="scroll"` instead makes the dock the scroll port
|
|
1026
|
-
on its layout axis, pairing the existing cap with a hidden-scrollbar
|
|
1027
|
-
scroll region so over-cap content stays reachable. The rounded pill
|
|
1028
|
-
masks the scroll edge; both axes keep their cap. */
|
|
1029
|
-
|
|
1030
|
-
/* Inline axis (horizontal docks). The active layer becomes the scroll
|
|
1031
|
-
port: `min-width: 0` releases the flex item's `min-content` floor so
|
|
1032
|
-
it can shrink under the clamped `.dock-layers` track, then `overflow-x:
|
|
1033
|
-
auto` scrolls its over-cap content. `.dock-layers` must KEEP clipping
|
|
1034
|
-
so the pill's rounded edge masks the scroll boundary — hence the
|
|
1035
|
-
grow-mode `overflow-x: visible` (`.dock-layers`, above) is overridden
|
|
1036
|
-
back to `hidden` here. */
|
|
1037
|
-
.glass-dock.dock-scroll-x.expanded:not(.dock-overflow-wrap) > .dock-layers {
|
|
1038
|
-
overflow-x: hidden;
|
|
1039
|
-
}
|
|
1040
|
-
|
|
1041
|
-
.glass-dock.dock-scroll-x .dock-layer--full {
|
|
1042
|
-
min-width: 0;
|
|
1043
|
-
overflow-x: auto;
|
|
1044
|
-
scrollbar-width: none;
|
|
1045
|
-
/* Trap the inline-scroll momentum at the dock's own boundary so a
|
|
1046
|
-
wheel/trackpad gesture that bottoms out the pill does NOT chain into
|
|
1047
|
-
scrolling the page behind it (the dock is a self-contained scroll
|
|
1048
|
-
port, not a window into the route scroller). */
|
|
1049
|
-
overscroll-behavior-x: contain;
|
|
1050
|
-
}
|
|
1051
|
-
|
|
1052
|
-
.glass-dock.dock-scroll-x .dock-layer--full::-webkit-scrollbar {
|
|
1053
|
-
display: none;
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
/* Block axis (vertical rails). The root keeps its `max-block-size` cap
|
|
1057
|
-
and scrolls its over-cap children — cap + scroll is the correct
|
|
1058
|
-
pairing the grow-mode contract split apart. Ties the
|
|
1059
|
-
`.vertical.always-expanded` visible default on specificity and wins on
|
|
1060
|
-
source order. */
|
|
1061
|
-
.glass-dock.vertical.dock-scroll-y {
|
|
1062
|
-
overflow-y: auto;
|
|
1063
|
-
scrollbar-width: none;
|
|
1064
|
-
/* Same momentum-trap as the inline port — a rail that bottoms out must
|
|
1065
|
-
not chain its remaining wheel delta into the page scroller behind it. */
|
|
1066
|
-
overscroll-behavior-y: contain;
|
|
1067
|
-
}
|
|
1068
|
-
|
|
1069
|
-
.glass-dock.vertical.dock-scroll-y::-webkit-scrollbar {
|
|
1070
|
-
display: none;
|
|
1071
|
-
}
|
|
1072
|
-
|
|
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). */
|
|
1088
|
-
.glass-dock.dock-overflow-wrap {
|
|
1089
|
-
white-space: normal;
|
|
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);
|
|
1100
|
-
padding: var(--dock-wrap-padding-block, var(--dock-padding-block, 0.375rem))
|
|
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);
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
.glass-dock.dock-overflow-wrap .dock-layer--full {
|
|
1140
|
-
flex-wrap: wrap;
|
|
1141
|
-
justify-content: center;
|
|
1142
|
-
height: auto;
|
|
1143
|
-
min-height: var(--dock-wrap-layer-min-height, var(--dock-layer-height, 2rem));
|
|
1144
|
-
gap: var(--dock-wrap-row-gap, 0.25rem)
|
|
1145
|
-
var(--dock-wrap-column-gap, var(--dock-layer-gap, 0.375rem));
|
|
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. */
|
|
1152
|
-
}
|
|
1153
|
-
|
|
1154
|
-
.glass-dock.dock-overflow-wrap .dock-layer--summary {
|
|
1155
|
-
height: auto;
|
|
1156
|
-
min-height: var(--dock-wrap-layer-min-height, var(--dock-layer-height, 2rem));
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
.glass-dock.dock-overflow-wrap .dock-separator {
|
|
1160
|
-
display: none;
|
|
1161
|
-
}
|
|
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%). */
|
|
1170
|
-
.glass-dock.dock-overflow-wrap.collapsed {
|
|
1171
|
-
white-space: nowrap;
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
.dock-separator {
|
|
1175
|
-
@apply flex-shrink-0;
|
|
1176
|
-
width: 1px;
|
|
1177
|
-
height: var(--dock-separator-height);
|
|
1178
|
-
margin: 0 0.375rem;
|
|
1179
|
-
background: var(--surface-tint-15);
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
.dock-spacer {
|
|
1183
|
-
@apply flex-1;
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
.dock-layer-group {
|
|
1187
|
-
display: flex;
|
|
1188
|
-
gap: var(--dock-layer-group-gap, var(--dock-layer-gap, 0.25rem));
|
|
1189
|
-
min-width: 0;
|
|
1190
|
-
min-height: 0;
|
|
1191
|
-
}
|
|
1192
|
-
|
|
1193
|
-
.dock-layer-group.horizontal {
|
|
1194
|
-
flex-direction: row;
|
|
1195
|
-
align-items: stretch;
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
.dock-layer-group.horizontal.rail-end {
|
|
1199
|
-
flex-direction: row-reverse;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
.dock-layer-group.vertical {
|
|
1203
|
-
flex-direction: column;
|
|
1204
|
-
align-items: stretch;
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
.dock-layer-group.vertical.rail-end {
|
|
1208
|
-
flex-direction: column-reverse;
|
|
1209
|
-
}
|
|
1210
|
-
|
|
1211
|
-
.dock-layer-rail {
|
|
1212
|
-
display: flex;
|
|
1213
|
-
flex-direction: column;
|
|
1214
|
-
flex-shrink: 0;
|
|
1215
|
-
gap: var(--dock-layer-rail-gap, 0.125rem);
|
|
1216
|
-
padding: var(--dock-layer-rail-padding, 0.125rem);
|
|
1217
|
-
border-right: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
|
1218
|
-
}
|
|
1219
|
-
|
|
1220
|
-
.dock-layer-group.vertical .dock-layer-rail {
|
|
1221
|
-
flex-direction: row;
|
|
1222
|
-
border-right: none;
|
|
1223
|
-
border-bottom: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
.dock-layer-group.horizontal.rail-end .dock-layer-rail {
|
|
1227
|
-
border-right: none;
|
|
1228
|
-
border-left: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
|
1229
|
-
}
|
|
1230
|
-
|
|
1231
|
-
.dock-layer-group.vertical.rail-end .dock-layer-rail {
|
|
1232
|
-
border-bottom: none;
|
|
1233
|
-
border-top: 1px solid color-mix(in srgb, var(--border) 30%, transparent);
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
/* AU.W8.4 — the rail is a reka-ui Tabs contract. The travelling
|
|
1237
|
-
`.dock-layer-tab-indicator` (the reka TabsIndicator) now carries the
|
|
1238
|
-
active affordance; the rail is `position: relative` so the indicator's
|
|
1239
|
-
absolute placement is rail-local. */
|
|
1240
|
-
.dock-layer-rail {
|
|
1241
|
-
position: relative;
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
.dock-layer-rail .dock-layer-tab {
|
|
1245
|
-
position: relative;
|
|
1246
|
-
display: inline-flex;
|
|
1247
|
-
align-items: center;
|
|
1248
|
-
justify-content: center;
|
|
1249
|
-
width: var(--dock-layer-tab-size, var(--dock-control-size, 1.75rem));
|
|
1250
|
-
height: var(--dock-layer-tab-size, var(--dock-control-size, 1.75rem));
|
|
1251
|
-
border: 0;
|
|
1252
|
-
border-radius: var(--dock-layer-tab-radius, var(--radius-sm));
|
|
1253
|
-
background: transparent;
|
|
1254
|
-
color: var(--muted-foreground);
|
|
1255
|
-
cursor: pointer;
|
|
1256
|
-
font: inherit;
|
|
1257
|
-
font-size: 0.75rem;
|
|
1258
|
-
/* The tab glyph rides above the travelling indicator backplate. */
|
|
1259
|
-
z-index: 1;
|
|
1260
|
-
transition:
|
|
1261
|
-
background var(--dock-motion-fast),
|
|
1262
|
-
color var(--dock-motion-fast);
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
.dock-layer-rail .dock-layer-tab:hover {
|
|
1266
|
-
background: color-mix(in srgb, var(--accent) 40%, transparent);
|
|
1267
|
-
color: var(--foreground);
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
/* AU.W8.4 — KEEP the active glyph tint on the selected tab (reka emits
|
|
1271
|
-
`data-state="active"` + `aria-selected="true"`); the per-button active
|
|
1272
|
-
BACKGROUND is RETIRED — the travelling indicator carries that affordance. */
|
|
1273
|
-
.dock-layer-rail .dock-layer-tab[data-state="active"] {
|
|
1274
|
-
color: var(--primary);
|
|
1275
|
-
}
|
|
1276
|
-
|
|
1277
|
-
/* AU.W8.4 — the dock control focus-ring contract does not cover
|
|
1278
|
-
`.dock-layer-tab` (the rail tab is not in the `.dock-icon-button` family).
|
|
1279
|
-
The roving tabindex means only the active tab is in the tab order; a
|
|
1280
|
-
focus-visible tab paints the shared dock ring. */
|
|
1281
|
-
.dock-layer-rail [role="tab"]:focus-visible {
|
|
1282
|
-
box-shadow: var(--focus-ring-shadow);
|
|
1283
|
-
outline: none;
|
|
1284
|
-
}
|
|
1285
|
-
|
|
1286
|
-
/* AU.W8.4 — the travelling indicator (reka TabsIndicator). reka computes
|
|
1287
|
-
`--reka-tabs-indicator-position` + `--reka-tabs-indicator-size` from the
|
|
1288
|
-
active tab's geometry; the indicator morphs between tabs riding
|
|
1289
|
-
`--dock-motion-resize` (= `--spring-dock` after AU.W8.2) — NOT a hardcoded
|
|
1290
|
-
`--spring-snappy`. It paints the active-tab backplate the per-button
|
|
1291
|
-
`.is-active` background used to. */
|
|
1292
|
-
.dock-layer-rail .dock-layer-tab-indicator {
|
|
1293
|
-
position: absolute;
|
|
1294
|
-
left: 0;
|
|
1295
|
-
top: 0;
|
|
1296
|
-
height: var(--dock-layer-tab-size, var(--dock-control-size, 1.75rem));
|
|
1297
|
-
width: var(--reka-tabs-indicator-size);
|
|
1298
|
-
transform: translateX(var(--reka-tabs-indicator-position));
|
|
1299
|
-
border-radius: var(--dock-layer-tab-radius, var(--radius-sm));
|
|
1300
|
-
background: color-mix(in srgb, var(--primary) 15%, transparent);
|
|
1301
|
-
transition:
|
|
1302
|
-
width var(--dock-motion-resize),
|
|
1303
|
-
transform var(--dock-motion-resize);
|
|
1304
|
-
pointer-events: none;
|
|
1305
|
-
}
|
|
1306
|
-
|
|
1307
|
-
/* For a vertical rail the indicator travels along the inline axis still
|
|
1308
|
-
(the horizontal-always keyboard decision keeps the indicator inline);
|
|
1309
|
-
reka's position var resolves to the active tab offset regardless. */
|
|
1310
|
-
|
|
1311
|
-
.dock-layer-stack {
|
|
1312
|
-
position: relative;
|
|
1313
|
-
display: grid;
|
|
1314
|
-
/* AW.W2 — the morph axis (width for a horizontal group, height for a
|
|
1315
|
-
vertical one) is driven by the `useLayerTransition` SpringProgress in
|
|
1316
|
-
pixel space (FLIP path) or the View-Transition (native path); a CSS
|
|
1317
|
-
`width`/`height` transition here would be a SECOND driver on the same
|
|
1318
|
-
axis (the AV.W9.0 dual-driver race that froze the dock). The cross axis
|
|
1319
|
-
is intrinsic-sized and never morphs. So NO size transition on the stack
|
|
1320
|
-
— one owner per axis. */
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
/* Base layout — the crossfade + hit-test contract is shared with
|
|
1324
|
-
`.dock-layer` above (see "Layer crossfade + hit-test contract"). The
|
|
1325
|
-
default state is inactive: absolute + inset:0. */
|
|
1326
|
-
.dock-layer-item-host {
|
|
1327
|
-
grid-area: 1 / 1;
|
|
1328
|
-
display: flex;
|
|
1329
|
-
align-items: center;
|
|
1330
|
-
white-space: nowrap;
|
|
1331
|
-
gap: var(--dock-layer-gap, 0.375rem);
|
|
1332
|
-
position: absolute;
|
|
1333
|
-
inset: 0;
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
.dock-layer-item-host.is-active {
|
|
1337
|
-
position: relative;
|
|
1338
|
-
inset: auto;
|
|
1339
|
-
width: max-content;
|
|
1340
|
-
min-width: 0;
|
|
1341
|
-
}
|
|
1342
|
-
|
|
1343
|
-
/* AP.W3 — axis-aware layer pane. The stack + `useLayerTransition` are
|
|
1344
|
-
axis-aware, but the pane was hardcoded to a no-wrap ROW with
|
|
1345
|
-
`width: max-content` — forcing a `vertical` group's content onto one
|
|
1346
|
-
horizontal line that could not grow down (the vertical-overflow fight).
|
|
1347
|
-
A vertical group stacks in a column, stretches, wraps, and block-sizes
|
|
1348
|
-
to the height the stack animates. Horizontal byte-identical. */
|
|
1349
|
-
.dock-layer-group.vertical .dock-layer-item-host {
|
|
1350
|
-
flex-direction: column;
|
|
1351
|
-
align-items: stretch;
|
|
1352
|
-
white-space: normal;
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
.dock-layer-group.vertical .dock-layer-item-host.is-active {
|
|
1356
|
-
width: auto;
|
|
1357
|
-
height: max-content;
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
/* AU.W8b.3 — the five dock CONTROL families (.dock-icon-button,
|
|
1361
|
-
.dark-mode-toggle-button, .dock-tab-button + tiers, the
|
|
1362
|
-
.dock-select-trigger / .dock-dropdown-trigger pair, and the coarse-pointer
|
|
1363
|
-
per-button touch floor) carved out to dock-controls.css (imported directly
|
|
1364
|
-
after this file in index.css, same @layer components). dock.css keeps the
|
|
1365
|
-
shell / density / grain / layer-crossfade contract + the shared
|
|
1366
|
-
cross-control four-state comma-groups (the :focus-visible / :disabled groups
|
|
1367
|
-
+ the motion-token :where() group above). */
|
|
1368
|
-
|
|
1369
|
-
/* J.W3.B — `.dock-popover` substrate + `pop-up-*` / `pop-down-*`
|
|
1370
|
-
Vue Transition keyframes retired. Hover-driven dock popovers
|
|
1371
|
-
compose `<HoverPopover keep-dock-open>`, which inherits reka-ui
|
|
1372
|
-
HoverCard's collision-avoidance + the canonical
|
|
1373
|
-
`popover-animate` motion vocabulary. Click-anchored popovers
|
|
1374
|
-
(no dock-keep semantics) compose `<Popover>` directly. */
|
|
1375
|
-
|
|
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. */
|
|
1384
|
-
|
|
1385
|
-
/* O.W6 Lane D — Touch-target floor (speedtest AC.W6 F2.AA-03 / WCAG
|
|
1386
|
-
2.5.5). On coarse-pointer devices (touch), every dock-control's
|
|
1387
|
-
width/height floor lifts to the 44px WCAG target-size minimum.
|
|
1388
|
-
The lift composes via `--dock-control-size` (the canonical knob
|
|
1389
|
-
every dock-control surface — `.dock-icon-button`,
|
|
1390
|
-
`.dock-tab-button`, `.dock-select-trigger`, `.dock-dropdown-trigger`
|
|
1391
|
-
— already consumes) so the cascade reaches every control without
|
|
1392
|
-
per-selector re-declaration. `--size-icon-btn` lifts in lockstep
|
|
1393
|
-
so bare icon-button surfaces outside the dock (e.g.,
|
|
1394
|
-
`.dark-mode-toggle-button[data-size="dock"]` and any consumer
|
|
1395
|
-
that wires `var(--size-icon-btn)` for trigger sizing) inherit
|
|
1396
|
-
the same floor.
|
|
1397
|
-
|
|
1398
|
-
AP.W3 R0G-6 — selector is `.glass-dock[data-density]`, not bare
|
|
1399
|
-
`.glass-dock`: the always-present density setter (0,2,0) shadowed a
|
|
1400
|
-
bare (0,1,0) coarse floor, pinning the touch box at 40px. The
|
|
1401
|
-
presence-selector (0,2,0) wins by source order, lifting
|
|
1402
|
-
`--dock-control-size` to 44px — read by both the button box and the
|
|
1403
|
-
dock width-math, so the slot reserves 44px (no overflow). Fine pointer
|
|
1404
|
-
byte-identical. Proof: design/W1.2-motion-carve-and-dock.md §B.2. */
|
|
1405
|
-
@media (pointer: coarse) {
|
|
1406
|
-
.glass-dock[data-density] {
|
|
1407
|
-
--dock-control-size: var(--dock-touch-target, 2.75rem);
|
|
1408
|
-
--size-icon-btn: var(--dock-touch-target, 2.75rem);
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
/* S-2 — the in-dock floor above lifts the control-SIZE token (shell /
|
|
1412
|
-
width-math), which only reaches a DockIconButton that has a
|
|
1413
|
-
`.glass-dock` ancestor. The companion button-level floor (the
|
|
1414
|
-
`.dock-icon-button:not(--compact)` `min-{block,inline}-size` that
|
|
1415
|
-
reaches a STANDALONE DockIconButton with no dock wrapper) moved to
|
|
1416
|
-
dock-controls.css with the rest of the control family (AU.W8b.3). */
|
|
1417
|
-
}
|
|
1418
111
|
}
|