@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
@@ -11,6 +11,27 @@
11
11
  */
12
12
 
13
13
  :root {
14
+ /* ═══════════════════════════════════════════════
15
+ §-1 COLOR-SCHEME (AQ.W2 §1)
16
+
17
+ Lets native UI (scrollbars, spinbuttons, form-control chrome, the
18
+ default focus ring) honor the OS preference when the consumer has
19
+ NOT pinned a `.dark` class. glass-ui's dark mode is class-driven
20
+ (`.dark`, theme.css `@variant dark`), so `.dark` overrides to a hard
21
+ `dark` regardless of OS — but absent the class, native chrome should
22
+ still track `prefers-color-scheme`. `light dark` (not `only light`)
23
+ on `:root` delivers that; `.dark` hard-pins `dark`.
24
+
25
+ Baseline Widely Available → adopt natively, no `@supports` guard
26
+ (older engines ignore the property and keep default-light chrome).
27
+ `accent-color` (AQ.W2 §4) is the companion native-control brand;
28
+ both are inherited built-in <color>/keyword properties re-specified
29
+ inside `.dark`. The `--accent-color` token is defined in the §5
30
+ color block below (custom properties resolve order-independently).
31
+ ═══════════════════════════════════════════════ */
32
+ color-scheme: light dark;
33
+ accent-color: var(--accent-color);
34
+
14
35
  /* ═══════════════════════════════════════════════
15
36
  §0 THEME BRIDGE FALLBACKS
16
37
 
@@ -79,21 +100,10 @@
79
100
  headline and the thank-you headline stay in lockstep. */
80
101
  --motion-duration-complete-shimmer: 2.4s;
81
102
  --motion-delay-complete-shimmer: 220ms;
82
- /* AJ.W2-ζ canon checkpoint — the gold-headline shimmer at
83
- CompleteHeadline + ThankYou reads these two tokens under a
84
- one-shot CSS animation. The gradient (background-size: 240% 100%
85
- with --color-gold-light at 46%), the @keyframes
86
- (gold-headline-shimmer: background-position 120% 0 → -120% 0),
87
- and the animation declaration are mutually consistent: at 2.4s
88
- duration + 220ms delay the bright band traverses the headline
89
- glyphs cleanly. A regression that drops either token to 0ms /
90
- unset / 0 would silently collapse the celebratory shimmer to an
91
- imperceptible blow-through (live regression P1-12 surfaced this
92
- risk; investigation closed at the publisher as a verify — both
93
- values resolve correctly today). These two values are LOAD-
94
- BEARING. Do not retire / zero / un-publish without an explicit
95
- decision + companion consumer-side migration at speedtest's
96
- CompleteHeadline.vue + ThankYou.vue. */
103
+ /* The gold-headline shimmer reads these two tokens under a one-shot
104
+ animation: at 2.4s + 220ms delay the bright band traverses the headline
105
+ glyphs cleanly. Load-bearing zeroing either collapses the shimmer to
106
+ an imperceptible blow-through. */
97
107
 
98
108
  /* CompleteBadge staged-reveal cluster — the disc / ring / check curve
99
109
  fires at three asymmetric durations + delays per the A4-AF staged-
@@ -106,43 +116,16 @@
106
116
  --motion-delay-badge-ring: 220ms;
107
117
  --motion-delay-badge-check: 460ms;
108
118
 
109
- /* AJ-W4-κ — staggered-reveal increment canon (per A5 §8.9). Promotes
110
- the scattered per-consumer constants
111
- (`STATS_CARD_STAGGER_MS = 40` in MetricGaugeCards,
112
- `BAR_STAGGER_MS = 80` in DistributionChart,
113
- `SERIES_STAGGER_MS = 120` in TimeSeriesChart,
114
- `useStagger` default 80ms) to one shared canon so a per-row /
115
- per-cell / per-bar cascade across consumer surfaces reads at one
116
- of three named tiers.
117
-
118
- The three tiers are perceptually distinct registers:
119
- • tight (40ms) — dense row cascades where the gap between
120
- consecutive reveals should be sub-perceptual (StatsCards row
121
- strip, results-table rows under their `:nth-child(N+1)` delays)
122
- • default (80ms) — the canonical row-stagger rhythm (the
123
- speedtest ResultStack row-tint sweep, the DistributionChart
124
- bar entrance — both already at 80ms). Aliased as `default`
125
- to match `useStagger`'s built-in fallback so consumers
126
- omitting `delayMs` resolve to the same token.
127
- • relaxed (120ms) — wider cascades where each reveal carries
128
- its own attention budget (TimeSeriesChart series entrance)
129
-
130
- The FD2 §6 rule-1 "shared period multiple" canon for ambient
131
- cycles extends here to staggers: at 40/80/120ms, the default
132
- (80ms) is the LCM of tight (40) AND a 2/3 of relaxed (120)
133
- — a tight cascade beating against a default cascade syncs on
134
- every-other-reveal, and a default cascade against a relaxed
135
- cascade syncs on every-three-reveals. Consumers that nest
136
- multiple cascades on adjacent surfaces should pick adjacent
137
- tiers so the cross-beats stay quiet.
138
-
139
- Consumers can read these tokens directly from inline-style
140
- calc() expressions (`animation-delay: calc(var(--motion-stagger-default) * var(--row-index))`)
141
- or via JS by resolving the CSS custom property at runtime
142
- (`getComputedStyle(document.documentElement).getPropertyValue('--motion-stagger-default')`).
143
- The latter shape collapses the speedtest TS-side constants
144
- (SERIES_STAGGER_MS, BAR_STAGGER_MS, STATS_CARD_STAGGER_MS) into
145
- single-source token reads. */
119
+ /* Staggered-reveal increment canon three perceptually-distinct tiers for
120
+ per-row/per-cell/per-bar cascades:
121
+ • tight (40ms) dense row cascades, sub-perceptual gap
122
+ default (80ms) the canonical row-stagger rhythm (matches
123
+ `useStagger`'s built-in fallback)
124
+ relaxed (120ms) wider cascades where each reveal carries its own
125
+ attention budget
126
+ Adjacent tiers keep cross-beats quiet (80 is the LCM of 40 and 2/3 of
127
+ 120). Consumers read these via inline-style calc() or `getComputedStyle`
128
+ at runtime. */
146
129
  --motion-stagger-tight: 40ms;
147
130
  --motion-stagger-default: 80ms;
148
131
  --motion-stagger-relaxed: 120ms;
@@ -199,23 +182,13 @@
199
182
  --ease-accelerate: var(--ease-in);
200
183
 
201
184
  /* ═══════════════════════════════════════════════
202
- §2.A AMBIENT MOTION — Pulse aura tokens (AB.W3.T1)
203
-
204
- Parameterise the breathing rhythm for `<Pulse variant="aura">`
205
- so consumers don't re-author the cycle per site. The 6s
206
- duration is the canon ambient-pulse rate (matches the dial's
207
- idle breathing). Scale 1.0 1.15 reads as a quiet halo at
208
- intensity="normal"; the Pulse component remaps min/max from
209
- its `intensity` prop ('subtle' = 1.06; 'vivid' = 1.22).
210
-
211
- Opacity min/max scope is `--pulse-aura-opacity-{min,max}` —
212
- the aura ALWAYS keeps a visible halo (min 0.55) so the colour
213
- stays read at the trough; the peak goes to 0.95 so the breath
214
- reads as a soft swell, not a fade-in-fade-out.
215
-
216
- Reduced motion: Pulse.vue's scoped @media bracket forces
217
- `animation: none` and parks at the min stop. Depth + colour
218
- remain visible; the breath cycle disables.
185
+ §2.A AMBIENT MOTION — Pulse aura tokens
186
+
187
+ Breathing rhythm for `<Pulse variant="aura">`. The 6s duration is the
188
+ canon ambient-pulse rate; scale 1.0 1.15 reads as a quiet halo at
189
+ intensity="normal" (Pulse remaps min/max from its `intensity` prop).
190
+ The aura always keeps a visible halo at the trough (opacity min 0.55).
191
+ Reduced motion: Pulse.vue parks at the min stop, breath cycle disabled.
219
192
  ═══════════════════════════════════════════════ */
220
193
  --animate-ambient-pulse-duration: 6s;
221
194
  --animate-ambient-pulse-scale-min: 1.0;
@@ -247,37 +220,18 @@
247
220
  --progress-sectioned-track: var(--secondary);
248
221
 
249
222
  /* ═══════════════════════════════════════════════
250
- §2.C ANIMATION EXPRESSIVENESS — AI.W4 grammar
251
- (publisher-side; consumer-side companions live in speedtest)
252
-
253
- Three idiom families compose the W4 wave:
254
-
255
- Progress lifecycle (M.1) the under-meter / survey progress bar
256
- rides an intake pulse on rising-edge, a crescendo brightening at
257
- ≥85%, and a one-shot discharge flash at 100%. The crescendo is a
258
- typed CSS variable (`@property --progress-crescendo`) so the
259
- indicator's leading-edge gradient stop interpolates smoothly.
260
-
261
- Chassis phase-tint companion (M.1) — the `--phase-color` cross-
262
- fade established by the chassis cascade gains an amount companion
263
- (`@property --phase-tint-amount`) so the chassis backdrop "warms
264
- toward" the active phase. Both typed vars interpolate together
265
- across the speedtest-owned `--motion-duration-phase-handoff`
266
- window; the chassis reads the consumer-tuned clock with a safe
267
- 600ms default so a non-speedtest consumer still gets the cross-
268
- fade shape.
269
-
270
- • Audacious button press-ripple (M.2 Q5 — ratified G-AI-D27) — the
271
- `btn-audacious` utility gains an in-place `@property --ripple-
272
- radius` ripple emanating from the pressed surface. Single typed
273
- length, ramps 0 → max over the ripple duration, retires on
274
- release. Q3 (needle micro-jitter) + Q4 (DockLayerGroup sympath-
275
- etic motion) were pruned at G-AI-D27 — no tokens reserved.
276
-
277
- All three families coexist with the existing `--motion-*` /
278
- `--phase-*` cluster. Speedtest re-uses these tokens at the existing
279
- --motion-duration-phase-handoff (consumer-side, 600ms). PRM brackets
280
- live alongside each consumer rule. */
223
+ §2.C ANIMATION EXPRESSIVENESS
224
+
225
+ Three idiom families:
226
+ Progress lifecycle the progress bar rides an intake pulse on
227
+ rising-edge, a crescendo brightening at ≥85%, and a one-shot discharge
228
+ flash at 100% (the crescendo is the typed `@property --progress-crescendo`).
229
+ Chassis phase-tint companion `@property --phase-tint-amount` so the
230
+ chassis backdrop warms toward the active phase, interpolating with
231
+ `--phase-color` across the consumer's phase-handoff window (600ms default).
232
+ Audacious button press-ripple `btn-audacious` gains a typed
233
+ `@property --ripple-radius` ramping 0 → max over the ripple duration.
234
+ ═══════════════════════════════════════════════ */
281
235
 
282
236
  /* Progress lifecycle — typed crescendo + segment-local durations */
283
237
  --motion-duration-progress-intake: 220ms; /* rising-edge pulse */
@@ -391,6 +345,13 @@
391
345
  --popover: var(--neutral-0);
392
346
  --popover-foreground: var(--foreground);
393
347
 
348
+ /* R0G-5 (AO.W4) — warm-neutral public-data panel surface. One warmth step
349
+ off --card (hue 44 vs 48, +4 sat, −2 L) so a consumer's aurora-OFF
350
+ /dashboard/* surfaces read with the admin canon's warm-neutral chrome
351
+ instead of the colder bare card. Opaque surface (the --card family), not
352
+ a --surface-tint-* overlay. Consumer applies on /dashboard/* only. */
353
+ --surface-public-data-panel: hsl(44 16% 96%);
354
+
394
355
  --muted: var(--neutral-1);
395
356
  --muted-foreground: var(--neutral-5);
396
357
  /* W7-α' (AK-FD1) — one rung less-faint than --muted-foreground for
@@ -413,6 +374,34 @@
413
374
  --shadow: hsl(24 10% 10%);
414
375
  --shadow-color: var(--foreground);
415
376
 
377
+ /* AQ.W2 §4 — native-control accent. `accent-color` is an inherited
378
+ built-in <color>, so per the §2b resolve-late discipline it reads a
379
+ dedicated UNREGISTERED token set per-mode (NOT light-dark()) and is
380
+ re-specified inside `.dark` — otherwise the accent freezes to the
381
+ light shade at the cascade root. Light: muted-black checkmarks /
382
+ sliders on warm cream. Dark arm (`.dark`) reads `--ring` (mid-tone),
383
+ not the near-white dark `--primary`, so a checkbox's white checkmark
384
+ keeps contrast headroom (accent-color.md §5). */
385
+ --accent-color: var(--primary);
386
+
387
+ /* Border hairline at whisper alpha — the canonical rung for
388
+ section-spine / panel-edge hairlines a consumer wants to read as an
389
+ iOS-26 whisper rather than a hard rule. Consumers compose this named
390
+ rung instead of hand-mixing `color-mix(... var(--border) ...)`
391
+ per-site (token-first). 45% is the canonical whisper. Auto-dark via
392
+ `--border` (which is `var(--neutral-4)`, light-dark()-resolved). */
393
+ --border-soft: color-mix(in srgb, var(--border) 45%, transparent);
394
+
395
+ /* AQ.W3 §W3.4 — tokenized scrollbar thumb + track. Minted in the color
396
+ block so the `scrollbar-color` / `::-webkit-scrollbar-thumb` rungs read a
397
+ single source. Auto-dark via `--muted-foreground` (light-dark()-resolved,
398
+ AQ.W2) — the OS scrollbar chrome also honors `color-scheme: dark`, so the
399
+ custom thumb tracks the dark surface without an explicit dark mirror. The
400
+ thumb α (25%) matches the prior inline `.scrollbar-thin` value byte-for-
401
+ byte; `transparent` track keeps the scroll-pane glass reading through. */
402
+ --scrollbar-thumb: color-mix(in srgb, var(--muted-foreground) 25%, transparent);
403
+ --scrollbar-track: transparent;
404
+
416
405
  /* Foreground-tint rungs — canonical handles for the 36+ raw
417
406
  `color-mix(in srgb, var(--foreground) N%, transparent)` sites surveyed
418
407
  in R5 axis-1. Each rung's α is named in its key (4 → 4%, 22 → 22%).
@@ -547,21 +536,12 @@
547
536
  variable at any ancestor. Auto-dark via `--card`. */
548
537
  --card-header-bg: color-mix(in srgb, var(--card) 60%, transparent);
549
538
 
550
- /* Dock shadows */
551
- /* User 2026-05-13 (third + fourth report). The dock previously layered:
552
- 1) directional `0 4px 20px` drop → retired (third report; the Y-
553
- offset concentrated on the pill's rounded right cap and read as
554
- a right-edge halo on the rightmost child).
555
- 2) `0 0 0 1px` hairline outer ring → retired (fourth report; in
556
- dark mode the 10% cream-white ring traced the right-cap arc and
557
- still read as a shadow even after the directional drop was
558
- gone).
559
- The dock's own `border: 1.5px solid var(--glass-border-dock)` already
560
- provides silhouette definition, so the outer ring was redundant. The
561
- canonical dock shadow is now a single omnidirectional glow in the
562
- `--shadow-md`/`--shadow-lg` family. Per-instance directional drop
563
- can still be reinstated via `--shadow-dock-override` (consumed by
564
- every `.glass-dock` state selector — see dock.css). */
539
+ /* Dock shadows — a single omnidirectional glow in the
540
+ `--shadow-md`/`--shadow-lg` family (a directional drop concentrated on
541
+ the pill's rounded right cap as a right-edge halo; the dock's own
542
+ border already defines the silhouette). Per-instance directional drop
543
+ reinstates via `--shadow-dock-override` (consumed by every `.glass-dock`
544
+ state selector see dock.css). */
565
545
  --shadow-dock: 0 0 20px color-mix(in srgb, var(--shadow-color) 14%, transparent);
566
546
  --shadow-dock-collapsed: 0 0 12px color-mix(in srgb, var(--shadow-color) 12%, transparent);
567
547
  --dock-shadow: var(--shadow-dock);
@@ -617,27 +597,11 @@
617
597
  --glass-blur-resting-radius: 12px;
618
598
  --glass-blur-floating-radius: 16px;
619
599
  --glass-blur-overlay-radius: 24px;
620
- /* AJ.W2-β — dock blur lifted to 14px (was 0px at J.W3.C, was 1px
621
- pre-J.W3.C). Per FD1 §4 §1.9 (AJ-time live regression P1-11):
622
- "the dock should feel anchored to its surface; too much blur
623
- dissociates" but zero blur reads as "transparent-with-tint",
624
- NOT as "feathered glass." The AJ-time perceptual register
625
- overrides the J.W3.C compositor-cost concern: 14px is the lower
626
- end of the FD1 §4 target range (14-16px); the dock composes
627
- `blur()` only (no saturate — preserved from J.W3.C); the
628
- `prefers-reduced-transparency` PRM bracket at glass.css:229
629
- still maps the dock to its opacity-only register.
630
- Quiet tier (above) lifted 3px → 10px on the same perceptual-
631
- register reset (FD1 §4 target range 10-12px; 10px is the lower
632
- end). The MetricBadge pills + InstrumentChassis-internal cells
633
- now read as translucent gauge rather than flat tint.
634
-
635
- AL-W3-α (T10 per A-synthesis §1.5): retune 14px → 11px with a
636
- paired opacity lift 0.32 → 0.42 (below). The user mandate at
637
- AL-time was "slight blur" + "refined glassyness" — at 11px /
638
- 0.42 the dock reads as a CRISPER GLASS PILL (the iOS Control
639
- Center register), not a feathered watercolour wash. Holds the
640
- register at the lower blur radius. */
600
+ /* Dock blur radius 11px, paired with the 0.42 opacity below: a crisp
601
+ glass pill (the iOS Control Center register), not a feathered wash.
602
+ The dock composes `blur()` only (no saturate); the
603
+ `prefers-reduced-transparency` bracket at glass.css maps it to the
604
+ opacity-only register. */
641
605
  --glass-blur-dock-radius: 11px;
642
606
 
643
607
  --glass-blur-wash: blur(var(--glass-blur-wash-radius)) saturate(1.05);
@@ -645,23 +609,14 @@
645
609
  --glass-blur-resting: blur(var(--glass-blur-resting-radius)) saturate(1.05);
646
610
  --glass-blur-floating: blur(var(--glass-blur-floating-radius)) saturate(1.4);
647
611
  --glass-blur-overlay: blur(var(--glass-blur-overlay-radius)) saturate(1.5);
648
- /* Dock blur composes blur() only — no saturate. The 14px radius
649
- feathers the aurora bleed-through into a watercolour register
650
- while `--glass-bg-dock` (32% card opacity) carries the
651
- translucent register. The dock reads as "feathered glass" rather
652
- than "transparent tint" (AJ.W2-β). */
612
+ /* Dock blur composes blur() only — no saturate. */
653
613
  --glass-blur-dock: blur(var(--glass-blur-dock-radius));
654
614
 
655
- /* Dock-specific opacity. Lighter than `resting` (0.65) so the dock reads
656
- as a translucent overlay rather than a panel backdrop bleed visible
657
- through it. Consumed by `.glass-dock` via the `--glass-bg-dock` token.
658
-
659
- AL-W3-α (T10 per A-synthesis §1.5): retune 0.32 0.42 paired with
660
- the dock blur radius drop (14px → 11px above). The user mandate at
661
- AL-time was "slight blur" + "refined glassyness" — the +0.10 opacity
662
- lift HOLDS the surface register against the tightened blur, so the
663
- dock still reads as a clearly painted chrome rather than dissociating
664
- into a frosted ghost. */
615
+ /* Dock-specific opacity (0.42) lighter than `resting` (0.65) so the dock
616
+ reads as a translucent overlay rather than a panel, backdrop bleed
617
+ visible through it. Consumed by `.glass-dock` via `--glass-bg-dock`. The
618
+ value holds the surface register against the tightened 11px blur so the
619
+ dock reads as painted chrome, not a frosted ghost. */
665
620
  --glass-opacity-dock: 0.42;
666
621
 
667
622
  /* Chassis-specific opacity. Looser than `default` (0.50) so the
@@ -881,6 +836,13 @@
881
836
  - var(--page-padding-top, 0rem)
882
837
  - 1rem
883
838
  );
839
+ /* R0G-2 (AO.W3/W4) — chassis mobile dial-reserve canon. instrument-
840
+ chassis.css's mobile breakpoint reserves the dial's final box from
841
+ frame 0 via these vars (with the same values as inline fallbacks, the
842
+ safety net). Token-first home so the vars resolve canonically. */
843
+ --instrument-dial-min-height-mobile: 24rem;
844
+ --instrument-dial-meter-reserve-mobile: minmax(0, 1fr);
845
+
884
846
  --max-width-input: 24rem;
885
847
  --input-min-width-sm: 5rem;
886
848
  --min-width-input-sm: var(--input-min-width-sm);
@@ -961,6 +923,15 @@
961
923
  WCAG 2.5.5 floor on touch devices. */
962
924
  --dock-touch-target: 2.75rem; /* 44px */
963
925
 
926
+ /* AQ.W3 §7 — canonical WCAG 2.5.5 (44px) touch-target floor for the
927
+ NON-dock coarse-pointer surfaces (`Button size="icon"`,
928
+ ExpandableContainer triggers, ResponsiveTabs mobile trigger). One
929
+ named rung the `@media (pointer: coarse)` block in utilities.css reads,
930
+ retiring the per-consumer one-liner `min-h-[44px]` patches. Equals
931
+ `--dock-touch-target` numerically; kept as a distinct token so the
932
+ dock floor and the general floor can be retuned independently. */
933
+ --touch-target: 2.75rem; /* 44px */
934
+
964
935
  /* MetricBadge — stacked variant geometry. The 2-row stacked layout
965
936
  (label / value+unit) wants a taller floor than the inline pill so the
966
937
  label has breathing room above the baseline pair. T.W2.T2 +
@@ -1000,27 +971,10 @@
1000
971
  --scale-press: 0.96;
1001
972
  --scale-press-dock: 0.92;
1002
973
 
1003
- /* Press-scale the canonical iOS Liquid Glass press value.
1004
- `--scale-press` (0.96) is the canonical rung every primitive
1005
- should reach for unless it has a documented reason — see
1006
- DESIGN.md §L3. `--scale-press-btn` (aliased to `--scale-press-sm`,
1007
- 0.97) is the slightly-softer rung the legacy button + slider
1008
- recipes consume.
1009
-
1010
- AL-W10 SLIM reconciliation (per audit G-W1-2 / G-W1-4 F-2):
1011
- the prior `--scale-press: 0.95` value drifted from the §L3
1012
- canonical 0.96 rung; the canon-amend lifts the token to match
1013
- the iOS `.regular` control rung the precept ratifies.
1014
-
1015
- Q.W4 Lane D (Q-sty-5) retired the P.W4 `--scale-press-{xs,md,lg}`
1016
- rungs: the ladder was minted as preemptive consumer-facing
1017
- substrate for a words/frontend `active:scale-[X.XX]` absorption
1018
- that never landed — a fleet-wide grep (words/frontend, fourier,
1019
- bbnf-buddy, speedtest, keyframes.js + glass-ui src/) found zero
1020
- `var(--scale-press-{xs,md,lg})` consumers. Substrate-without-
1021
- consumer is binary (N invariant 23 / L invariant 8); the three
1022
- unused rungs are gone. `sm` is retained — `--scale-press-btn`
1023
- aliases it. */
974
+ /* Press-scale rungs. `--scale-press` (0.96) is the canonical iOS Liquid
975
+ Glass press value every primitive reaches for unless it has a documented
976
+ reason (DESIGN.md §L3); `--scale-press-btn` aliases the slightly-softer
977
+ `--scale-press-sm` (0.97) the button + slider recipes consume. */
1024
978
  --scale-press-sm: 0.97;
1025
979
  --scale-press-btn: var(--scale-press-sm);
1026
980
  --opacity-disabled: 0.5;
@@ -1168,26 +1122,12 @@
1168
1122
  /* ═══════════════════════════════════════════════
1169
1123
  §17 METRIC
1170
1124
 
1171
- MetricRow / MetricStack value-clamp dialect. The post-P
1172
- `9ba68ca` + `d244dd5` commits introduced this 8-token family
1173
- (plus the P.W5 Lane A.1 MetricRow clamp work) as a private SFC
1174
- dialect the defaults lived as `var(…, fallback)` literals
1175
- scattered across MetricRow.vue / MetricStack.vue, never
1176
- discoverable or `:root`-overridable. Q.W4 Lane A promotes the
1177
- whole family here per the DESIGN.md feature-token-home rule;
1178
- the SFCs now consume them bare.
1179
-
1180
- The declared values ARE the `audacious` poster register — the
1181
- hero-scale clamp for a single giant number the user watches
1182
- climb. MetricStack's `[data-register="result"]` scoped selector
1183
- legitimately overrides this register-locally for the compact
1184
- multi-row ledger; that override now retunes a globally declared
1185
- default rather than minting a fallback.
1186
-
1187
- Three clamp arms each: `min` (floor), `cqi` (the binding
1188
- container-query middle term), `max` (ceiling). value + label
1189
- carry all three; unit carries min/max only (its cqi coefficient
1190
- is a fixed 6cqi, not consumer-tuned).
1125
+ MetricRow / MetricStack value-clamp dialect. The declared values are the
1126
+ `audacious` poster register the hero-scale clamp for a single giant
1127
+ number; MetricStack's `[data-register="result"]` selector overrides it
1128
+ locally for the compact multi-row ledger. Three clamp arms each: `min`
1129
+ (floor), `cqi` (the binding container-query middle term), `max`
1130
+ (ceiling); unit carries min/max only (its cqi is a fixed 6cqi).
1191
1131
  ═══════════════════════════════════════════════ */
1192
1132
 
1193
1133
  /* Value register — audacious-poster hero clamp */
@@ -1206,69 +1146,35 @@
1206
1146
  --metric-row-label-clamp-max: 2.75rem;
1207
1147
 
1208
1148
  /* ═══════════════════════════════════════════════
1209
- §2.D INSTRUMENT-CLUSTER COMPOSITION RHYTHM
1210
- AK.W3 / FD1 TRANSPOSITION 5 absorb.
1211
-
1212
- The under-meter progress bar nests INTO the dial's painted-disc
1213
- bound (FD2 §5.2) and any two stacked progress rails inside a
1214
- cluster share the same vertical rhythm token. Both tokens were
1215
- authored speedtest-local (`AJ.W3-α`, `AJ.W3-μ.3`) but the design
1216
- intent is library-canon: the instrument-chassis family owns the
1217
- under-meter / progress-cluster grammar, so the tokens absorb here
1218
- at AK.W3. Speedtest reads transitively through the canon.
1219
-
1220
- AM-W7-δ — `--meter-progress-gap` RETIRED (dead-canon). It was
1221
- absorbed pre-emptively at AK.W3 for a post-nest "meter ↔ per-phase
1222
- progress-bar gap" composition that never materialised: speedtest's
1223
- bar uses the negative `--meter-progress-inset` instead, and a
1224
- fleet grep (glass-ui src/ + demo + speedtest) found ZERO `var()`
1225
- consumers (only doc references in pre-AL/pre-AK audits flagging it
1226
- as G-AL-D-METER-PROGRESS-GAP-DEAD-CANON, routed to retire). Per
1227
- NO-legacy-code it is removed rather than kept as speculative
1228
- forward-compat reservation; a future glass-ui Meter primitive that
1229
- needs the gap re-authors it at its real consumer.
1230
-
1231
- • `--meter-progress-inset` — the negative-margin inset that pulls
1232
- the under-meter bar INTO the unpainted ring lane around the
1233
- dial canvas (~4% of meter-size, two-thirds of the way through
1234
- the lane). Consumed at `.phase-progress` with `margin-block-
1235
- start: calc(-1 * var(--meter-progress-inset))`.
1236
- • `--progress-stack-gap` — vertical rhythm between any two stacked
1237
- progress rails inside one cluster (the under-meter bar cluster
1238
- + the global PhaseTimeline siblinged at W3-β).
1149
+ §2.D INSTRUMENT-CLUSTER COMPOSITION RHYTHM
1150
+
1151
+ The instrument-chassis family owns the under-meter / progress-cluster
1152
+ grammar.
1239
1153
 
1240
- The `--meter-size` reference inside the inset clamp resolves
1241
- against the consumer's own `--meter-size` declaration; when no
1242
- consumer ships one (a non-speedtest demo of the chassis), the
1243
- inline fallback of 200px keeps the calc well-defined. */
1154
+ `--meter-progress-inset` the negative-margin inset that pulls the
1155
+ under-meter bar INTO the unpainted ring lane around the dial canvas
1156
+ (~4% of meter-size). Consumed at `.phase-progress` via
1157
+ `margin-block-start: calc(-1 * var(--meter-progress-inset))`. The
1158
+ `--meter-size` reference resolves against the consumer's own
1159
+ declaration; the 200px fallback keeps the calc well-defined.
1160
+ • `--progress-stack-gap` — vertical rhythm between any two stacked
1161
+ progress rails inside one cluster.
1162
+ ═══════════════════════════════════════════════ */
1244
1163
  --meter-progress-inset: calc(var(--meter-size, 200px) * 0.04);
1245
1164
  --progress-stack-gap: clamp(0.1875rem, 0.4cqi, 0.375rem);
1246
1165
 
1247
1166
  /* ═══════════════════════════════════════════════
1248
- §2.E CELEBRATION-TIER REGISTER — AK.W3 / FD1
1249
- TRANSPOSITION 5 absorb.
1250
-
1251
- The celebration cluster (speedtest "Complete!" headline,
1252
- ThankYou's "Thanks for taking the time" headline) is a SHARED
1253
- peak across multiple consumer surfaces. Before AK.W3 these
1254
- tokens were speedtest-local (`AJ.W3-μ.4`, W2-C headline-parity)
1255
- but the design intent is library-canon: any glass-ui consumer
1256
- composing a "completion" / "thank-you" surface should reach
1257
- for the same row-rhythm + headline-ceiling pair.
1258
-
1259
- • `--celebration-row-rhythm` — gap between the celebration
1260
- cluster's rows (cqi-axis so the rhythm tracks the card's
1261
- intrinsic width).
1262
- • `--text-celebration-headline-size` — the SINGLE designed peak
1263
- both celebration surfaces clamp toward (the W2-C unification).
1264
- cqi-axis so the size tracks each card's intrinsic width.
1265
- • `--complete-headline-size` — the per-consumer FONT-SIZE HOOK
1266
- that `CompleteHeadline.vue` reads (`font-size:
1267
- var(--complete-headline-size, …)`). Each consumer assigns the
1268
- canon clamp (`--text-celebration-headline-size`) to this hook
1269
- at the container so the headline pegs at the shared peak.
1270
- The default falls back to a smaller hero-rung clamp for
1271
- consumers that haven't opted into the celebration ceiling. */
1167
+ §2.E CELEBRATION-TIER REGISTER
1168
+
1169
+ Shared peak for any "completion" / "thank-you" surface.
1170
+
1171
+ `--celebration-row-rhythm` gap between the cluster's rows (cqi-axis).
1172
+ `--text-celebration-headline-size` the single designed peak both
1173
+ celebration surfaces clamp toward (cqi-axis).
1174
+ `--complete-headline-size` the per-consumer font-size hook a consumer
1175
+ assigns the canon clamp to so its headline pegs at the shared peak;
1176
+ the default falls back to a smaller hero-rung clamp.
1177
+ ═══════════════════════════════════════════════ */
1272
1178
  --celebration-row-rhythm: clamp(0.5rem, 1.6cqi, 1rem);
1273
1179
  --text-celebration-headline-size: clamp(2.5rem, 12cqi, 9rem);
1274
1180
  --complete-headline-size: clamp(2.25rem, 11cqi, 4rem);
@@ -1276,36 +1182,196 @@
1276
1182
  /* ═══════════════════════════════════════════════
1277
1183
  §19 TABLE DENSITY
1278
1184
 
1279
- A single unitless knob `--table-density` scales the cell
1280
- padding and header row height of the Table / DataTable
1281
- primitive. Default `1` is backward-compatible (resolves to
1282
- the same `1rem` cell padding and `3rem` header height as the
1283
- pre-knob hardcoded values). Consumers set this on a wrapping
1284
- element or on `:root` to tune density for their context:
1285
-
1286
- • 0.75 — compact admin table (tighter rows, more data/screen)
1287
- • 1 — default (unchanged)
1288
- • 1.25 — comfortable / touch-friendly rows
1289
-
1290
- The derived tokens are read by the `table-cell` and `table-head`
1291
- CSS utilities (utilities.css) which TableCell.vue and TableHead.vue
1292
- consume instead of the former Tailwind `p-4` / `h-12` literals.
1293
- Changing `--table-density` cascades instantly via CSS inheritance —
1294
- no JS prop is needed.
1185
+ A single unitless knob `--table-density` scales the cell padding +
1186
+ header row height of the Table / DataTable primitive. Default `1`
1187
+ resolves to 1rem cell padding + 3rem header height; 0.75 is a compact
1188
+ admin table, 1.25 is comfortable/touch-friendly. The derived tokens are
1189
+ read by the `table-cell` / `table-head` utilities; changing the knob
1190
+ cascades instantly via CSS inheritance no JS prop needed.
1295
1191
  ═══════════════════════════════════════════════ */
1296
1192
  --table-density: 1;
1297
1193
  --table-cell-px: calc(1rem * var(--table-density));
1298
1194
  --table-cell-py: calc(1rem * var(--table-density));
1299
1195
  --table-head-h: calc(3rem * var(--table-density));
1300
1196
  --table-head-px: calc(1rem * var(--table-density));
1197
+
1198
+ /* ═══════════════════════════════════════════════
1199
+ §20 PLATFORM MOTION (AQ.W5)
1200
+
1201
+ The native-platform motion substrate axes. Three families, each read
1202
+ by a `@supports`-gated CSS recipe in `scroll-driven.css`,
1203
+ `animations.css` (§TOP-LAYER), and `view-transition.css` — every visual
1204
+ knob a token so a consumer retunes without editing library source.
1205
+
1206
+ SCROLL-DRIVEN (scroll-driven.css). Values mirror the JS-fallback
1207
+ composable defaults (`useScrollProgress` / `useStaggerReveal`) so the
1208
+ native CSS path and the fallback path read identically — no visual seam
1209
+ at the `@supports` boundary.
1210
+
1211
+ TOP-LAYER (animations.css §TOP-LAYER). The `@starting-style` entry/exit
1212
+ grammar for native `<dialog>` / `[popover]` glass surfaces. Backdrop dim
1213
+ uses the `hsl(var(--background) / α)` channel form — the legitimate
1214
+ single-token alpha case (AQ.W2's color-mix migration is orthogonal).
1215
+
1216
+ VIEW-TRANSITION (view-transition.css). The shared `.gl-list-item` group
1217
+ recipe + the `--vt-*` axes the `useViewTransition` substrate consumers
1218
+ (dock layer swap, muster J's verdict re-rank) tune their swap against.
1219
+ ═══════════════════════════════════════════════ */
1220
+ --scroll-progress-scroller: root;
1221
+ --scroll-reveal-rise: 6px;
1222
+ --scroll-reveal-range-end: 60%;
1223
+
1224
+ --top-layer-enter-scale: 0.96;
1225
+ --top-layer-backdrop-blur: 8px;
1226
+ --top-layer-backdrop-dim: 0.5;
1227
+
1228
+ --vt-duration: var(--duration-normal);
1229
+ --vt-ease: var(--ease-apple-spring);
1230
+ --vt-rise: 8px;
1231
+ }
1232
+
1233
+ /* ═══════════════════════════════════════════════
1234
+ §-1b LIGHT-DARK() COLOR ARCHITECTURE (AQ.W2 §2)
1235
+
1236
+ Every PAIRED color token (a token whose `:root` and `.dark` values are
1237
+ BOTH a <color> and differ) folds onto one `light-dark(light, dark)`
1238
+ declaration, keyed off the element's `color-scheme` (§-1). This is the
1239
+ single-source-of-truth collapse of the `.dark` mirror AND the dynamism
1240
+ win: an unregistered custom property holding a `light-dark()` expression
1241
+ re-resolves under a descendant `color-scheme` override (a `.dark`
1242
+ code-block embedded in a light page, or vice-versa).
1243
+
1244
+ DISCIPLINE (§2b — BINDING): these tokens MUST stay UNREGISTERED (no
1245
+ `@property … syntax:"<color>"`). A registered <color> would resolve ONCE
1246
+ at the declaring element and inherit the RESOLVED color, freezing the
1247
+ descendant re-resolution. glass-ui's only `@property` registrations (§18)
1248
+ are non-color (percentage/length), so the discipline holds — W2 adds NO
1249
+ color `@property`.
1250
+
1251
+ The semantic `var()`-aliases (`--background`, `--muted`, `--border`,
1252
+ `--secondary`, `--accent`, `--card-foreground`, …) do NOT appear here:
1253
+ they point at the SAME source name in both modes and auto-track once the
1254
+ `--neutral-*` ladder + `--foreground` resolve via `light-dark()`. Their
1255
+ redundant `.dark` re-declarations DELETE below.
1256
+
1257
+ FALLBACK (§2c): this whole block is `@supports`-gated, so an engine
1258
+ WITHOUT `light-dark()` skips it and the retained `.dark` class block (the
1259
+ SOLE fallback floor) drives dark exactly as at HEAD. `light-dark()` is the
1260
+ enhancement OVER the class — not a parallel alias. Baseline Newly
1261
+ Available; the fallback floor is the pre-existing class block (net-zero
1262
+ new fallback LOC).
1263
+ ═══════════════════════════════════════════════ */
1264
+ @supports (color: light-dark(white, black)) {
1265
+ :root {
1266
+ /* Neutral ladder — the source the var()-aliases track */
1267
+ --neutral-0: light-dark(hsl(48 12% 98%), hsl(24 8% 6%));
1268
+ --neutral-1: light-dark(hsl(48 10% 95%), hsl(24 6% 11%));
1269
+ --neutral-2: light-dark(hsl(48 9% 90%), hsl(24 5% 16%));
1270
+ --neutral-3: light-dark(hsl(48 8% 82%), hsl(24 5% 22%));
1271
+ --neutral-4: light-dark(hsl(48 7% 70%), hsl(24 5% 34%));
1272
+ --neutral-5: light-dark(hsl(48 6% 40%), hsl(48 5% 62%));
1273
+ --neutral-6: light-dark(hsl(48 7% 30%), hsl(48 6% 72%));
1274
+
1275
+ /* Core surfaces + ink */
1276
+ --foreground: light-dark(hsl(24 10% 10%), hsl(48 10% 90%));
1277
+ --card: light-dark(var(--neutral-0), hsl(24 8% 10%));
1278
+ --popover: light-dark(var(--neutral-0), hsl(24 8% 10%));
1279
+ --surface-public-data-panel: light-dark(hsl(44 16% 96%), hsl(36 9% 12%));
1280
+
1281
+ --primary: light-dark(hsl(24 10% 10%), hsl(48 10% 90%));
1282
+ --primary-foreground: light-dark(var(--neutral-0), hsl(24 10% 10%));
1283
+ --destructive: light-dark(hsl(0 72% 50%), hsl(0 62.8% 30.6%));
1284
+ --destructive-foreground: light-dark(var(--neutral-0), hsl(48 10% 90%));
1285
+ --ring: light-dark(hsl(24 10% 10%), hsl(48 10% 70%));
1286
+ --shadow: light-dark(hsl(24 10% 10%), hsl(0 0% 5%));
1287
+
1288
+ /* §4 native-control accent — the per-mode arms (dark reads the
1289
+ mid-tone ring for checkmark-glyph contrast headroom, NOT the
1290
+ near-white dark primary). Joins the light-dark() collapse; still
1291
+ re-specified as `accent-color` inside `.dark` per §2b. */
1292
+ --accent-color: light-dark(var(--primary), var(--ring));
1293
+
1294
+ /* Section palette — jewel tones brightened ~20% L for dark */
1295
+ --section-color-0: light-dark(hsl(334 63% 47%), hsl(334 72% 70%));
1296
+ --section-color-1: light-dark(hsl(272 44% 47%), hsl(272 54% 73%));
1297
+ --section-color-2: light-dark(hsl(224 58% 46%), hsl(224 67% 72%));
1298
+ --section-color-3: light-dark(hsl(194 62% 36%), hsl(194 61% 64%));
1299
+ --section-color-4: light-dark(hsl(163 46% 35%), hsl(163 50% 60%));
1300
+ --section-color-5: light-dark(hsl(35 70% 42%), hsl(37 73% 67%));
1301
+ --section-color-6: light-dark(hsl(6 72% 49%), hsl(6 77% 66%));
1302
+ --section-color-7: light-dark(hsl(286 46% 47%), hsl(286 58% 72%));
1303
+ --section-color-8: light-dark(hsl(342 62% 44%), hsl(342 71% 69%));
1304
+ --section-color-9: light-dark(hsl(205 20% 38%), hsl(205 24% 70%));
1305
+ --section-color-10: light-dark(hsl(86 38% 36%), hsl(86 44% 63%));
1306
+ --section-color-11: light-dark(hsl(187 58% 39%), hsl(187 63% 65%));
1307
+ --section-color-12: light-dark(hsl(256 44% 52%), hsl(256 60% 74%));
1308
+
1309
+ --accent-pink: light-dark(hsl(330 65% 55%), hsl(335 55% 65%));
1310
+ --section-heading: light-dark(hsl(328 60% 46%), hsl(330 55% 68%));
1311
+ --accent-red: light-dark(hsl(0 72% 50%), hsl(0 68% 62%));
1312
+
1313
+ /* Viz basis (amber/green stay var()-aliases → auto-track) */
1314
+ --viz-fourier: light-dark(hsl(6 72% 49%), hsl(6 77% 66%));
1315
+ --viz-chebyshev: light-dark(hsl(224 58% 46%), hsl(224 67% 72%));
1316
+ --viz-legendre: light-dark(hsl(286 46% 47%), hsl(286 58% 72%));
1317
+
1318
+ /* WCAG companion chart labels */
1319
+ --chart-ping-label: light-dark(oklch(0.40 0.18 230), oklch(0.85 0.12 230));
1320
+ --chart-download-label: light-dark(oklch(0.40 0.20 22), oklch(0.85 0.14 22));
1321
+ --chart-upload-label: light-dark(oklch(0.40 0.16 55), oklch(0.85 0.12 55));
1322
+ --chart-jitter-label: light-dark(oklch(0.40 0.20 305), oklch(0.85 0.14 305));
1323
+
1324
+ /* Semantic UI accents */
1325
+ --tier-featured: light-dark(hsl(45 100% 50%), hsl(45 100% 60%));
1326
+ --tier-saved: light-dark(hsl(210 100% 60%), hsl(210 100% 70%));
1327
+ --like: light-dark(hsl(0 80% 60%), hsl(0 80% 68%));
1328
+ --success: light-dark(hsl(142 71% 45%), hsl(142 71% 58%));
1329
+ --warning: light-dark(hsl(38 92% 50%), hsl(38 92% 60%));
1330
+ --info: light-dark(hsl(217 91% 60%), hsl(217 91% 70%));
1331
+ --delete: light-dark(hsl(0 70% 55%), hsl(0 70% 62%));
1332
+
1333
+ /* Semantic foregrounds (warning-foreground is identical both modes
1334
+ → stays a single light-mode declaration, no light-dark() needed) */
1335
+ --success-foreground: light-dark(var(--neutral-0), hsl(48 10% 96%));
1336
+ --info-foreground: light-dark(var(--neutral-0), hsl(48 10% 96%));
1337
+
1338
+ /* Cartoon-shadow color primitives (§2d — plain colors, convert) */
1339
+ --shadow-cartoon-color: light-dark(rgb(0 0 0 / 0.12), rgb(255 255 255 / 0.07));
1340
+ --shadow-cartoon-color-soft: light-dark(rgb(0 0 0 / 0.06), rgb(255 255 255 / 0.03));
1341
+
1342
+ /* Gold family */
1343
+ --gold: light-dark(hsl(43 74% 49%), hsl(43 74% 55%));
1344
+ --gold-light: light-dark(hsl(51 100% 50%), hsl(51 100% 55%));
1345
+ --gold-dark: light-dark(hsl(34 87% 38%), hsl(34 87% 45%));
1346
+ }
1301
1347
  }
