@mkbabb/glass-ui 2.1.0 → 3.1.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 (194) hide show
  1. package/dist/{CardFooter-Yi0xtLLd.js → CardFooter-CSGcJkqa.js} +1 -1
  2. package/dist/{CommandShortcut-_INFUMu6.js → CommandShortcut-DWT19a2Y.js} +3 -3
  3. package/dist/{ContextMenuSubContent-DCkweFW9.js → ContextMenuSubContent-gAFxJ-qi.js} +1 -1
  4. package/dist/{DataTable-Ce00dbHD.js → DataTable-R8-Zidms.js} +3 -3
  5. package/dist/{DialogContent-CmCijgX9.js → DialogContent-2fALDSvc.js} +3 -3
  6. package/dist/{DialogFooter-DRdaCok0.js → DialogFooter-ClrNEOVU.js} +2 -2
  7. package/dist/{DiscoGlyph-wRA02zAJ.js → DiscoGlyph-C3JfMnRV.js} +1 -1
  8. package/dist/{GlyphFace-BnPMUZ16.js → GlyphFace-BRS8vUb7.js} +1 -1
  9. package/dist/HoverPopover-CWFCfLx3.js +96 -0
  10. package/dist/{IconTooltip-ge_mBSWR.js → IconTooltip-BkaA7tZ2.js} +1 -1
  11. package/dist/{Input-CbakTe3B.js → Input-DDpFn568.js} +3 -5
  12. package/dist/Label-DJty89bp.js +36 -0
  13. package/dist/{MetricBadge-DRBB18Xq.js → MetricBadge-DmAihkXd.js} +1 -1
  14. package/dist/{Notification-DrI1DT2v.js → Notification-OqIpADml.js} +2 -2
  15. package/dist/NumberFieldContent-DTH9gb_N.js +141 -0
  16. package/dist/{PopoverContent-BCH4eYs8.js → PopoverContent-EiklFrna.js} +1 -1
  17. package/dist/{Progress-CCH-2UBR.js → Progress-FApA9fm_.js} +1 -1
  18. package/dist/{ScrollingText-7P8skg5W.js → ScrollingText-BFd0i2zJ.js} +2 -2
  19. package/dist/{SelectScrollDownButton-yu8EYUnu.js → SelectScrollDownButton-Dth8-wXQ.js} +2 -2
  20. package/dist/{Toaster-DY8_jtHv.js → Toaster-Bjlunvq4.js} +69 -58
  21. package/dist/UnderlineTabs-DAWMLmJG.js +37 -0
  22. package/dist/animated-digit.js +2 -2
  23. package/dist/api/index.d.ts +2 -0
  24. package/dist/api.js +1 -1
  25. package/dist/aurora.js +103 -90
  26. package/dist/badge.js +1 -1
  27. package/dist/{button-BlOW34DT.js → button-C0aHmBbt.js} +2 -0
  28. package/dist/button.js +1 -1
  29. package/dist/card.js +1 -1
  30. package/dist/carousel.js +1 -1
  31. package/dist/collapsible.js +1 -1
  32. package/dist/command.js +1 -1
  33. package/dist/components/custom/aurora/composables/runtime.d.ts +24 -1
  34. package/dist/components/custom/dialog-native/GlassDialogNative.vue.d.ts +57 -0
  35. package/dist/components/custom/dialog-native/index.d.ts +1 -0
  36. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +20 -10
  37. package/dist/components/custom/hover-popover/HoverPopover.vue.d.ts +26 -4
  38. package/dist/components/custom/labeled-field/LabeledField.vue.d.ts +16 -2
  39. package/dist/components/custom/labeled-field/LabeledInput.vue.d.ts +17 -1
  40. package/dist/components/custom/labeled-field/LabeledSelect.vue.d.ts +2 -0
  41. package/dist/components/custom/labeled-field/LabeledSlider.vue.d.ts +2 -0
  42. package/dist/components/custom/labeled-field/LabeledSwitch.vue.d.ts +2 -0
  43. package/dist/components/custom/toggle-chip/ToggleChip.vue.d.ts +6 -4
  44. package/dist/components/ui/input/Input.vue.d.ts +10 -7
  45. package/dist/components/ui/label/Label.vue.d.ts +8 -0
  46. package/dist/components/ui/textarea/Textarea.vue.d.ts +45 -8
  47. package/dist/components/ui/toast/Toaster.vue.d.ts +7 -1
  48. package/dist/components/ui/toast/index.d.ts +1 -0
  49. package/dist/composables/dark/index.d.ts +1 -0
  50. package/dist/composables/dom/index.d.ts +2 -0
  51. package/dist/composables/dom/useIdleReady.d.ts +63 -0
  52. package/dist/composables/dom/useUserInvalidAria.d.ts +32 -0
  53. package/dist/composables/index.d.ts +1 -0
  54. package/dist/composables/motion/core/index.d.ts +8 -0
  55. package/dist/composables/motion/index.d.ts +0 -7
  56. package/dist/composables/motion/supportsCssTimeline.d.ts +8 -0
  57. package/dist/composables/motion/useRAFLoop.d.ts +7 -0
  58. package/dist/composables/motion/useScrollProgress.d.ts +6 -2
  59. package/dist/composables/motion/useStaggerReveal.d.ts +6 -0
  60. package/dist/composables/motion/useViewTransition.d.ts +31 -0
  61. package/dist/composables/motion/useYieldToMain.d.ts +29 -0
  62. package/dist/configurator.js +1 -1
  63. package/dist/confirm-dialog.js +2 -2
  64. package/dist/constants-DwBwnG8N.js +13 -0
  65. package/dist/context-menu.js +2 -2
  66. package/dist/controls.js +2 -2
  67. package/dist/dark.d.ts +1 -1
  68. package/dist/dark.js +13 -2
  69. package/dist/data-table.js +1 -1
  70. package/dist/dialog.js +2 -2
  71. package/dist/disco-glyph.js +1 -1
  72. package/dist/dock.js +195 -176
  73. package/dist/dom.js +5 -4
  74. package/dist/{dropdown-menu-2K-SGkZU.js → dropdown-menu-BvRUamNs.js} +2 -2
  75. package/dist/dropdown-menu.js +1 -1
  76. package/dist/expandable-container.js +3 -3
  77. package/dist/forms.d.ts +1 -0
  78. package/dist/forms.js +47 -42
  79. package/dist/glass-carousel.js +1 -1
  80. package/dist/glass-panel.js +2 -2
  81. package/dist/glass-ui.css +1 -1
  82. package/dist/glass-ui.js +156 -275
  83. package/dist/glyph-face.js +2 -2
  84. package/dist/header-ribbon.js +1 -1
  85. package/dist/hover-card.js +1 -1
  86. package/dist/hover-popover.js +1 -1
  87. package/dist/icon-tooltip.js +1 -1
  88. package/dist/index.d.ts +1 -0
  89. package/dist/instrument-chassis.js +1 -1
  90. package/dist/instrument-rail.js +1 -1
  91. package/dist/keyboard.js +1 -1
  92. package/dist/label.js +1 -1
  93. package/dist/labeled-field.js +96 -57
  94. package/dist/metric-badge.js +1 -1
  95. package/dist/metric-stack.js +1 -1
  96. package/dist/motion-core.d.ts +1 -0
  97. package/dist/motion-core.js +229 -0
  98. package/dist/motion.js +26 -228
  99. package/dist/notification.js +1 -1
  100. package/dist/number-field.d.ts +1 -0
  101. package/dist/number-field.js +2 -0
  102. package/dist/paper-backdrop.js +1 -1
  103. package/dist/popover.js +1 -1
  104. package/dist/progress.js +1 -1
  105. package/dist/pulse.js +1 -1
  106. package/dist/reactive.js +2 -2
  107. package/dist/responsive-tabs.js +3 -3
  108. package/dist/scrolling-text.js +1 -1
  109. package/dist/search.js +6 -6
  110. package/dist/select.js +3 -3
  111. package/dist/separator.js +1 -1
  112. package/dist/{sheet-CLVkb3AO.js → sheet-CukNDezz.js} +53 -53
  113. package/dist/sheet.js +1 -1
  114. package/dist/{slider-BQaLYFLh.js → slider-DJvHkTRe.js} +3 -3
  115. package/dist/slider.js +1 -1
  116. package/dist/sortable-list.js +2 -2
  117. package/dist/styles/animations.css +77 -0
  118. package/dist/styles/cards.css +6 -2
  119. package/dist/styles/dock.css +109 -109
  120. package/dist/styles/drawer.css +2 -2
  121. package/dist/styles/glass.css +89 -6
  122. package/dist/styles/index.css +10 -1
  123. package/dist/styles/instrument-chassis.css +28 -1
  124. package/dist/styles/scroll-driven.css +72 -0
  125. package/dist/styles/theme.css +6 -0
  126. package/dist/styles/tokens.css +345 -289
  127. package/dist/styles/typography.css +65 -131
  128. package/dist/styles/utilities.css +199 -81
  129. package/dist/styles/view-transition.css +62 -0
  130. package/dist/switch.d.ts +1 -0
  131. package/dist/switch.js +2 -0
  132. package/dist/tabs.js +40 -36
  133. package/dist/timeline.js +2 -2
  134. package/dist/toast.js +1 -1
  135. package/dist/toggle-group.js +1 -1
  136. package/dist/tooltip.js +1 -1
  137. package/dist/typewriter.js +1 -1
  138. package/dist/{useAnimatedNumber-DcvTR9B4.js → useAnimatedNumber-DKQYVB7s.js} +9 -20
  139. package/dist/{useConfiguratorState-BlaevW0S.js → useConfiguratorState-BR5vUDL8.js} +5 -5
  140. package/dist/{useBreakpoint-BHlX-MhR.js → useIdleReady-Cmkhm03v.js} +30 -2
  141. package/dist/{useTouchGate-BhhEMlwJ.js → useTouchGate-D9Zvrzyc.js} +1 -1
  142. package/dist/useUserInvalidAria-DVu1eTXG.js +29 -0
  143. package/dist/useViewTransition-DYIK6Gzb.js +16 -0
  144. package/dist/utils/index.d.ts +1 -0
  145. package/dist/utils/moveBefore.d.ts +15 -0
  146. package/package.json +27 -6
  147. package/src/styles/animations.css +77 -0
  148. package/src/styles/cards.css +6 -2
  149. package/src/styles/dock.css +109 -109
  150. package/src/styles/drawer.css +2 -2
  151. package/src/styles/glass.css +89 -6
  152. package/src/styles/index.css +10 -1
  153. package/src/styles/instrument-chassis.css +28 -1
  154. package/src/styles/scroll-driven.css +72 -0
  155. package/src/styles/theme.css +6 -0
  156. package/src/styles/tokens.css +345 -289
  157. package/src/styles/typography.css +65 -131
  158. package/src/styles/utilities.css +199 -81
  159. package/src/styles/view-transition.css +62 -0
  160. package/dist/HoverPopover-Btv4RQfv.js +0 -80
  161. package/dist/Label-C8QMJSsf.js +0 -32
  162. package/dist/UnderlineTabs-BtrUcXn-.js +0 -64
  163. package/dist/composables/motion/useSpringOrchestrator.d.ts +0 -15
  164. /package/dist/{CollapsibleContent-DHRuXE3P.js → CollapsibleContent-CVMOcYlV.js} +0 -0
  165. /package/dist/{ContextMenuContent-CvXfU5qz.js → ContextMenuContent-otjFIu8v.js} +0 -0
  166. /package/dist/{HoverCardContent-4nN5-5bz.js → HoverCardContent-DaGrgJBO.js} +0 -0
  167. /package/dist/{InstrumentChassis-DOaVYyWq.js → InstrumentChassis-CnHTMxds.js} +0 -0
  168. /package/dist/{InstrumentRail-jHDqXj70.js → InstrumentRail-C6dEbi8E.js} +0 -0
  169. /package/dist/{ModalOverlay-DKLVY-cj.js → ModalOverlay-iWiAgbYH.js} +0 -0
  170. /package/dist/{PaperBackdrop-Bc2drCqJ.js → PaperBackdrop-CeZ-w0R0.js} +0 -0
  171. /package/dist/{SelectGroup-O69GTQ77.js → SelectGroup-DdR4tdDY.js} +0 -0
  172. /package/dist/{SelectSeparator-GTHxKO0a.js → SelectSeparator-CXm_hlqA.js} +0 -0
  173. /package/dist/{Separator-_NCypg_C.js → Separator-D8AUMhxY.js} +0 -0
  174. /package/dist/{Switch-CL0uxu8F.js → Switch-Cr1t_F_U.js} +0 -0
  175. /package/dist/{ToggleGroupItem-BYG_8M9M.js → ToggleGroupItem-OesUouE7.js} +0 -0
  176. /package/dist/{TooltipProvider-C5QLSPto.js → TooltipProvider-DE78vbEP.js} +0 -0
  177. /package/dist/{_plugin-vue_export-helper-n-_DRHWS.js → _plugin-vue_export-helper-Dq1MygBL.js} +0 -0
  178. /package/dist/{badge-BbxVKZfw.js → badge-x46my_Fo.js} +0 -0
  179. /package/dist/composables/{motion → dark}/installDarkModeSync.d.ts +0 -0
  180. /package/dist/{dockContext-BDGSrwsV.js → dockContext-D5NZCWJs.js} +0 -0
  181. /package/dist/{keys-DVkcUktU.js → keys-CaTQS-vx.js} +0 -0
  182. /package/dist/{menuItemVariants-B2nDL7zH.js → menuItemVariants-BsbGNq9C.js} +0 -0
  183. /package/dist/{presets-BMzCDrmR.js → presets-a-D93K1S.js} +0 -0
  184. /package/dist/{search-ocd8tmL9.js → search-DBAiUABx.js} +0 -0
  185. /package/dist/{useGlassRenderer-DMDdMH55.js → useGlassRenderer-Ds-nmrGz.js} +0 -0
  186. /package/dist/{useGlobalDark-PMiP5Jku.js → useGlobalDark-B0WvLJE3.js} +0 -0
  187. /package/dist/{useIntersectionPause-CXYfYg_C.js → useIntersectionPause-IY2CwPQb.js} +0 -0
  188. /package/dist/{useInterval-COlTCeVa.js → useInterval-DVgGUf_y.js} +0 -0
  189. /package/dist/{useKeyboardShortcuts-B1ev1YEC.js → useKeyboardShortcuts-Dpw_RUcB.js} +0 -0
  190. /package/dist/{useResizeObserver-F4aRR4Cj.js → useResizeObserver-Cg9npuM3.js} +0 -0
  191. /package/dist/{useSortable-Ck0rBJ4g.js → useSortable-Cq2Y1JLO.js} +0 -0
  192. /package/dist/{useSpringMount-BTRBNzXP.js → useSpringMount-Cfk1XK1R.js} +0 -0
  193. /package/dist/{useTimer-lp5NlH4w.js → useTimer-NAaj9zNq.js} +0 -0
  194. /package/dist/{x-cdWAmO-q.js → x-q7pJa83X.js} +0 -0
