@mkbabb/glass-ui 3.9.0 → 3.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (265) hide show
  1. package/dist/{CardAction-DuArVky-.js → CardAction-DrAcAV4d.js} +2 -2
  2. package/dist/{CommandShortcut-CefCj5mt.js → CommandShortcut-mV2e1aG6.js} +2 -2
  3. package/dist/{DataTable-CUHMukiQ.js → DataTable-C3E6jZ5B.js} +2 -2
  4. package/dist/{DialogContent-BRkT1cjP.js → DialogContent-BxaaafFi.js} +1 -1
  5. package/dist/{HoverPopover-2LOIW34a.js → HoverPopover-CDA_SaCe.js} +1 -1
  6. package/dist/{MetricBadge-lTc002u2.js → MetricBadge-idgrkqoP.js} +1 -1
  7. package/dist/{Notification-BxK8LZMw.js → Notification-Cu0nN17_.js} +3 -3
  8. package/dist/{NumberFieldContent-BbLOh8RU.js → NumberFieldContent-CHEWghnY.js} +2 -2
  9. package/dist/{PopoverContent-BId6ggf_.js → PopoverContent-DpUvdYY-.js} +1 -1
  10. package/dist/{Progress-iEuD9pxG.js → Progress-BW-StFw2.js} +1 -1
  11. package/dist/{ScrollingText-BPP84wKo.js → ScrollingText-DruYCni_.js} +1 -1
  12. package/dist/{SelectScrollDownButton-T32cVFeM.js → SelectScrollDownButton-pirzjm--.js} +3 -3
  13. package/dist/{Switch-LDKLmmgx.js → Switch-DeAqg6pi.js} +1 -1
  14. package/dist/{TabsList-B8CVOQPC.js → TabsList-BAVzOZpg.js} +2 -2
  15. package/dist/{Toaster-1rYWrmAm.js → Toaster-CvuuW_y9.js} +49 -46
  16. package/dist/{ToggleGroupItem-Cev4pOVK.js → ToggleGroupItem-DtD37b4G.js} +4 -4
  17. package/dist/animated-digit.js +2 -2
  18. package/dist/api/index.d.ts +4 -4
  19. package/dist/api.js +1 -1
  20. package/dist/aurora.js +238 -547
  21. package/dist/{badge-BvwvT50i.js → badge-NdCQMvvB.js} +2 -2
  22. package/dist/badge.js +1 -1
  23. package/dist/{button-DN39cGqL.js → button-DyiWFAOE.js} +12 -12
  24. package/dist/button.js +1 -1
  25. package/dist/canvas.js +2 -2
  26. package/dist/card.js +1 -1
  27. package/dist/carousel.js +5 -5
  28. package/dist/collapsible.js +1 -1
  29. package/dist/{color-8jBjWiJ6.js → color-B65wWyQz.js} +9 -7
  30. package/dist/color.js +1 -1
  31. package/dist/command.js +1 -1
  32. package/dist/{compile-DAjIoEy2.js → compile-Ce_V55zi.js} +23 -23
  33. package/dist/components/custom/aurora/composables/atoms.d.ts +21 -4
  34. package/dist/components/custom/aurora/composables/runtime.d.ts +0 -9
  35. package/dist/components/custom/aurora/composables/uniformBridge.d.ts +0 -11
  36. package/dist/components/custom/aurora/constants/renderMode.d.ts +0 -32
  37. package/dist/components/custom/aurora/constants/shaders/brush.glsl.d.ts +1 -1
  38. package/dist/components/custom/aurora/constants/shaders/mediums.glsl.d.ts +2 -2
  39. package/dist/components/custom/aurora/constants/shaders/tonemap.glsl.d.ts +1 -1
  40. package/dist/components/custom/aurora/constants/shaders/vangogh-medium.glsl.d.ts +1 -0
  41. package/dist/components/custom/aurora/index.d.ts +1 -1
  42. package/dist/components/custom/constellation/Constellation.vue.d.ts +85 -1
  43. package/dist/components/custom/constellation/composables/createConstellationField.d.ts +35 -0
  44. package/dist/components/custom/constellation/composables/useConstellationPointer.d.ts +35 -0
  45. package/dist/components/custom/constellation/constants.d.ts +36 -0
  46. package/dist/components/custom/constellation/constellationDraw.d.ts +18 -0
  47. package/dist/components/custom/constellation/constellationField.d.ts +174 -63
  48. package/dist/components/custom/constellation/constellationInteraction.d.ts +102 -0
  49. package/dist/components/custom/constellation/index.d.ts +4 -2
  50. package/dist/components/custom/controls/DarkModeToggle.vue.d.ts +11 -0
  51. package/dist/components/custom/dock/GlassDock.vue.d.ts +2 -110
  52. package/dist/components/custom/dock/composables/dockMorphContext.d.ts +36 -0
  53. package/dist/components/custom/dock/composables/useDockMorphWindow.d.ts +15 -0
  54. package/dist/components/custom/dock/composables/useDockShellProps.d.ts +131 -0
  55. package/dist/components/custom/dock/composables/useLayerTransition.d.ts +44 -0
  56. package/dist/components/custom/dock/constants.d.ts +23 -0
  57. package/dist/components/custom/fourier-field/FourierField.vue.d.ts +6 -0
  58. package/dist/components/custom/fourier-field/index.d.ts +25 -1
  59. package/dist/components/custom/fourier-field/math.d.ts +20 -8
  60. package/dist/components/custom/fourier-field/presets.d.ts +54 -0
  61. package/dist/components/custom/goo-blob/GooBlob.vue.d.ts +8 -10
  62. package/dist/components/custom/goo-blob/composables/buildMetaballProgram.d.ts +18 -0
  63. package/dist/components/custom/goo-blob/composables/uploadBlobUniforms.d.ts +41 -0
  64. package/dist/components/custom/goo-blob/composables/useBlobPointer.d.ts +4 -3
  65. package/dist/components/custom/goo-blob/composables/useMetaballRenderer.d.ts +16 -21
  66. package/dist/components/custom/goo-blob/constants.d.ts +52 -0
  67. package/dist/components/custom/goo-blob/index.d.ts +1 -1
  68. package/dist/components/custom/goo-blob/shaders/metaball-uniforms.glsl.d.ts +1 -0
  69. package/dist/components/custom/goo-blob/types.d.ts +59 -25
  70. package/dist/components/custom/instrument-chassis/InstrumentChassis.vue.d.ts +2 -2
  71. package/dist/components/custom/tabs/constants.d.ts +12 -0
  72. package/dist/components/custom/underline/GlassUnderline.vue.d.ts +84 -0
  73. package/dist/components/custom/underline/index.d.ts +2 -0
  74. package/dist/components/custom/underline/types.d.ts +56 -0
  75. package/dist/components/ui/drawer/Drawer.vue.d.ts +1 -0
  76. package/dist/components/ui/dropdown-menu/DropdownMenuSubContent.vue.d.ts +2 -2
  77. package/dist/components/ui/slider/index.d.ts +25 -18
  78. package/dist/components/ui/toast/use-toast.d.ts +2 -2
  79. package/dist/composables/color/index.d.ts +24 -7
  80. package/dist/composables/glass/useSpecularTracking.d.ts +12 -3
  81. package/dist/composables/glass/webgl/shaders/procedural-color.glsl.d.ts +1 -6
  82. package/dist/composables/motion/curves.d.ts +48 -0
  83. package/dist/composables/motion/index.d.ts +2 -0
  84. package/dist/composables/motion/springPresets.d.ts +33 -0
  85. package/dist/composables/motion/suite.d.ts +2 -0
  86. package/dist/composables/motion/useSpringMount.d.ts +1 -1
  87. package/dist/configurator.js +1 -1
  88. package/dist/confirm-dialog.js +2 -2
  89. package/dist/constellation.js +322 -147
  90. package/dist/controls.js +48 -14
  91. package/dist/dark.js +1 -1
  92. package/dist/data-table.js +1 -1
  93. package/dist/dialog.js +2 -2
  94. package/dist/dock.js +340 -327
  95. package/dist/dockContext-bho8B1A4.js +17 -0
  96. package/dist/{dropdown-menu-D77jX6Df.js → dropdown-menu-DVnQcA0E.js} +7 -4
  97. package/dist/dropdown-menu.js +1 -1
  98. package/dist/expandable-container.js +1 -1
  99. package/dist/forms.js +2 -2
  100. package/dist/fourier-field.js +147 -120
  101. package/dist/fourier-math.d.ts +1 -0
  102. package/dist/fourier-math.js +2 -0
  103. package/dist/glass-ui.css +1 -1
  104. package/dist/glass-ui.js +286 -207
  105. package/dist/goo-blob.js +368 -322
  106. package/dist/hover-popover.js +1 -1
  107. package/dist/icon-tooltip.js +1 -1
  108. package/dist/index.d.ts +0 -2
  109. package/dist/keyboard.js +1 -1
  110. package/dist/labeled-field.js +5 -5
  111. package/dist/math-BUU9hHID.js +43 -0
  112. package/dist/metric-badge.js +1 -1
  113. package/dist/metric-stack.js +2 -2
  114. package/dist/motion-core.js +4 -4
  115. package/dist/motion-curves.d.ts +1 -0
  116. package/dist/motion-curves.js +130 -0
  117. package/dist/motion.js +38 -37
  118. package/dist/notification.js +1 -1
  119. package/dist/number-field.js +1 -1
  120. package/dist/popover.js +1 -1
  121. package/dist/progress.js +1 -1
  122. package/dist/pulse.js +1 -1
  123. package/dist/reactive.js +1 -1
  124. package/dist/scrolling-text.js +1 -1
  125. package/dist/search.js +6 -6
  126. package/dist/select.js +1 -1
  127. package/dist/{sheet-VZEtNFvO.js → sheet-ChSXcJpU.js} +1 -1
  128. package/dist/sheet.js +1 -1
  129. package/dist/{slider-DC2mwuoe.js → slider-sfl8gFDD.js} +8 -8
  130. package/dist/slider.js +1 -1
  131. package/dist/sortable-list.js +2 -2
  132. package/dist/springPresets-aRSm-4_k.js +40 -0
  133. package/dist/stacked-icons.js +6 -6
  134. package/dist/styles/cards.css +2 -2
  135. package/dist/styles/components.css +1 -1
  136. package/dist/styles/dock/layer-group.css +38 -4
  137. package/dist/styles/dock/layers.css +11 -1
  138. package/dist/styles/dock/morph.css +95 -19
  139. package/dist/styles/dock/shell.css +12 -0
  140. package/dist/styles/dock-controls.css +25 -12
  141. package/dist/styles/drawer.css +14 -4
  142. package/dist/styles/floating-panel.css +2 -0
  143. package/dist/styles/glass/a11y-fallback.css +245 -0
  144. package/dist/styles/glass/ladder.css +304 -0
  145. package/dist/styles/glass/material.css +238 -0
  146. package/dist/styles/glass/progress-rail.css +78 -0
  147. package/dist/styles/glass/squircle.css +66 -0
  148. package/dist/styles/glass/surfaces.css +306 -0
  149. package/dist/styles/glass-refract.css +2 -0
  150. package/dist/styles/glass.css +31 -1052
  151. package/dist/styles/hover-popover.css +2 -0
  152. package/dist/styles/index.css +24 -6
  153. package/dist/styles/instrument-chassis.css +4 -0
  154. package/dist/styles/theme.css +14 -14
  155. package/dist/styles/tokens/color-radius.css +250 -0
  156. package/dist/styles/tokens/dark-arm.css +194 -0
  157. package/dist/styles/tokens/glass.css +413 -0
  158. package/dist/styles/tokens/light-dark.css +158 -0
  159. package/dist/styles/tokens/offsets-sizing.css +406 -0
  160. package/dist/styles/tokens/property-regs.css +169 -0
  161. package/dist/styles/tokens/scale-paper.css +361 -0
  162. package/dist/styles/tokens/scheme-motion.css +334 -0
  163. package/dist/styles/tokens/shadow.css +132 -0
  164. package/dist/styles/tokens.css +22 -2269
  165. package/dist/styles/transitions.css +20 -2
  166. package/dist/styles/typography.css +18 -6
  167. package/dist/styles/utilities/a11y-overrides.css +140 -0
  168. package/dist/styles/utilities/animate.css +26 -0
  169. package/dist/styles/utilities/base.css +365 -0
  170. package/dist/styles/utilities/btn.css +399 -0
  171. package/dist/styles/utilities/components.css +317 -0
  172. package/dist/styles/utilities.css +19 -1170
  173. package/dist/switch.js +1 -1
  174. package/dist/tabs.js +98 -98
  175. package/dist/timeline.js +2 -2
  176. package/dist/toast.js +1 -1
  177. package/dist/toggle-group.js +1 -1
  178. package/dist/typewriter.js +1 -1
  179. package/dist/underline.d.ts +1 -0
  180. package/dist/underline.js +85 -0
  181. package/dist/{useAnimatedNumber-C5I3wWd8.js → useAnimatedNumber-DfVgP4te.js} +1 -1
  182. package/dist/{useConfiguratorState-DxAqksK6.js → useConfiguratorState-BdQXh9ie.js} +1 -1
  183. package/dist/useSpecularTracking-DFK_fhpG.js +32 -0
  184. package/dist/useSpringMount-DXUzxBjV.js +108 -0
  185. package/dist/watercolor-dot.js +2 -2
  186. package/package.json +62 -38
  187. package/src/styles/cards.css +2 -2
  188. package/src/styles/dock/layer-group.css +38 -4
  189. package/src/styles/dock/layers.css +11 -1
  190. package/src/styles/dock/morph.css +95 -19
  191. package/src/styles/dock/shell.css +12 -0
  192. package/src/styles/dock-controls.css +25 -12
  193. package/src/styles/drawer.css +12 -4
  194. package/src/styles/glass/a11y-fallback.css +245 -0
  195. package/src/styles/glass/ladder.css +304 -0
  196. package/src/styles/glass/material.css +238 -0
  197. package/src/styles/glass/progress-rail.css +78 -0
  198. package/src/styles/glass/squircle.css +66 -0
  199. package/src/styles/glass/surfaces.css +306 -0
  200. package/src/styles/glass.css +31 -1052
  201. package/src/styles/index.css +24 -6
  202. package/src/styles/theme.css +14 -14
  203. package/src/styles/tokens/color-radius.css +250 -0
  204. package/src/styles/tokens/dark-arm.css +194 -0
  205. package/src/styles/tokens/glass.css +413 -0
  206. package/src/styles/tokens/light-dark.css +158 -0
  207. package/src/styles/tokens/offsets-sizing.css +406 -0
  208. package/src/styles/tokens/property-regs.css +169 -0
  209. package/src/styles/tokens/scale-paper.css +361 -0
  210. package/src/styles/tokens/scheme-motion.css +334 -0
  211. package/src/styles/tokens/shadow.css +132 -0
  212. package/src/styles/tokens.css +22 -2269
  213. package/src/styles/transitions.css +20 -2
  214. package/src/styles/typography.css +18 -6
  215. package/src/styles/utilities/a11y-overrides.css +140 -0
  216. package/src/styles/utilities/animate.css +26 -0
  217. package/src/styles/utilities/base.css +365 -0
  218. package/src/styles/utilities/btn.css +399 -0
  219. package/src/styles/utilities/components.css +317 -0
  220. package/src/styles/utilities.css +19 -1170
  221. package/dist/DeckProgress-Dmk4_AKN.js +0 -23
  222. package/dist/InstrumentRail-CUJ05YVG.js +0 -44
  223. package/dist/components/custom/aurora/composables/gpuRuntime.d.ts +0 -16
  224. package/dist/components/custom/aurora/constants/shaders/aurora.wgsl.d.ts +0 -7
  225. package/dist/components/custom/deck-progress/DeckProgress.vue.d.ts +0 -27
  226. package/dist/components/custom/deck-progress/index.d.ts +0 -2
  227. package/dist/components/custom/dialog-native/GlassDialogNative.vue.d.ts +0 -57
  228. package/dist/components/custom/dialog-native/index.d.ts +0 -1
  229. package/dist/components/custom/glass-panel/GlassPanel.vue.d.ts +0 -41
  230. package/dist/components/custom/glass-panel/index.d.ts +0 -2
  231. package/dist/components/custom/header-ribbon/HeaderRibbon.vue.d.ts +0 -31
  232. package/dist/components/custom/header-ribbon/index.d.ts +0 -2
  233. package/dist/components/custom/header-ribbon/types.d.ts +0 -7
  234. package/dist/components/custom/instrument-rail/InstrumentRail.vue.d.ts +0 -91
  235. package/dist/components/custom/instrument-rail/index.d.ts +0 -2
  236. package/dist/composables/glass/createGPUCanvas.d.ts +0 -40
  237. package/dist/deck-progress.d.ts +0 -1
  238. package/dist/deck-progress.js +0 -2
  239. package/dist/dockContext-BKeIMmNk.js +0 -9
  240. package/dist/glass-panel.d.ts +0 -1
  241. package/dist/glass-panel.js +0 -44
  242. package/dist/header-ribbon.d.ts +0 -1
  243. package/dist/header-ribbon.js +0 -63
  244. package/dist/instrument-rail.d.ts +0 -1
  245. package/dist/instrument-rail.js +0 -2
  246. package/dist/useGlassRenderer-5I0YkI4t.js +0 -69
  247. package/dist/useSpecularTracking-BVRZsRHA.js +0 -26
  248. package/dist/useSpringMount-BJSHcLl3.js +0 -113
  249. /package/dist/{CollapsibleContent-CP9qF1v4.js → CollapsibleContent-Drow5WkV.js} +0 -0
  250. /package/dist/{DialogFooter-Gprw8H_A.js → DialogFooter-DufLHi0y.js} +0 -0
  251. /package/dist/{IconTooltip-yefK7cJc.js → IconTooltip-BrQ5p181.js} +0 -0
  252. /package/dist/{Input-DWQQIOC4.js → Input-B-F818RU.js} +0 -0
  253. /package/dist/{_plugin-vue_export-helper-ok8pgSl5.js → _plugin-vue_export-helper-DWghtRt7.js} +0 -0
  254. /package/dist/{constants-CS75AWHG.js → constants-C8NMonuo.js} +0 -0
  255. /package/dist/{presets-BKVyQfbt.js → presets-1OhFpaIC.js} +0 -0
  256. /package/dist/{prng-wHuHlNHE.js → prng-CjVgzjQT.js} +0 -0
  257. /package/dist/{resolveCanvasColor-BBiYfp8g.js → resolveCanvasColor-CRvVzOvP.js} +0 -0
  258. /package/dist/{useCanvas2D-ClrQuZtp.js → useCanvas2D-CSeH8h16.js} +0 -0
  259. /package/dist/{useGlobalDark-yhL4Wp-s.js → useGlobalDark-D7R9OypB.js} +0 -0
  260. /package/dist/{useIntersectionPause-Cc-H9ees.js → useIntersectionPause-DAdVPVp4.js} +0 -0
  261. /package/dist/{useInterval-Dsmqwi03.js → useInterval-D3USn0yc.js} +0 -0
  262. /package/dist/{useKeyboardShortcuts-Be3w_Rwk.js → useKeyboardShortcuts-i8tHd5WO.js} +0 -0
  263. /package/dist/{useScrollProgress-CAH8Ofwt.js → useScrollProgress-CcgmgMQt.js} +0 -0
  264. /package/dist/{useSortable-C8ReQ50P.js → useSortable-DnyGXKKY.js} +0 -0
  265. /package/dist/{useTextHighlight-DON84L8w.js → useTextHighlight-B3b10W6r.js} +0 -0