1302
1348
 
1303
1349
  /* ═══════════════════════════════════════════════
1304
1350
  DARK MODE — warm dark, section palette brightened ~20% L
1351
+
1352
+ FALLBACK FLOOR (AQ.W2 §2c): this class block is the SOLE non-light-dark()
1353
+ dark path. On a `light-dark()`-supporting engine with `.dark` present,
1354
+ `.dark { color-scheme: dark }` (§1) makes every §-1b token resolve to its
1355
+ dark arm and these explicit dark values agree with it (kept as the floor
1356
+ for non-supporting engines). The pure `var()`-alias re-declarations
1357
+ (`--muted`/`--secondary`/`--accent`/`--border`/`--input`/… and the
1358
+ `--background`/`*-foreground` aliases) are DELETED — they auto-track the
1359
+ `--neutral-*` ladder + `--foreground` resolved above; only EXPLICIT-color
1360
+ dark values (and the non-color overrides §2d) stay.
1305
1361
  ═══════════════════════════════════════════════ */
1306
1362
  .dark {
1363
+ /* §1 — hard-pin native chrome to dark regardless of OS preference. §4 —
1364
+ re-specify the inherited `accent-color` so it re-resolves to the dark
1365
+ arm (§2b: an inherited built-in <color> set at `:root` would freeze to
1366
+ the light shade without this re-specification). */
1367
+ color-scheme: dark;
1368
+ accent-color: var(--accent-color);
1369
+
1307
1370
  /* Neutral scale mirrors light-mode pattern: step UP from the background's
1308
- low L toward foreground. Same perceptual deltas as light. */
1371
+ low L toward foreground. Same perceptual deltas as light. FALLBACK
1372
+ FLOOR — kept verbatim for non-light-dark() engines (§2c); on a
1373
+ supporting engine `color-scheme: dark` (above) drives the §-1b
1374
+ light-dark() arms and these agree. */
1309
1375
  --neutral-0: hsl(24 8% 6%); /* L 6 — page surface (dark) */
1310
1376
  --neutral-1: hsl(24 6% 11%); /* L 11 — soft field */
1311
1377
  --neutral-2: hsl(24 5% 16%); /* L 16 — chip / tab-inactive */
@@ -1319,25 +1385,19 @@
1319
1385
  (cf. neutral-5's 7.39:1). */
1320
1386
  --neutral-6: hsl(48 6% 72%); /* L 72 — strong-muted text (secondary register) */
1321
1387
 
1322
- --background: var(--neutral-0);
1388
+ /* --background / --card-foreground / --popover-foreground / --muted /
1389
+ --muted-foreground{,-strong} / --secondary{,-foreground} /
1390
+ --accent{,-foreground} / --border / --input are pure var()-aliases —
1391
+ DELETED here (AQ.W2 §2a): they auto-track the --neutral-* ladder +
1392
+ --foreground above. Re-declaring them would be redundant. */
1323
1393
  --foreground: hsl(48 10% 90%);
1324
1394
  --card: hsl(24 8% 10%);
1325
- --card-foreground: var(--foreground);
1326
1395
  --popover: hsl(24 8% 10%);
1327
- --popover-foreground: var(--foreground);
1328
-
1329
- --muted: var(--neutral-1);
1330
- --muted-foreground: var(--neutral-5);
1331
- /* W7-α' (AK-FD1) — strong-muted secondary text. Auto-tracks the dark
1332
- neutral-6 rung above; by-colour, not alpha. */
1333
- --muted-foreground-strong: var(--neutral-6);
1334
- --secondary: var(--neutral-2);
1335
- --secondary-foreground: var(--foreground);
1336
- --accent: var(--neutral-3);
1337
- --accent-foreground: var(--foreground);
1338
1396
 
1339
- --border: var(--neutral-4);
1340
- --input: var(--neutral-4);
1397
+ /* R0G-5 (AO.W4) — dark mirror of the warm-neutral public-data panel.
1398
+ --card's dark hsl(24 8% 10%) nudged one warmth step toward amber
1399
+ (24→36) + +1 sat + +2 L so the dark dashboard panel lifts off the page. */
1400
+ --surface-public-data-panel: hsl(36 9% 12%);
1341
1401
 
1342
1402
  --primary: hsl(48 10% 90%);
1343
1403
  --primary-foreground: hsl(24 10% 10%);
@@ -1368,8 +1428,9 @@
1368
1428
  --viz-fourier: hsl(6 77% 66%);
1369
1429
  --viz-chebyshev: hsl(224 67% 72%);
1370
1430
  --viz-legendre: hsl(286 58% 72%);
1371
- --viz-amber: var(--section-color-5);
1372
- --viz-green: var(--section-color-4);
1431
+ /* --viz-amber / --viz-green / --meter-track-stroke are pure var()-aliases
1432
+ (--section-color-5/-4 / --foreground) — DELETED (§2a); they auto-track
1433
+ their sources, which convert via §-1b. */
1373
1434
 
1374
1435
  /* O.W6 Lane D — WCAG companion labels lift to L≈0.85 against the
1375
1436
  deep dark canvas; same two-token discipline as light mode (canvas
@@ -1379,11 +1440,6 @@
1379
1440
  --chart-upload-label: oklch(0.85 0.12 55);
1380
1441
  --chart-jitter-label: oklch(0.85 0.14 305);
1381
1442
 
1382
- /* O.W6 Lane D — Meter track stroke dark companion. Mirrors `:root`
1383
- (was speedtest's consumer-side `var(--background)` — bg-on-bg
1384
- invisible at dark mode; F1.V-02 closure). */
1385
- --meter-track-stroke: var(--foreground);
1386
-
1387
1443
  --tier-featured: hsl(45 100% 60%);
1388
1444
  --tier-saved: hsl(210 100% 70%);
1389
1445
  --like: hsl(0 80% 68%);