@@ -101,13 +101,30 @@
101
101
  Interactive cards live in <Card> (which owns its own hover composition)
102
102
  or in components that explicitly opt into a hover variant. */
103
103
  .glass-card {
104
+ /* Focus-elevation rungs (AQ.W3 §W3.1a) — identity = at-rest paint; the
105
+ `:has(:focus-visible)` rule redefines them (one source, shared with
106
+ the fallback). */
107
+ --card-focus-shadow: var(--shadow-card);
108
+ --card-focus-border: var(--glass-border-quiet);
104
109
  position: relative;
105
110
  background: var(--glass-bg-quiet);
106
111
  backdrop-filter: var(--glass-blur-quiet);
107
- border: 1px solid var(--glass-border-quiet);
112
+ border: 1px solid var(--card-focus-border);
108
113
  border-radius: var(--radius-card);
109
- box-shadow: var(--shadow-card);
114
+ box-shadow: var(--card-focus-shadow);
110
115
  contain: layout style;
116
+ transition:
117
+ box-shadow var(--duration-fast) var(--ease-standard),
118
+ border-color var(--duration-fast) var(--ease-standard);
119
+ }
120
+
121
+ /* Elevate one rung on descendant KEYBOARD focus (`:focus-visible`, not
122
+ pointer). Scoped to `.glass-card`. `:has()` Baseline Widely; the
123
+ `@supports not selector(:has(*))` class fallback (below) ships anyway
124
+ (focus-elevation is UX-critical — child-state-styling MANDATORY clause). */
125
+ .glass-card:has(:focus-visible) {
126
+ --card-focus-shadow: var(--shadow-md);
127
+ --card-focus-border: var(--glass-border-floating);
111
128
  }