@@ -1,1170 +1,19 @@
1
- /* Shared utility classes */
2
-
3
- /* ── Popover/dropdown shared animation ──
4
- `@utility` form (V.W3.T8 / A5 §5.9 standardisation): data-state animation
5
- pair for popover-class containers (Popover, DropdownMenu, ContextMenu,
6
- Tooltip, HoverCard, Select). Composed alongside `.slide-in-from-side`
7
- for direction-keyed entries. */
8
- @utility popover-animate {
9
- @apply data-[state=open]:animate-in data-[state=closed]:animate-out
10
- data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0
11
- data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95;
12
- }
13
-
14
- /* ── Slide-in entry by side data-attr ──
15
- `@utility` form (V.W3.T8). Side-keyed slide entry that pairs with
16
- reka-ui's `data-side` (`top|right|bottom|left`). The animation
17
- direction inverts each side so panels enter from outside the
18
- anchor's edge. */
19
- @utility slide-in-from-side {
20
- @apply data-[side=bottom]:slide-in-from-top-2
21
- data-[side=left]:slide-in-from-right-2
22
- data-[side=right]:slide-in-from-left-2
23
- data-[side=top]:slide-in-from-bottom-2;
24
- }
25
-
26
- @layer components {
27
- /* ── Section description (V.W3.T7) ──────────────────────────────
28
- Canonical recipe for the `<Section>` primitive's description
29
- paragraph. Composes the body type + muted-foreground color in
30
- one declaration so consumers don't fight twMerge's
31
- typography-class collapse. */
32
- .section-description {
33
- font-size: var(--type-body);
34
- color: var(--muted-foreground);
35
- line-height: 1.5;
36
- text-wrap: pretty; /* AQ.W3 §W3.3 — prose-register orphan/river fix */
37
- }
38
-
39
- /* ── Labeled-field label (V.W3.T5 / A5 §5.5) ────────────────────
40
- Canonical recipe for `<LabeledField>`'s tooltip-wrapped label
41
- layer. Four sibling wrappers (LabeledInput, LabeledSelect,
42
- LabeledSlider, LabeledSwitch) used to repeat this literal across
43
- their templates; promoting it to a utility lets the parent SFC
44
- own one canonical declaration. */
45
- .labeled-field-label {
46
- font-family: var(--font-display);
47
- font-size: var(--type-body);
48
- /* AQ.W4 §W3.1c — the label color reads the group-state variable so the
49
- `:has(:user-invalid)` rule below reddens it (one source of the
50
- override value, shared with the `.has-error` fallback class). */
51
- color: var(--field-label-color, var(--muted-foreground));
52
- cursor: help;
53
- }
54
-
55
- /* AQ.W4 §W3.1c — LabeledField group error highlight. When any descendant
56
- control is `:user-invalid`, the whole field group marks (the label
57
- reddens via `--field-label-color`, the error region reveals). Scoped to
58
- `.labeled-field` — never `body`, never a bare element. `:has()` Baseline
59
- Widely; the `.has-error` / `.has-valid` fallback classes (toggled by the
60
- `useUserInvalidAria` fallback path) are the SOLE degradation for engines
61
- without `:has()`/`:user-invalid` (not a live+dead alias). */
62
- .labeled-field {
63
- --field-label-color: var(--muted-foreground);
64
- }
65
- .labeled-field:has(:user-invalid),
66
- .labeled-field.has-error {
67
- --field-label-color: var(--destructive);
68
- }
69
-
70
- /* The error region: hidden at rest, revealed once a descendant is
71
- `:user-invalid` (or the `.has-error` fallback class is set). Non-color
72
- reinforcement for the validity tint — the error TEXT is the primary
73
- cue, the border/bg shift the supplement (forms guide: never color
74
- alone). */
75
- .labeled-field-error {
76
- display: none;
77
- font-size: var(--type-small);
78
- color: var(--destructive);
79
- margin-block-start: 0.25rem;
80
- }
81
- .labeled-field:has(:user-invalid) .labeled-field-error,
82
- .labeled-field.has-error .labeled-field-error {
83
- display: block;
84
- }
85
- /* Hide the error text once the field reads valid (the user corrected it). */
86
- .labeled-field:has(:user-valid) .labeled-field-error,
87
- .labeled-field.has-valid .labeled-field-error {
88
- display: none;
89
- }
90
-
91
- /* ── Popover-content recipe (V.W3.T3 / A5 §3.2) ─────────────────
92
- Canonical recipe for floating-tier portal containers
93
- (PopoverContent, DropdownMenuContent, SelectContent, etc.).
94
- Covers radius + outline + popover-foreground; consumers compose
95
- this with `.glass-floating` (bg + blur + border + shadow), with
96
- `.popover-animate` (data-state animation), and with the per-host
97
- z-rung. The floating-tier shadow comes from
98
- `--glass-shadow-floating` via `.glass-floating`, replacing the
99
- `shadow-md`/`shadow-lg` literals that bypassed the canonical
100
- cascade. */
101
- .popover-content {
102
- border-radius: var(--radius-panel);
103
- color: var(--popover-foreground);
104
- outline: none;
105
- }
106
-
107
- /* ── Scrollbar ── */
108
- .scrollbar-hidden {
109
- scrollbar-width: none;
110
- }
111
- .scrollbar-hidden::-webkit-scrollbar {
112
- display: none;
113
- }
114
-
115
- /* AQ.W3 §W3.4 — tokenized thin scrollbar. Standard `scrollbar-width` +
116
- `scrollbar-color` (Baseline Widely, Chromium 121+) is the primary path,
117
- reading `--scrollbar-{thumb,track}` (auto-dark via `--muted-foreground`).
118
- The legacy `::-webkit-scrollbar` family is the SOLE fallback for older
119
- WebKit/Blink, gated on `@supports not (scrollbar-color: auto)` so modern
120
- engines never paint it — not a live+dead alias. */
121
- .scrollbar-thin {
122
- scrollbar-width: thin;
123
- scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
124
- }
125
- @supports not (scrollbar-color: auto) {
126
- .scrollbar-thin::-webkit-scrollbar {
127
- width: 8px;
128
- height: 8px;
129
- }
130
- .scrollbar-thin::-webkit-scrollbar-track {
131
- background: var(--scrollbar-track);
132
- }
133
- .scrollbar-thin::-webkit-scrollbar-thumb {
134
- background: var(--scrollbar-thumb);
135
- border-radius: var(--radius-pill);
136
- }
137
- }
138
-
139
- /* ── Focus ring — auto-activates on :focus-visible ── */
140
- .focus-ring:focus-visible {
141
- outline: none;
142
- border-radius: var(--radius-pill);
143
- box-shadow: var(--focus-ring-shadow);
144
- }
145
-
146
- /* ── Hairline-accent — 0.5px catch-light + under-shadow pair ──
147
- Composes the canonical `--border-hairline` token (tokens.css §
148
- Glass-decorative). Adopt at any surface that wants the canonical
149
- 2-stop hairline (dock surfaces, instrument-chassis). Auto-mirrors
150
- in dark via the .dark token override. */
151
- .hairline-accent {
152
- box-shadow: var(--border-hairline);
153
- }
154
-
155
- /* ── Interactive item (hover bg + focus ring + active scale) ── */
156
- .interactive-item {
157
- /* AQ.W3 §W3.2 identity base */
158
- scale: 1;
159
- border-radius: var(--radius-lg);
160
- user-select: none;
161
- transition:
162
- background-color var(--duration-fast) var(--ease-standard),
163
- color var(--duration-fast) var(--ease-standard),
164
- border-color var(--duration-fast) var(--ease-standard),
165
- box-shadow var(--duration-fast) var(--ease-standard),
166
- scale var(--duration-fast) var(--ease-standard);
167
- }
168
- .interactive-item:hover {
169
- background-color: color-mix(in srgb, var(--accent) 50%, transparent);
170
- }
171
- .interactive-item:focus-visible {
172
- outline: none;
173
- box-shadow: var(--focus-ring-shadow);
174
- }
175
- .interactive-item:active {
176
- /* AW.W31.a — fold the residual literal press scale onto the canonical
177
- `--scale-press*` cohort (the prior `0.98` was the sole per-atom press
178
- literal surviving the W2/W3/W25 sweeps). `--scale-press-sm` (0.97) is
179
- the soft press rung the button + slider recipes consume — ONE press
180
- vocabulary, no per-atom literal. The 0.98→0.97 delta is sub-perceptual. */
181
- scale: var(--scale-press-sm);
182
- }
183
- .interactive-item:disabled,
184
- .interactive-item[data-disabled] {
185
- pointer-events: none;
186
- opacity: var(--opacity-disabled);
187
- cursor: not-allowed;
188
- }
189
-
190
- /* ── Tap-squish — universal press-state choreography ──
191
- AL-W10 SLIM (X6 §M-1 + Y7 §3 + DESIGN.md §L3). I compose this
192
- class onto every interactive surface that wants the iOS tap-
193
- squish idiom; the press scales to `--scale-press` (0.96, the
194
- canonical iOS `.regular` control rung). I keep this as a single
195
- canonical rung — NOT a 3-rung ladder. The one outlier I leave
196
- alone is the button `0.97` (`--scale-press-btn`), which consumes
197
- its own slightly-softer token directly. The dock control now
198
- tracks the canonical `--scale-press` (0.96) too (AT.W7-dock-b
199
- press canon — the prior deeper `0.92` was retired to ONE source).
200
-
201
- AX.W52 §6 doctrine — the `scale` register is reconciled onto
202
- `--spring-smooth` (was `--spring-snappy`), the ONE button/interactive
203
- scale register the §6 easing doctrine records and the gate asserts
204
- across `.btn-pill`/`.tap-squish`/`.glass-btn`/`btn-interactive`. At
205
- ζ=0.86 `--spring-smooth` settles a press crisply with a sub-perceptual
206
- (~0.5%) peak — no visible bounce — so press still reads alive while
207
- hover reads as a smooth glide on the SAME spring.
208
-
209
- The transition lists the SURFACE legs (bg/border/box-shadow/color/
210
- opacity) on the bezier `--ease-standard` alongside the spring `scale`
211
- leg — the SAME coherent set `.btn-pill` carries. This is load-bearing:
212
- `.tap-squish` and `.btn-pill` are co-composed on the button base and
213
- this `transition` shorthand would otherwise CLOBBER `.btn-pill`'s
214
- surface legs down to a scale-only animation (the cascade bug that left
215
- every button transitioning ONLY `scale` — the live-readback RED). With
216
- both classes carrying the full set, whichever wins the surface cross-
217
- fade survives. On a non-button press surface the extra legs are inert
218
- unless that prop changes, in which case a smooth cross-fade is the
219
- desired interactive read anyway.
220
-
221
- Under PRM I retire the press transform entirely and lean on the
222
- consumer's own hover/active bg-tint cascade to acknowledge the
223
- press. */
224
- .tap-squish {
225
- /* AQ.W3 §W3.2 identity base */
226
- scale: 1;
227
- transition:
228
- background-color var(--duration-fast) var(--ease-standard),
229
- border-color var(--duration-fast) var(--ease-standard),
230
- box-shadow var(--duration-fast) var(--ease-standard),
231
- color var(--duration-fast) var(--ease-standard),
232
- opacity var(--duration-fast) var(--ease-standard),
233
- scale var(--duration-fast) var(--spring-smooth);
234
- transform-origin: center center;
235
- }
236
- .tap-squish:active {
237
- scale: var(--scale-press);
238
- }
239
- @media (prefers-reduced-motion: reduce) {
240
- .tap-squish:active {
241
- /* Reset to the longhand identity (not `transform: none`) so the
242
- press scale is neutralized under PRM. */
243
- scale: 1;
244
- }
245
- }
246
-
247
- /* ── Status dot indicator ── */
248
- .status-dot {
249
- display: inline-block;
250
- width: 0.5rem;
251
- height: 0.5rem;
252
- border-radius: var(--radius-pill);
253
- flex-shrink: 0;
254
- transition:
255
- color var(--duration-fast) var(--ease-standard),
256
- background var(--duration-fast) var(--ease-standard),
257
- box-shadow var(--duration-fast) var(--ease-standard);
258
- }
259
- /* ── Depth text (layered offset stamp) ──
260
- AW.W26 — composes the `--text-shadow-depth` @theme identity token (the
261
- hard offset stack + soft ambient tail) instead of a hand-rolled multi-stop
262
- literal. The token holds the stack inside the `@theme` defs (gate 4) and
263
- re-tints under `.dark` via `--shadow`/`--shadow-color` BY CONSTRUCTION. */
264
- .depth-text {
265
- --depth-color-primary: var(--primary);
266
-
267
- color: var(--depth-color-primary);
268
- text-shadow: var(--text-shadow-depth);
269
- }
270
-
271
- /* ── 3D preserve ── */
272
- .preserve-3d {
273
- transform-style: preserve-3d;
274
- }
275
-
276
- /* ── iOS input font-size fix (prevent auto-zoom) ── */
277
- .ios input,
278
- .ios select,
279
- .ios textarea,
280
- .ios [contenteditable] {
281
- font-size: max(1rem, 1em);
282
- }
283
-
284
- /* ── Scroll fade masks ──
285
- Single-source `mask-image` (AV.W16 TW7): the `-webkit-` companion is
286
- dropped — Tailwind v4's Lightning CSS build pipeline auto-prefixes per
287
- the browserslist targets, mirroring the glass ladder's single-source
288
- `backdrop-filter` (glass.css). NOTE: this is the consistency cut; it
289
- does NOT conflict with W15's `@supports`-gated older-Safari mask
290
- fallback (that fallback is the distinct case where the companion is
291
- genuinely needed and W15 gates it). */
292
- .scroll-fade-mask {
293
- mask-image: linear-gradient(to right, transparent, black var(--mask-fade-width), black calc(100% - var(--mask-fade-width)), transparent);
294
- }
295
-
296
- .scroll-fade-top {
297
- mask-image: linear-gradient(to bottom, transparent, black var(--mask-fade-width));
298
- }
299
-
300
- .scroll-fade-bottom {
301
- mask-image: linear-gradient(to bottom, black calc(100% - var(--mask-fade-width)), transparent);
302
- }
303
-
304
- .scroll-fade-y {
305
- mask-image: linear-gradient(to bottom, transparent, black var(--mask-fade-width), black calc(100% - var(--mask-fade-width)), transparent);
306
- }
307
-
308
- /* ── Deferred section — render-skip an offscreen subtree (AQ.W3 §5) ──────
309
- `content-visibility: auto` skips layout/paint/style of an offscreen
310
- subtree — the INP-under-load lever (fourier γ, muster, speedtest, words).
311
- `contain-intrinsic-size: auto <estimate>` is measurement-safe: the `auto`
312
- prefix makes the engine REMEMBER the last-rendered size (no scroll-jump on
313
- re-entry); plain `<estimate>` freezes the section + thrashes the scrollbar
314
- — the trap this closes. Estimate is token-driven (`--deferred-section-
315
- size`, default 30rem). `.deferred-section--cached` →
316
- `content-visibility: hidden` (always skipped, state CACHED — cheaper to
317
- re-show than `display:none`). Baseline Widely; unsupporting engines render
318
- normally. JS HOOK: the engine fires `contentvisibilityautostatechange`
319
- { skipped } at the render-skip boundary — pair with `useRAFLoop`
320
- pause/resume: `el.addEventListener('contentvisibilityautostatechange',
321
- e => e.skipped ? loop.pause() : loop.resume())`. */
322
- .deferred-section {
323
- content-visibility: auto;
324
- contain-intrinsic-size: auto var(--deferred-section-size, 30rem);
325
- }
326
- .deferred-section--cached {
327
- content-visibility: hidden;
328
- contain-intrinsic-size: auto var(--deferred-section-size, 30rem);
329
- }
330
-
331
- /* ── Card scroll-timeline host (AI.W1-α) ───────────────────────────────
332
- Canonical scroll-overflow host that emits the `--card-scroll` named
333
- scroll-timeline consumed by `<CardHeader shrink>`. Apply to the
334
- scroll-overflow ancestor (typically the `<Card>` itself OR a wrapper
335
- inside it that carries `overflow-y: auto`).
336
-
337
- `contain: layout style paint` isolates the named timeline so child
338
- animations respond to THIS host's scroll only — not to portal-
339
- triggered layout shifts in ancestor containers (the load-bearing
340
- isolation guarantee the value.js `PaneHeader.vue:18-29` comment
341
- called out and the AI.W1 spec §1.2 ratified as canon).
342
-
343
- Disambiguated from `.scroll-fade-*` (mask-image fade gradient at
344
- the container's leading/trailing edge) — `.card-scroll-host` does
345
- NOT paint any visual; it only emits the timeline. */
346
- .card-scroll-host {
347
- contain: layout style paint;
348
- scroll-timeline: --card-scroll block;
349
- }
350
-
351
- /* ── Shimmer text effects ──
352
- The text-fill + background-clip composition is load-bearing visual
353
- (the gold gradient itself); only the `animation:` line is wrapped in
354
- the PRM no-preference bracket so PRM users see the static gradient
355
- without the slide animation. */
356
- .gold-shimmer {
357
- background: linear-gradient(90deg, var(--color-gold-dark), var(--color-gold-light), var(--color-gold), var(--color-gold-light), var(--color-gold-dark));
358
- background-size: 250% 100%;
359
- background-clip: text;
360
- -webkit-background-clip: text;
361
- color: transparent;
362
- }
363
- @media (prefers-reduced-motion: no-preference) {
364
- .gold-shimmer {
365
- animation: gold-shimmer-slide var(--duration-shimmer) linear infinite;
366
- }
367
- }
368
-
369
- /* ── Keyboard key ── */
370
- .kbd {
371
- display: inline-flex;
372
- align-items: center;
373
- justify-content: center;
374
- min-height: 1.5rem;
375
- min-width: 1.5rem;
376
- padding: 0 0.375rem;
377
- font-family: var(--font-mono);
378
- font-size: var(--type-micro);
379
- background: var(--muted);
380
- border: 1px solid var(--border);
381
- border-radius: var(--radius-sm);
382
- box-shadow: 0 1px 0 1px color-mix(in srgb, var(--border) 30%, transparent);
383
- line-height: 1;
384
- }
385
-
386
- /* ── Metric badge pill — compact glass label for numeric telemetry ── */
387
- .metric-badge {
388
- display: inline-flex;
389
- align-items: center;
390
- justify-content: center;
391
- text-align: center;
392
- /* AQ.W3 §W3.2 identity base */
393
- scale: 1;
394
- gap: var(--metric-badge-gap, 0.125rem);
395
- max-width: var(--metric-badge-max-width, 8rem);
396
- min-height: var(--metric-badge-min-height, 1.5rem);
397
- padding:
398
- var(--metric-badge-padding-block, 0.125rem)
399
- var(--metric-badge-padding-inline, 0.5rem);
400
- overflow: hidden;
401
- flex-shrink: 0;
402
- line-height: 1;
403
- /* Canonical 5-tier glass surface: the `quiet` rung paints the badge
404
- plate at the `--glass-bg-quiet` α (0.50) with `--glass-blur-quiet`.
405
- Reduced-transparency / no-backdrop-filter fallbacks propagate
406
- through the lazy custom-property resolution that `glass.css`
407
- sets up — the badge no longer bypasses the canon.
408
- (Per audit U.W0.C-c §7.2.) */
409
- border: 1px solid var(--metric-badge-border, var(--glass-border-quiet));
410
- border-radius: var(--metric-badge-radius, var(--radius-badge, var(--radius-pill)));
411
- background: var(--metric-badge-bg, var(--glass-bg-quiet));
412
- backdrop-filter: var(--metric-badge-blur, var(--glass-blur-quiet));
413
- box-shadow: var(--metric-badge-shadow, 0 1px 6px color-mix(in srgb, var(--shadow-color) 8%, transparent), var(--glass-highlight));
414
- transition:
415
- background var(--duration-fast) var(--ease-standard),
416
- border-color var(--duration-fast) var(--ease-standard),
417
- box-shadow var(--duration-fast) var(--ease-standard),
418
- scale var(--duration-fast) var(--ease-standard);
419
- }
420
-
421
- .metric-badge > span {
422
- line-height: 1;
423
- /* AW.W26 — `wrap-anywhere` (overflow-wrap: anywhere) on the value slot:
424
- a long metric value breaks WITHIN the badge rather than being clipped
425
- by the host `overflow: hidden`. v4.1 `wrap-anywhere` / mwg css §7.
426
- Scoped to the value span, NOT a universal selector (mwg perf caveat). */
427
- overflow-wrap: anywhere;
428
- }
429
-
430
- .metric-badge:hover {
431
- /* Hover lifts to the `resting` rung — one step up the canonical
432
- ladder (audit U.W0.C-c §7.2). */
433
- border-color: var(--metric-badge-hover-border, var(--glass-border-resting));
434
- background: var(--metric-badge-hover-bg, var(--glass-bg-resting));
435
- box-shadow: var(--metric-badge-hover-shadow, 0 2px 10px color-mix(in srgb, var(--shadow-color) 12%, transparent), var(--glass-highlight));
436
- scale: var(--metric-badge-hover-scale, 1.02);
437
- }
438
-
439
- .metric-badge:active {
440
- scale: var(--metric-badge-press-scale, 0.96);
441
- }
442
-
443
- .metric-badge:focus-visible {
444
- outline: none;
445
- box-shadow: var(--focus-ring-shadow);
446
- }
447
-
448
- /* Phase-finish catch-light — the quieter cousin of --glass-specular.
449
- Speedtest toggles `data-just-resolved="true"` on a metric pill once
450
- its phase completes; the badge briefly carries a 1px catch-light
451
- streak at the top edge. Reads as the pill catching club lighting at
452
- the moment its result resolves. */
453
- .metric-badge[data-just-resolved="true"] {
454
- box-shadow:
455
- inset 0 1px 0 0 rgb(255 255 255 / 0.18),
456
- var(--metric-badge-shadow,
457
- 0 1px 6px color-mix(in srgb, var(--shadow-color) 8%, transparent),
458
- var(--glass-highlight));
459
- }
460
-
461
- /* ── Label-bearing variants ───────────────────────────────────────────
462
- When the badge carries a `labelPosition`, the prose-style annotation
463
- slot precedes the amount. Inline keeps the row baseline-aligned;
464
- stacked breaks to a column with items flush-left. The label slot
465
- carries its own tracked uppercase rules; the badge's max-width
466
- relaxes so the wider register fits. */
467
- .metric-badge--label-inline {
468
- flex-direction: row;
469
- align-items: baseline;
470
- justify-content: flex-start;
471
- gap: var(--metric-badge-label-gap, 0.375rem);
472
- max-width: var(--metric-badge-label-max-width, none);
473
- text-align: left;
474
- }
475
-
476
- .metric-badge--label-stacked {
477
- flex-direction: column;
478
- align-items: flex-start;
479
- justify-content: center;
480
- gap: var(--metric-badge-label-gap-stacked, 0.0625rem);
481
- max-width: var(--metric-badge-label-max-width, none);
482
- text-align: left;
483
- min-height: var(--metric-badge-min-height-stacked, 2.625rem);
484
- padding-block: var(--metric-badge-padding-block-stacked, 0.375rem);
485
- }
486
-
487
- /* T.W2.T2 — stacked variant pairs amount + unit on a single row (row 2)
488
- below the label (row 1). The `.metric-badge__row` wrapper baseline-
489
- aligns the value and unit so the quantity reads as one phrase, not as
490
- three siblings split across three rows (the pre-T behaviour the
491
- audit B-spec §2.1 flagged). */
492
- .metric-badge--label-stacked .metric-badge__row {
493
- display: inline-flex;
494
- align-items: baseline;
495
- gap: var(--metric-badge-row-gap-stacked, 0.25rem);
496
- }
497
-
498
- /* T.W2.T3 — MetricPill density modifiers. The pill is a thin composition
499
- over MetricBadge with `labelPosition="stacked"` defaults; the density
500
- knob adjusts block padding + horizontal padding so the pill reads at
501
- the right register for its dock host. `spacious` is the default
502
- (chassis-strip rhythm), `comfortable` keeps the tighter compact
503
- register for densely-packed dock clusters. The selectors compose with
504
- `.metric-badge--label-stacked` so the inline ladder remains untouched
505
- — these are stacked-only refinements. */
506
- .metric-pill[data-density="spacious"].metric-badge--label-stacked {
507
- --metric-badge-padding-block-stacked: 0.5rem;
508
- --metric-badge-padding-inline: 0.75rem;
509
- }
510
-
511
- .metric-pill[data-density="comfortable"].metric-badge--label-stacked {
512
- --metric-badge-padding-block-stacked: 0.25rem;
513
- --metric-badge-padding-inline: 0.5rem;
514
- }
515
-
516
- /* AS.W4 — @container style(--density) companion. A pill nested under a host
517
- that sets `--density: comfortable | spacious` on a wrapping element picks
518
- up the matching padding register with no `data-density` markup contract;
519
- the attribute rules above stay the SOLE fallback (inv 47).
520
- The inner `.metric-pill.metric-badge--label-stacked` selector (0,2,0) sits
521
- just BELOW the `.metric-pill[data-density]…` attribute rules (0,3,0) — so a
522
- pill carrying BOTH the attribute and a `--density` ancestor lands on the
523
- attribute rule (same tokens, identical paint), while a pill with only the
524
- ancestor token still resolves the right register (no competing rule sets
525
- these padding custom props at higher weight in that case).
526
-
527
- No `@supports` wrapper: unlike the sibling scroll-state recipe (which
528
- probes `@supports (container-type: scroll-state)` — a probeable
529
- container-type VALUE), style queries introduce no new `container-type`
530
- value (every element is a style container by default), so there is no
531
- clean declaration test for style-query support. This relies on
532
- `@container style()`'s own graceful degradation: an engine without
533
- style-query support parses the unknown at-rule as invalid, drops the
534
- block, and keeps the `[data-density]` attribute base. (The earlier
535
- `@supports (container-type: inline-size)` wrapper was wrong — it probed
536
- SIZE-query support, a distinct feature with a distinct support timeline.) */
537
- @container style(--density: spacious) {
538
- .metric-pill.metric-badge--label-stacked {
539
- --metric-badge-padding-block-stacked: 0.5rem;
540
- --metric-badge-padding-inline: 0.75rem;
541
- }
542
- }
543
- @container style(--density: comfortable) {
544
- .metric-pill.metric-badge--label-stacked {
545
- --metric-badge-padding-block-stacked: 0.25rem;
546
- --metric-badge-padding-inline: 0.5rem;
547
- }
548
- }
549
-
550
- .metric-badge__label {
551
- letter-spacing: 0.18em;
552
- line-height: 1;
553
- }
554
-
555
- /* Dual-slot default visibility (R2-spec):
556
- The library renders both `--full` and `--abbr` siblings whenever both
557
- props are passed. Default identity is the full label; the abbreviation
558
- sits hidden until consumer container-query CSS flips it. The adjacent-
559
- sibling selector preserves single-slot back-compat: when a consumer
560
- passes only `abbreviation` (no `--full` sibling rendered), the abbr
561
- reads at default visibility. */
562
- .metric-badge__label--full + .metric-badge__label--abbr {
563
- display: none;
564
- }
565
-
566
- /* sm-tier label tracking — tighter than the md/lg/xl 0.18em rung so the
567
- compact register reads as a tighter annotation against the smaller
568
- glyph rise. R2-spec D-Rec-2 (audit-D). */
569
- .metric-badge[data-size="sm"] .metric-badge__label {
570
- letter-spacing: 0.1em;
571
- }
572
-
573
- /* Q.W3 Lane A — the `.glass-dock[data-density="…"]` density rungs that
574
- set `--dock-tab-h` + `--dock-label-size` were consolidated into
575
- `dock.css` (their canonical dock-styles home). They formerly lived
576
- here and resolved only by the index.css import order (utilities.css
577
- after dock.css); the cascade-order dependency is now gone. */
578
-
579
- /* ── Input bar — glassmorphic inline input container ──
580
- Composes the canonical `floating` glass rung (--glass-bg-floating
581
- ≈ 80% α, --glass-blur-floating ≈ 24px) — same surface read as the
582
- prior raw composition but routed through the canonical 5-tier
583
- ladder so PRT / no-backdrop-filter fallbacks propagate cleanly.
584
- (Per audit U.W0.C-c §7.2.) */
585
- .input-bar {
586
- display: flex;
587
- align-items: center;
588
- gap: 0.5rem;
589
- border-radius: var(--radius-2xl);
590
- border: 1px solid var(--glass-border-floating);
591
- background: var(--glass-bg-floating);
592
- backdrop-filter: var(--glass-blur-floating);
593
-
594
- padding: 0 0.75rem;
595
- height: 2.25rem;
596
- max-width: var(--max-width-input);
597
- width: 100%;
598
- transition:
599
- box-shadow var(--duration-fast) var(--ease-standard),
600
- border-color var(--duration-fast) var(--ease-standard);
601
- }
602
- .input-bar:focus-within {
603
- box-shadow: var(--focus-ring-shadow);
604
- border-color: var(--border);
605
- }
606
-
607
- .input-bar-field {
608
- font-family: var(--font-mono, monospace);
609
- font-size: var(--type-small);
610
- background: transparent;
611
- border: none;
612
- outline: none;
613
- flex: 1;
614
- min-width: 0;
615
- }
616
- .input-bar-field::placeholder {
617
- color: color-mix(in srgb, var(--muted-foreground) 50%, transparent);
618
- }
619
-
620
- /* ── Hover lift — translate-y + shadow on hover (3 levels) ──
621
- The shared transition is expressed once over the family; the three
622
- :hover rules carry the per-level translate + shadow. */
623
- :where(.hover-lift, .hover-lift-md, .hover-lift-lg) {
624
- /* Individual-transform identity base (AQ.W3 §W3.2) — `translate: 0` at
625
- rest mints the stacking context once so the hover lift does not
626
- flicker it into being. */
627
- translate: 0;
628
- transition-property: translate, box-shadow;
629
- transition-duration: var(--duration-normal);
630
- transition-timing-function: var(--ease-standard);
631
- }
632
- .hover-lift:hover:not(:disabled):not([aria-disabled='true']) {
633
- translate: 0 var(--lift-sm);
634
- box-shadow: var(--shadow-md);
635
- }
636
- .hover-lift-md:hover:not(:disabled):not([aria-disabled='true']) {
637
- translate: 0 var(--lift-md);
638
- box-shadow: var(--shadow-md);
639
- }
640
- .hover-lift-lg:hover:not(:disabled):not([aria-disabled='true']) {
641
- translate: 0 var(--lift-lg);
642
- box-shadow: var(--shadow-lg);
643
- }
644
-
645
- /* ── Cartoon shadows — token-driven box-shadow + bezel border + lift ──
646
- The box-shadow stack reads from the canonical
647
- `--shadow-cartoon-{sm,md,lg}` rungs declared at tokens.css:304-312.
648
- Those rungs use `color-mix(in srgb, var(--shadow-color) N%, transparent)`
649
- so dark-mode flips the cast through `--shadow-color` automatically.
650
- The 2px bezel border + translateY are the cartoon-stamp geometry
651
- atop the canonical depth — kept here so a single class delivers
652
- the whole cartoon read.
653
- (Per audit U.W0.C-c §1.3 / Union 1 — collapses the dual-system
654
- drift onto the token-driven shadow.) */
655
- :where(.shadow-cartoon-sm, .shadow-cartoon-md, .shadow-cartoon-lg) {
656
- border: 2px solid var(--border);
657
- }
658
- /* Static cartoon-stamp lift (AQ.W3 §W3.2). NOT state-driven, so the
659
- identity base is not strictly required, but the `translate:` longhand
660
- keeps the family uniform with the state-driven sites above. */
661
- .shadow-cartoon-sm {
662
- box-shadow: var(--shadow-cartoon-sm);
663
- translate: 0 -1px;
664
- }
665
- .shadow-cartoon-md {
666
- box-shadow: var(--shadow-cartoon-md);
667
- translate: 0 -1px;
668
- }
669
- .shadow-cartoon-lg {
670
- box-shadow: var(--shadow-cartoon-lg);
671
- translate: 0 -2px;
672
- }
673
-
674
- /* ── Divider utilities ── */
675
- .divider-h {
676
- height: 2px;
677
- background: linear-gradient(
678
- to right,
679
- transparent 1%,
680
- var(--border) 8%,
681
- var(--border) 92%,
682
- transparent 99%
683
- );
684
- }
685
-
686
- .divider-h-tapered {
687
- height: 2px;
688
- background: linear-gradient(
689
- to right,
690
- transparent 3%,
691
- var(--border) 15%,
692
- var(--border) 85%,
693
- transparent 97%
694
- );
695
- }
696
-
697
- }
698
-
699
- /* ── Hover scale (O.W6 Lane C) ──
700
- Canonical hover-transform utility consuming the `--scale-hover` token
701
- (tokens.css §11). Promoted from consumer-side `hover:scale-105`
702
- recipe — 13 sites in keyframes.js demo + 9 sites in words/frontend
703
- per O11/d L3 + O11/a I4. Single-token recipe (no ladder); the dual
704
- `--scale-press-{xs..lg}` ladder discussion is the press-axis cohort
705
- (O-N-7), not hover. Consumers reach the utility via
706
- `class="scale-on-hover"`; transition + easing bind to the canonical
707
- `--duration-fast` + `--ease-standard` tokens. */
708
- @utility scale-on-hover {
709
- /* Individual-transform identity base (AQ.W3 §W3.2). Transition the `scale`
710
- longhand (not `transform`) so the migrated hover scale animates.
711
- AX.W52 §6 doctrine — the `scale` transform leg rides `--spring-smooth`
712
- (the settle register), NOT the bezier `--ease-standard` (a transform on a
713
- bezier reads mechanical; springs read alive on transform). */
714
- scale: 1;
715
- transition: scale var(--duration-fast) var(--spring-smooth);
716
-
717
- &:hover {
718
- scale: var(--scale-hover);
719
- }
720
- }
721
-
722
- /* ── Twin-line divider — the chassis catch-light / under-shadow groove ───────
723
- AW.W15 DRY extraction. The twin-line idiom (a 1px white catch-light over a
724
- 1px black under-shadow reading as one engraved hairline groove) is the
725
- chassis-divider signature. The exact light/dark α pair was DUPLICATED in
726
- `instrument-chassis.css` (`.bezel-line.top`/`.bottom`) and `instrument-rail.css`
727
- (the sibling `::before`/`::after`). This utility is the SINGLE source of that
728
- α pair: it publishes `--twin-line-catch` (the top catch-light) and
729
- `--twin-line-shadow` (the bottom under-shadow) as cascade tokens, dark-adaptive
730
- by construction (the `.dark &` arm re-resolves them). Both consumers read the
731
- tokens; a retint touches one rule. Real DRY, ≥2 consumers. */
732
- @utility twin-line-divider {
733
- --twin-line-catch: rgb(255 255 255 / 0.10);
734
- --twin-line-shadow: rgb(0 0 0 / 0.12);
735
-
736
- :where(.dark) & {
737
- --twin-line-catch: rgb(255 255 255 / 0.06);
738
- --twin-line-shadow: rgb(0 0 0 / 0.18);
739
- }
740
- }
741
-
742
- /* ── Control transition recipe (AU.W8b.4) ───────────────────────────────
743
- Shared compound transition for interactive controls that animate their
744
- surface (background-color/color/box-shadow/border-color) on the four-state
745
- contract. Replaces the per-site
746
- `transition-[background-color,color,box-shadow,border-color] duration-[var(--duration-fast)] ease-[var(--ease-standard)]`
747
- arbitrary wraps at ≥2 sites (TabsTrigger, SelectTrigger, Toggle `card`
748
- variant). Binds the canonical --duration-fast + --ease-standard tokens. */
749
- @utility transition-control {
750
- transition-property: background-color, color, box-shadow, border-color;
751
- transition-duration: var(--duration-fast);
752
- transition-timing-function: var(--ease-standard);
753
- }
754
-
755
- /* ── Collapse transition recipe (AU.W8b.4) ──────────────────────────────
756
- Shared height+opacity transition for reka-ui collapse surfaces (Accordion
757
- content, Collapsible content). Replaces the per-site `transition-[height,opacity]`
758
- wrap at ≥2 sites. The duration/easing rides the data-state
759
- `animate-accordion-*`/`animate-collapsible-*` keyframes (this only declares
760
- WHICH properties transition; the keyframes own the timing). */
761
- @utility transition-collapse {
762
- transition-property: height, opacity;
763
- }
764
-
765
- /* ── Sheet/drawer slide-out animation grammar ──
766
- Mirror of `.popover-animate` for sheet/drawer panels. Pairs with
767
- `slide-in-from-{top,right,bottom,left}-N` to compose side-keyed entries.
768
- The open path uses --duration-panel (slow, deliberate); the close path
769
- uses --duration-fast so dismiss feels snappy. R5 vocab.γ gap row 6;
770
- consumed by W2.A sheet/drawer migration. */
771
- @utility sheet-animate {
772
- @apply data-[state=open]:animate-in data-[state=closed]:animate-out
773
- data-[state=open]:fade-in data-[state=closed]:fade-out
774
- data-[state=open]:duration-[var(--duration-panel)]
775
- data-[state=closed]:duration-[var(--duration-fast)];
776
- }
777
-
778
- /* ── Audacious primary CTA recipe ────────────────────────────────────────
779
- Composes three at-rest marks (top-highlight via --glass-highlight, bottom
780
- under-shadow via --border-hairline, baseline glass) with three disco accents
781
- on hover (specular swap via --glass-specular, sparkle sweep via the ::after
782
- star, disco-grain via --paper-clean-texture blended with a --primary radial).
783
- Disco fires on hover only — at rest the button reads as a restrained glass
784
- surface. Pair with `bg-primary text-primary-foreground`; the utility owns
785
- the texture/highlight/sparkle composition only. */
786
- @utility btn-audacious {
787
- position: relative;
788
- isolation: isolate;
789
- overflow: hidden;
790
- border: 1px solid var(--glass-border-quiet);
791
- box-shadow:
792
- var(--border-hairline),
793
- var(--glass-highlight);
794
- transition:
795
- background var(--duration-fast) var(--ease-standard),
796
- color var(--duration-fast) var(--ease-standard),
797
- transform var(--duration-fast) var(--ease-standard),
798
- box-shadow var(--duration-fast) var(--ease-standard),
799
- --ripple-radius var(--motion-duration-ripple, 340ms) var(--ease-out-expo);
800
-
801
- /* Hover composition: paper-grain texture overlaid on a soft
802
- --primary radial, with the specular catch-light replacing the
803
- resting hairline highlight. The radial uses --primary at 18%
804
- — same alpha rung the dock primary tier consumes for phase
805
- tinting, just bound to the canonical CTA color instead. */
806
- &:hover:not(:disabled) {
807
- background-image:
808
- var(--paper-clean-texture),
809
- radial-gradient(
810
- ellipse at 30% 30%,
811
- color-mix(in srgb, var(--primary) 18%, transparent),
812
- transparent 70%
813
- );
814
- background-blend-mode: overlay, normal;
815
- background-size: var(--paper-texture-size), auto;
816
- box-shadow:
817
- var(--glass-specular),
818
- 0 0.5px 0 0 rgb(0 0 0 / 0.06);
819
- }
820
-
821
- /* AI.W4-M.2 (Q5 — G-AI-D27 ratified) — press-ripple via a typed
822
- `--ripple-radius` length custom property. The `::before`
823
- element paints a radial gradient whose stop radius equals the
824
- typed length; the `:active` rule sets the length to the cap
825
- (`--ripple-radius-max`, 12rem), and the host's transition
826
- (above) interpolates the radius via the @property registration
827
- (tokens.css §18). Release returns the length to its 0px initial
828
- value and the ripple retires. The ripple paints at z-index 0
829
- (above the host's background, below the slot content which sits
830
- in the default 0 stacking context but with text inheriting the
831
- slot's foreground colour). */
832
- &::before {
833
- content: "";
834
- position: absolute;
835
- inset: 0;
836
- pointer-events: none;
837
- z-index: 0;
838
- border-radius: inherit;
839
- background: radial-gradient(
840
- circle at center,
841
- color-mix(in srgb, var(--primary-foreground, hsl(0 0% 100%)) 35%, transparent) 0,
842
- color-mix(in srgb, var(--primary-foreground, hsl(0 0% 100%)) 18%, transparent)
843
- calc(var(--ripple-radius, 0px) * 0.55),
844
- transparent var(--ripple-radius, 0px)
845
- );
846
- transition: inherit;
847
- will-change: background;
848
- }
849
-
850
- &:active:not(:disabled) {
851
- --ripple-radius: var(--ripple-radius-max, 12rem);
852
- }
853
-
854
- /* Sparkle glyph — hidden at rest, animated on hover. The star
855
- sweeps diagonally from top-left to bottom-right per the canonical
856
- sparkle-sweep keyframe (animations.css). */
857
- &::after {
858
- content: "✦";
859
- position: absolute;
860
- top: 0.25rem;
861
- left: 0.5rem;
862
- color: hsl(0 0% 100% / 0.7);
863
- font-size: 0.75rem;
864
- line-height: 1;
865
- pointer-events: none;
866
- opacity: 0;
867
- will-change: transform, opacity;
868
- z-index: 1;
869
- }
870
-
871
- @media (prefers-reduced-motion: no-preference) {
872
- &:hover::after {
873
- animation: sparkle-sweep var(--duration-sparkle) var(--ease-out-expo);
874
- }
875
- }
876
-
877
- /* PRM bracket — the press-ripple retires; the press still reads
878
- via the audacious recipe's transform/scale beat (the ripple is
879
- affirmation atop affirmation). */
880
- @media (prefers-reduced-motion: reduce) {
881
- transition:
882
- background var(--duration-fast) var(--ease-standard),
883
- color var(--duration-fast) var(--ease-standard),
884
- transform var(--duration-fast) var(--ease-standard),
885
- box-shadow var(--duration-fast) var(--ease-standard);
886
-
887
- &:active:not(:disabled) {
888
- --ripple-radius: 0px;
889
- }
890
- }
891
- }
892
-
893
- /* ── Gold CTA shimmer modifier — AN.R0 D9 ───────────────────────────────
894
- `btn-audacious-gold` extends `btn-audacious` with a gold sweep shimmer
895
- on hover. Pair as `btn-audacious btn-audacious-gold` (or use the Button
896
- `variant="gold-audacious"` which composes both). The hover shimmer is a
897
- translucent linear-gradient sweep (low alpha — tasteful, not garish)
898
- that slides left-to-right via the existing `gold-shimmer-slide` keyframe
899
- (animations.css). The gold gradient uses the canonical `--color-gold-*`
900
- token triad (tokens.css §13).
901
-
902
- Design register:
903
- • PRM no-preference: shimmer sweeps continuously at `--duration-shimmer`
904
- rate; the sparkle-sweep (from btn-audacious) coexists on hover.
905
- • PRM reduce: static gold tint shows on hover; no animation.
906
- • The gold shimmer is a background-image layer ABOVE the existing
907
- btn-audacious paper-grain + primary-radial layers, blended with
908
- `overlay` so the glass substrate reads through at partial opacity.
909
- • The `::before` ripple and `::after` sparkle from btn-audacious are
910
- unchanged; this modifier only retunes the hover background layers.
911
- • Consumer applies: `<Button variant="gold-audacious">Next →</Button>` */
912
- @utility btn-audacious-gold {
913
- /* At rest: a faint warm gold tint over the glass surface reads as "warm
914
- glass" without announcing the hover state prematurely. */
915
- background-image:
916
- linear-gradient(
917
- 135deg,
918
- color-mix(in srgb, var(--color-gold) 8%, transparent),
919
- color-mix(in srgb, var(--color-gold-light) 5%, transparent) 50%,
920
- color-mix(in srgb, var(--color-gold) 8%, transparent)
921
- );
922
-
923
- /* Hover: replace the audacious primary-radial with a gold sweep shimmer.
924
- The shimmer gradient rides above the paper-grain texture; the `overlay`
925
- blend-mode concentrates the gold on bright grain facets and recedes on
926
- dark ones — the same lens metaphor as the btn-audacious primary radial. */
927
- &:hover:not(:disabled) {
928
- background-image:
929
- var(--paper-clean-texture),
930
- linear-gradient(
931
- 90deg,
932
- transparent 0%,
933
- color-mix(in srgb, var(--color-gold-dark) 22%, transparent) 25%,
934
- color-mix(in srgb, var(--color-gold-light) 30%, transparent) 50%,
935
- color-mix(in srgb, var(--color-gold-dark) 22%, transparent) 75%,
936
- transparent 100%
937
- );
938
- background-blend-mode: overlay, normal;
939
- background-size: var(--paper-texture-size), 250% 100%;
940
- background-position: 0 0, 100% 0;
941
- box-shadow:
942
- var(--glass-specular),
943
- 0 0 0 1px color-mix(in srgb, var(--color-gold) 30%, transparent),
944
- 0 0.5px 0 0 rgb(0 0 0 / 0.06);
945
- }
946
-
947
- @media (prefers-reduced-motion: no-preference) {
948
- &:hover:not(:disabled) {
949
- animation: btn-gold-bg-sweep var(--duration-shimmer) linear infinite;
950
- }
951
- }
952
- }
953
-
954
- /* Background-position sweep for the gold CTA hover shimmer.
955
- Distinct from `gold-shimmer-slide` (which animates background-position for
956
- a text-clip gradient). This variant sweeps the `background-position` of the
957
- 250% wide gradient across the button's bounding box. */
958
- @keyframes btn-gold-bg-sweep {
959
- 0% { background-position: 0 0, 100% 0; }
960
- 100% { background-position: 0 0, -100% 0; }
961
- }
962
-
963
- /* ── Table density utilities — AN.R0 ─────────────────────────────────────
964
- `table-cell` and `table-head` replace the former Tailwind `p-4` / `h-12`
965
- literals in TableCell.vue / TableHead.vue. Both read `--table-density`
966
- (tokens.css §19) so a single CSS-var assignment on a wrapping element
967
- scales all row padding + header height simultaneously. Default density=1
968
- resolves to the identical geometry as the previous Tailwind literals. */
969
- @utility table-cell {
970
- padding-inline: var(--table-cell-px, 1rem);
971
- padding-block: var(--table-cell-py, 1rem);
972
- }
973
-
974
- @utility table-head {
975
- height: var(--table-head-h, 3rem);
976
- padding-inline: var(--table-head-px, 1rem);
977
- }
978
-
979
- /* ── Rainbow gradient backgrounds ───────────────────────────────────────
980
- `.rainbow-vivid` + `.rainbow-pastel` paint a left-to-right 7-stop spectrum
981
- from the canonical `--rainbow-*` / `--rainbow-pastel-*` token families
982
- (tokens.css §14). Consumed by keyframes.js's `AnimationMenuBar.vue` round
983
- play button — `rainbow-vivid` (playing) / `rainbow-pastel` (idle). */
984
- @utility rainbow-vivid {
985
- background: linear-gradient(
986
- to right,
987
- var(--rainbow-red),
988
- var(--rainbow-orange),
989
- var(--rainbow-yellow),
990
- var(--rainbow-green),
991
- var(--rainbow-blue),
992
- var(--rainbow-indigo),
993
- var(--rainbow-violet)
994
- );
995
- }
996
-
997
- @utility rainbow-pastel {
998
- background: linear-gradient(
999
- to right,
1000
- var(--rainbow-pastel-red),
1001
- var(--rainbow-pastel-orange),
1002
- var(--rainbow-pastel-yellow),
1003
- var(--rainbow-pastel-green),
1004
- var(--rainbow-pastel-blue),
1005
- var(--rainbow-pastel-indigo),
1006
- var(--rainbow-pastel-violet)
1007
- );
1008
- }
1009
-
1010
- /* ── Text-highlight paint (CSS Custom Highlight API) ─────────────────────
1011
- The default `::highlight()` paint for the `useTextHighlight` composable
1012
- (composables/motion; the `/motion-core` subpath, AX.W37). A named `Highlight`
1013
- registered in `CSS.highlights`
1014
- under one of these keys paints its `Range` set without a `<mark>` wrapper.
1015
- Token-bridged: the search mark reads the canonical pastel-yellow rainbow
1016
- token at a soft alpha; the equation/variable mark reads `--primary`. Both
1017
- axes are overridable via the `--text-highlight-*` custom properties. */
1018
- ::highlight(glass-search-mark) {
1019
- background-color: var(
1020
- --text-highlight-search-bg,
1021
- color-mix(in srgb, var(--rainbow-pastel-yellow) 55%, transparent)
1022
- );
1023
- color: var(--text-highlight-search-fg, inherit);
1024
- }
1025
- ::highlight(glass-mark) {
1026
- background-color: var(
1027
- --text-highlight-bg,
1028
- color-mix(in srgb, var(--primary) 18%, transparent)
1029
- );
1030
- color: var(--text-highlight-fg, inherit);
1031
- }
1032
-
1033
- /* ── Interactive-button four-state recipe ────────────────────────────────
1034
- `.btn-interactive` carries the canonical "Button-with-spring-hover"
1035
- four-state contract — transition + hover-scale + active-press + disabled-
1036
- opacity + focus-ring fade-in. The Button primitive's variants emit the four
1037
- states except `hover:scale-*`; this is the canonical opt-in that adds the
1038
- spring-hover lift. Consumed by keyframes.js at 7 sites.
1039
-
1040
- AX.W52 §6 — the hover lift is the restrained `--scale-hover-btn` (1.035, NOT
1041
- the emphatic 1.08 `--scale-hover`) routed through `--spring-smooth` — the ONE
1042
- button scale register the §6 doctrine records and the gate asserts across
1043
- `.btn-pill`/`.tap-squish`/`.glass-btn`/`btn-interactive`. The surface legs
1044
- stay on the bezier `--ease-standard` (a colour cross-fade reads as a wobble
1045
- on a spring); only the `scale` transform leg springs. */
1046
- @utility btn-interactive {
1047
- /* AQ.W3 §W3.2 identity base */
1048
- scale: 1;
1049
- transition:
1050
- background-color var(--duration-fast) var(--ease-standard),
1051
- color var(--duration-fast) var(--ease-standard),
1052
- scale var(--duration-fast) var(--spring-smooth),
1053
- opacity var(--duration-fast) var(--ease-standard);
1054
-
1055
- &:hover {
1056
- scale: var(--scale-hover-btn);
1057
- }
1058
-
1059
- &:active {
1060
- scale: var(--scale-press);
1061
- }
1062
-
1063
- &:disabled {
1064
- opacity: var(--opacity-disabled);
1065
- pointer-events: none;
1066
- }
1067
-
1068
- &:focus-visible {
1069
- box-shadow: var(--focus-ring-shadow);
1070
- outline: none;
1071
- /* Fade in; base state has no box-shadow transition → instant
1072
- removal. The `scale` leg keeps the `--spring-smooth` register. */
1073
- transition:
1074
- background-color var(--duration-fast) var(--ease-standard),
1075
- color var(--duration-fast) var(--ease-standard),
1076
- scale var(--duration-fast) var(--spring-smooth),
1077
- opacity var(--duration-fast) var(--ease-standard),
1078
- box-shadow var(--duration-fast) var(--ease-standard);
1079
- }
1080
- }
1081
-
1082
- /* ── Reduced motion: nuanced — preserve opacity, remove spatial motion ── */
1083
- @media (prefers-reduced-motion: reduce) {
1084
- *:not([data-allow-motion]) {
1085
- animation-duration: 0.01ms !important;
1086
- animation-iteration-count: 1 !important;
1087
- }
1088
-
1089
- /* Keep opacity transitions (safe, non-spatial) but shorten */
1090
- *:not([data-allow-motion]) {
1091
- transition-duration: 0.1s !important;
1092
- transition-property: opacity, color, background-color, border-color, box-shadow !important;
1093
- }
1094
- }
1095
-
1096
- /* ── No-transition class (for theme switches, etc.) ── */
1097
- html.no-transition,
1098
- html.no-transition *,
1099
- html.no-transition *::before,
1100
- html.no-transition *::after {
1101
- transition-duration: 0s !important;
1102
- }
1103
-
1104
- /* ── Forced-colors focus + silhouette rung (AQ.W2 §5 · generalized AX.W36) ────
1105
- Windows High Contrast / forced-colors mode STRIPS `box-shadow` — so the
1106
- glass focus rings (box-shadow + `outline: none`) vanish, leaving keyboard
1107
- users with no visible focus. Restore a real `outline` keyed to the system
1108
- `Highlight` color (outline survives forced-colors; box-shadow does not). The
1109
- box-shadow ring stays the primary in normal mode (it carries the glass
1110
- aesthetic) — these two are mutually exclusive by media query, NOT a parallel
1111
- path.
1112
-
1113
- AX.W36 — the focus-survival selector set is GENERALIZED to the broader
1114
- interactive surface: the dock CONTROLS (`.dock-icon-button` / `.dock-tab-button`
1115
- / `.dock-select-trigger` / `.dock-dropdown-trigger`) + the pill button base
1116
- (`.btn-pill`) all carry a box-shadow focus ring (dock.css / utilities.css) that
1117
- vanishes under WHC just like the original five. This is the SAME `Highlight`
1118
- outline rung extended to cover them — ONE block, ONE path (the glass-language
1119
- structure-survival skin for the tier panes / StatusDot / floating surfaces lives
1120
- co-located with the ladder it skins, in glass.css).
1121
-
1122
- `forced-color-adjust: none` is deliberately NOT used — glass-ui's glassmorphic
1123
- chrome is decorative and yields to the user's forced palette (css forced-colors
1124
- guidance). Baseline Widely Available; this IS the fallback mechanism (it only
1125
- activates under forced-colors), so no nested guard. */
1126
- @media (forced-colors: active) {
1127
- .focus-ring:focus-visible,
1128
- .glass-btn:focus-visible,
1129
- .interactive-item:focus-visible,
1130
- .btn-pill:focus-visible,
1131
- .dock-icon-button:focus-visible,
1132
- .dock-tab-button:focus-visible,
1133
- .dock-select-trigger:focus-visible,
1134
- .dock-dropdown-trigger:focus-visible,
1135
- .input-pill:focus,
1136
- .input-pill:focus-visible {
1137
- outline: 2px solid Highlight;
1138
- outline-offset: 2px;
1139
- }
1140
-
1141
- /* Structural edges borne ONLY by box-shadow (the hairline catch-light + the
1142
- dock SHELL pill edge) also vanish — restore a real border so the silhouette
1143
- survives. CanvasText is the system text/border color. The `.glass-dock`
1144
- shell is OUT of the glass-material group BY DESIGN (it hand-rolls a parallel
1145
- surface — see glass.css), so it keeps its WHC edge HERE; the five-rung ladder
1146
- + `.glass-card` get their WHC border from the co-located glass-language skin
1147
- in glass.css (one source per surface family, no double-declaration). */
1148
- .hairline-accent,
1149
- .glass-dock {
1150
- border: 1px solid CanvasText;
1151
- }
1152
- }
1153
-
1154
- /* ── Coarse-pointer touch-target floor (AQ.W3 §7) ───────────────────────────
1155
- General-surface companion to the dock-scoped R0G-6 floor (dock.css). On
1156
- coarse pointers the small icon-button/trigger surfaces OUTSIDE the dock lift
1157
- to the WCAG 2.5.5 (44px) minimum — ONE amendment retiring the per-consumer
1158
- `min-h-[44px]` one-liners. Token-driven (`--touch-target`); fine-pointer
1159
- byte-identical. Targets `Button size="icon"` (via the `data-size="icon"`
1160
- attr Button.vue reflects), ExpandableContainer + SegmentedTabs (responsive
1161
- mobile Select) triggers.
1162
- `min-block/inline-size` only RAISES — a larger explicit size is never lost. */
1163
- @media (pointer: coarse) {
1164
- [data-size="icon"],
1165
- .expandable-container__trigger,
1166
- .segmented-tabs__trigger {
1167
- min-block-size: var(--touch-target, 2.75rem);
1168
- min-inline-size: var(--touch-target, 2.75rem);
1169
- }
1170
- }
1
+ /* Shared utility classes
2
+ *
3
+ * ── Thin @import ROOT (cohesion-aware carve) ───────────────────────────────
4
+ * The utility body is carved into cohesive `utilities/*.css` partials (each
5
+ * under the 500-line no-god-module bound), @import-ed below in CASCADE ORDER.
6
+ * The leading @utility animation pair, the @layer components block (split at
7
+ * the metric-badge seam into two adjacent same-layer blocks — isomorphic), the
8
+ * @utility button cluster, and the a11y @media overrides keep their source
9
+ * order so the cascade is unchanged. See docs/precepts/design-idioms.md
10
+ * §cohesion-aware partials.
11
+ */
12
+
13
+ /* CSS @import rules must precede every other rule. The five partials @import in
14
+ cascade order: */
15
+ @import "./utilities/animate.css";
16
+ @import "./utilities/base.css";
17
+ @import "./utilities/components.css";
18
+ @import "./utilities/btn.css";
19
+ @import "./utilities/a11y-overrides.css";