112
129
 
113
130
  /* ── Glassmorphic circular icon button ── */
@@ -115,6 +132,10 @@
115
132
  .glass-btn {
116
133
  @apply flex items-center justify-center cursor-pointer;
117
134
 
135
+ /* Individual-transform identity base (AQ.W3 §W3.2) — `scale: 1` at rest
136
+ mints the stacking context once so the hover/press scale below does
137
+ not flicker it into being (the z-index/anchor hazard). */
138
+ scale: 1;
118
139
  width: var(--size-icon-btn);
119
140
  height: var(--size-icon-btn);
120
141
  border-radius: var(--radius-pill);
@@ -126,18 +147,18 @@
126
147
  background var(--duration-fast) var(--ease-standard),
127
148
  border-color var(--duration-fast) var(--ease-standard),
128
149
  color var(--duration-fast) var(--ease-standard),
129
- transform var(--duration-normal) var(--spring-snappy);
150
+ scale var(--duration-normal) var(--spring-snappy);
130
151
  }
131
152
 
132
153
  .glass-btn:hover:not(:disabled) {
133
154
  background: color-mix(in srgb, var(--background) 85%, transparent);
134
155
  border-color: var(--surface-tint-22);
135
156
  color: var(--foreground);
136
- transform: scale(var(--scale-hover));
157
+ scale: var(--scale-hover);
137
158
  }
138
159
 
139
160
  .glass-btn:active:not(:disabled) {
140
- transform: scale(var(--scale-press));
161
+ scale: var(--scale-press);
141
162
  }
142
163
 
143
164
  .glass-btn:focus-visible {
@@ -210,12 +231,60 @@
210
231
  color: var(--surface-tint-35);
211
232
  }
212
233
 
213
- .input-pill:focus {
234
+ /* AQ.W4 §W4.6 — keyboard-focus ring only. Was bare `:focus` (showed the
235
+ accent ring on a mouse click); `:focus-visible` matches the
236
+ `.focus-ring` / `.glass-btn` / dock-control discipline. Ordered BEFORE
237
+ the `:user-invalid` rungs so an invalid focused field shows destructive,
238
+ not accent (the `:user-invalid:focus-visible` rule below wins by order +
239
+ specificity). `:focus-visible` Baseline Widely — no fallback. */
240
+ .input-pill:focus-visible {
214
241
  outline: none;
215
242
  border-color: var(--color-accent-opaque, var(--ring));
216
243
  box-shadow: 0 0 0 2px var(--color-accent, color-mix(in srgb, var(--ring) 30%, transparent));
217
244
  }
218
245
 
246
+ /* AQ.W4 §W4.1 — validity vocabulary on `.input-pill` (Input + Textarea).
247
+ The forgiving `:where(:user-invalid, .user-invalid-fallback)` group is
248
+ ONE rule covering native + the `useUserInvalidAria` fallback class (css
249
+ §3.2; NOT a live+dead alias — the class is the SOLE fallback for engines
250
+ without `:user-invalid`). The destructive/success tints reuse the
251
+ semantic tokens via `color-mix` per the house pattern (W2). Non-color
252
+ reinforcement is the error TEXT (W4.5 `error` slot) + the `required`
253
+ asterisk — the border/bg shift is the supplementary cue, never the sole
254
+ one. `:user-valid` is intentionally subtle (border only, no bg fill) so
255
+ a long valid form is not a wall of green. */
256
+ .input-pill:where(:user-invalid, .user-invalid-fallback) {
257
+ border-color: var(--destructive);
258
+ background: color-mix(in srgb, var(--destructive) 8%, var(--glass-bg-quiet));
259
+ }
260
+ .input-pill:where(:user-valid, .user-valid-fallback) {
261
+ border-color: var(--success);
262
+ }
263
+ /* Invalid + keyboard-focused → destructive ring (overrides the accent
264
+ `:focus-visible` ring above by order + the extra `:user-invalid`
265
+ compound). */
266
+ .input-pill:where(:user-invalid, .user-invalid-fallback):focus-visible {
267
+ border-color: var(--destructive);
268
+ box-shadow: 0 0 0 var(--focus-ring-width)
269
+ color-mix(in srgb, var(--destructive) 35%, transparent);
270
+ }
271
+
272
+ /* AQ.W4 §W4.3 — `field-sizing: content` autosize (opt-in via the Textarea
273
+ `autosize` prop → `[data-autosize]`). The textarea grows vertically with
274
+ content between a 3-line floor and a token-driven ceiling, then scrolls.
275
+ `field-sizing` Baseline Newly (Chromium 2024) — on a non-supporting
276
+ engine the declaration is ignored and the element keeps the
277
+ `min/max-block-size` bounds + standard scroll (no JS, no `@supports`,
278
+ no grid-mirror polyfill). The fixed-size path (default, `min-h-20`) is
279
+ the unchanged no-op fallback. */
280
+ .input-pill[data-autosize] {
281
+ field-sizing: content;
282
+ width: 100%;
283
+ min-block-size: 3lh;
284
+ max-block-size: var(--textarea-autosize-max, 12lh);
285
+ resize: vertical;
286
+ }
287
+
219
288
  .input-pill:disabled {
220
289
  opacity: 0.5;
221
290
  cursor: not-allowed;
@@ -275,3 +344,17 @@
275
344
  }
276
345
  }
277
346
  }
347
+
348
+ /* ── :has() focus-elevation fallback (AQ.W3 §W3.1a) ──────────────────────
349
+ SOLE fallback for engines without `:has()`. `.is-focus-within` is toggled
350
+ by a ≤6-LOC focusin/focusout guard in `Card.vue` that runs ONLY when
351
+ `!CSS.supports('selector(:has(*))')` (modern engines run zero JS). The
352
+ class redefines the SAME `--card-focus-*` rungs as the `:has()` rule, so the
353
+ override values have one source. NOT a live+dead alias — `:has()` is the
354
+ enhancement, this the documented degradation path. */
355
+ @supports not selector(:has(*)) {
356
+ .glass-card.is-focus-within {
357
+ --card-focus-shadow: var(--shadow-md);
358
+ --card-focus-border: var(--glass-border-floating);
359
+ }
360
+ }
@@ -63,7 +63,14 @@
63
63
  * pop, dialog-scale, dropdown, tab-fade).
64
64
  * 10. animations.css — @keyframes for components consumed via
65
65
  * `animation:` properties in (9) and component
66
- * <style> blocks.
66
+ * <style> blocks. Includes the §TOP-LAYER
67
+ * `@starting-style` entry/exit grammar (AQ.W5).
68
+ * 10a. scroll-driven.css — native scroll-driven recipes (.scroll-progress
69
+ * + [data-scroll-reveal]); the `@supports`-gated
70
+ * primary over the JS-composable fallback (AQ.W5).
71
+ * 10b. view-transition.css — the `.gl-list-item` View-Transitions group
72
+ * recipe + `--vt-*` axes (AQ.W5; the
73
+ * `useViewTransition` substrate's CSS half).
67
74
  * 11. utilities.css — focus-ring, btn-audacious + btn-interactive
68
75
  * (press cluster; K W6 + Q.W3 Lane E),
69
76
  * rainbow-vivid + rainbow-pastel. Consumes earlier
@@ -95,6 +102,8 @@
95
102
  @import "./floating-panel.css";
96
103
  @import "./transitions.css";
97
104
  @import "./animations.css";
105
+ @import "./scroll-driven.css";
106
+ @import "./view-transition.css";
98
107
  @import "./utilities.css";
99
108
  @import "./instrument-chassis.css";
100
109
  @import "./instrument-rail.css";
@@ -292,7 +292,34 @@
292
292
  @media (max-width: 720px) {
293
293
  .instrument-chassis .instrument-dial {
294
294
  grid-template-columns: 1fr;
295
- grid-template-rows: auto auto auto;
295
+ /* R0G-2 (AO.W3) reserve the dial's FINAL box from frame 0. The
296
+ desktop axis is already CLS-clean (the 3-column `align-items:
297
+ center` grid reserves row height from intrinsic min + the AP-Pγ
298
+ transform-only idle recentre). The mobile reflow previously
299
+ collapsed to `grid-template-rows: auto auto auto`, which reserves
300
+ NO height — the meter row, divider, and readout column sit at
301
+ zero height until the consumer's meter <canvas> + readout
302
+ numbers hydrate, then grow collapsed → final and push everything
303
+ below down ~326-331px → mobile-390 CLS 0.32-0.38.
304
+
305
+ The fix pins the dial box from frame 0: the meter row carries the
306
+ dominant reserve (`minmax(0, 1fr)` — it expands to fill the
307
+ envelope the `min-height` establishes), divider + readout stay
308
+ intrinsic (`auto`). The load-bearing reserve is `min-height` —
309
+ it fixes the dial's outer box so the rows distribute WITHIN a
310
+ reserved envelope rather than growing it post-hydration.
311
+
312
+ Both knobs are CSS custom properties (token-first). The
313
+ `--instrument-dial-min-height-mobile` canonical rung lands in
314
+ tokens.css at AO.W4; until then the inline `24rem` fallback IS
315
+ the default and carries the contract. A consumer whose meter is
316
+ a different size retunes the token — a tuning knob, not a
317
+ workaround for a missing reserve. */
318
+ grid-template-rows:
319
+ var(--instrument-dial-meter-reserve-mobile, minmax(0, 1fr))
320
+ auto
321
+ auto;
322
+ min-height: var(--instrument-dial-min-height-mobile, 24rem);
296
323
  gap: var(--instrument-dial-gap-mobile, 1.5rem);
297
324
  }
298
325
 
@@ -0,0 +1,72 @@
1
+ /*
2
+ * scroll-driven.css — native scroll-driven CSS animations (AQ.W5 §Design 1).
3
+ *
4
+ * Cascade rung after animations.css. Two token-first recipe families that move
5
+ * the scroll-progress + stagger-reveal work OFF the main thread (the consumer
6
+ * INP lever): the browser runs them on the compositor instead of a rAF/IO
7
+ * listener loop in JS.
8
+ *
9
+ * .scroll-progress — a 0..1 scaleX bar driven by a `scroll()` timeline.
10
+ * The `useScrollProgress` composable replacement.
11
+ * [data-scroll-reveal] — fade + lift on entry, one `view()` timeline PER
12
+ * child (the stagger is implicit — no setTimeout
13
+ * cascade). The `useStaggerReveal` composable
14
+ * replacement.
15
+ *
16
+ * DUAL-PATH with a SINGLE writer (no double-run): when the engine supports
17
+ * `animation-timeline`, the CSS here owns the visual axis and the composables
18
+ * gate their listener/observer machinery OFF (so CSS and JS never both write
19
+ * the same target). When the engine does NOT support it, this block is skipped
20
+ * by `@supports` and the composable is the sole writer. See the gate at the top
21
+ * of `useScrollProgress.ts` / `useStaggerReveal.ts`.
22
+ *
23
+ * Baseline: `scroll-driven-animations` = Newly Available → adopt CSS as
24
+ * primary, keep the composable as the ≤ 20-LOC feature-detected fallback.
25
+ *
26
+ * Reduced-motion is the OUTER gate: the whole `@supports` block sits under
27
+ * `prefers-reduced-motion: no-preference`, so under PRM no scroll animation
28
+ * attaches at all and content renders in its terminal state (the `from`
29
+ * keyframe is never applied because the animation never binds).
30
+ */
31
+
32
+ /* ── Scroll progress (scroll() timeline) — drives a 0..1 scaleX bar.
33
+ * Consumers add `.scroll-progress` on a position:fixed/absolute element; the
34
+ * scroller is the nearest ancestor block scroller (`root` by default; override
35
+ * via `--scroll-progress-scroller`). */
36
+ @media (prefers-reduced-motion: no-preference) {
37
+ @supports (animation-timeline: scroll()) {
38
+ @keyframes gl-scroll-grow {
39
+ from { transform: scaleX(0); }
40
+ to { transform: scaleX(1); }
41
+ }
42
+ .scroll-progress {
43
+ transform-origin: 0 50%;
44
+ animation: gl-scroll-grow auto linear;
45
+ animation-timeline: scroll(var(--scroll-progress-scroller, root) block);
46
+ }
47
+ }
48
+ }
49
+
50
+ /* ── View-driven entry (view() timeline) — the useStaggerReveal replacement.
51
+ * Each child of a `[data-scroll-reveal]` scroller fades + lifts on entry. The
52
+ * stagger is implicit in the per-element view-timeline (each child owns its
53
+ * own timeline), so NO setTimeout cascade is needed. Horizontal scrollers add
54
+ * `.scroll-reveal--inline` for a `view(inline)` axis. */
55
+ @media (prefers-reduced-motion: no-preference) {
56
+ @supports ((animation-timeline: view()) and (animation-range: entry)) {
57
+ @keyframes gl-reveal-in {
58
+ from {
59
+ opacity: 0;
60
+ transform: translateY(var(--scroll-reveal-rise, 6px));
61
+ }
62
+ }
63
+ [data-scroll-reveal] > * {
64
+ animation: gl-reveal-in auto linear both;
65
+ animation-timeline: view(block);
66
+ animation-range: entry 0% entry var(--scroll-reveal-range-end, 60%);
67
+ }
68
+ [data-scroll-reveal].scroll-reveal--inline > * {
69
+ animation-timeline: view(inline);
70
+ }
71
+ }
72
+ }
@@ -55,6 +55,9 @@
55
55
  Colors — core
56
56
  ═══════════════════════════════════════════════ */
57
57
  --color-border: var(--border);
58
+ /* AQ.W2 §3d — the whisper-alpha border hairline rung (border-border-soft /
59
+ bg-border-soft utilities). Auto-dark via --border. */
60
+ --color-border-soft: var(--border-soft);
58
61
  --color-input: var(--input);
59
62
  --color-ring: var(--ring);
60
63
  --color-background: var(--background);
@@ -81,6 +84,9 @@
81
84
  --color-card: var(--card);
82
85
  --color-card-foreground: var(--card-foreground);
83
86
 
87
+ /* R0G-5 — bg-surface-public-data-panel utility. */
88
+ --color-surface-public-data-panel: var(--surface-public-data-panel);
89
+
84
90
  --color-shadow: var(--shadow);
85
91
 
86
92
  /* Semantic foregrounds — bg-{success,warning,info}-foreground +