@mkbabb/glass-ui 3.10.1 → 3.11.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.
- package/dist/{CardAction-DrAcAV4d.js → CardAction-DuArVky-.js} +2 -2
- package/dist/{CommandShortcut-mV2e1aG6.js → CommandShortcut-CefCj5mt.js} +2 -2
- package/dist/{DataTable-C3E6jZ5B.js → DataTable-CUHMukiQ.js} +2 -2
- package/dist/DeckProgress-Dmk4_AKN.js +23 -0
- package/dist/{DialogContent-BxaaafFi.js → DialogContent-BRkT1cjP.js} +1 -1
- package/dist/{HoverPopover-CDA_SaCe.js → HoverPopover-2LOIW34a.js} +1 -1
- package/dist/InstrumentRail-CUJ05YVG.js +44 -0
- package/dist/{MetricBadge-idgrkqoP.js → MetricBadge-BZVWIxNy.js} +7 -5
- package/dist/{Notification-Cu0nN17_.js → Notification-DLMhblXR.js} +1 -1
- package/dist/{NumberFieldContent-CHEWghnY.js → NumberFieldContent-BbLOh8RU.js} +2 -2
- package/dist/{PopoverContent-DpUvdYY-.js → PopoverContent-BId6ggf_.js} +1 -1
- package/dist/{Progress-BW-StFw2.js → Progress-iEuD9pxG.js} +1 -1
- package/dist/{ScrollingText-DruYCni_.js → ScrollingText-BPP84wKo.js} +1 -1
- package/dist/{SelectScrollDownButton-pirzjm--.js → SelectScrollDownButton-T32cVFeM.js} +3 -3
- package/dist/{Switch-DeAqg6pi.js → Switch-Ch-k3Rv-.js} +1 -1
- package/dist/{TabsList-BAVzOZpg.js → TabsList-B8CVOQPC.js} +2 -2
- package/dist/{Toaster-CvuuW_y9.js → Toaster-1rYWrmAm.js} +46 -49
- package/dist/{ToggleGroupItem-DtD37b4G.js → ToggleGroupItem-COu_4IW4.js} +21 -17
- package/dist/animated-digit.js +2 -2
- package/dist/api/index.d.ts +5 -4
- package/dist/api.js +2 -2
- package/dist/aurora.js +70 -70
- package/dist/{badge-NdCQMvvB.js → badge-CaoFJzRb.js} +1 -1
- package/dist/badge.js +1 -1
- package/dist/{button-DyiWFAOE.js → button-DN39cGqL.js} +12 -12
- package/dist/button.js +1 -1
- package/dist/canvas.js +2 -2
- package/dist/card.js +1 -1
- package/dist/carousel.js +5 -5
- package/dist/collapsible.js +1 -1
- package/dist/{color-B65wWyQz.js → color-C5ls_QF7.js} +7 -9
- package/dist/color.js +1 -1
- package/dist/command.js +1 -1
- package/dist/components/custom/aurora/constants/presets.d.ts +62 -5
- package/dist/components/custom/aurora/constants/shaders/mediums.glsl.d.ts +1 -1
- package/dist/components/custom/aurora/index.d.ts +1 -1
- package/dist/components/custom/constellation/Constellation.vue.d.ts +0 -12
- package/dist/components/custom/constellation/constellationField.d.ts +151 -10
- package/dist/components/custom/constellation/index.d.ts +1 -3
- package/dist/components/custom/controls/DarkModeToggle.vue.d.ts +0 -11
- package/dist/components/custom/deck-progress/DeckProgress.vue.d.ts +27 -0
- package/dist/components/custom/deck-progress/index.d.ts +2 -0
- package/dist/components/custom/dialog-native/GlassDialogNative.vue.d.ts +57 -0
- package/dist/components/custom/dialog-native/index.d.ts +1 -0
- package/dist/components/custom/dock/DockTabButton.vue.d.ts +4 -3
- package/dist/components/custom/dock/GlassDock.vue.d.ts +115 -3
- package/dist/components/custom/dock/composables/dockMorphContext.d.ts +0 -36
- package/dist/components/custom/dock/composables/useLayerTransition.d.ts +0 -44
- package/dist/components/custom/expandable-container/ExpandableContainer.vue.d.ts +37 -5
- package/dist/components/custom/fourier-field/index.d.ts +1 -1
- package/dist/components/custom/fourier-field/math.d.ts +0 -17
- package/dist/components/custom/glass-panel/GlassPanel.vue.d.ts +41 -0
- package/dist/components/custom/glass-panel/index.d.ts +2 -0
- package/dist/components/custom/goo-blob/composables/useBlobPointer.d.ts +3 -4
- package/dist/components/custom/goo-blob/composables/useMetaballRenderer.d.ts +8 -11
- package/dist/components/custom/handmark/HandMark.vue.d.ts +29 -0
- package/dist/components/custom/handmark/brush.d.ts +242 -0
- package/dist/components/custom/handmark/freehand.d.ts +69 -0
- package/dist/components/custom/handmark/geometry.d.ts +50 -0
- package/dist/components/custom/handmark/index.d.ts +21 -0
- package/dist/components/custom/handmark/ink.d.ts +11 -0
- package/dist/components/custom/handmark/texture.d.ts +39 -0
- package/dist/components/custom/handmark/types.d.ts +53 -0
- package/dist/components/custom/handmark/useHandMark.d.ts +87 -0
- package/dist/components/custom/header-ribbon/HeaderRibbon.vue.d.ts +31 -0
- package/dist/components/custom/header-ribbon/index.d.ts +2 -0
- package/dist/components/custom/header-ribbon/types.d.ts +7 -0
- package/dist/components/custom/instrument-chassis/InstrumentChassis.vue.d.ts +2 -2
- package/dist/components/custom/instrument-rail/InstrumentRail.vue.d.ts +91 -0
- package/dist/components/custom/instrument-rail/index.d.ts +2 -0
- package/dist/components/custom/metric-badge/MetricBadge.vue.d.ts +8 -0
- package/dist/components/ui/drawer/Drawer.vue.d.ts +0 -1
- package/dist/components/ui/dropdown-menu/DropdownMenuSubContent.vue.d.ts +2 -2
- package/dist/components/ui/slider/index.d.ts +19 -22
- package/dist/components/ui/toast/use-toast.d.ts +2 -2
- package/dist/components/ui/toggle/Toggle.vue.d.ts +1 -1
- package/dist/components/ui/toggle/index.d.ts +1 -1
- package/dist/components/ui/toggle-group/ToggleGroup.vue.d.ts +7 -1
- package/dist/components/ui/toggle-group/ToggleGroupItem.vue.d.ts +3 -1
- package/dist/components/ui/toggle-group/toggleGroupContext.d.ts +13 -0
- package/dist/composables/color/index.d.ts +0 -12
- package/dist/composables/dark/index.d.ts +1 -1
- package/dist/composables/dark/useGlobalDark.d.ts +21 -1
- package/dist/composables/glass/useSpecularTracking.d.ts +3 -12
- package/dist/composables/motion/core/index.d.ts +1 -0
- package/dist/composables/motion/index.d.ts +0 -2
- package/dist/composables/motion/useRouteTransition.d.ts +42 -0
- package/dist/composables/motion/useSpringMount.d.ts +1 -1
- package/dist/configurator.js +1 -1
- package/dist/confirm-dialog.js +2 -2
- package/dist/constellation.js +225 -260
- package/dist/controls.js +14 -48
- package/dist/dark.d.ts +1 -1
- package/dist/dark.js +1 -1
- package/dist/data-table.js +1 -1
- package/dist/deck-progress.d.ts +1 -0
- package/dist/deck-progress.js +2 -0
- package/dist/dialog.js +2 -2
- package/dist/dock.js +345 -340
- package/dist/dockContext-BKeIMmNk.js +9 -0
- package/dist/{dropdown-menu-DVnQcA0E.js → dropdown-menu-D77jX6Df.js} +4 -7
- package/dist/dropdown-menu.js +1 -1
- package/dist/expandable-container.js +79 -38
- package/dist/forms.js +2 -2
- package/dist/fourier-field.js +102 -137
- package/dist/fourier-math.js +2 -2
- package/dist/glass-panel.d.ts +1 -0
- package/dist/glass-panel.js +44 -0
- package/dist/glass-ui.css +1 -1
- package/dist/glass-ui.js +209 -287
- package/dist/goo-blob.js +212 -243
- package/dist/handmark.d.ts +1 -0
- package/dist/handmark.js +663 -0
- package/dist/header-ribbon.d.ts +1 -0
- package/dist/header-ribbon.js +63 -0
- package/dist/hover-popover.js +1 -1
- package/dist/icon-tooltip.js +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/instrument-rail.d.ts +1 -0
- package/dist/instrument-rail.js +2 -0
- package/dist/keyboard.js +1 -1
- package/dist/labeled-field.js +5 -5
- package/dist/{math-BUU9hHID.js → math-DTpRVC0e.js} +2 -18
- package/dist/metric-badge.js +1 -1
- package/dist/metric-stack.js +1 -1
- package/dist/motion-core.js +70 -69
- package/dist/motion.js +37 -38
- package/dist/notification.js +1 -1
- package/dist/number-field.js +1 -1
- package/dist/popover.js +1 -1
- package/dist/{presets-1OhFpaIC.js → presets-BP_ALM0m.js} +14 -1
- package/dist/progress.js +1 -1
- package/dist/pulse.js +1 -1
- package/dist/reactive.js +1 -1
- package/dist/scrolling-text.js +1 -1
- package/dist/search.js +6 -6
- package/dist/select.js +1 -1
- package/dist/{sheet-ChSXcJpU.js → sheet-VZEtNFvO.js} +1 -1
- package/dist/sheet.js +1 -1
- package/dist/{slider-sfl8gFDD.js → slider-ClgpP7EB.js} +4 -4
- package/dist/slider.js +1 -1
- package/dist/sortable-list.js +2 -2
- package/dist/stacked-icons.js +6 -6
- package/dist/styles/animations.css +111 -15
- package/dist/styles/components.css +1 -1
- package/dist/styles/dock/layer-group.css +0 -22
- package/dist/styles/dock/layers.css +1 -11
- package/dist/styles/dock/morph.css +19 -95
- package/dist/styles/dock/shell.css +0 -12
- package/dist/styles/dock-controls.css +31 -28
- package/dist/styles/drawer.css +0 -2
- package/dist/styles/floating-panel.css +0 -2
- package/dist/styles/glass-refract.css +0 -2
- package/dist/styles/glass.css +1188 -31
- package/dist/styles/hover-popover.css +0 -2
- package/dist/styles/index.css +6 -24
- package/dist/styles/instrument-chassis.css +0 -4
- package/dist/styles/paper.css +68 -2
- package/dist/styles/theme.css +20 -13
- package/dist/styles/tokens.css +2360 -22
- package/dist/styles/typography.css +6 -18
- package/dist/styles/utilities.css +1291 -19
- package/dist/styles/view-transition.css +51 -0
- package/dist/switch.js +1 -1
- package/dist/tabs.js +98 -98
- package/dist/timeline.js +2 -2
- package/dist/toast.js +1 -1
- package/dist/toggle-group.js +1 -1
- package/dist/typewriter.js +1 -1
- package/dist/{useAnimatedNumber-DfVgP4te.js → useAnimatedNumber-Bcpy5Etf.js} +1 -1
- package/dist/{useConfiguratorState-BdQXh9ie.js → useConfiguratorState-DxAqksK6.js} +1 -1
- package/dist/useGlassRenderer-D7YGOYiM.js +69 -0
- package/dist/{useGlobalDark-D7R9OypB.js → useGlobalDark-D1wgEqfW.js} +21 -2
- package/dist/useSpecularTracking-BVRZsRHA.js +26 -0
- package/dist/useSpringMount-BJSHcLl3.js +113 -0
- package/dist/useViewTransition-DaN5Zrox.js +21 -0
- package/dist/vReveal-zUIQk-rJ.js +53 -0
- package/dist/watercolor-dot.js +2 -2
- package/package.json +57 -33
- package/src/styles/animations.css +111 -15
- package/src/styles/dock/layer-group.css +0 -22
- package/src/styles/dock/layers.css +1 -11
- package/src/styles/dock/morph.css +19 -95
- package/src/styles/dock/shell.css +0 -12
- package/src/styles/dock-controls.css +31 -28
- package/src/styles/glass.css +1188 -31
- package/src/styles/index.css +6 -24
- package/src/styles/paper.css +68 -2
- package/src/styles/theme.css +20 -13
- package/src/styles/tokens.css +2360 -22
- package/src/styles/typography.css +6 -18
- package/src/styles/utilities.css +1291 -19
- package/src/styles/view-transition.css +51 -0
- package/dist/components/custom/aurora/constants/shaders/vangogh-medium.glsl.d.ts +0 -1
- package/dist/components/custom/constellation/composables/createConstellationField.d.ts +0 -35
- package/dist/components/custom/constellation/composables/useConstellationPointer.d.ts +0 -35
- package/dist/components/custom/constellation/constants.d.ts +0 -36
- package/dist/components/custom/constellation/constellationDraw.d.ts +0 -18
- package/dist/components/custom/constellation/constellationInteraction.d.ts +0 -102
- package/dist/components/custom/dock/composables/useDockMorphWindow.d.ts +0 -15
- package/dist/components/custom/dock/composables/useDockShellProps.d.ts +0 -131
- package/dist/components/custom/dock/constants.d.ts +0 -23
- package/dist/components/custom/fourier-field/presets.d.ts +0 -54
- package/dist/components/custom/goo-blob/composables/buildMetaballProgram.d.ts +0 -18
- package/dist/components/custom/goo-blob/composables/uploadBlobUniforms.d.ts +0 -41
- package/dist/components/custom/goo-blob/constants.d.ts +0 -52
- package/dist/components/custom/goo-blob/shaders/metaball-uniforms.glsl.d.ts +0 -1
- package/dist/components/custom/tabs/constants.d.ts +0 -12
- package/dist/components/custom/underline/GlassUnderline.vue.d.ts +0 -84
- package/dist/components/custom/underline/index.d.ts +0 -2
- package/dist/components/custom/underline/types.d.ts +0 -56
- package/dist/composables/motion/curves.d.ts +0 -48
- package/dist/composables/motion/springPresets.d.ts +0 -33
- package/dist/composables/motion/suite.d.ts +0 -2
- package/dist/dockContext-bho8B1A4.js +0 -17
- package/dist/motion-curves.d.ts +0 -1
- package/dist/motion-curves.js +0 -130
- package/dist/springPresets-aRSm-4_k.js +0 -40
- package/dist/styles/glass/a11y-fallback.css +0 -245
- package/dist/styles/glass/ladder.css +0 -304
- package/dist/styles/glass/material.css +0 -238
- package/dist/styles/glass/progress-rail.css +0 -78
- package/dist/styles/glass/squircle.css +0 -66
- package/dist/styles/glass/surfaces.css +0 -306
- package/dist/styles/tokens/color-radius.css +0 -250
- package/dist/styles/tokens/dark-arm.css +0 -194
- package/dist/styles/tokens/glass.css +0 -413
- package/dist/styles/tokens/light-dark.css +0 -158
- package/dist/styles/tokens/offsets-sizing.css +0 -406
- package/dist/styles/tokens/property-regs.css +0 -169
- package/dist/styles/tokens/scale-paper.css +0 -361
- package/dist/styles/tokens/scheme-motion.css +0 -334
- package/dist/styles/tokens/shadow.css +0 -132
- package/dist/styles/utilities/a11y-overrides.css +0 -140
- package/dist/styles/utilities/animate.css +0 -26
- package/dist/styles/utilities/base.css +0 -365
- package/dist/styles/utilities/btn.css +0 -399
- package/dist/styles/utilities/components.css +0 -317
- package/dist/underline.d.ts +0 -1
- package/dist/underline.js +0 -85
- package/dist/useSpecularTracking-DFK_fhpG.js +0 -32
- package/dist/useSpringMount-DXUzxBjV.js +0 -108
- package/dist/vReveal-CqaCz_mC.js +0 -44
- package/src/styles/glass/a11y-fallback.css +0 -245
- package/src/styles/glass/ladder.css +0 -304
- package/src/styles/glass/material.css +0 -238
- package/src/styles/glass/progress-rail.css +0 -78
- package/src/styles/glass/squircle.css +0 -66
- package/src/styles/glass/surfaces.css +0 -306
- package/src/styles/tokens/color-radius.css +0 -250
- package/src/styles/tokens/dark-arm.css +0 -194
- package/src/styles/tokens/glass.css +0 -413
- package/src/styles/tokens/light-dark.css +0 -158
- package/src/styles/tokens/offsets-sizing.css +0 -406
- package/src/styles/tokens/property-regs.css +0 -169
- package/src/styles/tokens/scale-paper.css +0 -361
- package/src/styles/tokens/scheme-motion.css +0 -334
- package/src/styles/tokens/shadow.css +0 -132
- package/src/styles/utilities/a11y-overrides.css +0 -140
- package/src/styles/utilities/animate.css +0 -26
- package/src/styles/utilities/base.css +0 -365
- package/src/styles/utilities/btn.css +0 -399
- package/src/styles/utilities/components.css +0 -317
- /package/dist/{CollapsibleContent-Drow5WkV.js → CollapsibleContent-CP9qF1v4.js} +0 -0
- /package/dist/{DialogFooter-DufLHi0y.js → DialogFooter-Gprw8H_A.js} +0 -0
- /package/dist/{IconTooltip-BrQ5p181.js → IconTooltip-Cus0fvK0.js} +0 -0
- /package/dist/{Input-B-F818RU.js → Input-xuDwALQR.js} +0 -0
- /package/dist/{_plugin-vue_export-helper-DWghtRt7.js → _plugin-vue_export-helper-ok8pgSl5.js} +0 -0
- /package/dist/{compile-Ce_V55zi.js → compile-BOXjLUxu.js} +0 -0
- /package/dist/{constants-C8NMonuo.js → constants-yKeKnE84.js} +0 -0
- /package/dist/{prng-CjVgzjQT.js → prng-D27-B3tK.js} +0 -0
- /package/dist/{resolveCanvasColor-CRvVzOvP.js → resolveCanvasColor-BBiYfp8g.js} +0 -0
- /package/dist/{useCanvas2D-CSeH8h16.js → useCanvas2D-ClrQuZtp.js} +0 -0
- /package/dist/{useIntersectionPause-DAdVPVp4.js → useIntersectionPause-Cck5Uxk8.js} +0 -0
- /package/dist/{useInterval-D3USn0yc.js → useInterval-Dsmqwi03.js} +0 -0
- /package/dist/{useKeyboardShortcuts-i8tHd5WO.js → useKeyboardShortcuts-CyIYrndH.js} +0 -0
- /package/dist/{useScrollProgress-CcgmgMQt.js → useScrollProgress-CffFGLa5.js} +0 -0
- /package/dist/{useSortable-DnyGXKKY.js → useSortable-C8ReQ50P.js} +0 -0
- /package/dist/{useTextHighlight-B3b10W6r.js → useTextHighlight-CWEi25hf.js} +0 -0
package/dist/styles/tokens.css
CHANGED
|
@@ -8,27 +8,2365 @@
|
|
|
8
8
|
* Structural tokens (durations, easings, springs, z-index, focus ring,
|
|
9
9
|
* interactive scales) are stable across consumers. Visual tokens (colors,
|
|
10
10
|
* shadows, radii, grain opacities) are consumer-overridable.
|
|
11
|
-
*
|
|
12
|
-
* This file is the thin @import ROOT of the token cascade. The token body is
|
|
13
|
-
* carved into cohesive `tokens/*.css` partials (each under the no-god-module
|
|
14
|
-
* 500-line bound), @import-ed below in CASCADE ORDER. The cascade is isomorphic:
|
|
15
|
-
* the master :root sub-ranges each carry their own :root{} (adjacent
|
|
16
|
-
* same-selector blocks resolve identically), and the post-root overrides
|
|
17
|
-
* (light-dark, the .dark arm, the @property registrations) keep their source
|
|
18
|
-
* order. See docs/precepts/design-idioms.md §cohesion-aware partials. The
|
|
19
|
-
* partial cascade order is BINDING — light-dark after the master partials
|
|
20
|
-
* (overrides them), dark-arm after light-dark, property-regs last
|
|
21
|
-
* (registrations + the specular magnitude cohort that reads them).
|
|
22
11
|
*/
|
|
23
12
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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
|
+
|
|
35
|
+
/* ═══════════════════════════════════════════════
|
|
36
|
+
§0 FONT TOKEN SOURCE-OF-TRUTH
|
|
37
|
+
|
|
38
|
+
The single authoritative declaration of the library's font register.
|
|
39
|
+
theme.css bridges each --font-stack-* to its Tailwind --font-* namespace
|
|
40
|
+
var; typography.css consumes the bridged --font-* names. The public
|
|
41
|
+
runtime knobs remain --font-*, --leading-*, --tracking-*.
|
|
42
|
+
|
|
43
|
+
ONE brand register: Plus Jakarta Sans (text + display) + Fira Code (mono).
|
|
44
|
+
--font-stack-text drives the body/heading/prose/display register — the
|
|
45
|
+
library DEFAULT is the register every live surface paints (the demo +
|
|
46
|
+
speedtest render Plus Jakarta everywhere). The calibrated "Plus Jakarta
|
|
47
|
+
Sans Fallback" / "Fira Code Fallback" faces (declared in typography.css)
|
|
48
|
+
wrap the system stacks with Capsize metric overrides so the swap window
|
|
49
|
+
is geometry-neutral (zero CLS). --font-stack-display aliases the text
|
|
50
|
+
register: there is no separate display-serif voice. */
|
|
51
|
+
--font-stack-text: "Plus Jakarta Sans", "Plus Jakarta Sans Fallback", system-ui, sans-serif;
|
|
52
|
+
--font-stack-display: var(--font-stack-text);
|
|
53
|
+
--font-stack-sans: var(--font-stack-text);
|
|
54
|
+
--font-stack-mono: "Fira Code", "Fira Code Fallback", "Fira Mono", monospace;
|
|
55
|
+
|
|
56
|
+
--type-leading-micro: 1.2;
|
|
57
|
+
--type-leading-caption: 1.3;
|
|
58
|
+
--type-leading-small: 1.4;
|
|
59
|
+
--type-leading-body: 1.5;
|
|
60
|
+
--type-leading-prose: 1.618;
|
|
61
|
+
--type-leading-heading: 1.2;
|
|
62
|
+
--type-leading-display: 1.1;
|
|
63
|
+
|
|
64
|
+
--type-tracking-tight: -0.025em;
|
|
65
|
+
--type-tracking-snug: -0.01em;
|
|
66
|
+
--type-tracking-normal: 0;
|
|
67
|
+
--type-tracking-wide: 0.025em;
|
|
68
|
+
--type-tracking-wider: 0.05em;
|
|
69
|
+
--type-tracking-caps: 0.1em;
|
|
70
|
+
|
|
71
|
+
/* ═══════════════════════════════════════════════
|
|
72
|
+
§1 DURATION
|
|
73
|
+
═══════════════════════════════════════════════ */
|
|
74
|
+
--duration-instant: 0.1s;
|
|
75
|
+
--duration-fast: 0.2s;
|
|
76
|
+
--duration-normal: 0.3s;
|
|
77
|
+
--duration-slow: 0.45s;
|
|
78
|
+
--duration-panel: 0.55s;
|
|
79
|
+
--duration-xl: 1s;
|
|
80
|
+
--duration-xxl: 1.5s;
|
|
81
|
+
--duration-shimmer-fast: 3s;
|
|
82
|
+
--duration-shimmer: 5s;
|
|
83
|
+
/* The gold ONE-SHOT seal envelope (E7c) — a PRESSED seal is a quick gesture
|
|
84
|
+
(in + hold + out), ≈1.5s end-to-end, NOT the 5s infinite-loop `--duration-
|
|
85
|
+
shimmer`. `.text-gilt` reads THIS so "catches the light once and recedes"
|
|
86
|
+
reads as a gesture, never a marquee that then hard-cuts. */
|
|
87
|
+
--duration-seal: 1.5s;
|
|
88
|
+
/* Sparkle micro-event — primary-CTA disco-grain sparkle sweep.
|
|
89
|
+
@deprecated 3.10 — the disco-star is EXCISED (D6.b); the `sparkle-sweep`
|
|
90
|
+
keyframe is tombstoned (animations.css) and no live recipe consumes this
|
|
91
|
+
duration. Retained one minor so an out-of-tree consumer resolves a value
|
|
92
|
+
rather than `unset`; full delete (this token + the theme bridge + the
|
|
93
|
+
keyframe) lands in 3.11. */
|
|
94
|
+
--duration-sparkle: 600ms;
|
|
95
|
+
|
|
96
|
+
/* AH.W5-e (FA-8 §4d) — motion-duration + staged-reveal canon.
|
|
97
|
+
|
|
98
|
+
Six duration tokens + three delay tokens promoted from raw literals
|
|
99
|
+
at speedtest's celebratory-reveal SFCs (SpeedtestResults, ThankYou,
|
|
100
|
+
ResultStack, CompleteBadge). Unified under the `--motion-*`
|
|
101
|
+
namespace (parallel to `--motion-ease-*`) so all motion tokens
|
|
102
|
+
cluster at one canon — duration + easing arm together. */
|
|
103
|
+
|
|
104
|
+
/* Staged-entrance pairing — opacity + transform Vue <Transition> arms
|
|
105
|
+
in the celebratory headline + result-row reveals. Partners with
|
|
106
|
+
`--motion-ease-staged-entrance` / `--motion-ease-overshoot`. */
|
|
107
|
+
--motion-duration-staged: 320ms;
|
|
108
|
+
|
|
109
|
+
/* One-shot celebratory shimmer — gold-headline shimmer animation
|
|
110
|
+
duration + staging delay. Shared canon so the speedtest results
|
|
111
|
+
headline and the thank-you headline stay in lockstep. */
|
|
112
|
+
--motion-duration-complete-shimmer: 2.4s;
|
|
113
|
+
--motion-delay-complete-shimmer: 220ms;
|
|
114
|
+
/* The gold-headline shimmer reads these two tokens under a one-shot
|
|
115
|
+
animation: at 2.4s + 220ms delay the bright band traverses the headline
|
|
116
|
+
glyphs cleanly. Load-bearing — zeroing either collapses the shimmer to
|
|
117
|
+
an imperceptible blow-through. */
|
|
118
|
+
|
|
119
|
+
/* CompleteBadge staged-reveal cluster — the disc / ring / check curve
|
|
120
|
+
fires at three asymmetric durations + delays per the A4-AF staged-
|
|
121
|
+
variety design intent. Promoting the magic numbers makes the
|
|
122
|
+
staged-variety visible at the canon. */
|
|
123
|
+
--motion-duration-badge-disc: 420ms;
|
|
124
|
+
--motion-duration-badge-ring: 560ms;
|
|
125
|
+
--motion-duration-badge-check: 380ms;
|
|
126
|
+
--motion-delay-badge-disc: 80ms;
|
|
127
|
+
--motion-delay-badge-ring: 220ms;
|
|
128
|
+
--motion-delay-badge-check: 460ms;
|
|
129
|
+
|
|
130
|
+
/* Staggered-reveal increment canon — three perceptually-distinct tiers for
|
|
131
|
+
per-row/per-cell/per-bar cascades:
|
|
132
|
+
• tight (40ms) — dense row cascades, sub-perceptual gap
|
|
133
|
+
• default (80ms) — the canonical row-stagger rhythm (matches
|
|
134
|
+
`useStagger`'s built-in fallback)
|
|
135
|
+
• relaxed (120ms) — wider cascades where each reveal carries its own
|
|
136
|
+
attention budget
|
|
137
|
+
Adjacent tiers keep cross-beats quiet (80 is the LCM of 40 and 2/3 of
|
|
138
|
+
120). Consumers read these via inline-style calc() or `getComputedStyle`
|
|
139
|
+
at runtime. */
|
|
140
|
+
--motion-stagger-tight: 40ms;
|
|
141
|
+
--motion-stagger-default: 80ms;
|
|
142
|
+
--motion-stagger-relaxed: 120ms;
|
|
143
|
+
|
|
144
|
+
/* ═══════════════════════════════════════════════
|
|
145
|
+
§2 EASING — Spring curves via linear()
|
|
146
|
+
|
|
147
|
+
Generated from `scripts/regen-spring-tokens.mjs` — DO NOT hand-edit.
|
|
148
|
+
To tune a spring: edit the PRESETS table in the script and re-run
|
|
149
|
+
`node scripts/regen-spring-tokens.mjs`. The script invokes
|
|
150
|
+
`springLinearStops()` from `@mkbabb/keyframes.js` which solves the
|
|
151
|
+
analytic second-order damped harmonic oscillator and emits CSS
|
|
152
|
+
`linear()` stops; this is the single source of truth tying each
|
|
153
|
+
(response, ζ) pair to its serialized curve.
|
|
154
|
+
|
|
155
|
+
iOS-canonical (response, dampingFraction) per AL-X4 §3:
|
|
156
|
+
smooth: (0.50s, ζ=0.86) — gentle settle, sub-perceptual overshoot ~0.5%
|
|
157
|
+
snappy: (0.35s, ζ=0.65) — quick crisp, overshoot ~+6.8%
|
|
158
|
+
bouncy: (0.50s, ζ=0.45) — emphatic overshoot ~+20.5%
|
|
159
|
+
gentle: (0.70s, ζ=1.00) — patient critically-damped
|
|
160
|
+
dock: (0.32s, ζ=0.70) — dock expand/collapse morph, overshoot ~+4.6%
|
|
161
|
+
|
|
162
|
+
Note on `smooth`: at ζ=0.86 the analytic solver produces a peak
|
|
163
|
+
of 1.00498 (+0.5%) at the 24% slot — mathematically present but
|
|
164
|
+
sub-perceptual. I keep ζ=0.86 rather than promoting to ζ=1.0
|
|
165
|
+
because true critical damping is `gentle`'s register, and
|
|
166
|
+
`smooth` wants a slightly faster visual settle than `gentle`'s
|
|
167
|
+
patient curve. The 0.5% peak does not read as overshoot to the
|
|
168
|
+
eye but does narrowly distinguish `smooth` from `gentle`.
|
|
169
|
+
|
|
170
|
+
── EASING DOCTRINE (AX.W52 §6 — which easing fits which job) ──
|
|
171
|
+
ONE recorded rule so the animation easing stops forking live. This
|
|
172
|
+
FORMALIZES the already-correct `transitions.css` idiom (enter=spring,
|
|
173
|
+
exit=bezier) as the house rule every recipe reaches for:
|
|
174
|
+
|
|
175
|
+
| Transition kind | Easing |
|
|
176
|
+
|--------------------------------------------------|-------------------------------------|
|
|
177
|
+
| Surface props (bg, border, color, box-shadow, | `--ease-standard` (bezier — a |
|
|
178
|
+
| opacity) | colour cross-fade reads as a |
|
|
179
|
+
| | wobble on a spring) |
|
|
180
|
+
| Transform — hover/press/active (scale, translate,| `--spring-smooth` (the ONE button/ |
|
|
181
|
+
| rotate) | interactive scale register) or |
|
|
182
|
+
| | `--spring-snappy` (crisp press) |
|
|
183
|
+
| Enter (mount, popover open, dialog in) | `--spring-bouncy` / `--spring-snappy`|
|
|
184
|
+
| Exit (unmount, close) | `--ease-out` / `--ease-standard` |
|
|
185
|
+
| | (bezier, NO overshoot — an exit |
|
|
186
|
+
| | must never overshoot past gone) |
|
|
187
|
+
| Position-tracked (specular pointer follow) | `--ease-standard` |
|
|
188
|
+
|
|
189
|
+
The BUTTON family (`.btn-pill` / `.tap-squish` / `.glass-btn` /
|
|
190
|
+
`btn-interactive`) UNIFIES its `scale` transform leg onto ONE register —
|
|
191
|
+
`--spring-smooth` — so hover + press read as one motion language (the
|
|
192
|
+
hover lift is the restrained `--scale-hover-btn` = 1.05, not the 1.08
|
|
193
|
+
`--scale-hover`). Springs read alive on TRANSFORM and ENTER (overshoot =
|
|
194
|
+
physicality); a spring on a COLOR or an EXIT reads as a wobble/hesitation.
|
|
195
|
+
`--ease-apple` is the ambient-only register (consumed solely by the Pulse
|
|
196
|
+
aura `--animate-ambient-pulse-easing` — NOT a second smooth-ease authority
|
|
197
|
+
for interactive transforms; those use `--spring-smooth`).
|
|
198
|
+
═══════════════════════════════════════════════ */
|
|
199
|
+
--spring-smooth: linear(0, 0.09804 2.041%, 0.29288 4.082%, 0.49447 6.122%, 0.66436 8.163%, 0.79208 10.204%, 0.88050 12.245%, 0.93754 14.286%, 0.97182 16.327%, 0.99083 18.367%, 1.00027 20.408%, 1.00413 22.449%, 1.00502 24.490%, 1.00453 26.531%, 1.00355 28.571%, 1.00254 30.612%, 1.00169 32.653%, 1.00105 34.694%, 1.00060 36.735%, 1.00031 38.776%, 1.00014 40.816%, 1.00005 42.857%, 1.00000 44.898%, 1.00000 46.939%, 1.00000 48.980%, 1.00000 51.020%, 1.00000 53.061%, 1.00000 55.102%, 1.00000 57.143%, 1.00000 59.184%, 1.00000 61.224%, 1.00000 63.265%, 1.00000 65.306%, 1.00000 67.347%, 1.00000 69.388%, 1.00000 71.429%, 1.00000 73.469%, 1.00000 75.510%, 1.00000 77.551%, 1.00000 79.592%, 1.00000 81.633%, 1.00000 83.673%, 1.00000 85.714%, 1.00000 87.755%, 1.00000 89.796%, 1.00000 91.837%, 1.00000 93.878%, 1.00000 95.918%, 1.00000 97.959%, 1);
|
|
200
|
+
--spring-snappy: linear(0, 0.10438 2.041%, 0.32622 4.082%, 0.56668 6.122%, 0.77153 8.163%, 0.91961 10.204%, 1.01073 12.245%, 1.05549 14.286%, 1.06804 16.327%, 1.06171 18.367%, 1.04686 20.408%, 1.03044 22.449%, 1.01629 24.490%, 1.00596 26.531%, 0.99954 28.571%, 0.99633 30.612%, 0.99537 32.653%, 0.99575 34.694%, 0.99674 36.735%, 0.99786 38.776%, 0.99884 40.816%, 0.99956 42.857%, 1.00001 44.898%, 1.00024 46.939%, 1.00000 48.980%, 1.00000 51.020%, 1.00000 53.061%, 1.00000 55.102%, 1.00000 57.143%, 1.00000 59.184%, 1.00000 61.224%, 1.00000 63.265%, 1.00000 65.306%, 1.00000 67.347%, 1.00000 69.388%, 1.00000 71.429%, 1.00000 73.469%, 1.00000 75.510%, 1.00000 77.551%, 1.00000 79.592%, 1.00000 81.633%, 1.00000 83.673%, 1.00000 85.714%, 1.00000 87.755%, 1.00000 89.796%, 1.00000 91.837%, 1.00000 93.878%, 1.00000 95.918%, 1.00000 97.959%, 1);
|
|
201
|
+
--spring-bouncy: linear(0, 0.11105 2.041%, 0.36430 4.082%, 0.65496 6.122%, 0.90929 8.163%, 1.08828 10.204%, 1.18289 12.245%, 1.20482 14.286%, 1.17641 16.327%, 1.12214 18.367%, 1.06276 20.408%, 1.01239 22.449%, 0.97809 24.490%, 0.96099 26.531%, 0.95826 28.571%, 0.96514 30.612%, 0.97666 32.653%, 0.98873 34.694%, 0.99867 36.735%, 1.00520 38.776%, 1.00825 40.816%, 1.00847 42.857%, 1.00686 44.898%, 1.00443 46.939%, 1.00199 48.980%, 1.00004 51.020%, 0.99880 53.061%, 0.99827 55.102%, 0.99829 57.143%, 0.99866 59.184%, 0.99916 61.224%, 0.99966 63.265%, 1.00004 65.306%, 1.00027 67.347%, 1.00000 69.388%, 1.00000 71.429%, 1.00000 73.469%, 1.00000 75.510%, 1.00000 77.551%, 1.00000 79.592%, 1.00000 81.633%, 1.00000 83.673%, 1.00000 85.714%, 1.00000 87.755%, 1.00000 89.796%, 1.00000 91.837%, 1.00000 93.878%, 1.00000 95.918%, 1.00000 97.959%, 1);
|
|
202
|
+
--spring-gentle: linear(0, 0.09415 2.041%, 0.27374 4.082%, 0.45506 6.122%, 0.60779 8.163%, 0.72570 10.204%, 0.81213 12.245%, 0.87336 14.286%, 0.91570 16.327%, 0.94445 18.367%, 0.96371 20.408%, 0.97645 22.449%, 0.98481 24.490%, 0.99025 26.531%, 0.99377 28.571%, 0.99604 30.612%, 0.99749 32.653%, 0.99841 34.694%, 0.99900 36.735%, 0.99937 38.776%, 0.99961 40.816%, 0.99975 42.857%, 0.99985 44.898%, 1.00000 46.939%, 1.00000 48.980%, 1.00000 51.020%, 1.00000 53.061%, 1.00000 55.102%, 1.00000 57.143%, 1.00000 59.184%, 1.00000 61.224%, 1.00000 63.265%, 1.00000 65.306%, 1.00000 67.347%, 1.00000 69.388%, 1.00000 71.429%, 1.00000 73.469%, 1.00000 75.510%, 1.00000 77.551%, 1.00000 79.592%, 1.00000 81.633%, 1.00000 83.673%, 1.00000 85.714%, 1.00000 87.755%, 1.00000 89.796%, 1.00000 91.837%, 1.00000 93.878%, 1.00000 95.918%, 1.00000 97.959%, 1);
|
|
203
|
+
--spring-dock: linear(0, 0.10282 2.041%, 0.31773 4.082%, 0.54783 6.122%, 0.74309 8.163%, 0.88550 10.204%, 0.97598 12.245%, 1.02452 14.286%, 1.04368 16.327%, 1.04501 18.367%, 1.03739 20.408%, 1.02681 22.449%, 1.01672 24.490%, 1.00873 26.531%, 1.00323 28.571%, 0.99996 30.612%, 0.99837 32.653%, 0.99789 34.694%, 0.99805 36.735%, 0.99848 38.776%, 0.99897 40.816%, 0.99940 42.857%, 0.99972 44.898%, 0.99993 46.939%, 1.00004 48.980%, 1.00000 51.020%, 1.00000 53.061%, 1.00000 55.102%, 1.00000 57.143%, 1.00000 59.184%, 1.00000 61.224%, 1.00000 63.265%, 1.00000 65.306%, 1.00000 67.347%, 1.00000 69.388%, 1.00000 71.429%, 1.00000 73.469%, 1.00000 75.510%, 1.00000 77.551%, 1.00000 79.592%, 1.00000 81.633%, 1.00000 83.673%, 1.00000 85.714%, 1.00000 87.755%, 1.00000 89.796%, 1.00000 91.837%, 1.00000 93.878%, 1.00000 95.918%, 1.00000 97.959%, 1);
|
|
204
|
+
|
|
205
|
+
/* Core cubic-bezier (exits, fallbacks, non-spring uses) */
|
|
206
|
+
--motion-ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
|
|
207
|
+
--motion-ease-out: cubic-bezier(0, 0, 0.2, 1);
|
|
208
|
+
--motion-ease-in: cubic-bezier(0.4, 0, 1, 1);
|
|
209
|
+
--motion-ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1);
|
|
210
|
+
|
|
211
|
+
--ease-standard: var(--motion-ease-standard);
|
|
212
|
+
--ease-out: var(--motion-ease-out);
|
|
213
|
+
--ease-in: var(--motion-ease-in);
|
|
214
|
+
--ease-out-expo: var(--motion-ease-out-expo);
|
|
215
|
+
|
|
216
|
+
/* Apple-inspired — micro-interactions, switches, dock hover */
|
|
217
|
+
--motion-ease-apple: cubic-bezier(0.25, 0.1, 0.25, 1);
|
|
218
|
+
|
|
219
|
+
--ease-apple: var(--motion-ease-apple);
|
|
220
|
+
--ease-spring: var(--spring-snappy);
|
|
221
|
+
--ease-decelerate: var(--ease-out);
|
|
222
|
+
--ease-accelerate: var(--ease-in);
|
|
223
|
+
|
|
224
|
+
/* ═══════════════════════════════════════════════
|
|
225
|
+
§2.A AMBIENT MOTION — Pulse aura tokens
|
|
226
|
+
|
|
227
|
+
Breathing rhythm for `<Pulse variant="aura">`. The 6s duration is the
|
|
228
|
+
canon ambient-pulse rate; scale 1.0 ↔ 1.15 reads as a quiet halo at
|
|
229
|
+
intensity="normal" (Pulse remaps min/max from its `intensity` prop).
|
|
230
|
+
Reduced motion: Pulse.vue parks at the min stop, breath cycle disabled.
|
|
231
|
+
|
|
232
|
+
AX.W57 (P6) — the aura re-baselined from a glowing DISC to an AMBIENT
|
|
233
|
+
halo. The egregiousness was doubly-stacked: a 0.55-density currentColor
|
|
234
|
+
radial multiplied by an element opacity the `ambient-pulse` keyframe
|
|
235
|
+
drove up to 0.95 mid-breath (so a saturated viz hue read as a near-
|
|
236
|
+
opaque throbbing blob). The fix is two decoupled, single-source knobs:
|
|
237
|
+
· `--pulse-aura-strength` (0..1) — the ONE gradient-density scalar
|
|
238
|
+
both color-mix stops derive via calc() (replaces the
|
|
239
|
+
`--pulse-aura-opacity-pct` / `-pct-num` twin desync trap — the
|
|
240
|
+
percent and the raw number had to be hand-kept in sync).
|
|
241
|
+
· `--pulse-aura-breath-{min,max}` — the aura's OWN element-opacity
|
|
242
|
+
range, decoupled from the shared `--pulse-aura-opacity-*` shimmer
|
|
243
|
+
tokens (those stay 0.55/0.95 for the neutral skeleton-breath, where
|
|
244
|
+
a grey shimmer at that range is the correct soft swell).
|
|
245
|
+
The loud old read is the explicit `intensity="vivid"` opt-in. */
|
|
246
|
+
--animate-ambient-pulse-duration: 6s;
|
|
247
|
+
--animate-ambient-pulse-scale-min: 1.0;
|
|
248
|
+
--animate-ambient-pulse-scale-max: 1.15;
|
|
249
|
+
--animate-ambient-pulse-easing: var(--ease-apple);
|
|
250
|
+
|
|
251
|
+
/* Aura gradient density — ONE scalar (0..1). The center stop paints at
|
|
252
|
+
`strength`, the mid stop at `strength * 0.35` (both via calc() in
|
|
253
|
+
Pulse.vue). 0.22 reads as an ambient wash, not a glowing disc. */
|
|
254
|
+
--pulse-aura-strength: 0.22;
|
|
255
|
+
|
|
256
|
+
/* Aura element-opacity breath range (the `ambient-pulse` keyframe stops).
|
|
257
|
+
Quiet: the halo stays a wash at every phase of the 6s cycle. */
|
|
258
|
+
--pulse-aura-breath-min: 0.28;
|
|
259
|
+
--pulse-aura-breath-max: 0.42;
|
|
260
|
+
|
|
261
|
+
/* Skeleton-breath shimmer range — the SHARED neutral-shimmer stops
|
|
262
|
+
(`.skeleton-breath` reads these; a grey shimmer at 0.55↔0.95 is the
|
|
263
|
+
correct soft swell, distinct from the aura's calmer breath above). */
|
|
264
|
+
--pulse-aura-opacity-min: 0.55;
|
|
265
|
+
--pulse-aura-opacity-max: 0.95;
|
|
266
|
+
|
|
267
|
+
/* ═══════════════════════════════════════════════
|
|
268
|
+
§2.B SECTIONED PROGRESS — phase-bus rail (AB.W3.T2)
|
|
269
|
+
|
|
270
|
+
The sectioned `<Progress variant="sectioned">` exposes one
|
|
271
|
+
height knob + one track tint knob. Defaults size the rail at
|
|
272
|
+
0.875rem (14px) — the W3 spec minimum (≥ 14px mobile, ≥ 18px
|
|
273
|
+
desktop). Consumers override the height per breakpoint via the
|
|
274
|
+
same token name on the consumer-side surface.
|
|
275
|
+
|
|
276
|
+
The bar reads as a recessed glass channel: inner top
|
|
277
|
+
catch-light + lower inner shadow + small outer drop. The
|
|
278
|
+
depth lives entirely in the Progress.vue scoped block; this
|
|
279
|
+
token only parameterises the rail BACKGROUND and HEIGHT —
|
|
280
|
+
depth shadows compose from the existing --shadow-color rung.
|
|
281
|
+
═══════════════════════════════════════════════ */
|
|
282
|
+
--progress-sectioned-height: 0.875rem;
|
|
283
|
+
--progress-sectioned-track: var(--secondary);
|
|
284
|
+
|
|
285
|
+
/* ═══════════════════════════════════════════════
|
|
286
|
+
§2.C ANIMATION EXPRESSIVENESS
|
|
287
|
+
|
|
288
|
+
Three idiom families:
|
|
289
|
+
• Progress lifecycle — the progress bar rides an intake pulse on
|
|
290
|
+
rising-edge, a crescendo brightening at ≥85%, and a one-shot discharge
|
|
291
|
+
flash at 100% (the crescendo is the typed `@property --progress-crescendo`).
|
|
292
|
+
• Chassis phase-tint companion — `@property --phase-tint-amount` so the
|
|
293
|
+
chassis backdrop warms toward the active phase, interpolating with
|
|
294
|
+
`--phase-color` across the consumer's phase-handoff window (600ms default).
|
|
295
|
+
• Audacious button press-ripple — `btn-audacious` gains a typed
|
|
296
|
+
`@property --ripple-radius` ramping 0 → max over the ripple duration.
|
|
297
|
+
═══════════════════════════════════════════════ */
|
|
298
|
+
|
|
299
|
+
/* Progress lifecycle — typed crescendo + segment-local durations */
|
|
300
|
+
--motion-duration-progress-intake: 220ms; /* rising-edge pulse */
|
|
301
|
+
--motion-duration-progress-crescendo: 240ms; /* leading-edge brighten */
|
|
302
|
+
--motion-duration-progress-indeterminate: 4s; /* indeterminate sweep period */
|
|
303
|
+
|
|
304
|
+
/* Chassis depth-of-tint peak — the amount `--phase-tint-amount`
|
|
305
|
+
interpolates toward when a phase is active. Subtle by intent;
|
|
306
|
+
a 6% color-mix reads as "warmth toward the phase" without
|
|
307
|
+
overwhelming the chassis chrome's resting register. */
|
|
308
|
+
--phase-tint-peak: 6%;
|
|
309
|
+
|
|
310
|
+
/* Audacious button press-ripple — geometry + duration. The ripple
|
|
311
|
+
radius caps at 12rem so an oversized button doesn't paint a
|
|
312
|
+
transparent halo beyond its bounds (the parent's `overflow:
|
|
313
|
+
hidden` clips the visible region; the cap keeps the gradient
|
|
314
|
+
falloff well-defined). */
|
|
315
|
+
--ripple-radius-max: 12rem;
|
|
316
|
+
--motion-duration-ripple: 340ms;
|
|
317
|
+
|
|
318
|
+
/* Skeleton breath variant — the M.3 "known-imminent" loading
|
|
319
|
+
register. 6s cycle (the canon ambient rate) so a known-imminent
|
|
320
|
+
skeleton breathes in lockstep with the dial and the Pulse aura.
|
|
321
|
+
Coexists with the 1.5s shimmer (sliding gradient) and the
|
|
322
|
+
Tailwind animate-pulse (2s, short-wait) variants — distinct
|
|
323
|
+
temporal registers per use-case. */
|
|
324
|
+
--skeleton-breath-duration: 6s;
|
|
325
|
+
|
|
326
|
+
/* ═══════════════════════════════════════════════
|
|
327
|
+
§3 Z-INDEX SCALE
|
|
328
|
+
═══════════════════════════════════════════════ */
|
|
329
|
+
/* V.W2 T12 — Aurora background tier (sits behind --z-background).
|
|
330
|
+
Consumed by `<Aurora>` in speedtest's App.vue (`-z-10` literal today). */
|
|
331
|
+
--z-behind: -10;
|
|
332
|
+
--z-background: 0;
|
|
333
|
+
--z-content: 10;
|
|
334
|
+
--z-controls: 20;
|
|
335
|
+
--z-bar: 30;
|
|
336
|
+
--z-header: 35;
|
|
337
|
+
--z-dock: 40;
|
|
338
|
+
--z-panel: 45;
|
|
339
|
+
--z-overlay: 50;
|
|
340
|
+
--z-hovercard: 120;
|
|
341
|
+
--z-tooltip: 120;
|
|
342
|
+
--z-popover: 130;
|
|
343
|
+
--z-modal: 140;
|
|
344
|
+
--z-fullscreen: 150;
|
|
345
|
+
--z-toast: 160;
|
|
346
|
+
--z-toggle: 999;
|
|
347
|
+
--z-max: 9999;
|
|
348
|
+
--z-debug: 99999;
|
|
349
|
+
|
|
350
|
+
/* §4 BORDER RADIUS — authored ONCE in theme.css's leading plain @theme
|
|
351
|
+
block (AV.W16 TW1). A plain @theme mints each `--radius-*` as a global
|
|
352
|
+
:root var, so the `var(--radius-card)` recipe reads across this file
|
|
353
|
+
resolve from that source. The prior §4 twin here doubled the override
|
|
354
|
+
surface (the anti-pattern the @theme-inline migration kills) — excised;
|
|
355
|
+
retune the scale at theme.css. */
|
|
356
|
+
|
|
357
|
+
/* ═══════════════════════════════════════════════
|
|
358
|
+
§5 COLOR PALETTE — Warm cream / muted black
|
|
359
|
+
|
|
360
|
+
Neutral scale: perceptually-uniform L* steps at hue 48 (warm paper).
|
|
361
|
+
Each pair visibly distinct at 20px viewing distance.
|
|
362
|
+
0 → 1 : 3 L (page → soft field)
|
|
363
|
+
1 → 2 : 5 L (soft field → chip / tab-inactive)
|
|
364
|
+
2 → 3 : 8 L (chip → hover / highlight)
|
|
365
|
+
3 → 4 : 12 L (highlight → subtle border)
|
|
366
|
+
4 → 5 : 25 L (border → muted text, contrast jump)
|
|
367
|
+
5 → 6 : 10 L (muted text → strong-muted text, secondary register)
|
|
368
|
+
|
|
369
|
+
Semantic aliases re-point into the scale — no back-compat shims.
|
|
370
|
+
═══════════════════════════════════════════════ */
|
|
371
|
+
--neutral-0: hsl(48 12% 98%); /* L 98 — page surface */
|
|
372
|
+
--neutral-1: hsl(48 10% 95%); /* L 95 — soft field bg */
|
|
373
|
+
--neutral-2: hsl(48 9% 90%); /* L 90 — chip / tab-inactive bg */
|
|
374
|
+
--neutral-3: hsl(48 8% 82%); /* L 82 — hover / highlight bg */
|
|
375
|
+
--neutral-4: hsl(48 7% 70%); /* L 70 — subtle border */
|
|
376
|
+
--neutral-5: hsl(48 6% 40%); /* L 40 — muted text (WCAG AA: 5.23:1 vs L98 page / 4.91:1 vs L95 muted) */
|
|
377
|
+
/* W7-α' (AK-FD1) — strong-muted text rung. One principled ladder step
|
|
378
|
+
(10 L darker, the 5→6 cadence above) past muted text toward
|
|
379
|
+
--foreground (L10). Sits at the 1/3 point of the L40→L10 muted→primary
|
|
380
|
+
gap: legible secondary text that reads less-faint than muted but not as
|
|
381
|
+
assertive as primary. By-COLOUR per the canon (a neutral step, not an
|
|
382
|
+
alpha mute); hue held at 48, sat nudged 6→7 toward --foreground's 10.
|
|
383
|
+
WCAG AA: 7.79:1 vs L98 page / 7.31:1 vs L95 muted (cf. neutral-5's
|
|
384
|
+
5.23:1) — comfortably above the 4.5:1 body floor. */
|
|
385
|
+
--neutral-6: hsl(48 7% 30%); /* L 30 — strong-muted text (secondary register) */
|
|
386
|
+
|
|
387
|
+
--background: var(--neutral-0);
|
|
388
|
+
--foreground: hsl(24 10% 10%);
|
|
389
|
+
--card: var(--neutral-0);
|
|
390
|
+
--card-foreground: var(--foreground);
|
|
391
|
+
--popover: var(--neutral-0);
|
|
392
|
+
--popover-foreground: var(--foreground);
|
|
393
|
+
|
|
394
|
+
/* R0G-5 (AO.W4) — warm-neutral public-data panel surface. One warmth step
|
|
395
|
+
off --card (hue 44 vs 48, +4 sat, −2 L) so a consumer's aurora-OFF
|
|
396
|
+
/dashboard/* surfaces read with the admin canon's warm-neutral chrome
|
|
397
|
+
instead of the colder bare card. Opaque surface (the --card family), not
|
|
398
|
+
a --surface-tint-* overlay. Consumer applies on /dashboard/* only. */
|
|
399
|
+
--surface-public-data-panel: hsl(44 16% 96%);
|
|
400
|
+
|
|
401
|
+
--muted: var(--neutral-1);
|
|
402
|
+
--muted-foreground: var(--neutral-5);
|
|
403
|
+
/* W7-α' (AK-FD1) — one rung less-faint than --muted-foreground for
|
|
404
|
+
secondary text that reads too-faint at the muted rung over resting
|
|
405
|
+
glass (CardDescription). By-colour neutral step, not alpha. */
|
|
406
|
+
--muted-foreground-strong: var(--neutral-6);
|
|
407
|
+
--secondary: var(--neutral-2);
|
|
408
|
+
--secondary-foreground: var(--foreground);
|
|
409
|
+
--accent: var(--neutral-3);
|
|
410
|
+
--accent-foreground: var(--foreground);
|
|
411
|
+
|
|
412
|
+
--border: var(--neutral-4);
|
|
413
|
+
--input: var(--neutral-4);
|
|
414
|
+
|
|
415
|
+
--primary: hsl(24 10% 10%);
|
|
416
|
+
--primary-foreground: var(--neutral-0);
|
|
417
|
+
--destructive: hsl(0 72% 50%);
|
|
418
|
+
--destructive-foreground: var(--neutral-0);
|
|
419
|
+
--ring: hsl(24 10% 10%);
|
|
420
|
+
--shadow: hsl(24 10% 10%);
|
|
421
|
+
--shadow-color: var(--foreground);
|
|
422
|
+
|
|
423
|
+
/* AQ.W2 §4 — native-control accent. `accent-color` is an inherited
|
|
424
|
+
built-in <color>, so per the §2b resolve-late discipline it reads a
|
|
425
|
+
dedicated UNREGISTERED token set per-mode (NOT light-dark()) and is
|
|
426
|
+
re-specified inside `.dark` — otherwise the accent freezes to the
|
|
427
|
+
light shade at the cascade root. Light: muted-black checkmarks /
|
|
428
|
+
sliders on warm cream. Dark arm (`.dark`) reads `--ring` (mid-tone),
|
|
429
|
+
not the near-white dark `--primary`, so a checkbox's white checkmark
|
|
430
|
+
keeps contrast headroom (accent-color.md §5). */
|
|
431
|
+
--accent-color: var(--primary);
|
|
432
|
+
|
|
433
|
+
/* Border hairline at whisper alpha — the canonical rung for
|
|
434
|
+
section-spine / panel-edge hairlines a consumer wants to read as an
|
|
435
|
+
iOS-26 whisper rather than a hard rule. Consumers compose this named
|
|
436
|
+
rung instead of hand-mixing `color-mix(... var(--border) ...)`
|
|
437
|
+
per-site (token-first). 45% is the canonical whisper. Auto-dark via
|
|
438
|
+
`--border` (which is `var(--neutral-4)`, light-dark()-resolved). */
|
|
439
|
+
--border-soft: color-mix(in srgb, var(--border) 45%, transparent);
|
|
440
|
+
|
|
441
|
+
/* AQ.W3 §W3.4 — tokenized scrollbar thumb + track. Minted in the color
|
|
442
|
+
block so the `scrollbar-color` / `::-webkit-scrollbar-thumb` rungs read a
|
|
443
|
+
single source. Auto-dark via `--muted-foreground` (light-dark()-resolved,
|
|
444
|
+
AQ.W2) — the OS scrollbar chrome also honors `color-scheme: dark`, so the
|
|
445
|
+
custom thumb tracks the dark surface without an explicit dark mirror. The
|
|
446
|
+
thumb α (25%) matches the prior inline `.scrollbar-thin` value byte-for-
|
|
447
|
+
byte; `transparent` track keeps the scroll-pane glass reading through. */
|
|
448
|
+
--scrollbar-thumb: color-mix(in srgb, var(--muted-foreground) 25%, transparent);
|
|
449
|
+
--scrollbar-track: transparent;
|
|
450
|
+
|
|
451
|
+
/* Foreground-tint rungs — canonical handles for the 36+ raw
|
|
452
|
+
`color-mix(in srgb, var(--foreground) N%, transparent)` sites surveyed
|
|
453
|
+
in R5 axis-1. Each rung's α is named in its key (4 → 4%, 22 → 22%).
|
|
454
|
+
Auto-dark via --foreground; no explicit dark mirrors needed. R5
|
|
455
|
+
vocab.γ gap row 1. Consumers land in W2.B + W3.C. */
|
|
456
|
+
--surface-tint-4: color-mix(in srgb, var(--foreground) 4%, transparent);
|
|
457
|
+
--surface-tint-6: color-mix(in srgb, var(--foreground) 6%, transparent);
|
|
458
|
+
--surface-tint-8: color-mix(in srgb, var(--foreground) 8%, transparent);
|
|
459
|
+
--surface-tint-10: color-mix(in srgb, var(--foreground) 10%, transparent);
|
|
460
|
+
--surface-tint-12: color-mix(in srgb, var(--foreground) 12%, transparent);
|
|
461
|
+
--surface-tint-15: color-mix(in srgb, var(--foreground) 15%, transparent);
|
|
462
|
+
--surface-tint-18: color-mix(in srgb, var(--foreground) 18%, transparent);
|
|
463
|
+
--surface-tint-22: color-mix(in srgb, var(--foreground) 22%, transparent);
|
|
464
|
+
--surface-tint-25: color-mix(in srgb, var(--foreground) 25%, transparent);
|
|
465
|
+
/* Higher-α rungs added at L.W5 (absorbs K R4 — 4 P1 sites whose
|
|
466
|
+
literal `color-mix(in srgb, var(--foreground) {35,40,70}%, transparent)`
|
|
467
|
+
expressions bypassed the canonical token family). See `docs/tranches/L/
|
|
468
|
+
audit/W5-A-doc-cohort-proof.md`. */
|
|
469
|
+
--surface-tint-35: color-mix(in srgb, var(--foreground) 35%, transparent);
|
|
470
|
+
--surface-tint-40: color-mix(in srgb, var(--foreground) 40%, transparent);
|
|
471
|
+
--surface-tint-70: color-mix(in srgb, var(--foreground) 70%, transparent);
|
|
472
|
+
|
|
473
|
+
/* Muted-tinted surface rungs — canonical handles for the 9 raw
|
|
474
|
+
`color-mix(in srgb, var(--muted) N%, transparent)` sites in
|
|
475
|
+
FuzzySearch / SegmentedTabs / Slider scoped CSS. (AI.W5-δ — the
|
|
476
|
+
ProgressiveSidebar consumer retired at the wave; the canonical token
|
|
477
|
+
rung lives on for the remaining consumers.) Auto-dark via --muted.
|
|
478
|
+
R5 vocab.γ axis-1 row. */
|
|
479
|
+
--muted-soft: color-mix(in srgb, var(--muted) 30%, transparent);
|
|
480
|
+
--muted-medium: color-mix(in srgb, var(--muted) 50%, transparent);
|
|
481
|
+
|
|
482
|
+
/* ═══════════════════════════════════════════════
|
|
483
|
+
§5c CONSTELLATION — Canvas2D proximity-graph lattice (AX.W17)
|
|
484
|
+
|
|
485
|
+
The H.W4 legibility intelligence promoted from the slides deck to
|
|
486
|
+
LIBRARY identity: the node tones, the edge hairline color, the per-mode
|
|
487
|
+
edge-alpha multipliers, and the field-yields-to-type translucency knob.
|
|
488
|
+
Only `--constellation-accent` (the anomaly tint) stays a CONSUMER preset
|
|
489
|
+
(slides aliases it to `--ncsu-red`); the library ships a neutral default.
|
|
490
|
+
|
|
491
|
+
PLAIN-hsl LITERALS, per arm — NEVER `light-dark()` and NEVER a
|
|
492
|
+
`var(--neutral-*)`/`var(--foreground)`/`var(--border)`/`var(--card)`
|
|
493
|
+
alias. Canvas2D silently REJECTS a `light-dark()` value into
|
|
494
|
+
`strokeStyle`/`fillStyle` (the W30 86.3%-red-splatter cardinal defect),
|
|
495
|
+
and the rejection is identical whether the value is a literal
|
|
496
|
+
`light-dark(…)` OR a `var()` that RESOLVES to one — so the constellation
|
|
497
|
+
tokens are plain-hsl LEAVES, the `:root` vs `.dark` cascade carrying two
|
|
498
|
+
literals. `proof:constellation-tokens` clause (c) machine-locks this
|
|
499
|
+
(the no-`light-dark(`-substring NOR transitive-`var()` static assertion).
|
|
500
|
+
═══════════════════════════════════════════════ */
|
|
501
|
+
/* Node tones — readable on the warm-cream ground. The two-tone split (the
|
|
502
|
+
`dim` half rides `-node-dim`). Warm-grey ink, NOT a neutral-ladder alias. */
|
|
503
|
+
--constellation-node: hsl(36 8% 46%);
|
|
504
|
+
--constellation-node-dim: hsl(36 8% 60%);
|
|
505
|
+
/* Edge hairline stroke — warm near-black on cream (the plain-hsl complement
|
|
506
|
+
the slides deck reads to fix the `--foreground` light-dark() leak). */
|
|
507
|
+
--constellation-line: hsl(24 14% 14%);
|
|
508
|
+
/* Anomaly tint — NEUTRAL library default (a desaturated warm accent). The
|
|
509
|
+
consumer overrides this (slides → `--ncsu-red`); the library does NOT
|
|
510
|
+
bake a brand hue. This is the single consumer-preset boundary. */
|
|
511
|
+
--constellation-accent: hsl(18 58% 46%);
|
|
512
|
+
/* Edge-alpha multipliers — replace the magic `0.17` hairline / pointer-web
|
|
513
|
+
literals. The cream ground lifts the node tones, so the field can recede;
|
|
514
|
+
the focus-proximity edge reads a touch stronger. */
|
|
515
|
+
--constellation-edge-alpha: 0.22;
|
|
516
|
+
--constellation-edge-focus-alpha: 0.34;
|
|
517
|
+
/* §7 field-yields-to-type translucency knob — the legible-but-RECESSIVE
|
|
518
|
+
MIDPOINT, NOT max-legibility. On cream the node tones already read, so the
|
|
519
|
+
field recedes further: BELOW the slides 0.92 max-legibility reference. */
|
|
520
|
+
--constellation-alpha: 0.80;
|
|
521
|
+
|
|
522
|
+
/* §interaction — the warp spring + the gravity-well tunings (NUMERIC, NOT
|
|
523
|
+
colors — read ONCE on mount via parseFloat, never reach a Canvas2D
|
|
524
|
+
fillStyle, so immune to the W30 light-dark()/Canvas2D leak; AY.W-CON2).
|
|
525
|
+
Mode-INVARIANT, declared ONCE in :root (the .dark arm needs no numeric
|
|
526
|
+
re-declare — a per-mode value SPLIT is what proof:constellation-tokens
|
|
527
|
+
clause (c) flags, and these tunings are identical in both modes).
|
|
528
|
+
`--constellation-warp-response` is the keyframes.js ANGULAR PERIOD (the
|
|
529
|
+
SwiftUI .spring(response:) axis), NOT a settle-duration — at ζ=1 the 2%
|
|
530
|
+
settle lands at t₂ ≈ 5.83/ω₀ ≈ 0.93·response (the engine keeps the
|
|
531
|
+
keyframes.js ω₀ = 2π/response convention, mints no second ω). */
|
|
532
|
+
--constellation-warp-response: 0.55; /* s — keyframes.js angular period (NOT a settle) */
|
|
533
|
+
--constellation-warp-zeta: 1.0; /* critically damped — a focal mark must NOT ring */
|
|
534
|
+
--constellation-well-gain: 14000; /* inverse-square force scale (the held-pull gain) */
|
|
535
|
+
--constellation-well-reach: 340; /* base-width px — the well's reach (k-scaled at step) */
|
|
536
|
+
--constellation-well-ramp: 4.0; /* 1/s — the ARM rate (≈0.25s bloom; release is the fixed brisk WELL_RELEASE_RAMP — the field-cools invariant, not consumer-tunable) */
|
|
537
|
+
--constellation-well-max-speed: 4.0; /* base-width px/frame cap — the no-slingshot clamp */
|
|
538
|
+
--constellation-well-hold-ms: 140; /* ms hold before the well arms */
|
|
539
|
+
--constellation-wander-idle: 8000; /* ms — min idle between auto re-targets (the W-CON1 drift cadence) */
|
|
540
|
+
--constellation-wander-jitter: 8000; /* ms — random extra idle per cadence (so the rhythm is not metronomic) */
|
|
541
|
+
|
|
542
|
+
/* ═══════════════════════════════════════════════
|
|
543
|
+
§6 SECTION PALETTE — 13-stop jewel tones (light)
|
|
544
|
+
═══════════════════════════════════════════════ */
|
|
545
|
+
/* AV.W16 TW2 — oklch ramp (perceptually-even L; hue preserved from the
|
|
546
|
+
prior hsl() cadence). Categorical jewel tones — distinct hues, not a
|
|
547
|
+
monotone scale. Authored as oklch pairs with the .dark mirror. */
|
|
548
|
+
--section-color-0: oklch(0.552 0.192 359.8); /* rose */
|
|
549
|
+
--section-color-1: oklch(0.502 0.165 305.9); /* purple */
|
|
550
|
+
--section-color-2: oklch(0.484 0.163 265.5); /* indigo */
|
|
551
|
+
--section-color-3: oklch(0.542 0.089 222.8); /* teal-cyan */
|
|
552
|
+
--section-color-4: oklch(0.551 0.088 171.1); /* forest */
|
|
553
|
+
--section-color-5: oklch(0.623 0.124 69.6); /* amber */
|
|
554
|
+
--section-color-6: oklch(0.579 0.201 30.4); /* tomato-red */
|
|
555
|
+
--section-color-7: oklch(0.532 0.180 317.5); /* violet */
|
|
556
|
+
--section-color-8: oklch(0.520 0.176 8.4); /* ruby */
|
|
557
|
+
--section-color-9: oklch(0.492 0.038 239.6); /* slate-blue */
|
|
558
|
+
--section-color-10: oklch(0.556 0.103 128.8); /* olive */
|
|
559
|
+
--section-color-11: oklch(0.601 0.092 208.0); /* ocean */
|
|
560
|
+
--section-color-12: oklch(0.513 0.163 291.9); /* periwinkle */
|
|
561
|
+
|
|
562
|
+
/* Accent colors */
|
|
563
|
+
--accent-pink: oklch(0.613 0.197 353.8);
|
|
564
|
+
--section-heading: oklch(0.545 0.189 352.8);
|
|
565
|
+
--accent-red: oklch(0.574 0.216 27.5);
|
|
566
|
+
|
|
567
|
+
/* ═══════════════════════════════════════════════
|
|
568
|
+
§6b VIZ BASIS — core brand hues
|
|
569
|
+
═══════════════════════════════════════════════ */
|
|
570
|
+
--viz-fourier: oklch(0.579 0.201 30.4);
|
|
571
|
+
--viz-chebyshev: oklch(0.484 0.163 265.5);
|
|
572
|
+
--viz-legendre: oklch(0.532 0.180 317.5);
|
|
573
|
+
--viz-amber: var(--section-color-5);
|
|
574
|
+
--viz-green: var(--section-color-4);
|
|
575
|
+
|
|
576
|
+
/* Semantic UI accents */
|
|
577
|
+
--tier-featured: oklch(0.841 0.173 84.2);
|
|
578
|
+
--tier-saved: oklch(0.676 0.176 252.3);
|
|
579
|
+
--like: oklch(0.633 0.200 24.9);
|
|
580
|
+
--success: oklch(0.720 0.192 149.5);
|
|
581
|
+
--warning: oklch(0.770 0.165 70.6);
|
|
582
|
+
--info: oklch(0.626 0.186 259.6);
|
|
583
|
+
--delete: oklch(0.597 0.198 25.5);
|
|
584
|
+
|
|
585
|
+
/* Semantic foregrounds — text/glyph atop --success/--warning/--info plates.
|
|
586
|
+
Notification.vue currently hardcodes `text-white`/`text-foreground`
|
|
587
|
+
inline; W2 migrates consumers to read these tokens. Warning carries a
|
|
588
|
+
dark glyph because the amber plate is too luminous for white. R5
|
|
589
|
+
vocab.γ gap row 4. */
|
|
590
|
+
--success-foreground: var(--neutral-0);
|
|
591
|
+
--warning-foreground: hsl(24 10% 10%);
|
|
592
|
+
--info-foreground: var(--neutral-0);
|
|
593
|
+
|
|
594
|
+
/* ═══════════════════════════════════════════════
|
|
595
|
+
§7 SHADOWS — cartoon offset is the signature
|
|
596
|
+
═══════════════════════════════════════════════ */
|
|
597
|
+
--shadow-cartoon: 3px 3px 0px 0px color-mix(in srgb, var(--foreground) 8%, transparent);
|
|
598
|
+
--shadow-cartoon-hover: 4px 4px 0px 0px color-mix(in srgb, var(--foreground) 10%, transparent);
|
|
599
|
+
--shadow-soft: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
600
|
+
--shadow-elevated: 0 8px 24px rgba(0, 0, 0, 0.12);
|
|
601
|
+
--shadow-modal:
|
|
602
|
+
4px 4px 0px 0px color-mix(in srgb, var(--foreground) 8%, transparent),
|
|
603
|
+
0 24px 64px color-mix(in srgb, var(--foreground) 12%, transparent);
|
|
604
|
+
|
|
605
|
+
--cartoon-shadow: var(--shadow-cartoon);
|
|
606
|
+
--cartoon-shadow-hover: var(--shadow-cartoon-hover);
|
|
607
|
+
--soft-shadow: var(--shadow-soft);
|
|
608
|
+
--elevated-shadow: var(--shadow-elevated);
|
|
609
|
+
--modal-shadow: var(--shadow-modal);
|
|
610
|
+
|
|
611
|
+
/* Elevation scale */
|
|
612
|
+
--shadow-xs: 0 1px 3px color-mix(in srgb, var(--shadow-color) 4%, transparent),
|
|
613
|
+
0 1px 2px color-mix(in srgb, var(--shadow-color) 6%, transparent);
|
|
614
|
+
--shadow-sm: 0 2px 8px color-mix(in srgb, var(--shadow-color) 6%, transparent);
|
|
615
|
+
--shadow-md: 0 4px 16px color-mix(in srgb, var(--shadow-color) 8%, transparent);
|
|
616
|
+
--shadow-lg: 0 4px 20px color-mix(in srgb, var(--shadow-color) 12%, transparent);
|
|
617
|
+
--shadow-xl: 0 8px 24px color-mix(in srgb, var(--shadow-color) 14%, transparent);
|
|
618
|
+
--shadow-2xl: 0 25px 50px -12px color-mix(in srgb, var(--shadow-color) 25%, transparent);
|
|
619
|
+
|
|
620
|
+
/* Z.W2.T3a — uniform-cast shadow rung. Offset 0 / 0, no directional
|
|
621
|
+
Y bias. Use case: dock-hosted icons (e.g. the speedtest settings
|
|
622
|
+
gear) where the surrounding dock shadow's downward cast reads as
|
|
623
|
+
a per-icon right-edge halo on the rightmost child (A2 §B7). The
|
|
624
|
+
uniform variant carries the same color-mix recipe family as the
|
|
625
|
+
sized rungs (`--shadow-md`, `--shadow-lg`) so the perceived
|
|
626
|
+
elevation is a peer, not a sibling. Consumers compose via
|
|
627
|
+
`--shadow-dock-override: var(--shadow-uniform)` per-instance, or
|
|
628
|
+
attach to per-icon-button stacks where directional cast is wrong-
|
|
629
|
+
shape. Documented in DESIGN.md token table. */
|
|
630
|
+
--shadow-uniform: 0 0 12px color-mix(in srgb, var(--shadow-color) 8%, transparent);
|
|
631
|
+
|
|
632
|
+
/* Card = soft drop plate by default. The cartoon offset is a brand-flavoured
|
|
633
|
+
decoration (a sticker look), not the canonical card shape. Consumers
|
|
634
|
+
wanting the cartoon look pass <Card surface="cartoon">, which composes the
|
|
635
|
+
`.cartoon-surface` utility (it reads --shadow-cartoon directly). R3-spec
|
|
636
|
+
§F.1, S.W4; Q.W3 Lane H. */
|
|
637
|
+
--shadow-card: var(--shadow-md);
|
|
638
|
+
--card-shadow: var(--shadow-card);
|
|
639
|
+
|
|
640
|
+
/* AI.W1-α — sticky CardHeader background. Parameterises the
|
|
641
|
+
`bg-card/60` literal value.js's PaneHeader.vue carried so the
|
|
642
|
+
glass-ui canon owns the recipe. The scroll-driven `<CardHeader
|
|
643
|
+
shrink>` choreography reads this token for its sticky-header
|
|
644
|
+
backdrop tint; consumers retune per-app by overriding the
|
|
645
|
+
variable at any ancestor. Auto-dark via `--card`. */
|
|
646
|
+
--card-header-bg: color-mix(in srgb, var(--card) 60%, transparent);
|
|
647
|
+
|
|
648
|
+
/* Dock shadows — a single omnidirectional glow in the
|
|
649
|
+
`--shadow-md`/`--shadow-lg` family (a directional drop concentrated on
|
|
650
|
+
the pill's rounded right cap as a right-edge halo; the dock's own
|
|
651
|
+
border already defines the silhouette). Per-instance directional drop
|
|
652
|
+
reinstates via `--shadow-dock-override` (consumed by every `.glass-dock`
|
|
653
|
+
state selector — see dock.css). */
|
|
654
|
+
--shadow-dock: 0 0 20px color-mix(in srgb, var(--shadow-color) 14%, transparent);
|
|
655
|
+
--shadow-dock-collapsed: 0 0 12px color-mix(in srgb, var(--shadow-color) 12%, transparent);
|
|
656
|
+
--dock-shadow: var(--shadow-dock);
|
|
657
|
+
--dock-shadow-collapsed: var(--shadow-dock-collapsed);
|
|
658
|
+
|
|
659
|
+
/* AX.W04 F1 — the wrap/card-tier dock shadow. A wrapped multi-row dock (and
|
|
660
|
+
any finite-radius card silhouette) is a THICKER material than a flat thin
|
|
661
|
+
pill — WWDC25 §219 "material thickens as glass flexes larger". So when the
|
|
662
|
+
wrap dock expands it lifts its elevation onto the FLOATING-tier shadow
|
|
663
|
+
stack (the `--glass-shadow-floating` family — `--shadow-xl` + the
|
|
664
|
+
`--glass-material-rim` hairline + the `--glass-under-shadow-vivid` under-cast)
|
|
665
|
+
rather than carrying the flat `--shadow-dock` glow of a 40px pill. Composed
|
|
666
|
+
on `:root` as ONE consumer-overridable token (per the cartoon-shadow
|
|
667
|
+
override contract — override on the cascade, never a dead local). The dock
|
|
668
|
+
reads it via `calc()`-on-`--dock-expand-t` so the lift glides in lockstep
|
|
669
|
+
with the pill→card radius morph (ONE clock, ONE register). */
|
|
670
|
+
--glass-material-rim: 0 0 0 0.5px color-mix(in srgb, var(--shadow-color) 5%, transparent);
|
|
671
|
+
--shadow-dock-wrap: var(--shadow-xl),
|
|
672
|
+
var(--glass-material-rim),
|
|
673
|
+
var(--glass-under-shadow-vivid);
|
|
674
|
+
|
|
675
|
+
/* Cartoon shadow color primitives (kept for tiered cartoon utilities) */
|
|
676
|
+
--shadow-cartoon-color: rgb(0 0 0 / 0.12);
|
|
677
|
+
--shadow-cartoon-color-soft: rgb(0 0 0 / 0.06);
|
|
678
|
+
|
|
679
|
+
/* Tiered cartoon shadows */
|
|
680
|
+
--shadow-cartoon-sm: -3px 2px 1px color-mix(in srgb, var(--shadow-color) 10%, transparent),
|
|
681
|
+
0 3px 1px color-mix(in srgb, var(--shadow-color) 10%, transparent),
|
|
682
|
+
-3px 3px 1px color-mix(in srgb, var(--shadow-color) 6%, transparent);
|
|
683
|
+
--shadow-cartoon-md: -4px 3px 1px color-mix(in srgb, var(--shadow-color) 12%, transparent),
|
|
684
|
+
0 4px 1px color-mix(in srgb, var(--shadow-color) 12%, transparent),
|
|
685
|
+
-4px 4px 2px color-mix(in srgb, var(--shadow-color) 8%, transparent);
|
|
686
|
+
--shadow-cartoon-lg: -6px 4px 1px color-mix(in srgb, var(--shadow-color) 12%, transparent),
|
|
687
|
+
0 6px 1px color-mix(in srgb, var(--shadow-color) 12%, transparent),
|
|
688
|
+
-6px 6px 2px color-mix(in srgb, var(--shadow-color) 8%, transparent);
|
|
689
|
+
--cartoon-shadow-sm: var(--shadow-cartoon-sm);
|
|
690
|
+
--cartoon-shadow-md: var(--shadow-cartoon-md);
|
|
691
|
+
--cartoon-shadow-lg: var(--shadow-cartoon-lg);
|
|
692
|
+
|
|
693
|
+
/* ═══════════════════════════════════════════════
|
|
694
|
+
§8 GLASSMORPHISM — Five-tier surface ladder (v0.8.0)
|
|
695
|
+
|
|
696
|
+
Tier semantics, alpha-monotonic:
|
|
697
|
+
wash ~0.30α + light blur (was `subtle`)
|
|
698
|
+
quiet ~0.50α + medium blur (the formerly missing rung)
|
|
699
|
+
resting ~0.65α + canonical blur (was `default`; the speedtest plate)
|
|
700
|
+
floating ~0.80α + heavier blur (was `elevated`)
|
|
701
|
+
overlay ~0.95α + heaviest blur (NEW; modal-over-modal)
|
|
702
|
+
|
|
703
|
+
v0.8.0 retires the four-tier `subtle | default | medium | elevated`
|
|
704
|
+
ladder outright. No legacy aliases. Consumers migrate at the same
|
|
705
|
+
breaking change. R3-spec §A.
|
|
706
|
+
═══════════════════════════════════════════════ */
|
|
707
|
+
|
|
708
|
+
/* Opacity primitives */
|
|
709
|
+
--glass-opacity-wash: 0.30;
|
|
710
|
+
--glass-opacity-quiet: 0.50;
|
|
711
|
+
--glass-opacity-resting: 0.65;
|
|
712
|
+
--glass-opacity-floating: 0.80;
|
|
713
|
+
--glass-opacity-overlay: 0.95;
|
|
714
|
+
|
|
715
|
+
/* Blur primitives. The radii here feather the dock + meter card to a
|
|
716
|
+
barely-perceptible diffusion that lets the substrate behind it bleed
|
|
717
|
+
through cleanly while keeping hero typography crisp at meter scale.
|
|
718
|
+
The resting blur sits at 12px so a glass plate reads as a diffusion
|
|
719
|
+
without consumer-side override. */
|
|
720
|
+
--glass-blur-wash-radius: 1px;
|
|
721
|
+
--glass-blur-quiet-radius: 10px;
|
|
722
|
+
--glass-blur-resting-radius: 12px;
|
|
723
|
+
--glass-blur-floating-radius: 16px;
|
|
724
|
+
/* AV.W7 F2 — clamped from 24px into the 8–15px budget band. A blur radius
|
|
725
|
+
past ~20px is exponentially costlier (`backdrop-filter` is glass-ui's most
|
|
726
|
+
expensive idiom — the radius is the dominant cost). 15px is the band
|
|
727
|
+
ceiling; the lower rungs (wash/quiet/resting 1/10/12) sit in-band and the
|
|
728
|
+
floating 16px is the design ceiling at the band edge (left as-is). A
|
|
729
|
+
high-resolution display restores the richer 24px wash via the @media arm
|
|
730
|
+
below — the cost is amortised by the extra device pixels. */
|
|
731
|
+
--glass-blur-overlay-radius: 15px;
|
|
732
|
+
/* Dock blur radius — 11px, paired with the 0.42 opacity below: a crisp
|
|
733
|
+
glass pill (the iOS Control Center register), not a feathered wash.
|
|
734
|
+
The dock composes `blur()` only (no saturate); the
|
|
735
|
+
`prefers-reduced-transparency` bracket at glass.css maps it to the
|
|
736
|
+
opacity-only register. */
|
|
737
|
+
--glass-blur-dock-radius: 11px;
|
|
738
|
+
|
|
739
|
+
/* AX.W54 — each blur radius is scaled by the ONE `--glass-level` scalar (in
|
|
740
|
+
lockstep with the opacity seam above): level=1 byte-identical; level=0 →
|
|
741
|
+
blur(0) (the clean solid floor with the opacity); level>1 → more diffusion.
|
|
742
|
+
The per-rung `saturate()`/`brightness()` companions are UNTOUCHED (the level
|
|
743
|
+
scales the RADIUS, not the saturation — W52's calm light-concentration). */
|
|
744
|
+
--glass-blur-wash: blur(calc(var(--glass-blur-wash-radius) * var(--glass-level))) saturate(1.05);
|
|
745
|
+
/* AV.W15 M1 — the `quiet` rung gained `saturate(1.05) brightness(1.02)`
|
|
746
|
+
so the lower ladder reads with the same saturation life as `resting`+
|
|
747
|
+
(Apple: Liquid Glass concentrates light, it does not desaturate). The
|
|
748
|
+
`brightness(1.02)` is the small lift the spec names — it lands `quiet`
|
|
749
|
+
between bare `wash` and `resting` without over-brightening the rung.
|
|
750
|
+
The `prefers-reduced-transparency: reduce` bracket at glass.css maps
|
|
751
|
+
`--glass-blur-quiet: none`, so this whole chain drops with the blur. */
|
|
752
|
+
--glass-blur-quiet: blur(calc(var(--glass-blur-quiet-radius) * var(--glass-level))) saturate(1.05) brightness(1.02);
|
|
753
|
+
--glass-blur-resting: blur(calc(var(--glass-blur-resting-radius) * var(--glass-level))) saturate(1.05);
|
|
754
|
+
/* AX.W52 D19 — the floating/overlay backdrop saturate tamed from 1.4/1.5 to a
|
|
755
|
+
gentle ~1.18/1.2 (real liquid glass concentrates light ~1.1–1.2×; the prior
|
|
756
|
+
1.4–1.5× over-juiced the bleed-through into a garish smear over a colored
|
|
757
|
+
substrate). wash/quiet/resting already sit at 1.05 — untouched. */
|
|
758
|
+
--glass-blur-floating: blur(calc(var(--glass-blur-floating-radius) * var(--glass-level))) saturate(1.18);
|
|
759
|
+
--glass-blur-overlay: blur(calc(var(--glass-blur-overlay-radius) * var(--glass-level))) saturate(1.2);
|
|
760
|
+
/* Dock blur composes blur() only — no saturate. */
|
|
761
|
+
--glass-blur-dock: blur(calc(var(--glass-blur-dock-radius) * var(--glass-level)));
|
|
762
|
+
|
|
763
|
+
/* AX.W52 — the GLASS BUTTON blur. The `glass`/`glass-wash` button variants
|
|
764
|
+
compose the `.glass-wash` tier (`--glass-blur-wash` = blur(1px)) — a
|
|
765
|
+
sub-perceptual diffusion authored for a small detail TILE, not a button
|
|
766
|
+
the user reads as "glass." A button is a hero control: it wants a real
|
|
767
|
+
glass blur. `--glass-blur-btn` lifts the variant onto the `quiet`-tier
|
|
768
|
+
radius (10px — a genuine liquid-glass diffusion) with the same gentle
|
|
769
|
+
`saturate(1.05) brightness(1.02)` light-concentration the quiet rung
|
|
770
|
+
carries (NOT a colour-juice). The wash TILE tier (MetricCell et al.) keeps
|
|
771
|
+
its 1px — only the glass BUTTON variants reach for this. */
|
|
772
|
+
--glass-blur-btn: blur(calc(var(--glass-blur-quiet-radius) * var(--glass-level))) saturate(1.05) brightness(1.02);
|
|
773
|
+
|
|
774
|
+
/* Dock-specific opacity (0.42) — lighter than `resting` (0.65) so the dock
|
|
775
|
+
reads as a translucent overlay rather than a panel, backdrop bleed
|
|
776
|
+
visible through it. Consumed by `.glass-dock` via `--glass-bg-dock`. The
|
|
777
|
+
value holds the surface register against the tightened 11px blur so the
|
|
778
|
+
dock reads as painted chrome, not a frosted ghost. */
|
|
779
|
+
--glass-opacity-dock: 0.42;
|
|
780
|
+
|
|
781
|
+
/* Dock foreground over an animated backdrop. A dock floating over an
|
|
782
|
+
aurora/animated surface (`value.js` dock-over-aurora, a slides routed
|
|
783
|
+
control, bbnf) sits on a mid-luminance, shifting field where the muted
|
|
784
|
+
default fg can drop below contrast. This token is the dock control's
|
|
785
|
+
foreground base — a complete `hsl()` color consumed via `var()`; for the
|
|
786
|
+
muted icon weight the control mixes it down with `--opacity-icon-muted`.
|
|
787
|
+
Defaults to `var(--foreground)` so the dock paints byte-identically to
|
|
788
|
+
today; a consumer overrides it per-backdrop (e.g. a near-white over a
|
|
789
|
+
dark aurora) without touching library source.
|
|
790
|
+
|
|
791
|
+
AX.W55 — this is the FOREGROUND half of the adaptive story, now reconciled
|
|
792
|
+
INTO the `--glass-backdrop` probe (not a third fork): under the bright bucket
|
|
793
|
+
(`@container style(--glass-backdrop: light)` in dock.css) it re-points toward
|
|
794
|
+
the contrast-clearing ink, and an `@supports (color: contrast-color(…))`
|
|
795
|
+
block flips it natively on supporting engines. The `var(--foreground)`
|
|
796
|
+
default keeps the zero-delta rest state. */
|
|
797
|
+
--dock-fg-on-aurora: var(--foreground);
|
|
798
|
+
|
|
799
|
+
/* Chassis-specific opacity. Looser than `default` (0.50) so the
|
|
800
|
+
<InstrumentChassis> surface reads as glass-over-aurora at its
|
|
801
|
+
64rem-wide footprint; the default tier stays calibrated for cards.
|
|
802
|
+
Mirrors the dock-tier pattern (own opacity primitive + composed bg).
|
|
803
|
+
Light 0.28 sits in the gap between dock (0.32) and a hypothetical
|
|
804
|
+
wash tier; dark 0.36 mirrors the +0.08 step the dock takes from
|
|
805
|
+
`glass-bg-medium` (0.65) down to its own 0.32. */
|
|
806
|
+
--glass-opacity-chassis: 0.28;
|
|
807
|
+
|
|
808
|
+
/* Composed backgrounds — AX.W54: the opacity is threaded through the ONE
|
|
809
|
+
`--glass-level` clarity scalar. Each rung's effective alpha is
|
|
810
|
+
`1 - (1 - <rung-opacity>) * --glass-level`: at level=1 it collapses to the
|
|
811
|
+
hand-tuned `<rung-opacity>` (byte-identical); at level=0 it resolves `1`
|
|
812
|
+
(solid `--card` — the opaque escape); at level>1 it goes clearer. ONE
|
|
813
|
+
expression, the same seven rungs. */
|
|
814
|
+
--glass-bg-wash: color-mix(in srgb, var(--card) calc((1 - (1 - var(--glass-opacity-wash)) * var(--glass-level)) * 100%), transparent);
|
|
815
|
+
--glass-bg-quiet: color-mix(in srgb, var(--card) calc((1 - (1 - var(--glass-opacity-quiet)) * var(--glass-level)) * 100%), transparent);
|
|
816
|
+
--glass-bg-resting: color-mix(in srgb, var(--card) calc((1 - (1 - var(--glass-opacity-resting)) * var(--glass-level)) * 100%), transparent);
|
|
817
|
+
--glass-bg-floating: color-mix(in srgb, var(--card) calc((1 - (1 - var(--glass-opacity-floating)) * var(--glass-level)) * 100%), transparent);
|
|
818
|
+
--glass-bg-overlay: color-mix(in srgb, var(--card) calc((1 - (1 - var(--glass-opacity-overlay)) * var(--glass-level)) * 100%), transparent);
|
|
819
|
+
/* The dock bg ALSO rides the oklab tint seam (AX.W54 amendment): the same
|
|
820
|
+
`color-mix(in oklab, …, --glass-tint-source --glass-tint-strength)` wrapper
|
|
821
|
+
the rungs reach for, ZERO-delta at `--glass-tint-strength: 0%` — so W55's
|
|
822
|
+
adaptive darken can reach the dock (the G2 over-light surface) without a
|
|
823
|
+
second hand-rolled recipe. */
|
|
824
|
+
--glass-bg-dock: color-mix(in oklab, color-mix(in srgb, var(--card) calc((1 - (1 - var(--glass-opacity-dock)) * var(--glass-level)) * 100%), transparent), var(--glass-tint-source) var(--glass-tint-strength));
|
|
825
|
+
--glass-bg-chassis: color-mix(in srgb, var(--card) calc((1 - (1 - var(--glass-opacity-chassis)) * var(--glass-level)) * 100%), transparent);
|
|
826
|
+
|
|
827
|
+
/* Composed borders — foreground-tinted */
|
|
828
|
+
--glass-border-wash: color-mix(in srgb, var(--foreground) 8%, transparent);
|
|
829
|
+
--glass-border-quiet: color-mix(in srgb, var(--foreground) 10%, transparent);
|
|
830
|
+
--glass-border-resting: color-mix(in srgb, var(--foreground) 12%, transparent);
|
|
831
|
+
--glass-border-floating: color-mix(in srgb, var(--foreground) 15%, transparent);
|
|
832
|
+
--glass-border-overlay: color-mix(in srgb, var(--foreground) 18%, transparent);
|
|
833
|
+
--glass-border-dock: color-mix(in srgb, var(--foreground) 11%, transparent);
|
|
834
|
+
--glass-border: var(--glass-border-quiet);
|
|
835
|
+
--glass-border-strong: var(--glass-border-floating);
|
|
836
|
+
|
|
837
|
+
/* Shared decorative. Light grain dropped 0.035 → 0.025 in P.W1.B —
|
|
838
|
+
at the chassis scale the original alpha read as crawl over the new
|
|
839
|
+
lower-alpha chassis bg; the grain's role is texture, not reading,
|
|
840
|
+
so it sits at the perceptual floor. Dark companion drops 0.06 →
|
|
841
|
+
0.045 below to keep the soft-light blend alive without stippling. */
|
|
842
|
+
--glass-grain-opacity: 0.025;
|
|
843
|
+
--glass-grain-opacity-disco: 0.08;
|
|
844
|
+
--glass-highlight: inset 0 0.5px 0 0 hsl(0 0% 100% / 0.25);
|
|
845
|
+
|
|
846
|
+
/* Hairline-accent — 0.5px catch-light + under-shadow pair.
|
|
847
|
+
Single token composes the canonical 2-stop hairline used by dock,
|
|
848
|
+
instrument-chassis. The `.hairline-accent` utility
|
|
849
|
+
(utilities.css §hairline) adopts these via `box-shadow:`. */
|
|
850
|
+
--hairline-catch-light: inset 0 0.5px 0 0 rgb(255 255 255 / 0.06);
|
|
851
|
+
--hairline-under-shadow: 0 0.5px 0 0 rgb(0 0 0 / 0.04);
|
|
852
|
+
--border-hairline: var(--hairline-catch-light), var(--hairline-under-shadow);
|
|
853
|
+
|
|
854
|
+
/* Specular catch-light — 1.5px-tall top-edge highlight that swaps in for
|
|
855
|
+
--glass-highlight on interactive moments (e.g. primary-action hover).
|
|
856
|
+
Reads as a real catch-light on a curved surface. The `-dark` companion
|
|
857
|
+
is overridden inside `.dark`; the named token here is the explicit
|
|
858
|
+
handle consumers can reference to compose dark-aware layers. */
|
|
859
|
+
--glass-specular: inset 0 1.5px 0 0 hsl(0 0% 100% / 0.45);
|
|
860
|
+
--glass-specular-dark: inset 0 1.5px 0 0 hsl(0 0% 100% / 0.30);
|
|
861
|
+
|
|
862
|
+
/* AV.W15 M3 — Full-perimeter rim light (the "rim that defines the
|
|
863
|
+
silhouette", WWDC25 sess. 219). Distinct from the top-only
|
|
864
|
+
`--glass-highlight` (a 0.5px top-edge catch-light): this is a 0.75px
|
|
865
|
+
inset ring around the WHOLE silhouette, four edges, reading as the
|
|
866
|
+
catch-light that wraps the glass plate the way iOS-26 Liquid Glass
|
|
867
|
+
carries a rim, not just a top highlight. Composed as a SECOND inset
|
|
868
|
+
box-shadow layer alongside `--glass-highlight` on the floating/dock
|
|
869
|
+
tiers (glass.css wires it). The alpha is deliberately low (0.18 light
|
|
870
|
+
/ 0.10 dark) — the rim is decoration and must not eat AA legibility
|
|
871
|
+
over a busy backdrop; it sits below the perceptual reading threshold
|
|
872
|
+
on text. The `-dark` companion is overridden inside `.dark` mirroring
|
|
873
|
+
the `--glass-specular-dark` precedent. */
|
|
874
|
+
--glass-edge-light: inset 0 0 0 0.75px hsl(0 0% 100% / 0.18);
|
|
875
|
+
--glass-edge-light-dark: inset 0 0 0 0.75px hsl(0 0% 100% / 0.10);
|
|
876
|
+
|
|
877
|
+
/* AW.W23 — content-aware adaptive tint (the Baseline-2025 "tint informed by
|
|
878
|
+
surrounding content" axis, WWDC25 sess. 219). A surface can tint toward a
|
|
879
|
+
consumer-provided dominant backdrop color via a `color-mix(in oklab, …)`
|
|
880
|
+
recipe (oklab is the mwg-preferred space for tint generation; NEVER a
|
|
881
|
+
lightness-shift in `oklch(from …)` — browsers don't gamut-map yet).
|
|
882
|
+
|
|
883
|
+
DEFAULT is zero delta: `--glass-tint-source` is the warm-white card itself
|
|
884
|
+
and `--glass-tint-strength` is 0%, so the rung background mixes 0% toward
|
|
885
|
+
the source = byte-identical to today. A consumer sets `--glass-tint-source`
|
|
886
|
+
to a sampled aurora hue + a strength ≤30% to bias the surface. Alpha-safe:
|
|
887
|
+
the mix is bounded ≤30% and never re-points the card's own alpha.
|
|
888
|
+
|
|
889
|
+
AX.W55 — the DEFAULTS stay `var(--card)`/`0%` (the zero-delta rest state).
|
|
890
|
+
The backdrop-luminance probe (`--glass-backdrop`, below) is what OVERRIDES
|
|
891
|
+
them under a bright backdrop; the `:root` defaults are NEVER touched — the
|
|
892
|
+
bucket blocks (glass.css / dock.css `@container style(--glass-backdrop:
|
|
893
|
+
light)`) do the lift, so a surface over today's rich/dark background reads
|
|
894
|
+
byte-identical. */
|
|
895
|
+
--glass-tint-source: var(--card);
|
|
896
|
+
--glass-tint-strength: 0%;
|
|
897
|
+
|
|
898
|
+
/* AX.W55 — adaptive glass legibility (the iOS-26/27 "locally darken the glass
|
|
899
|
+
over light content" move; G2). There is NO web API that reads the pixels
|
|
900
|
+
painted BEHIND a `backdrop-filter` element, so the backdrop-luminance signal
|
|
901
|
+
is a DECLARATIVE BUCKET a consumer sets where it KNOWS the backdrop is bright
|
|
902
|
+
(a near-white card surface, a pale aurora bleed, a bright data grid). It is
|
|
903
|
+
read by the `@container style(--glass-backdrop: light)` blocks on every glass
|
|
904
|
+
family (the shipped density-cascade mechanism — utilities.css §density) which
|
|
905
|
+
lift `--glass-tint-strength` toward the AA floor + re-point `--glass-tint-
|
|
906
|
+
source` to the warm-ink below, mixing the rung TOWARD ink via the EXISTING
|
|
907
|
+
`color-mix(in oklab)` seam — ZERO new compositing seam.
|
|
908
|
+
|
|
909
|
+
--glass-backdrop: the bucket. `dark` (or unset) = today's zero-delta;
|
|
910
|
+
`light` engages the bright-bucket darken. An
|
|
911
|
+
INHERITING ident set on any ancestor reaches every
|
|
912
|
+
descendant glass surface (the @container read).
|
|
913
|
+
--glass-backdrop-luma: the numeric escape hatch — a sampled backdrop
|
|
914
|
+
relative-luminance (0..1) a heavier JS observer sets
|
|
915
|
+
when the declarative bucket is too coarse. The TOKEN
|
|
916
|
+
is minted (the cascade reads it if set); the OBSERVER
|
|
917
|
+
that sets it stays demo-private until a 2nd consumer
|
|
918
|
+
arrives (the no-overfitting bar — the DEFAULT path is
|
|
919
|
+
the declarative bucket, not a speculative sampler).
|
|
920
|
+
--glass-tint-ink: the LOW-LUMINANCE warm-ink the bright bucket re-points
|
|
921
|
+
`--glass-tint-source` to — the warm dark `--foreground`
|
|
922
|
+
family (NOT white; a lightener over light content is
|
|
923
|
+
exactly the W52-fixed wrong direction). It auto-flips
|
|
924
|
+
with `--foreground` (dark-mode it resolves the light
|
|
925
|
+
warm ink — but the bright-backdrop case is a light-mode
|
|
926
|
+
concern). Overridable like every magnitude here.
|
|
927
|
+
|
|
928
|
+
The bright-bucket `--glass-tint-strength` is clamped to a BOUNDED AA-clearing
|
|
929
|
+
floor — `--glass-tint-strength-aa` (≤24%, the iOS clamp; the lowest value that
|
|
930
|
+
clears 4.5:1 over synthetic white, capped LOW so the surface STAYS translucent,
|
|
931
|
+
"let as much content through as possible"). Recorded here as the ceiling the
|
|
932
|
+
bucket blocks drive to; the live 4.5:1 readback (proof:adaptive-glass π arm)
|
|
933
|
+
ratifies the exact value. */
|
|
934
|
+
--glass-backdrop: dark;
|
|
935
|
+
--glass-backdrop-luma: ;
|
|
936
|
+
--glass-tint-ink: var(--foreground);
|
|
937
|
+
--glass-tint-strength-aa: 18%;
|
|
938
|
+
|
|
939
|
+
/* AW.W23 — chromatic edge dispersion (the "polished glass" rim fringe Apple
|
|
940
|
+
shows). A warm fringe on one edge + a cool fringe on the other, low-alpha,
|
|
941
|
+
biased warm-cream/NCSU-red (NOT iOS-blue). Composed OVER the W22 uniform
|
|
942
|
+
rim under `prefers-reduced-transparency: no-preference`; dropped under
|
|
943
|
+
`reduce` (it is a transparency garnish). The two directional inset rings
|
|
944
|
+
read as light refracting through the glass edge. */
|
|
945
|
+
--glass-fringe-warm: oklch(0.92 0.06 40 / 0.22);
|
|
946
|
+
--glass-fringe-cool: oklch(0.90 0.05 230 / 0.16);
|
|
947
|
+
--glass-edge-dispersion:
|
|
948
|
+
inset 0.75px 0 0 0 var(--glass-fringe-warm),
|
|
949
|
+
inset -0.75px 0 0 0 var(--glass-fringe-cool);
|
|
950
|
+
|
|
951
|
+
/* AX.W52 D19 — the moving-specular gleam radius (glass.css `.glass-material::
|
|
952
|
+
before`). The ONE knob that BOUNDS the gleam geometry as a percentage of the
|
|
953
|
+
plate so it can NEVER again become a whole-surface disc (the prior implicit
|
|
954
|
+
`circle at …` ran its stops to 55–75% of the half-diagonal — a wash on a
|
|
955
|
+
small tile). 36% reads as a tracked edge glint. Override on `:root` to retune
|
|
956
|
+
library-wide; a per-surface override clips the gleam tighter/wider. */
|
|
957
|
+
--glass-specular-size: 36%;
|
|
958
|
+
|
|
959
|
+
/* Chassis curvature illusion — a subtle radial gradient at the chassis
|
|
960
|
+
top centre that lifts the surface without committing to literal 3D.
|
|
961
|
+
Composed into <InstrumentChassis>'s background stack. AX.W52 D19 — the
|
|
962
|
+
prior pure-white `hsl(0 0% 100% / 0.06)` reaching `transparent 60%` was a
|
|
963
|
+
broad top-centre WASH (the #1 fixed-anchor rest-bloom culprit). Re-derived
|
|
964
|
+
onto the warm-cream house identity (`hsl(40 30% 96%)`, L < 100% so the warm
|
|
965
|
+
hue survives — mirroring the moving gleam), the alpha routed through the
|
|
966
|
+
SINGLE overridable `--glass-curvature-intensity` knob (0.02 default, a third
|
|
967
|
+
of the old 0.06), and the ellipse tightened to `transparent 38%` so it reads
|
|
968
|
+
as a thin top-edge sheen, not a central wash. */
|
|
969
|
+
--glass-curvature-intensity: 0.02;
|
|
970
|
+
--glass-curvature-overlay: radial-gradient(
|
|
971
|
+
ellipse at 50% -20%,
|
|
972
|
+
hsl(40 30% 96% / var(--glass-curvature-intensity)),
|
|
973
|
+
transparent 38%
|
|
974
|
+
);
|
|
975
|
+
/* The light-arm dark alias kept on the same warm-cream + token recipe so a
|
|
976
|
+
non-`.dark` consumer reading `…-overlay-dark` still resolves a softened
|
|
977
|
+
sheen; the `.dark` block below lowers `--glass-curvature-intensity` so the
|
|
978
|
+
deep-canvas arm is genuinely softer (the prior byte-identical dark arm read
|
|
979
|
+
HARDER over the dark canvas). */
|
|
980
|
+
--glass-curvature-overlay-dark: var(--glass-curvature-overlay);
|
|
981
|
+
|
|
982
|
+
/* Chart palette aliases — speedtest et al. read these for phase tinting.
|
|
983
|
+
Defaults map to viz-basis hues; consumers can override per app. */
|
|
984
|
+
--chart-ping: var(--viz-chebyshev);
|
|
985
|
+
--chart-download: var(--viz-fourier);
|
|
986
|
+
--chart-upload: var(--viz-amber);
|
|
987
|
+
--chart-jitter: var(--viz-legendre);
|
|
988
|
+
|
|
989
|
+
/* O.W6 Lane D — WCAG companion `--chart-{phase}-label` tokens
|
|
990
|
+
(speedtest AC.W6c.T2 — F1.V-04 closure).
|
|
991
|
+
|
|
992
|
+
The canvas-side hues above preserve their saturated brand register
|
|
993
|
+
(correct against the meter dial); the COMPANION tokens darken to
|
|
994
|
+
L≈0.40 so phase-label text on `--background` clears the WCAG 2.1
|
|
995
|
+
AA-body 4.5:1 contrast floor. Mirrors the two-token discipline
|
|
996
|
+
already established by `--meter-{background-color,track-stroke}`:
|
|
997
|
+
one token feeds the canvas/visual, the second feeds the label
|
|
998
|
+
text.
|
|
999
|
+
|
|
1000
|
+
Light-mode L≈0.40 in OKLCH preserves the hue rotation while
|
|
1001
|
+
dropping luminance enough for body contrast; dark-mode flips to
|
|
1002
|
+
L≈0.85 against the dark canvas. Consumers reach these via
|
|
1003
|
+
`color: var(--chart-ping-label)` (etc.) on label elements ONLY —
|
|
1004
|
+
chart strokes/fills continue to read `--chart-ping`. */
|
|
1005
|
+
--chart-ping-label: oklch(0.40 0.18 230);
|
|
1006
|
+
--chart-download-label: oklch(0.40 0.20 22);
|
|
1007
|
+
--chart-upload-label: oklch(0.40 0.16 55);
|
|
1008
|
+
--chart-jitter-label: oklch(0.40 0.20 305);
|
|
1009
|
+
|
|
1010
|
+
/* O.W6 Lane D — Meter track stroke (speedtest AC.W6c.T3 — F1.V-02
|
|
1011
|
+
closure). Promoted from speedtest's consumer-side declaration so
|
|
1012
|
+
glass-ui owns the canonical light + dark values. The light-mode
|
|
1013
|
+
value reads opaque foreground (composes through canvas
|
|
1014
|
+
`globalAlpha` in consumer renderers; e.g., speedtest's `rings.ts`
|
|
1015
|
+
`globalAlpha = 0.22` lands the phantom-track at the perceptual
|
|
1016
|
+
sweet-spot). The dark-mode companion lives under `.dark` below
|
|
1017
|
+
and ALSO reads `var(--foreground)` — the prior speedtest value
|
|
1018
|
+
`var(--background)` rendered bg-on-bg invisible at dark mode. */
|
|
1019
|
+
--meter-track-stroke: var(--foreground);
|
|
1020
|
+
|
|
1021
|
+
/* Shadow per tier — complete box-shadow lists for glass surface classes */
|
|
1022
|
+
--glass-shadow-wash: var(--shadow-sm), var(--glass-highlight);
|
|
1023
|
+
--glass-shadow-quiet: var(--shadow-md), var(--glass-highlight);
|
|
1024
|
+
--glass-shadow-resting: var(--shadow-lg), var(--glass-highlight);
|
|
1025
|
+
--glass-shadow-floating: var(--shadow-xl),
|
|
1026
|
+
0 0 0 0.5px color-mix(in srgb, var(--shadow-color) 5%, transparent),
|
|
1027
|
+
var(--glass-highlight);
|
|
1028
|
+
--glass-shadow-overlay: var(--shadow-2xl),
|
|
1029
|
+
0 0 0 0.5px color-mix(in srgb, var(--shadow-color) 8%, transparent),
|
|
1030
|
+
var(--glass-highlight);
|
|
1031
|
+
--glass-shadow: var(--glass-shadow-quiet);
|
|
1032
|
+
--glass-shadow-lg: var(--glass-shadow-floating);
|
|
1033
|
+
|
|
1034
|
+
/* ─────────────────────────────────────────────────────────────
|
|
1035
|
+
AL-W1-α augmented — SPINE 8th tier (HOUSING register)
|
|
1036
|
+
|
|
1037
|
+
Closes the AK W2 chassis-spine architectural underclaim per
|
|
1038
|
+
AL-X5 §4.1. The spine register is a polished SLEEVE, not glass:
|
|
1039
|
+
NO backdrop-filter, NO plate opacity, hairline outer stroke,
|
|
1040
|
+
interior radial vignette that subtly carries the phase-color
|
|
1041
|
+
cascade. Consumed exclusively by `<InstrumentChassis variant="spine">`
|
|
1042
|
+
at App-level mount paths (quiet-content routes).
|
|
1043
|
+
|
|
1044
|
+
The 4 tokens here cover the minimum viable substrate the SLIM
|
|
1045
|
+
Y4/Y6/Y7 retention set ratified. The 35 rejected axes (saturate
|
|
1046
|
+
band, edge-light per tier, depth-shadow per tier, tier-up macro)
|
|
1047
|
+
stay rejected per the conservative-creation mandate.
|
|
1048
|
+
───────────────────────────────────────────────────────────── */
|
|
1049
|
+
--glass-spine-opacity: 0;
|
|
1050
|
+
--glass-spine-blur: 0px;
|
|
1051
|
+
--glass-spine-border: var(--surface-tint-8);
|
|
1052
|
+
--glass-spine-vignette: radial-gradient(
|
|
1053
|
+
ellipse at 50% 0%,
|
|
1054
|
+
color-mix(in oklab, var(--phase-color, var(--surface-tint-8)) 8%, transparent),
|
|
1055
|
+
transparent 60%
|
|
1056
|
+
);
|
|
1057
|
+
|
|
1058
|
+
/* ─────────────────────────────────────────────────────────────
|
|
1059
|
+
AL-W10 SLIM — UNDER-SHADOW recipe rungs
|
|
1060
|
+
|
|
1061
|
+
Per AL-X5 §4 + Y7 §3. iOS Liquid Glass surfaces carry a 0.5px
|
|
1062
|
+
dark hairline along the bottom edge (reads as under-shadow /
|
|
1063
|
+
glass thickness). The substrate `--hairline-under-shadow`
|
|
1064
|
+
already publishes one quiet rung; the four-rung ladder here
|
|
1065
|
+
names the SLIM retention set (Y4 §3.2 / Y6 §4.3) — `quiet`,
|
|
1066
|
+
`default`, `vivid`, `spine` cover the consumer landings without
|
|
1067
|
+
multiplying tokens per tier. The 3 hand-rolled literals at
|
|
1068
|
+
`instrument-chassis.css:52`, `dock.css:279`, `dock.css:952`
|
|
1069
|
+
retire to these.
|
|
1070
|
+
|
|
1071
|
+
Composes as a NON-INSET box-shadow layer alongside the existing
|
|
1072
|
+
`--glass-shadow-*` recipe (the inset under-shadow stays at the
|
|
1073
|
+
hand-rolled literal where it's load-bearing on chassis-internal
|
|
1074
|
+
surfaces).
|
|
1075
|
+
───────────────────────────────────────────────────────────── */
|
|
1076
|
+
--glass-under-shadow-quiet: 0 2px 8px -1px oklch(0 0 0 / 0.04);
|
|
1077
|
+
--glass-under-shadow-default: 0 4px 16px -2px oklch(0 0 0 / 0.08);
|
|
1078
|
+
--glass-under-shadow-vivid: 0 8px 32px -4px oklch(0 0 0 / 0.12);
|
|
1079
|
+
--glass-under-shadow-spine: 0 1px 0 0 oklch(0 0 0 / 0.06);
|
|
1080
|
+
|
|
1081
|
+
/* Overlay scrim rungs — substrate-aware modal/dialog backdrop tints.
|
|
1082
|
+
Three weights cover the deployed range: dialog-scroll (subtle),
|
|
1083
|
+
canonical modal (default), drawer/full-cover (strong).
|
|
1084
|
+
|
|
1085
|
+
AY.W-PRIM-POLISH D3 — the scrim is its OWN identity token, NOT derived
|
|
1086
|
+
from `--shadow-color`. A scrim's role is to RECEDE: it must pin to INK in
|
|
1087
|
+
BOTH modes. The cartoon-shadow family rides `--shadow-color: var(--foreground)`
|
|
1088
|
+
(correct — a shadow re-tints under `.dark` by construction), but a scrim
|
|
1089
|
+
that does the same FLOODS the dark room with a cream fog (the old dark
|
|
1090
|
+
overlay painted `srgb(0.91… / 0.5)`, a near-white wash that BRIGHTENED the
|
|
1091
|
+
page at the modal moment). `--overlay-scrim-ink` is a fixed warm near-black
|
|
1092
|
+
(the light-mode `--foreground` value), re-resolved verbatim in `.dark` so
|
|
1093
|
+
the scrim recedes in both modes. Clean break, no alias (no-backwards-compat).
|
|
1094
|
+
The `--shadow-color` / `--shadow-cartoon-*` family is UNTOUCHED. */
|
|
1095
|
+
--overlay-scrim-ink: hsl(24 10% 10%);
|
|
1096
|
+
--overlay-scrim: color-mix(in srgb, var(--overlay-scrim-ink) 50%, transparent);
|
|
1097
|
+
--overlay-scrim-strong: color-mix(in srgb, var(--overlay-scrim-ink) 80%, transparent);
|
|
1098
|
+
--overlay-scrim-subtle: color-mix(in srgb, var(--overlay-scrim-ink) 40%, transparent);
|
|
1099
|
+
|
|
1100
|
+
/* ═══════════════════════════════════════════════
|
|
1101
|
+
§9 ANIMATION OFFSETS
|
|
1102
|
+
═══════════════════════════════════════════════ */
|
|
1103
|
+
/* Hover lift offsets */
|
|
1104
|
+
--lift-sm: -1px;
|
|
1105
|
+
--lift-md: -2px;
|
|
1106
|
+
--lift-lg: -4px;
|
|
1107
|
+
|
|
1108
|
+
/* Layout tokens */
|
|
1109
|
+
--mask-fade-width: 1rem;
|
|
1110
|
+
/* J.W3.C — dock content overflow caps. When dock content exceeds
|
|
1111
|
+
these dimensions, the inner `.dock-layers` (horizontal) /
|
|
1112
|
+
`.glass-dock.vertical` (rail) container scrolls with a
|
|
1113
|
+
`.scroll-fade-{x,y}` mask-fade so the boundary feathers rather
|
|
1114
|
+
than cliffs. Defaults clamp to 80vw / 80vh capped at sensible
|
|
1115
|
+
desktop widths; consumers override per-dock by setting either
|
|
1116
|
+
token directly on a `.glass-dock` instance. User findings 1 + 5a. */
|
|
1117
|
+
/* AX.W04 — `--dock-max-inline-size` is the canonical inline cap EVERY overflow
|
|
1118
|
+
strategy reads: `overflow="scroll"` scrolls past it, and `overflow="wrap"`
|
|
1119
|
+
wraps to N rows on the over-cap crossing (the dock shrink-wraps to content,
|
|
1120
|
+
`max-inline-size` caps that intrinsic width at this token). The prior
|
|
1121
|
+
`--dock-overflow-bp: 640px` viewport-breakpoint token (the magic-640
|
|
1122
|
+
snap-back) is DELETED — the wrap is content-driven, not viewport-coupled, so
|
|
1123
|
+
there is no breakpoint threshold to name. */
|
|
1124
|
+
--dock-max-inline-size: min(80vw, 64rem);
|
|
1125
|
+
--dock-max-block-size: min(80vh, 48rem);
|
|
1126
|
+
|
|
1127
|
+
/* AB.W1.T1 — chassis max-block-size guardrail.
|
|
1128
|
+
Maximum block size a centred consumer-app card may consume while
|
|
1129
|
+
preserving the inline dock footprint. The recipe subtracts the
|
|
1130
|
+
consumer-owned `--dock-footer-space` (dock height + dock inset +
|
|
1131
|
+
card-edge inset) and `--page-padding-top` from the dynamic viewport,
|
|
1132
|
+
then takes one further rem of breathing room so the card never
|
|
1133
|
+
butts the dock — the user mandate is `≥ 1rem visible gap above
|
|
1134
|
+
dock`. Both consumer tokens carry safe fallbacks for callers that
|
|
1135
|
+
have not declared them.
|
|
1136
|
+
|
|
1137
|
+
Consumers should shrink internal regions (meter, readout, timeline)
|
|
1138
|
+
before falling back to scroll. This token is a guardrail against
|
|
1139
|
+
chassis overflow, NOT a license to make the card scroll as the
|
|
1140
|
+
default solution; clamp-first / no-scroll-first is the canon.
|
|
1141
|
+
See DESIGN.md `## Chassis sizing — dock-adjusted viewport`. */
|
|
1142
|
+
--chassis-max-block-size: calc(
|
|
1143
|
+
100dvh
|
|
1144
|
+
- var(--dock-footer-space, 5.75rem)
|
|
1145
|
+
- var(--page-padding-top, 0rem)
|
|
1146
|
+
- 1rem
|
|
1147
|
+
);
|
|
1148
|
+
/* R0G-2 (AO.W3/W4) — chassis mobile dial-reserve canon. instrument-
|
|
1149
|
+
chassis.css's mobile breakpoint reserves the dial's final box from
|
|
1150
|
+
frame 0 via these vars (with the same values as inline fallbacks, the
|
|
1151
|
+
safety net). Token-first home so the vars resolve canonically. */
|
|
1152
|
+
--instrument-dial-min-height-mobile: 24rem;
|
|
1153
|
+
--instrument-dial-meter-reserve-mobile: minmax(0, 1fr);
|
|
1154
|
+
|
|
1155
|
+
--max-width-input: 24rem;
|
|
1156
|
+
--input-min-width-sm: 5rem;
|
|
1157
|
+
--min-width-input-sm: var(--input-min-width-sm);
|
|
1158
|
+
/* AU.W8b.4 — canonical popover width (Combobox list + anchor). Lifts the
|
|
1159
|
+
`w-[200px]` arbitrary-value wrap to the `w-popover` @theme utility. */
|
|
1160
|
+
--popover-width: 200px;
|
|
1161
|
+
--chart-height-compact: 15rem;
|
|
1162
|
+
--chart-height-default: 22.5rem;
|
|
1163
|
+
--chart-height-large: 25rem;
|
|
1164
|
+
--chart-margin: 1.25rem;
|
|
1165
|
+
--paper-texture-size: 200px 200px;
|
|
1166
|
+
|
|
1167
|
+
/* Border opacity scale */
|
|
1168
|
+
--border-opacity-light: 0.15;
|
|
1169
|
+
--border-opacity-medium: 0.25;
|
|
1170
|
+
--border-opacity-strong: 0.6;
|
|
1171
|
+
|
|
1172
|
+
/* ═══════════════════════════════════════════════
|
|
1173
|
+
§10 SIZING
|
|
1174
|
+
═══════════════════════════════════════════════ */
|
|
1175
|
+
/* ── The ONE comfortable-sizing scale doctrine (AX.W51 D18) ──────────────
|
|
1176
|
+
`--ui-scale` is the MASTER comfortable-sizing scalar — ONE unitless knob
|
|
1177
|
+
(registered @property <number>, inherits:true, default the identity 1)
|
|
1178
|
+
every interactive-control magnitude derives through `calc(<base> *
|
|
1179
|
+
var(--ui-scale))`, so a single override grows control HEIGHT + PADDING +
|
|
1180
|
+
GAP + FONT-SIZE + GLYPH in LOCKSTEP, proportion preserved, no per-component
|
|
1181
|
+
hack. The cohorts below (`--control-h-*` heights, `--control-text*` control
|
|
1182
|
+
fonts, `--ui-glyph*` glyphs) are its reading surfaces; the CVA bases + the
|
|
1183
|
+
`.btn-pill`/`.input-pill` pills consume them.
|
|
1184
|
+
|
|
1185
|
+
ONE scale system, not three. The dock (`--dock-scale`) and the dropdown
|
|
1186
|
+
family (`--dropdown-text`, W50) are SPECIALIZATIONS that read this axis:
|
|
1187
|
+
`--dock-scale: calc(var(--ui-scale) * var(--dock-local-scale, 1))` — the
|
|
1188
|
+
dock multiplies ON TOP of the global comfort axis (its existing geometry
|
|
1189
|
+
`calc` cascade inherits the global axis for free, zero edit). A consumer
|
|
1190
|
+
re-tints the whole library's comfort from ONE `:root { --ui-scale: … }`
|
|
1191
|
+
override (or a scoped region — a dense data-table sets it lower) — the
|
|
1192
|
+
token-first axis.
|
|
1193
|
+
|
|
1194
|
+
EXCLUDED — the φ-DISPLAY ladder (`--type-display-*` / `--type-title` /
|
|
1195
|
+
`--type-heading` / `--type-subheading`): a hero/title is a TYPOGRAPHIC
|
|
1196
|
+
identity, NOT a touch target, so it does NOT grow on the comfort/coarse
|
|
1197
|
+
axis. Only interactive-CONTROL text rides `--ui-scale`. Containers (card /
|
|
1198
|
+
panel radii + paddings) are separate `--radius-*` / `--space-*` axes.
|
|
1199
|
+
|
|
1200
|
+
The desktop default is the IDENTITY (1) — byte-exact preservation, no
|
|
1201
|
+
reflow of shipped consumers. The comfort GROWTH lives at the coarse-pointer
|
|
1202
|
+
default (`--ui-coarse-scale`, §below) + the consumer override. The
|
|
1203
|
+
WCAG-2.5.5 44px touch floor survives as a `max(…, --control-floor)` clamp
|
|
1204
|
+
inside the scaled control-size (the coarse block lifts `--control-floor` to
|
|
1205
|
+
`--touch-target`, so a sub-1 scale cannot drop a control under the target).
|
|
1206
|
+
Coordinates with W54's `--glass-level` + W55's `--glass-tint-*` — SEPARATE
|
|
1207
|
+
axes (size vs material vs legibility); a control is comfortably-sized AND
|
|
1208
|
+
glass AND legible, three orthogonal knobs. */
|
|
1209
|
+
--ui-scale: 1;
|
|
1210
|
+
/* The global coarse-pointer comfort default — the WHOLE library grows ~1.5×
|
|
1211
|
+
on touch from ONE place (the @media (pointer: coarse) block at §below lifts
|
|
1212
|
+
:root --ui-scale to this). The dock's prior parallel 1.5× becomes the global
|
|
1213
|
+
default it now shares. Public library-default identity — a consumer sets
|
|
1214
|
+
1.3 / 1.75 on :root or a scope. */
|
|
1215
|
+
--ui-coarse-scale: 1.5;
|
|
1216
|
+
/* The control-height cohort — the h-7/h-9/h-10/h-11 register (28/36/40/44px)
|
|
1217
|
+
the CVA size rungs encode, each scaled by the master axis. The CVA rungs
|
|
1218
|
+
read these via `h-[var(--control-h-*)]` instead of the raw `h-N` literal.
|
|
1219
|
+
`--control-floor` is the WCAG-2.5.5 clamp seam (0 at desktop, lifted to
|
|
1220
|
+
--touch-target under coarse-pointer); each height is `max(scaled, floor)`. */
|
|
1221
|
+
--control-floor: 0px;
|
|
1222
|
+
--control-h-xs: max(calc(1.75rem * var(--ui-scale)), var(--control-floor));
|
|
1223
|
+
--control-h-sm: max(calc(2.25rem * var(--ui-scale)), var(--control-floor));
|
|
1224
|
+
--control-h-md: max(calc(2.5rem * var(--ui-scale)), var(--control-floor));
|
|
1225
|
+
--control-h-lg: max(calc(2.75rem * var(--ui-scale)), var(--control-floor));
|
|
1226
|
+
/* The control-FONT register (RED 3 — the user's "font too small"). A comfort
|
|
1227
|
+
multiplier BETWEEN the static φ-ladder rung and the painted control font,
|
|
1228
|
+
so interactive-control text grows on the comfort axis while the φ-DISPLAY
|
|
1229
|
+
ladder stays a pure typographic scale (display headings do NOT grow on
|
|
1230
|
+
touch). `--control-text` is the workhorse (the `text-sm` register the
|
|
1231
|
+
buttons/inputs/triggers carried); `--control-text-sm` is the quieter rung
|
|
1232
|
+
(the `text-xs` badge/caption register). W50's `--dropdown-text` IS the
|
|
1233
|
+
picker-family specialization of this register. */
|
|
1234
|
+
--control-text: calc(var(--type-small) * var(--ui-scale));
|
|
1235
|
+
--control-text-sm: calc(var(--type-caption) * var(--ui-scale));
|
|
1236
|
+
/* The control-GLYPH cohort (RED 4 — the glyph grows WITH the box). The
|
|
1237
|
+
1rem/0.875rem control-glyph register the `size-4`/`size-3.5` literals
|
|
1238
|
+
encode; the un-sized-<svg> CVA rule reads these via
|
|
1239
|
+
`size-[var(--ui-glyph)]`, KEEPING the `:not([class*=size-])` host-sized-icon
|
|
1240
|
+
escape intact (an explicit `size-9` still wins). */
|
|
1241
|
+
--ui-glyph: calc(1rem * var(--ui-scale));
|
|
1242
|
+
--ui-glyph-sm: calc(0.875rem * var(--ui-scale));
|
|
1243
|
+
|
|
1244
|
+
/* ── The picker-family type-scale (AX.W50 D17) ───────────────────────────
|
|
1245
|
+
ONE governed two-rung scale the WHOLE shadcn picker family (Select /
|
|
1246
|
+
DropdownMenu / Combobox / ContextMenu / Command / MultiSelect) reads, so the
|
|
1247
|
+
family paints at ONE uniform scale instead of the scattered raw
|
|
1248
|
+
`text-sm`/`text-xs` Tailwind-literal lottery (item rows at `text-sm`,
|
|
1249
|
+
headings/shortcuts at `text-xs`, the two filter inputs at mismatched heights).
|
|
1250
|
+
A consumer re-tints the whole family from ONE override.
|
|
1251
|
+
|
|
1252
|
+
It is a SPECIALIZATION of W51's control-font register (one scale system, not
|
|
1253
|
+
three): `--dropdown-text` reads `--control-text` (the comfort-scaled `text-sm`)
|
|
1254
|
+
and `--dropdown-text-secondary` reads `--control-text-sm` (the comfort-scaled
|
|
1255
|
+
`text-xs`), so the picker family rides the SAME `--ui-scale` comfort axis as
|
|
1256
|
+
every other control — a `--ui-scale` bump grows the dropdowns too. A consumer
|
|
1257
|
+
wanting the family LARGER than the rest overrides `--dropdown-text` directly
|
|
1258
|
+
(e.g. `var(--type-body)`); the override re-resolves every family surface.
|
|
1259
|
+
|
|
1260
|
+
Scale-contract (which surface reads which rung):
|
|
1261
|
+
• PRIMARY (`--dropdown-text`) → item rows, triggers, filter inputs, empties.
|
|
1262
|
+
• SECONDARY (`--dropdown-text-secondary`) → section labels, group-headings,
|
|
1263
|
+
keyboard shortcuts (the quieter-than-item caption register; resolves the
|
|
1264
|
+
witness-2 contradiction — the Select/DropdownMenu/ContextMenu labels
|
|
1265
|
+
collapse DOWN to the secondary rung to match the Combobox/Command headings,
|
|
1266
|
+
ONE rung for the section-label role family-wide).
|
|
1267
|
+
`--dropdown-input-height` unifies the two filter-input heights (Combobox was
|
|
1268
|
+
h-10, Command was h-11) onto ONE register — a specialization of W51's
|
|
1269
|
+
`--control-h-md` so the picker input scales on the comfort axis with the font. */
|
|
1270
|
+
--dropdown-text: var(--control-text);
|
|
1271
|
+
--dropdown-text-secondary: var(--control-text-sm);
|
|
1272
|
+
--dropdown-input-height: var(--control-h-md);
|
|
1273
|
+
|
|
1274
|
+
--size-icon-btn: 2.5rem;
|
|
1275
|
+
--icon-xs: 0.75rem;
|
|
1276
|
+
--icon-sm: 0.875rem;
|
|
1277
|
+
--icon-md: 1rem;
|
|
1278
|
+
--icon-lg: 1.25rem;
|
|
1279
|
+
--icon-xl: 1.5rem;
|
|
1280
|
+
/* V.W2 T9 — 32px rung; spinner glyphs (Loader2) + dense table-row buttons.
|
|
1281
|
+
Naming follows the radius ladder + Tailwind convention (2xl > xl > xxl) —
|
|
1282
|
+
see B6 §2.4 for the naming rationale. */
|
|
1283
|
+
--icon-2xl: 2rem;
|
|
1284
|
+
/* V.W2 T10 — 40px rung; empty-state hero glyph (DashboardMap MapIcon).
|
|
1285
|
+
AI.W5-ζ — rebound from `2.5rem` literal to `var(--size-icon-btn)` so
|
|
1286
|
+
the alignment is contractual single-source-of-truth rather than the
|
|
1287
|
+
coincidental numerical match noted prior. */
|
|
1288
|
+
--icon-3xl: var(--size-icon-btn);
|
|
1289
|
+
/* V.W2 T11 — 56px rung; FlowSelector school/home survey-flow picker.
|
|
1290
|
+
Largest rung in the icon ladder; reserved for hero-class glyphs. */
|
|
1291
|
+
--icon-hero: 3.5rem;
|
|
1292
|
+
|
|
1293
|
+
/* Golden-ratio spacing rungs — φ² and φ³. Preemptive substrate; W4 hero
|
|
1294
|
+
chassis + W5 StoryChassis migration land the consumers. R3 §A row 1.
|
|
1295
|
+
The 0..4 rungs are not currently named (consumers reach via
|
|
1296
|
+
Tailwind's spacing scale); 5/6 land here because their values fall
|
|
1297
|
+
outside the default ladder and the audacious chassis pattern wants
|
|
1298
|
+
a named handle. */
|
|
1299
|
+
--space-phi-5: 2.618rem; /* φ² */
|
|
1300
|
+
--space-phi-6: 4.236rem; /* φ³ */
|
|
1301
|
+
|
|
1302
|
+
/* Dock geometry — consumers may override locally */
|
|
1303
|
+
--dock-h: calc(var(--size-icon-btn) + 0.75rem + 3px);
|
|
1304
|
+
--dock-margin: 0.5rem;
|
|
1305
|
+
--dock-menubar-reserve: 4rem;
|
|
1306
|
+
|
|
1307
|
+
/* AX.W45 — the dock geometry multiplier. `--dock-scale` threads the WHOLE
|
|
1308
|
+
`.glass-dock[data-density]` geometry cascade (box, padding, gap, tab,
|
|
1309
|
+
tile-min, glyph) via `calc(<base> * --dock-scale)`, so a single knob grows
|
|
1310
|
+
every dock axis in lockstep. The WCAG 2.5.5 44px floor survives as a `max(…,
|
|
1311
|
+
44px)` clamp INSIDE the scaled control-size.
|
|
1312
|
+
|
|
1313
|
+
AX.W51 RECONCILE (D18) — `--dock-scale` is RE-HOMED as a SPECIALIZATION of
|
|
1314
|
+
the global `--ui-scale` comfort axis: `calc(var(--ui-scale) *
|
|
1315
|
+
var(--dock-local-scale, 1))`. The dock now MULTIPLIES on top of the global
|
|
1316
|
+
comfort scalar — its whole existing geometry `calc` chain inherits the global
|
|
1317
|
+
axis for FREE (zero edit to the density cascade; the reconcile is at this ONE
|
|
1318
|
+
definition line). At the desktop identity (`--ui-scale: 1`,
|
|
1319
|
+
`--dock-local-scale: 1`) the dock is byte-identical to HEAD. On coarse-pointer
|
|
1320
|
+
the GLOBAL `:root { --ui-scale: var(--ui-coarse-scale, 1.5) }` block grows the
|
|
1321
|
+
dock WITH the rest of the library — ONE consistent touch scale, not a parallel
|
|
1322
|
+
dock-only 1.5×. `--dock-local-scale` is the dock-local EXTRA multiplier
|
|
1323
|
+
(default 1): a consumer who wants the dock LARGER than the global comfort sets
|
|
1324
|
+
it, and the coarse block lifts it to `--dock-mobile-scale` (default 1, the
|
|
1325
|
+
stack-extra) so the dock can grow an extra notch ON TOP of the global coarse
|
|
1326
|
+
default. `--dock-mobile-scale` is the public library-default identity
|
|
1327
|
+
(presets-in-consumers: a consumer sets 1.3/1.75 on `:root` or a dock scope). */
|
|
1328
|
+
--dock-scale: calc(var(--ui-scale) * var(--dock-local-scale, 1));
|
|
1329
|
+
--dock-local-scale: 1;
|
|
1330
|
+
--dock-mobile-scale: 1;
|
|
1331
|
+
/* Library glyph ownership — `.dock-icon-button > svg` reads this so the dock
|
|
1332
|
+
icon glyph scales WITH the box (mirroring `.dark-mode-toggle-button > svg`).
|
|
1333
|
+
A consumer-passed explicit lucide size class still WINS (utility layer >
|
|
1334
|
+
component layer); this is a DEFAULT, not a ceiling. */
|
|
1335
|
+
--dock-icon-glyph: calc(1.25rem * var(--dock-scale));
|
|
1336
|
+
|
|
1337
|
+
/* AX.W45-TUNE Q1 — the COLLAPSED-pill floor tokens. The collapsed summary
|
|
1338
|
+
used to fall to `--dock-layer-height` (the FULL control height, ~2.5rem) for
|
|
1339
|
+
its `min-width` with NO block floor, so the shrunken pill read as an
|
|
1340
|
+
un-collapsed control row, not a tight proportioned squircle. These two floor
|
|
1341
|
+
tokens (referenced by dock.css's `.collapsed .dock-layer--summary` min-size +
|
|
1342
|
+
the `--dock-pad-collapsed` morph floor) mint a TIGHT proportioned pill: the
|
|
1343
|
+
summary min-size is ≈70% of the full control height (a proportioned dot, not a
|
|
1344
|
+
full-row stub — the ratified default), and the collapsed padding is a step
|
|
1345
|
+
BELOW the expanded `--dock-padding-block` so the collapsed chrome hugs the
|
|
1346
|
+
glyph. The summary carries a SYMMETRIC `min-block-size` (dock.css) keyed to the
|
|
1347
|
+
same token so the pill floors on BOTH axes — a squircle, not a stub. Consumers
|
|
1348
|
+
retune the pill geometry per-instance via these two handles. */
|
|
1349
|
+
--dock-collapsed-summary-min-size: calc(var(--dock-layer-height, 2.5rem) * 0.7);
|
|
1350
|
+
/* AX.W61 — the collapsed padding now threads the ONE `--dock-scale` coarse-pointer
|
|
1351
|
+
multiplier DIRECTLY (at HEAD it was a flat 0.25rem off the scale, so the
|
|
1352
|
+
collapsed pad alone stayed desktop-sized at the 1.5x mobile scale while the
|
|
1353
|
+
box/glyph/min-size grew — a desync the morph then interpolated FROM). The
|
|
1354
|
+
summary min-size already threads `--dock-scale` transitively through
|
|
1355
|
+
`--dock-layer-height` (itself `calc(* --dock-scale)` at every density rung); this
|
|
1356
|
+
lands the collapsed pad on the same thread so the whole collapsed pill scales
|
|
1357
|
+
coherently on touch. The 0.25rem base stays the ratified tight floor. */
|
|
1358
|
+
--dock-collapsed-padding: calc(0.25rem * var(--dock-scale));
|
|
1359
|
+
|
|
1360
|
+
/* AX.W45-TUNE Q3/C3 + C5 — the dock-control family reads a real GLASS register
|
|
1361
|
+
on hover/active, NOT a same-hue `--card` mix at an alpha adjacent to the dock's
|
|
1362
|
+
own `--glass-bg-dock` substrate (a sub-1%-ΔL no-op — the loud Q3 tell: "nothing
|
|
1363
|
+
on hover, something on click"). Both legs now point at NAMED glass tiers a
|
|
1364
|
+
measurable step ABOVE the dock's 42%-opacity substrate:
|
|
1365
|
+
• hover → `--glass-bg-resting` (the 65% glass plate) — the control surface
|
|
1366
|
+
WAKES as a brighter glass tier on hover, reading the blurred dock
|
|
1367
|
+
substrate through it. The +ΔL above `--glass-bg-dock` is perceptible
|
|
1368
|
+
BEFORE click; the specular gleam + scale ride alongside (one register).
|
|
1369
|
+
• active → `--glass-bg-floating` (the 80% glass plate) — a tier ABOVE hover,
|
|
1370
|
+
the keyframes-dock "selected element reads as glass" model the user
|
|
1371
|
+
named (`pass-3:13`): the selected tile is a glass tier that shows the
|
|
1372
|
+
substrate through it, NOT the flat `--surface-tint-12` ink wash. The
|
|
1373
|
+
active ≠ hover register is the glass-tier step, not an alpha nudge.
|
|
1374
|
+
This is a REGISTER change (substrate→glass-tier), not a magnitude knob. The
|
|
1375
|
+
per-control `--dock-icon-hover-bg` override still wins if a consumer set it. */
|
|
1376
|
+
--dock-control-hover-bg: var(--glass-bg-resting);
|
|
1377
|
+
--dock-control-active-bg: var(--glass-bg-floating);
|
|
1378
|
+
|
|
1379
|
+
/* AX.W45-TUNE C4/C5 — the small-tile specular override. The 40px dock-control
|
|
1380
|
+
tile is a fraction of a card's plate, so the global `--glass-specular-size`
|
|
1381
|
+
(36% of the plate) blooms a disproportionate disc on a hover/active dock tile
|
|
1382
|
+
(the I.W6 finding). The dock controls scope a TIGHTER radius (22%) so the gleam
|
|
1383
|
+
wakes as a restrained EDGE-catch on the small tile, not a tile-filling bloom —
|
|
1384
|
+
the right resolution of I.W6 (sized-down on the small surface), not turning the
|
|
1385
|
+
specular off everywhere. Read by the dock-control `::before` recipe (glass.css)
|
|
1386
|
+
via the family-scoped override below; the global card/panel size is untouched. */
|
|
1387
|
+
--dock-control-specular-size: 22%;
|
|
1388
|
+
|
|
1389
|
+
/* AX.W45 DK8 — the layer-switcher rail surface ladder. The rail
|
|
1390
|
+
(`.dock-layer-rail` inside a `<DockLayerGroup>`) gets its own quiet plate +
|
|
1391
|
+
a tunable hover/active affordance, replacing the raw `--primary 15%` /
|
|
1392
|
+
`--accent 40%` mixes the indicator/tab used against an absent plate. */
|
|
1393
|
+
--dock-layer-rail-bg: var(--surface-tint-8);
|
|
1394
|
+
--dock-layer-rail-hover: color-mix(in srgb, var(--accent) 40%, transparent);
|
|
1395
|
+
--dock-layer-rail-active: color-mix(in srgb, var(--primary) 15%, transparent);
|
|
1396
|
+
|
|
1397
|
+
/* Dock active-state ladder (O.W6 Lane B)
|
|
1398
|
+
Token-overridable active paint for `.dock-icon-button`. Promoted
|
|
1399
|
+
from hardcoded `background: var(--muted); color: var(--foreground)`
|
|
1400
|
+
per bbnf-buddy O11/c R1: 7 `:deep()` escapes at `ToolsLayer.vue`
|
|
1401
|
+
redefine bg/color/scale/border/shadow on the active variant; the
|
|
1402
|
+
ladder absorbs ~3 of 7 at a stroke. Defaults preserve the prior
|
|
1403
|
+
visual contract (no transform, no border, no shadow) — overrides
|
|
1404
|
+
take effect per-instance via `:root` or a parent scope, e.g.
|
|
1405
|
+
`.tools-layer { --dock-active-scale: 1.2; --dock-active-bg: …; }`.
|
|
1406
|
+
≥ 2-consumer coverage: bbnf-buddy ToolsLayer (override consumer) +
|
|
1407
|
+
speedtest dock (default consumer).
|
|
1408
|
+
|
|
1409
|
+
AX.W45 DK2 — re-pointed off the opaque `--muted` plate onto the glass-
|
|
1410
|
+
correct `--dock-control-active-bg` (a translucent tint a ladder step above
|
|
1411
|
+
hover), so the icon-button active no longer stamps a solid cream rectangle
|
|
1412
|
+
over the dock glass. The O.W6 active-ladder override consumers still retint
|
|
1413
|
+
per-instance; only the DEFAULT moved to glass-correct. */
|
|
1414
|
+
--dock-active-bg: var(--dock-control-active-bg);
|
|
1415
|
+
--dock-active-color: var(--foreground);
|
|
1416
|
+
--dock-active-scale: 1;
|
|
1417
|
+
--dock-active-border: none;
|
|
1418
|
+
--dock-active-shadow: none;
|
|
1419
|
+
|
|
1420
|
+
/* Q.W3 Lane G (Q-cos-13) — the O.W6 Lane D `--icon-tooltip-hit-area`
|
|
1421
|
+
token retired here. IconTooltip no longer owns a wrap-span; the
|
|
1422
|
+
slotted child carries its own WCAG 2.5.5 hit-area (interactive
|
|
1423
|
+
children via their four-state contract, bare glyphs via a
|
|
1424
|
+
`min-h-11 min-w-11` host). No orphaned token left behind. */
|
|
1425
|
+
|
|
1426
|
+
/* O.W6 Lane D — Dock touch-target floor. Mirrors the IconTooltip
|
|
1427
|
+
hit-area but for the dock-control surface. The base value tracks
|
|
1428
|
+
the desktop default (`--size-icon-btn`); the
|
|
1429
|
+
`@media (pointer: coarse)` block at `dock.css` lifts it to the
|
|
1430
|
+
WCAG 2.5.5 floor on touch devices. */
|
|
1431
|
+
--dock-touch-target: 2.75rem; /* 44px */
|
|
1432
|
+
|
|
1433
|
+
/* AQ.W3 §7 — canonical WCAG 2.5.5 (44px) touch-target floor for the
|
|
1434
|
+
NON-dock coarse-pointer surfaces (`Button size="icon"`,
|
|
1435
|
+
ExpandableContainer triggers, SegmentedTabs responsive mobile trigger). One
|
|
1436
|
+
named rung the `@media (pointer: coarse)` block in utilities.css reads,
|
|
1437
|
+
retiring the per-consumer one-liner `min-h-[44px]` patches. Equals
|
|
1438
|
+
`--dock-touch-target` numerically; kept as a distinct token so the
|
|
1439
|
+
dock floor and the general floor can be retuned independently. */
|
|
1440
|
+
--touch-target: 2.75rem; /* 44px */
|
|
1441
|
+
|
|
1442
|
+
/* MetricBadge — stacked variant geometry. The 2-row stacked layout
|
|
1443
|
+
(label / value+unit) wants a taller floor than the inline pill so the
|
|
1444
|
+
label has breathing room above the baseline pair. T.W2.T2 +
|
|
1445
|
+
audit B-spec §3.2 vertical-rhythm table land 42px (2.625rem) as the
|
|
1446
|
+
min-height with 6px (0.375rem) block padding. The inline ladder
|
|
1447
|
+
keeps its tight defaults via `--metric-badge-min-height` /
|
|
1448
|
+
`--metric-badge-padding-block` (declared inline at the
|
|
1449
|
+
`.metric-badge` selector). */
|
|
1450
|
+
--metric-badge-min-height-stacked: 2.625rem;
|
|
1451
|
+
--metric-badge-padding-block-stacked: 0.375rem;
|
|
1452
|
+
|
|
1453
|
+
/* Configurator — N.W2 Lane A density axis (4 rungs).
|
|
1454
|
+
The `comfortable` rung restates the pre-N.W2 baked recipe exactly
|
|
1455
|
+
(`gap-1.5 py-2` = 0.375rem / 0.5rem) so unparameterised consumers
|
|
1456
|
+
see no visual change. `mobile` halves the vertical breathing room
|
|
1457
|
+
for narrow-viewport studios; `spacious` doubles it for settings-
|
|
1458
|
+
page hosts. See `<ConfiguratorRow>` scoped CSS for the attribute-
|
|
1459
|
+
selector binding. */
|
|
1460
|
+
--configurator-row-gap-mobile: 0.25rem; /* 4px — tight */
|
|
1461
|
+
--configurator-row-gap-compact: 0.3125rem; /* 5px — slightly tighter */
|
|
1462
|
+
--configurator-row-gap-comfortable: 0.375rem; /* 6px — pre-N.W2 default */
|
|
1463
|
+
--configurator-row-gap-spacious: 0.75rem; /* 12px — generous */
|
|
1464
|
+
|
|
1465
|
+
--configurator-row-py-mobile: 0.25rem; /* 4px — tight */
|
|
1466
|
+
--configurator-row-py-compact: 0.375rem; /* 6px — slightly tighter */
|
|
1467
|
+
--configurator-row-py-comfortable: 0.5rem; /* 8px — pre-N.W2 default */
|
|
1468
|
+
--configurator-row-py-spacious: 0.875rem; /* 14px — generous */
|
|
1469
|
+
|
|
1470
|
+
/* Component font override (consumers override locally) */
|
|
1471
|
+
--select-font: inherit;
|
|
1472
|
+
|
|
1473
|
+
/* ═══════════════════════════════════════════════
|
|
1474
|
+
§11 INTERACTIVE SCALES & FOCUS
|
|
1475
|
+
═══════════════════════════════════════════════ */
|
|
1476
|
+
--scale-hover: 1.08;
|
|
1477
|
+
/* AX.W52 — the restrained BUTTON hover lift. `--scale-hover` (1.08) is an
|
|
1478
|
+
8% jump — emphatic for a marquee CTA, jarring as the general hover. The
|
|
1479
|
+
button family (the audacious CTAs + `btn-interactive`) lifts on the
|
|
1480
|
+
smaller `--scale-hover-btn` routed through `--spring-smooth` (the
|
|
1481
|
+
sub-perceptual settle, not the snappy bounce), so the hover reads as ONE
|
|
1482
|
+
coherent glide with the surface-leg cross-fade rather than a mechanical
|
|
1483
|
+
pop. The dock keeps its proportionally-larger `--scale-hover-dock` (small
|
|
1484
|
+
icon, bigger lift reads smaller).
|
|
1485
|
+
AX.W54 Q3 — lifted 1.035 → 1.05: the 1.035 overshot DOWN (W52 tamed the
|
|
1486
|
+
1.08 snap so hard the lift read as nothing), so the glass hover now reads
|
|
1487
|
+
as THREE legs together on hover — the specular gleam waking, a perceptible
|
|
1488
|
+
scale, and the bg/border cross-fade — distinguishable from rest BEFORE the
|
|
1489
|
+
click. Still sub-perceptual-bounce on `--spring-smooth`; the magnitude
|
|
1490
|
+
moved, the easing register did not. */
|
|
1491
|
+
--scale-hover-btn: 1.05;
|
|
1492
|
+
--scale-hover-dock: 1.1;
|
|
1493
|
+
--scale-press: 0.96;
|
|
1494
|
+
|
|
1495
|
+
/* Press-scale rungs. `--scale-press` (0.96) is the canonical iOS Liquid
|
|
1496
|
+
Glass press value every primitive reaches for unless it has a documented
|
|
1497
|
+
reason (DESIGN.md §L3); `--scale-press-btn` aliases the slightly-softer
|
|
1498
|
+
`--scale-press-sm` (0.97) the button + slider recipes consume.
|
|
1499
|
+
|
|
1500
|
+
AT.W7-dock-b — press canon. `--scale-press-dock` previously hard-coded a
|
|
1501
|
+
deeper 0.92 (a second magic press value with no documented rationale),
|
|
1502
|
+
so a dock control pressed visibly harder than every other primitive. It
|
|
1503
|
+
now references the canonical `--scale-press` (0.96) — ONE source for the
|
|
1504
|
+
press scale across the system. A consumer wanting the dock's old deeper
|
|
1505
|
+
press overrides `--scale-press-dock` on the dock instance. */
|
|
1506
|
+
--scale-press-dock: var(--scale-press);
|
|
1507
|
+
--scale-press-sm: 0.97;
|
|
1508
|
+
--scale-press-btn: var(--scale-press-sm);
|
|
1509
|
+
|
|
1510
|
+
/* AX.W53 — the SegmentedTabs travel-squish cap. The active indicator
|
|
1511
|
+
(segmented/pill slider OR the underline rule) STRETCHES along its travel
|
|
1512
|
+
axis as it glides between tabs, then settles to fit — the Material 3
|
|
1513
|
+
ELASTIC / Apple Liquid-Glass "controls insist on animating themselves"
|
|
1514
|
+
register, kept RESTRAINED. The deform is volume-preserving (stretch X,
|
|
1515
|
+
compress Y in lockstep: `scale: var(--stretch) calc(1 / var(--stretch))`)
|
|
1516
|
+
so it reads as an elastic warp, never a size pump. The cap holds the peak
|
|
1517
|
+
LOW (1.08 ≈ +8%) — iOS 26.2 dialed motion DOWN; a high-frequency control
|
|
1518
|
+
wants a whisper of squish, not a bounce. A consumer dials the elasticity
|
|
1519
|
+
(or to 1 for none) without touching source. */
|
|
1520
|
+
--tab-indicator-max-stretch: 1.08;
|
|
1521
|
+
--opacity-disabled: 0.5;
|
|
1522
|
+
--opacity-icon-muted: 0.8;
|
|
1523
|
+
|
|
1524
|
+
--focus-ring-width: 2px;
|
|
1525
|
+
/* D6.b — the focus-ring color routes through a `--focus-ring-color`
|
|
1526
|
+
indirection (default `--ring`, so the resolved shadow is byte-identical to
|
|
1527
|
+
the prior hard `--ring` recipe). An opt-in channel (the `focus-ring-gold`
|
|
1528
|
+
utility, utilities.css) overrides ONLY this color to mint a gilded
|
|
1529
|
+
"you are here / this is live" ring — gold is the transient STATE voice;
|
|
1530
|
+
the resting active mark stays its structural color (the four-voice law). */
|
|
1531
|
+
--focus-ring-color: var(--ring);
|
|
1532
|
+
--focus-ring-shadow: 0 0 0 var(--focus-ring-width) color-mix(in srgb, var(--focus-ring-color) 30%, transparent),
|
|
1533
|
+
0 0 8px color-mix(in srgb, var(--focus-ring-color) 15%, transparent);
|
|
1534
|
+
--focus-ring: var(--focus-ring-shadow);
|
|
1535
|
+
|
|
1536
|
+
/* ═══════════════════════════════════════════════
|
|
1537
|
+
§12 PAPER TEXTURES
|
|
1538
|
+
═══════════════════════════════════════════════ */
|
|
1539
|
+
/* Canonical subtle paper-texture opacity — restored from fourier-original
|
|
1540
|
+
(`4df1a06:web/src/style.css:53-54`) after A.W3.5.ab confirmed the
|
|
1541
|
+
heretofore `opacity='1'` URI rendered as an overt grain field in every
|
|
1542
|
+
downstream consumer of `.paper-texture`. The SVG `opacity` attribute is
|
|
1543
|
+
baked at parse-time and cannot read a CSS var, so the subtle value must
|
|
1544
|
+
be inlined; if a consumer needs a heavier overlay, they should layer
|
|
1545
|
+
a wrapper element with its own `opacity:`/`mix-blend-mode:` atop. */
|
|
1546
|
+
--paper-clean-texture: url("data:image/svg+xml,%3Csvg width='200' height='200' viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.65' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
|
|
1547
|
+
--paper-aged-texture: url("data:image/svg+xml,%3Csvg width='200' height='200' viewBox='0 0 200 200' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.5' numOctaves='5' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E");
|
|
1548
|
+
|
|
1549
|
+
/* ═══════════════════════════════════════════════
|
|
1550
|
+
§13 GOLD (accent family kept for consumers using it)
|
|
1551
|
+
═══════════════════════════════════════════════ */
|
|
1552
|
+
--gold: oklch(0.751 0.147 84.2);
|
|
1553
|
+
--gold-light: oklch(0.890 0.183 96.1);
|
|
1554
|
+
--gold-dark: oklch(0.599 0.132 64.2);
|
|
1555
|
+
/* AY.W-PRIM-POLISH D1 — the saturated CTA plate the AW.W13 gold-CTA contract
|
|
1556
|
+
names. A FIXED deep gold (mode-INVARIANT — the gold-CTA hover backplate must
|
|
1557
|
+
be dark in BOTH modes so the white label clears ≥4.5:1; deepening toward the
|
|
1558
|
+
mode-flipping `--foreground` brightened the dark plate to a cream-gold and
|
|
1559
|
+
broke dark). ~`--gold-dark` deepened toward warm-ink → ~rgb(120,87,45),
|
|
1560
|
+
6.5:1 white in light / 5.5:1 in dark. The opaque base of `btn-audacious-gold`
|
|
1561
|
+
:hover. */
|
|
1562
|
+
--gold-deep: oklch(0.487 0.103 63.0);
|
|
1563
|
+
|
|
1564
|
+
/* D6.b — the chrome-gold additions (the rim + the legible ink), completing
|
|
1565
|
+
the gold quad into the gilt FAMILY. Gold is a metal, not a hue — it must
|
|
1566
|
+
read as reflectance, so it lives at the EDGE and the HIGHLIGHT, rarely as
|
|
1567
|
+
an area.
|
|
1568
|
+
|
|
1569
|
+
--gold-rim — the gilt EDGE catch: `--gold` at 40% over the surface, the
|
|
1570
|
+
1px tooled bevel light the `.glass-gilt` modifier + the gilt dock button
|
|
1571
|
+
paint. Non-text → no contrast floor.
|
|
1572
|
+
|
|
1573
|
+
--gold-ink — legible gold-toned TEXT. Derived (NOT guessed) to clear the
|
|
1574
|
+
cream-law ② floor (APCA |Lc| ≥ 45) against `--card` in BOTH arms; the raw
|
|
1575
|
+
`--gold-dark` does not (it was minted as a plate hue). LIGHT arm:
|
|
1576
|
+
oklch(0.560 0.118 70) → |Lc| 69.9 on the cream `--card` (hsl 48 12% 98%).
|
|
1577
|
+
The dark-arm pair lifts L (the warm-dark stock) in the `.dark` block,
|
|
1578
|
+
reaching |Lc| 77.1 on the dark `--card`. Both verified by
|
|
1579
|
+
`proof:gold-ink-contrast`. */
|
|
1580
|
+
--gold-rim: color-mix(in oklab, var(--gold) 40%, transparent);
|
|
1581
|
+
--gold-ink: oklch(0.560 0.118 70);
|
|
1582
|
+
|
|
1583
|
+
--color-gold: var(--gold);
|
|
1584
|
+
--color-gold-light: var(--gold-light);
|
|
1585
|
+
--color-gold-dark: var(--gold-dark);
|
|
1586
|
+
--color-gold-deep: var(--gold-deep);
|
|
1587
|
+
--color-gold-rim: var(--gold-rim);
|
|
1588
|
+
--color-gold-ink: var(--gold-ink);
|
|
1589
|
+
|
|
1590
|
+
/* ═══════════════════════════════════════════════
|
|
1591
|
+
§14 RAINBOW PALETTE — oklch (AV.W16 TW2; mode-independent, no .dark
|
|
1592
|
+
mirror; hue preserved from the prior hsl() cadence)
|
|
1593
|
+
═══════════════════════════════════════════════ */
|
|
1594
|
+
--rainbow-red: oklch(0.636 0.210 25.5);
|
|
1595
|
+
--rainbow-orange: oklch(0.737 0.163 58.9);
|
|
1596
|
+
--rainbow-yellow: oklch(0.900 0.183 103.7);
|
|
1597
|
+
--rainbow-green: oklch(0.772 0.233 144.8);
|
|
1598
|
+
--rainbow-blue: oklch(0.633 0.162 252.1);
|
|
1599
|
+
--rainbow-indigo: oklch(0.566 0.206 294.1);
|
|
1600
|
+
--rainbow-violet: oklch(0.684 0.250 327.9);
|
|
1601
|
+
|
|
1602
|
+
--rainbow-pastel-red: oklch(0.793 0.066 18.7);
|
|
1603
|
+
--rainbow-pastel-orange: oklch(0.823 0.059 57.3);
|
|
1604
|
+
--rainbow-pastel-yellow: oklch(0.889 0.068 98.1);
|
|
1605
|
+
--rainbow-pastel-green: oklch(0.826 0.072 149.5);
|
|
1606
|
+
--rainbow-pastel-blue: oklch(0.783 0.056 264.2);
|
|
1607
|
+
--rainbow-pastel-indigo: oklch(0.772 0.062 300.2);
|
|
1608
|
+
--rainbow-pastel-violet: oklch(0.799 0.070 314.4);
|
|
1609
|
+
|
|
1610
|
+
/* ═══════════════════════════════════════════════
|
|
1611
|
+
§16 TIMELINE
|
|
1612
|
+
Timeline primitive tokens. All three variants (scrubber +
|
|
1613
|
+
segmented + continuous) compose these. Both segmented + continuous
|
|
1614
|
+
arrays carry the same `TimelineSegment[]` data shape; only the
|
|
1615
|
+
rendering geometry differs. See DESIGN.md `## Timeline Primitive`.
|
|
1616
|
+
═══════════════════════════════════════════════ */
|
|
1617
|
+
|
|
1618
|
+
/* Heights — per-variant rail thickness */
|
|
1619
|
+
--timeline-scrubber-height: 0.5rem; /* 8px — single-track scrubber */
|
|
1620
|
+
--timeline-segmented-height: 0.625rem; /* 10px — N adjacent bands */
|
|
1621
|
+
--timeline-continuous-height: 0.75rem; /* 12px — ONE pill, N regions */
|
|
1622
|
+
|
|
1623
|
+
/* Geometry — shared across all variants */
|
|
1624
|
+
--timeline-dot-size: 0.875rem; /* 14px — boundary dot diameter (pointer: fine) */
|
|
1625
|
+
--timeline-dot-size-touch: 1.25rem; /* 20px — boundary dot diameter (pointer: coarse) */
|
|
1626
|
+
--timeline-touch-target: 44px; /* AC.W6d F2.I-04 — WCAG 2.5.5 target-size floor.
|
|
1627
|
+
The `::before` halo around each dot extends to
|
|
1628
|
+
this dimension so finger-precision users meet
|
|
1629
|
+
the (target-size: 44×44 minimum) clause without
|
|
1630
|
+
the visible dot growing to that footprint at
|
|
1631
|
+
pointer: fine. */
|
|
1632
|
+
--timeline-segment-flex: 1 1 0; /* per-cell flex distribution (segmented) */
|
|
1633
|
+
|
|
1634
|
+
/* Boundary-dot glass knobs (Q.W4 Lane B — promoted from
|
|
1635
|
+
ContinuousTimeline.vue SFC fallbacks; `3cb70db` minted these as a
|
|
1636
|
+
private dialect). The continuous-variant dot is a GLASS primitive:
|
|
1637
|
+
a translucent tinted fill over a backdrop blur with a hairline
|
|
1638
|
+
ring. These knobs let consumers retune the resting glass + the
|
|
1639
|
+
per-state tints without a `:deep()` reach.
|
|
1640
|
+
fill — resting translucent fill
|
|
1641
|
+
blur — backdrop blur tier behind the dot
|
|
1642
|
+
ring — hairline glass ring (border-color)
|
|
1643
|
+
tint-current — wash colour for the active-phase dot
|
|
1644
|
+
tint-completed — wash colour for the completed-phase dot
|
|
1645
|
+
check-color — completion-tick stroke (defaults to the
|
|
1646
|
+
completed tint) */
|
|
1647
|
+
--timeline-dot-fill: var(--surface-tint-12);
|
|
1648
|
+
--timeline-dot-blur: var(--glass-blur-quiet);
|
|
1649
|
+
--timeline-dot-ring: var(--glass-border-floating);
|
|
1650
|
+
--timeline-dot-tint-current: var(--accent, var(--foreground));
|
|
1651
|
+
--timeline-dot-tint-completed: var(--success, var(--foreground));
|
|
1652
|
+
--timeline-dot-check-color: var(--timeline-dot-tint-completed);
|
|
1653
|
+
|
|
1654
|
+
/* Continuous-variant specific — seam dividers between regions.
|
|
1655
|
+
Set `--timeline-continuous-seam-opacity: 0` to suppress the
|
|
1656
|
+
inter-region 1px dividers entirely. Default `0.25` reads as a
|
|
1657
|
+
subtle hairline; the `--timeline-continuous-seam-color` knob lets
|
|
1658
|
+
consumers override the seam tint independently of opacity. */
|
|
1659
|
+
--timeline-continuous-seam-opacity: 0.25;
|
|
1660
|
+
--timeline-continuous-seam-color: color-mix(
|
|
1661
|
+
in srgb,
|
|
1662
|
+
var(--foreground) calc(var(--timeline-continuous-seam-opacity) * 100%),
|
|
1663
|
+
transparent
|
|
1664
|
+
);
|
|
1665
|
+
|
|
1666
|
+
/* Per-segment default gradient fallback — applied when a segment
|
|
1667
|
+
omits its `gradient` field. Consumers can override per-phase via
|
|
1668
|
+
the `--timeline-segment-gradient-{key}` knobs below. */
|
|
1669
|
+
--timeline-segment-default-gradient: linear-gradient(
|
|
1670
|
+
90deg,
|
|
1671
|
+
var(--surface-tint-15),
|
|
1672
|
+
var(--surface-tint-25)
|
|
1673
|
+
);
|
|
1674
|
+
|
|
1675
|
+
/* Per-phase gradient defaults — paint the canonical chart palette
|
|
1676
|
+
at the gradient leading edge, fading to a 60%-opacity tail. The
|
|
1677
|
+
speedtest consumer wires these via `gradient: "var(--timeline-segment-gradient-ping)"`
|
|
1678
|
+
per segment; the same names work for any consumer who follows the
|
|
1679
|
+
ping/download/upload/jitter taxonomy. */
|
|
1680
|
+
--timeline-segment-gradient-ping: linear-gradient(
|
|
1681
|
+
90deg,
|
|
1682
|
+
var(--chart-ping),
|
|
1683
|
+
color-mix(in srgb, var(--chart-ping) 60%, transparent)
|
|
1684
|
+
);
|
|
1685
|
+
--timeline-segment-gradient-download: linear-gradient(
|
|
1686
|
+
90deg,
|
|
1687
|
+
var(--chart-download),
|
|
1688
|
+
color-mix(in srgb, var(--chart-download) 60%, transparent)
|
|
1689
|
+
);
|
|
1690
|
+
--timeline-segment-gradient-upload: linear-gradient(
|
|
1691
|
+
90deg,
|
|
1692
|
+
var(--chart-upload),
|
|
1693
|
+
color-mix(in srgb, var(--chart-upload) 60%, transparent)
|
|
1694
|
+
);
|
|
1695
|
+
--timeline-segment-gradient-jitter: linear-gradient(
|
|
1696
|
+
90deg,
|
|
1697
|
+
var(--chart-jitter),
|
|
1698
|
+
color-mix(in srgb, var(--chart-jitter) 60%, transparent)
|
|
1699
|
+
);
|
|
1700
|
+
|
|
1701
|
+
/* ═══════════════════════════════════════════════
|
|
1702
|
+
§17 METRIC
|
|
1703
|
+
|
|
1704
|
+
MetricRow / MetricStack value-clamp dialect. The declared values are the
|
|
1705
|
+
`audacious` poster register — the hero-scale clamp for a single giant
|
|
1706
|
+
number; MetricStack's `[data-register="result"]` selector overrides it
|
|
1707
|
+
locally for the compact multi-row ledger. Three clamp arms each: `min`
|
|
1708
|
+
(floor), `cqi` (the binding container-query middle term), `max`
|
|
1709
|
+
(ceiling); unit carries min/max only (its cqi is a fixed 6cqi).
|
|
1710
|
+
═══════════════════════════════════════════════ */
|
|
1711
|
+
|
|
1712
|
+
/* Value register — audacious-poster hero clamp */
|
|
1713
|
+
--metric-row-value-clamp-min: 4.5rem;
|
|
1714
|
+
--metric-row-value-clamp-cqi: 34cqi;
|
|
1715
|
+
--metric-row-value-clamp-max: var(--type-display-hero);
|
|
1716
|
+
|
|
1717
|
+
/* Unit register — one tier below the value it qualifies */
|
|
1718
|
+
--metric-row-unit-clamp-min: 1.5rem;
|
|
1719
|
+
--metric-row-unit-clamp-max: 3.25rem;
|
|
1720
|
+
|
|
1721
|
+
/* Label register — uppercase, the binding row-height term in the
|
|
1722
|
+
compact `result` register */
|
|
1723
|
+
--metric-row-label-clamp-min: 1.125rem;
|
|
1724
|
+
--metric-row-label-clamp-cqi: 5cqi;
|
|
1725
|
+
--metric-row-label-clamp-max: 2.75rem;
|
|
1726
|
+
|
|
1727
|
+
/* ═══════════════════════════════════════════════
|
|
1728
|
+
§2.D INSTRUMENT-CLUSTER COMPOSITION RHYTHM
|
|
1729
|
+
|
|
1730
|
+
The instrument-chassis family owns the under-meter / progress-cluster
|
|
1731
|
+
grammar.
|
|
1732
|
+
|
|
1733
|
+
• `--meter-progress-inset` — the negative-margin inset that pulls the
|
|
1734
|
+
under-meter bar INTO the unpainted ring lane around the dial canvas
|
|
1735
|
+
(~4% of meter-size). Consumed at `.phase-progress` via
|
|
1736
|
+
`margin-block-start: calc(-1 * var(--meter-progress-inset))`. The
|
|
1737
|
+
`--meter-size` reference resolves against the consumer's own
|
|
1738
|
+
declaration; the 200px fallback keeps the calc well-defined.
|
|
1739
|
+
• `--progress-stack-gap` — vertical rhythm between any two stacked
|
|
1740
|
+
progress rails inside one cluster.
|
|
1741
|
+
═══════════════════════════════════════════════ */
|
|
1742
|
+
--meter-progress-inset: calc(var(--meter-size, 200px) * 0.04);
|
|
1743
|
+
--progress-stack-gap: clamp(0.1875rem, 0.4cqi, 0.375rem);
|
|
1744
|
+
|
|
1745
|
+
/* ═══════════════════════════════════════════════
|
|
1746
|
+
§2.E CELEBRATION-TIER REGISTER
|
|
1747
|
+
|
|
1748
|
+
Shared peak for any "completion" / "thank-you" surface.
|
|
1749
|
+
|
|
1750
|
+
• `--celebration-row-rhythm` — gap between the cluster's rows (cqi-axis).
|
|
1751
|
+
• `--text-celebration-headline-size` — the single designed peak both
|
|
1752
|
+
celebration surfaces clamp toward (cqi-axis).
|
|
1753
|
+
• `--complete-headline-size` — the per-consumer font-size hook a consumer
|
|
1754
|
+
assigns the canon clamp to so its headline pegs at the shared peak;
|
|
1755
|
+
the default falls back to a smaller hero-rung clamp.
|
|
1756
|
+
═══════════════════════════════════════════════ */
|
|
1757
|
+
--celebration-row-rhythm: clamp(0.5rem, 1.6cqi, 1rem);
|
|
1758
|
+
--text-celebration-headline-size: clamp(2.5rem, 12cqi, 9rem);
|
|
1759
|
+
--complete-headline-size: clamp(2.25rem, 11cqi, 4rem);
|
|
1760
|
+
|
|
1761
|
+
/* ═══════════════════════════════════════════════
|
|
1762
|
+
§19 TABLE DENSITY
|
|
1763
|
+
|
|
1764
|
+
A single unitless knob `--table-density` scales the cell padding +
|
|
1765
|
+
header row height of the Table / DataTable primitive. Default `1`
|
|
1766
|
+
resolves to 1rem cell padding + 3rem header height; 0.75 is a compact
|
|
1767
|
+
admin table, 1.25 is comfortable/touch-friendly. The derived tokens are
|
|
1768
|
+
read by the `table-cell` / `table-head` utilities; changing the knob
|
|
1769
|
+
cascades instantly via CSS inheritance — no JS prop needed.
|
|
1770
|
+
═══════════════════════════════════════════════ */
|
|
1771
|
+
--table-density: 1;
|
|
1772
|
+
--table-cell-px: calc(1rem * var(--table-density));
|
|
1773
|
+
--table-cell-py: calc(1rem * var(--table-density));
|
|
1774
|
+
--table-head-h: calc(3rem * var(--table-density));
|
|
1775
|
+
--table-head-px: calc(1rem * var(--table-density));
|
|
1776
|
+
|
|
1777
|
+
/* ═══════════════════════════════════════════════
|
|
1778
|
+
§20 PLATFORM MOTION (AQ.W5)
|
|
1779
|
+
|
|
1780
|
+
The native-platform motion substrate axes. Three families, each read
|
|
1781
|
+
by a `@supports`-gated CSS recipe in `scroll-driven.css`,
|
|
1782
|
+
`animations.css` (§TOP-LAYER), and `view-transition.css` — every visual
|
|
1783
|
+
knob a token so a consumer retunes without editing library source.
|
|
1784
|
+
|
|
1785
|
+
SCROLL-DRIVEN (scroll-driven.css). Values mirror the JS-fallback
|
|
1786
|
+
composable defaults (`useScrollProgress` / `useStaggerReveal`) so the
|
|
1787
|
+
native CSS path and the fallback path read identically — no visual seam
|
|
1788
|
+
at the `@supports` boundary.
|
|
1789
|
+
|
|
1790
|
+
TOP-LAYER (animations.css §TOP-LAYER). The `@starting-style` entry/exit
|
|
1791
|
+
grammar for native `<dialog>` / `[popover]` glass surfaces. Backdrop dim
|
|
1792
|
+
uses the `hsl(var(--background) / α)` channel form — the legitimate
|
|
1793
|
+
single-token alpha case (AQ.W2's color-mix migration is orthogonal).
|
|
1794
|
+
|
|
1795
|
+
VIEW-TRANSITION (view-transition.css). The shared `.gl-list-item` group
|
|
1796
|
+
recipe + the `--vt-*` axes the `useViewTransition` substrate consumers
|
|
1797
|
+
(dock layer swap, muster J's verdict re-rank) tune their swap against.
|
|
1798
|
+
═══════════════════════════════════════════════ */
|
|
1799
|
+
--scroll-progress-scroller: root;
|
|
1800
|
+
--scroll-reveal-rise: 6px;
|
|
1801
|
+
--scroll-reveal-range-end: 60%;
|
|
1802
|
+
|
|
1803
|
+
--top-layer-enter-scale: 0.96;
|
|
1804
|
+
--top-layer-backdrop-blur: 8px;
|
|
1805
|
+
--top-layer-backdrop-dim: 0.5;
|
|
1806
|
+
|
|
1807
|
+
--vt-duration: var(--duration-normal);
|
|
1808
|
+
/* AX.W05 — ONE iOS-spring vocabulary: every spring-flavored transition reads
|
|
1809
|
+
a governed `--spring-*` register. The legacy apple-spring cubic-bezier
|
|
1810
|
+
(+27.5% overshoot) was a SECOND authority beside the regen `--spring-*`
|
|
1811
|
+
cohort; it is EXCISED. Its emphatic-overshoot register maps to the playful
|
|
1812
|
+
`--spring-bouncy` (the closest `linear()` overshoot stop-set), so the VT
|
|
1813
|
+
default + the cards/top-layer transitions share one spring primitive
|
|
1814
|
+
(CPU + GPU sample the same curve). No cubic-bezier fallback seed survives —
|
|
1815
|
+
the `linear()` spring degrades to `ease` where `linear()` is unsupported. */
|
|
1816
|
+
--vt-ease: var(--spring-bouncy);
|
|
1817
|
+
--vt-rise: 8px;
|
|
1818
|
+
|
|
1819
|
+
/* AT.W6-dock-c / AU.W8 — the dock layer-swap morph timing, minted ONCE so
|
|
1820
|
+
both engine paths are timing-IDENTICAL: the FLIP fallback (via
|
|
1821
|
+
`--dock-motion-resize`), the native View-Transition group (its
|
|
1822
|
+
`animation-timing-function`), AND the runtime SpringProgress driver
|
|
1823
|
+
(AU.W8.3) consume this same `(0.32, 0.7)` source curve. Retires the AQ.W6
|
|
1824
|
+
fork where the VT path ran `--vt-ease` (apple-spring, +27.5% overshoot)
|
|
1825
|
+
while the FLIP ran the snappy spring. `--vt-ease` still defaults the
|
|
1826
|
+
other VT recipes (`.gl-list-item`).
|
|
1827
|
+
|
|
1828
|
+
AU.W8 — RETARGET snappy → dock. `--spring-snappy` (ζ=0.65, +6.8%) read as
|
|
1829
|
+
mechanical: a stiff plateau at ~48% with too little overshoot to feel
|
|
1830
|
+
alive ("not iOS-smooth"). AW.W2 then retuned the dock spring to the
|
|
1831
|
+
iOS-control register: `--spring-dock` ((0.32, 0.7), ~+4.6%) settles snappy
|
|
1832
|
+
with a restrained overshoot — the felt iOS dock morph, off the prior
|
|
1833
|
+
playful +18.5% register. The runtime driver's DOCK_SPRING const MIRRORS the
|
|
1834
|
+
(0.32, 0.7) PRESETS row, so the CSS token and the JS-driven morph are
|
|
1835
|
+
bit-identical. */
|
|
1836
|
+
--dock-resize-spring: var(--spring-dock);
|
|
1837
|
+
|
|
1838
|
+
/* AT.W7-dock-b — dock-control press micro-feedback spring. A TRANSFORM-ONLY
|
|
1839
|
+
spring (`scale`/`rotate`) the dock controls apply to their hover/press
|
|
1840
|
+
activation so the squish reads with a touch of spring-back rather than a
|
|
1841
|
+
flat ease. STRICTLY transform-scoped: it must never touch the surface-tier
|
|
1842
|
+
`[data-held]` fades (background/border/box-shadow), which stay on
|
|
1843
|
+
`--duration-fast var(--ease-standard)`. The duration pairs with
|
|
1844
|
+
`--duration-fast`; consumers retune the whole feel via this one token.
|
|
1845
|
+
|
|
1846
|
+
AY.W-DOCK2 (D6) — the register is `--spring-smooth`, the §6 easing-doctrine
|
|
1847
|
+
transform-press register (tokens.css §2: transform hover/press/active →
|
|
1848
|
+
`--spring-smooth`/`--spring-snappy`, NEVER `--spring-bouncy`; a press must
|
|
1849
|
+
settle, never overshoot into a visible bounce). The prior `--spring-bouncy`
|
|
1850
|
+
ROOT default was off-doctrine, shadowed for the four named controls by a
|
|
1851
|
+
per-surface re-point in dock-controls.css — the exact per-surface fork the
|
|
1852
|
+
doctrine kills. The re-point is now a DEAD byte-identical redeclaration and is
|
|
1853
|
+
DELETED; the ROOT token IS the doctrine register, so any other consumer of
|
|
1854
|
+
`--dock-press-spring` inherits the correct smooth register. */
|
|
1855
|
+
--dock-press-spring: var(--duration-fast) var(--spring-smooth);
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
/* AX.W51 D18 — the GLOBAL coarse-pointer comfort amplification. The WHOLE library
|
|
1859
|
+
— buttons, inputs, badges, toggles, the dock (a specialization that reads
|
|
1860
|
+
`--ui-scale`) — grows ~1.5× on touch from this ONE place, the W45 dock-only 1.5×
|
|
1861
|
+
lifted to the master scalar so the touch scale is CONSISTENT across the library
|
|
1862
|
+
(at HEAD the dock grew but the buttons did not — the three-scale split). The
|
|
1863
|
+
WCAG-2.5.5 44px touch floor is enforced HERE too: `--control-floor` lifts to
|
|
1864
|
+
`--touch-target`, so every scaled control-height `max(scaled, floor)` clamps at
|
|
1865
|
+
≥ 44px regardless of the scalar (a consumer dialing `--ui-scale` below 1 still
|
|
1866
|
+
cannot drop a control under the target). Fine-pointer is byte-identical
|
|
1867
|
+
(`--ui-scale` stays 1). `--ui-coarse-scale` is the public default a consumer
|
|
1868
|
+
retunes. */
|
|
1869
|
+
@media (pointer: coarse) {
|
|
1870
|
+
:root {
|
|
1871
|
+
--ui-scale: var(--ui-coarse-scale, 1.5);
|
|
1872
|
+
--control-floor: var(--touch-target, 2.75rem);
|
|
1873
|
+
}
|
|
1874
|
+
}
|
|
1875
|
+
|
|
1876
|
+
/* AV.W7 F2 — high-resolution overlay-blur restore. On a 2dppx+ display the
|
|
1877
|
+
richer 24px overlay wash is amortised by the extra device pixels (the blur
|
|
1878
|
+
samples a denser backing store), so the design ceiling is restored where it
|
|
1879
|
+
is affordable. Standard-density displays keep the 15px budget radius set in
|
|
1880
|
+
§-1a `:root`. Token-only override — every overlay surface that reads
|
|
1881
|
+
`--glass-blur-overlay-radius` inherits the restored value automatically. */
|
|
1882
|
+
@media (min-resolution: 2dppx) {
|
|
1883
|
+
:root {
|
|
1884
|
+
--glass-blur-overlay-radius: 24px;
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
|
|
1888
|
+
/* ═══════════════════════════════════════════════
|
|
1889
|
+
§-1b LIGHT-DARK() COLOR ARCHITECTURE (AQ.W2 §2)
|
|
1890
|
+
|
|
1891
|
+
Every PAIRED color token (a token whose `:root` and `.dark` values are
|
|
1892
|
+
BOTH a <color> and differ) folds onto one `light-dark(light, dark)`
|
|
1893
|
+
declaration, keyed off the element's `color-scheme` (§-1). This is the
|
|
1894
|
+
single-source-of-truth collapse of the `.dark` mirror AND the dynamism
|
|
1895
|
+
win: an unregistered custom property holding a `light-dark()` expression
|
|
1896
|
+
re-resolves under a descendant `color-scheme` override (a `.dark`
|
|
1897
|
+
code-block embedded in a light page, or vice-versa).
|
|
1898
|
+
|
|
1899
|
+
DISCIPLINE (§2b — BINDING): these tokens MUST stay UNREGISTERED (no
|
|
1900
|
+
`@property … syntax:"<color>"`). A registered <color> would resolve ONCE
|
|
1901
|
+
at the declaring element and inherit the RESOLVED color, freezing the
|
|
1902
|
+
descendant re-resolution. glass-ui's only `@property` registrations (§18)
|
|
1903
|
+
are non-color (percentage/length), so the discipline holds — W2 adds NO
|
|
1904
|
+
color `@property`.
|
|
1905
|
+
|
|
1906
|
+
The semantic `var()`-aliases (`--background`, `--muted`, `--border`,
|
|
1907
|
+
`--secondary`, `--accent`, `--card-foreground`, …) do NOT appear here:
|
|
1908
|
+
they point at the SAME source name in both modes and auto-track once the
|
|
1909
|
+
`--neutral-*` ladder + `--foreground` resolve via `light-dark()`. Their
|
|
1910
|
+
redundant `.dark` re-declarations DELETE below.
|
|
1911
|
+
|
|
1912
|
+
FALLBACK (§2c): this whole block is `@supports`-gated, so an engine
|
|
1913
|
+
WITHOUT `light-dark()` skips it and the retained `.dark` class block (the
|
|
1914
|
+
SOLE fallback floor) drives dark exactly as at HEAD. `light-dark()` is the
|
|
1915
|
+
enhancement OVER the class — not a parallel alias. Baseline Newly
|
|
1916
|
+
Available; the fallback floor is the pre-existing class block (net-zero
|
|
1917
|
+
new fallback LOC).
|
|
1918
|
+
═══════════════════════════════════════════════ */
|
|
1919
|
+
@supports (color: light-dark(white, black)) {
|
|
1920
|
+
:root {
|
|
1921
|
+
/* Neutral ladder — the source the var()-aliases track */
|
|
1922
|
+
--neutral-0: light-dark(hsl(48 12% 98%), hsl(24 8% 6%));
|
|
1923
|
+
--neutral-1: light-dark(hsl(48 10% 95%), hsl(24 6% 11%));
|
|
1924
|
+
--neutral-2: light-dark(hsl(48 9% 90%), hsl(24 5% 16%));
|
|
1925
|
+
--neutral-3: light-dark(hsl(48 8% 82%), hsl(24 5% 22%));
|
|
1926
|
+
--neutral-4: light-dark(hsl(48 7% 70%), hsl(24 5% 34%));
|
|
1927
|
+
--neutral-5: light-dark(hsl(48 6% 40%), hsl(48 5% 62%));
|
|
1928
|
+
--neutral-6: light-dark(hsl(48 7% 30%), hsl(48 6% 72%));
|
|
1929
|
+
|
|
1930
|
+
/* Core surfaces + ink */
|
|
1931
|
+
--foreground: light-dark(hsl(24 10% 10%), hsl(48 10% 90%));
|
|
1932
|
+
--card: light-dark(var(--neutral-0), hsl(24 8% 10%));
|
|
1933
|
+
--popover: light-dark(var(--neutral-0), hsl(24 8% 10%));
|
|
1934
|
+
--surface-public-data-panel: light-dark(hsl(44 16% 96%), hsl(36 9% 12%));
|
|
1935
|
+
|
|
1936
|
+
--primary: light-dark(hsl(24 10% 10%), hsl(48 10% 90%));
|
|
1937
|
+
--primary-foreground: light-dark(var(--neutral-0), hsl(24 10% 10%));
|
|
1938
|
+
/* AX.W44 — dark-arm lift. The stock shadcn dark `hsl(0 62.8% 30.6%)`
|
|
1939
|
+
(L≈30.6) was a saturated-PLATE value used AS INK over `--card` by the
|
|
1940
|
+
Alert destructive variant — 1.75:1 over card (illegible) / 1.91:1 vs the
|
|
1941
|
+
page. Lifted to `hsl(0 80% 60%)`: 4.60:1 as text over `--card` (clears the
|
|
1942
|
+
4.5 body floor) AND 5.03:1 as a plate vs the dark page (clears the 3.0
|
|
1943
|
+
graphic floor). The light arm is UNCHANGED (already 4.70:1). Lockstep with
|
|
1944
|
+
the `.dark` fallback floor below (§2c). */
|
|
1945
|
+
--destructive: light-dark(hsl(0 72% 50%), hsl(0 80% 60%));
|
|
1946
|
+
--destructive-foreground: light-dark(var(--neutral-0), hsl(48 10% 90%));
|
|
1947
|
+
--ring: light-dark(hsl(24 10% 10%), hsl(48 10% 70%));
|
|
1948
|
+
--shadow: light-dark(hsl(24 10% 10%), hsl(0 0% 5%));
|
|
1949
|
+
|
|
1950
|
+
/* §4 native-control accent — the per-mode arms (dark reads the
|
|
1951
|
+
mid-tone ring for checkmark-glyph contrast headroom, NOT the
|
|
1952
|
+
near-white dark primary). Joins the light-dark() collapse; still
|
|
1953
|
+
re-specified as `accent-color` inside `.dark` per §2b. */
|
|
1954
|
+
--accent-color: light-dark(var(--primary), var(--ring));
|
|
1955
|
+
|
|
1956
|
+
/* Section palette — jewel tones brightened L for dark (oklch pairs;
|
|
1957
|
+
AV.W16 TW2 — hue preserved, L evened) */
|
|
1958
|
+
--section-color-0: light-dark(oklch(0.552 0.192 359.8), oklch(0.721 0.145 354.0));
|
|
1959
|
+
--section-color-1: light-dark(oklch(0.502 0.165 305.9), oklch(0.733 0.113 308.2));
|
|
1960
|
+
--section-color-2: light-dark(oklch(0.484 0.163 265.5), oklch(0.718 0.107 268.4));
|
|
1961
|
+
--section-color-3: light-dark(oklch(0.542 0.089 222.8), oklch(0.767 0.091 219.9));
|
|
1962
|
+
--section-color-4: light-dark(oklch(0.551 0.088 171.1), oklch(0.776 0.105 172.6));
|
|
1963
|
+
--section-color-5: light-dark(oklch(0.623 0.124 69.6), oklch(0.813 0.109 78.2));
|
|
1964
|
+
--section-color-6: light-dark(oklch(0.579 0.201 30.4), oklch(0.693 0.151 28.1));
|
|
1965
|
+
--section-color-7: light-dark(oklch(0.532 0.180 317.5), oklch(0.739 0.134 318.1));
|
|
1966
|
+
--section-color-8: light-dark(oklch(0.520 0.176 8.4), oklch(0.709 0.142 2.3));
|
|
1967
|
+
--section-color-9: light-dark(oklch(0.492 0.038 239.6), oklch(0.763 0.032 239.0));
|
|
1968
|
+
--section-color-10: light-dark(oklch(0.556 0.103 128.8), oklch(0.794 0.116 127.9));
|
|
1969
|
+
--section-color-11: light-dark(oklch(0.601 0.092 208.0), oklch(0.805 0.095 206.7));
|
|
1970
|
+
--section-color-12: light-dark(oklch(0.513 0.163 291.9), oklch(0.719 0.115 295.6));
|
|
1971
|
+
|
|
1972
|
+
--accent-pink: light-dark(oklch(0.613 0.197 353.8), oklch(0.683 0.131 354.7));
|
|
1973
|
+
--section-heading: light-dark(oklch(0.545 0.189 352.8), oklch(0.711 0.123 349.3));
|
|
1974
|
+
--accent-red: light-dark(oklch(0.574 0.216 27.5), oklch(0.644 0.165 22.9));
|
|
1975
|
+
|
|
1976
|
+
/* Viz basis (amber/green stay var()-aliases → auto-track) */
|
|
1977
|
+
--viz-fourier: light-dark(oklch(0.579 0.201 30.4), oklch(0.693 0.151 28.1));
|
|
1978
|
+
--viz-chebyshev: light-dark(oklch(0.484 0.163 265.5), oklch(0.718 0.107 268.4));
|
|
1979
|
+
--viz-legendre: light-dark(oklch(0.532 0.180 317.5), oklch(0.739 0.134 318.1));
|
|
1980
|
+
|
|
1981
|
+
/* WCAG companion chart labels */
|
|
1982
|
+
--chart-ping-label: light-dark(oklch(0.40 0.18 230), oklch(0.85 0.12 230));
|
|
1983
|
+
--chart-download-label: light-dark(oklch(0.40 0.20 22), oklch(0.85 0.14 22));
|
|
1984
|
+
--chart-upload-label: light-dark(oklch(0.40 0.16 55), oklch(0.85 0.12 55));
|
|
1985
|
+
--chart-jitter-label: light-dark(oklch(0.40 0.20 305), oklch(0.85 0.14 305));
|
|
1986
|
+
|
|
1987
|
+
/* Semantic UI accents */
|
|
1988
|
+
--tier-featured: light-dark(oklch(0.841 0.173 84.2), oklch(0.867 0.165 88.7));
|
|
1989
|
+
--tier-saved: light-dark(oklch(0.676 0.176 252.3), oklch(0.748 0.135 250.1));
|
|
1990
|
+
--like: light-dark(oklch(0.633 0.200 24.9), oklch(0.690 0.162 22.2));
|
|
1991
|
+
--success: light-dark(oklch(0.720 0.192 149.5), oklch(0.805 0.186 151.6));
|
|
1992
|
+
--warning: light-dark(oklch(0.770 0.165 70.6), oklch(0.809 0.150 76.6));
|
|
1993
|
+
--info: light-dark(oklch(0.626 0.186 259.6), oklch(0.713 0.138 259.5));
|
|
1994
|
+
--delete: light-dark(oklch(0.597 0.198 25.5), oklch(0.644 0.170 23.1));
|
|
1995
|
+
|
|
1996
|
+
/* Semantic foregrounds (warning-foreground is identical both modes
|
|
1997
|
+
→ stays a single light-mode declaration, no light-dark() needed) */
|
|
1998
|
+
--success-foreground: light-dark(var(--neutral-0), hsl(48 10% 96%));
|
|
1999
|
+
--info-foreground: light-dark(var(--neutral-0), hsl(48 10% 96%));
|
|
2000
|
+
|
|
2001
|
+
/* Cartoon-shadow color primitives (§2d — plain colors, convert) */
|
|
2002
|
+
--shadow-cartoon-color: light-dark(rgb(0 0 0 / 0.12), rgb(255 255 255 / 0.07));
|
|
2003
|
+
--shadow-cartoon-color-soft: light-dark(rgb(0 0 0 / 0.06), rgb(255 255 255 / 0.03));
|
|
2004
|
+
|
|
2005
|
+
/* Gold family */
|
|
2006
|
+
--gold: light-dark(oklch(0.751 0.147 84.2), oklch(0.784 0.143 86.0));
|
|
2007
|
+
--gold-light: light-dark(oklch(0.890 0.183 96.1), oklch(0.898 0.182 97.4));
|
|
2008
|
+
--gold-dark: light-dark(oklch(0.599 0.132 64.2), oklch(0.678 0.150 63.8));
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
/* ═══════════════════════════════════════════════
|
|
2013
|
+
DARK MODE — warm dark, section palette brightened ~20% L
|
|
2014
|
+
|
|
2015
|
+
FALLBACK FLOOR (AQ.W2 §2c): this class block is the SOLE non-light-dark()
|
|
2016
|
+
dark path. On a `light-dark()`-supporting engine with `.dark` present,
|
|
2017
|
+
`.dark { color-scheme: dark }` (§1) makes every §-1b token resolve to its
|
|
2018
|
+
dark arm and these explicit dark values agree with it (kept as the floor
|
|
2019
|
+
for non-supporting engines). The pure `var()`-alias re-declarations
|
|
2020
|
+
(`--muted`/`--secondary`/`--accent`/`--border`/`--input`/… and the
|
|
2021
|
+
`--background`/`*-foreground` aliases) are DELETED — they auto-track the
|
|
2022
|
+
`--neutral-*` ladder + `--foreground` resolved above; only EXPLICIT-color
|
|
2023
|
+
dark values (and the non-color overrides §2d) stay.
|
|
2024
|
+
═══════════════════════════════════════════════ */
|
|
2025
|
+
.dark {
|
|
2026
|
+
/* §1 — hard-pin native chrome to dark regardless of OS preference. §4 —
|
|
2027
|
+
re-specify the inherited `accent-color` so it re-resolves to the dark
|
|
2028
|
+
arm (§2b: an inherited built-in <color> set at `:root` would freeze to
|
|
2029
|
+
the light shade without this re-specification). */
|
|
2030
|
+
color-scheme: dark;
|
|
2031
|
+
accent-color: var(--accent-color);
|
|
2032
|
+
|
|
2033
|
+
/* Neutral scale mirrors light-mode pattern: step UP from the background's
|
|
2034
|
+
low L toward foreground. Same perceptual deltas as light. FALLBACK
|
|
2035
|
+
FLOOR — kept verbatim for non-light-dark() engines (§2c); on a
|
|
2036
|
+
supporting engine `color-scheme: dark` (above) drives the §-1b
|
|
2037
|
+
light-dark() arms and these agree. */
|
|
2038
|
+
--neutral-0: hsl(24 8% 6%); /* L 6 — page surface (dark) */
|
|
2039
|
+
--neutral-1: hsl(24 6% 11%); /* L 11 — soft field */
|
|
2040
|
+
--neutral-2: hsl(24 5% 16%); /* L 16 — chip / tab-inactive */
|
|
2041
|
+
--neutral-3: hsl(24 5% 22%); /* L 22 — hover / highlight */
|
|
2042
|
+
--neutral-4: hsl(24 5% 34%); /* L 34 — subtle border */
|
|
2043
|
+
--neutral-5: hsl(48 5% 62%); /* L 62 — muted text (WCAG AA: 7.39:1 vs L6 page / 6.58:1 vs L11 muted) */
|
|
2044
|
+
/* W7-α' (AK-FD1) — strong-muted text. Same principled ladder step as
|
|
2045
|
+
light, mirrored: 10 L LIGHTER than muted (62→72) toward --foreground
|
|
2046
|
+
(L90), the 1/3 point of the L62→L90 muted→primary gap. By-colour; hue
|
|
2047
|
+
48, sat nudged 5→6. WCAG AA: 9.86:1 vs L6 page / 8.78:1 vs L11 muted
|
|
2048
|
+
(cf. neutral-5's 7.39:1). */
|
|
2049
|
+
--neutral-6: hsl(48 6% 72%); /* L 72 — strong-muted text (secondary register) */
|
|
2050
|
+
|
|
2051
|
+
/* --background / --card-foreground / --popover-foreground / --muted /
|
|
2052
|
+
--muted-foreground{,-strong} / --secondary{,-foreground} /
|
|
2053
|
+
--accent{,-foreground} / --border / --input are pure var()-aliases —
|
|
2054
|
+
DELETED here (AQ.W2 §2a): they auto-track the --neutral-* ladder +
|
|
2055
|
+
--foreground above. Re-declaring them would be redundant. */
|
|
2056
|
+
--foreground: hsl(48 10% 90%);
|
|
2057
|
+
--card: hsl(24 8% 10%);
|
|
2058
|
+
--popover: hsl(24 8% 10%);
|
|
2059
|
+
|
|
2060
|
+
/* R0G-5 (AO.W4) — dark mirror of the warm-neutral public-data panel.
|
|
2061
|
+
--card's dark hsl(24 8% 10%) nudged one warmth step toward amber
|
|
2062
|
+
(24→36) + +1 sat + +2 L so the dark dashboard panel lifts off the page. */
|
|
2063
|
+
--surface-public-data-panel: hsl(36 9% 12%);
|
|
2064
|
+
|
|
2065
|
+
--primary: hsl(48 10% 90%);
|
|
2066
|
+
--primary-foreground: hsl(24 10% 10%);
|
|
2067
|
+
/* AX.W44 — the `.dark` class fallback floor, in LOCKSTEP with the light-dark()
|
|
2068
|
+
enhancement arm above (§2c). Same lifted `hsl(0 80% 60%)` so a
|
|
2069
|
+
@supports-split engine and a class-toggle engine paint the SAME dark red
|
|
2070
|
+
(4.60:1 as ink over --card / 5.03:1 as a plate vs page). */
|
|
2071
|
+
--destructive: hsl(0 80% 60%);
|
|
2072
|
+
--destructive-foreground: hsl(48 10% 90%);
|
|
2073
|
+
--ring: hsl(48 10% 70%);
|
|
2074
|
+
--shadow: hsl(0 0% 5%);
|
|
2075
|
+
|
|
2076
|
+
/* Section palette — brightened for dark backgrounds (oklch; AV.W16 TW2 —
|
|
2077
|
+
mirrors the light-dark() dark halves above; hue preserved) */
|
|
2078
|
+
--section-color-0: oklch(0.721 0.145 354.0);
|
|
2079
|
+
--section-color-1: oklch(0.733 0.113 308.2);
|
|
2080
|
+
--section-color-2: oklch(0.718 0.107 268.4);
|
|
2081
|
+
--section-color-3: oklch(0.767 0.091 219.9);
|
|
2082
|
+
--section-color-4: oklch(0.776 0.105 172.6);
|
|
2083
|
+
--section-color-5: oklch(0.813 0.109 78.2);
|
|
2084
|
+
--section-color-6: oklch(0.693 0.151 28.1);
|
|
2085
|
+
--section-color-7: oklch(0.739 0.134 318.1);
|
|
2086
|
+
--section-color-8: oklch(0.709 0.142 2.3);
|
|
2087
|
+
--section-color-9: oklch(0.763 0.032 239.0);
|
|
2088
|
+
--section-color-10: oklch(0.794 0.116 127.9);
|
|
2089
|
+
--section-color-11: oklch(0.805 0.095 206.7);
|
|
2090
|
+
--section-color-12: oklch(0.719 0.115 295.6);
|
|
2091
|
+
|
|
2092
|
+
--accent-pink: oklch(0.683 0.131 354.7);
|
|
2093
|
+
--section-heading: oklch(0.711 0.123 349.3);
|
|
2094
|
+
--accent-red: oklch(0.644 0.165 22.9);
|
|
2095
|
+
|
|
2096
|
+
--viz-fourier: oklch(0.693 0.151 28.1);
|
|
2097
|
+
--viz-chebyshev: oklch(0.718 0.107 268.4);
|
|
2098
|
+
--viz-legendre: oklch(0.739 0.134 318.1);
|
|
2099
|
+
/* --viz-amber / --viz-green / --meter-track-stroke are pure var()-aliases
|
|
2100
|
+
(→ --section-color-5/-4 / --foreground) — DELETED (§2a); they auto-track
|
|
2101
|
+
their sources, which convert via §-1b. */
|
|
2102
|
+
|
|
2103
|
+
/* O.W6 Lane D — WCAG companion labels lift to L≈0.85 against the
|
|
2104
|
+
deep dark canvas; same two-token discipline as light mode (canvas
|
|
2105
|
+
hue preserved at `--chart-*`; only the label register shifts). */
|
|
2106
|
+
--chart-ping-label: oklch(0.85 0.12 230);
|
|
2107
|
+
--chart-download-label: oklch(0.85 0.14 22);
|
|
2108
|
+
--chart-upload-label: oklch(0.85 0.12 55);
|
|
2109
|
+
--chart-jitter-label: oklch(0.85 0.14 305);
|
|
2110
|
+
|
|
2111
|
+
--tier-featured: oklch(0.867 0.165 88.7);
|
|
2112
|
+
--tier-saved: oklch(0.748 0.135 250.1);
|
|
2113
|
+
--like: oklch(0.690 0.162 22.2);
|
|
2114
|
+
--success: oklch(0.805 0.186 151.6);
|
|
2115
|
+
--warning: oklch(0.809 0.150 76.6);
|
|
2116
|
+
--info: oklch(0.713 0.138 259.5);
|
|
2117
|
+
--delete: oklch(0.644 0.170 23.1);
|
|
2118
|
+
|
|
2119
|
+
/* Semantic foregrounds — off-white over dark plates. Mirrors the
|
|
2120
|
+
`--destructive-foreground` dark pattern (hsl 48 10% 90%). The warning
|
|
2121
|
+
glyph stays dark-on-amber; the dark amber rung is luminous enough that
|
|
2122
|
+
a darker glyph still reads (matches light-mode behaviour). */
|
|
2123
|
+
--success-foreground: hsl(48 10% 96%);
|
|
2124
|
+
--warning-foreground: hsl(24 10% 10%);
|
|
2125
|
+
--info-foreground: hsl(48 10% 96%);
|
|
2126
|
+
|
|
2127
|
+
--shadow-cartoon: 3px 3px 0px 0px color-mix(in srgb, var(--foreground) 6%, transparent);
|
|
2128
|
+
--shadow-cartoon-hover: 4px 4px 0px 0px color-mix(in srgb, var(--foreground) 8%, transparent);
|
|
2129
|
+
--shadow-soft: 0 4px 12px rgba(0, 0, 0, 0.3);
|
|
2130
|
+
--shadow-elevated: 0 8px 24px rgba(0, 0, 0, 0.35);
|
|
2131
|
+
--shadow-modal:
|
|
2132
|
+
4px 4px 0px 0px color-mix(in srgb, var(--foreground) 6%, transparent),
|
|
2133
|
+
0 24px 64px color-mix(in srgb, var(--foreground) 18%, transparent);
|
|
2134
|
+
|
|
2135
|
+
--shadow-cartoon-color: rgb(255 255 255 / 0.07);
|
|
2136
|
+
--shadow-cartoon-color-soft: rgb(255 255 255 / 0.03);
|
|
2137
|
+
|
|
2138
|
+
/* §5c CONSTELLATION — dark arm (AX.W17). The H.W4 dark-mode lift: the node
|
|
2139
|
+
tones step UP off the ink ground (the light arm's mid-grey would vanish on
|
|
2140
|
+
L6 black), the hairline goes warm off-white, the field carries a touch more
|
|
2141
|
+
presence to read at all. PLAIN-hsl literals, NEVER light-dark()/var(). */
|
|
2142
|
+
--constellation-node: hsl(42 9% 72%);
|
|
2143
|
+
--constellation-node-dim: hsl(42 8% 56%);
|
|
2144
|
+
--constellation-line: hsl(45 12% 86%);
|
|
2145
|
+
/* Anomaly — brightened for the deep canvas (same neutral-default register;
|
|
2146
|
+
the consumer still overrides to its brand). */
|
|
2147
|
+
--constellation-accent: hsl(20 70% 60%);
|
|
2148
|
+
/* The dark hairlines lift harder over the ink ground, so the edge multipliers
|
|
2149
|
+
run a touch lower than light to keep the field recessive. */
|
|
2150
|
+
--constellation-edge-alpha: 0.20;
|
|
2151
|
+
--constellation-edge-focus-alpha: 0.32;
|
|
2152
|
+
/* §7 — the ink ground needs MORE field presence than cream to read at all, so
|
|
2153
|
+
the dark alpha is modestly HIGHER than the light arm — but still BELOW the
|
|
2154
|
+
slides 1.0 max-legibility reference (the recessive midpoint, not 1.0). */
|
|
2155
|
+
--constellation-alpha: 0.88;
|
|
2156
|
+
|
|
2157
|
+
/* Glass opacity + grain for dark — five-tier ladder, alpha-monotonic.
|
|
2158
|
+
Each rung lifts ~0.08 from its light counterpart so the dark surfaces
|
|
2159
|
+
carry comparable read-weight against the deeper canvas. */
|
|
2160
|
+
--glass-opacity-wash: 0.38;
|
|
2161
|
+
--glass-opacity-quiet: 0.58;
|
|
2162
|
+
--glass-opacity-resting: 0.72;
|
|
2163
|
+
--glass-opacity-floating: 0.88;
|
|
2164
|
+
--glass-opacity-overlay: 0.96;
|
|
2165
|
+
--glass-opacity-chassis: 0.36;
|
|
2166
|
+
--glass-grain-opacity: 0.045;
|
|
2167
|
+
--glass-highlight: inset 0 0.5px 0 0 hsl(0 0% 100% / 0.08);
|
|
2168
|
+
|
|
2169
|
+
/* Hairline-accent dark mirror — see light counterpart at line ~404. */
|
|
2170
|
+
--hairline-catch-light: inset 0 0.5px 0 0 rgb(255 255 255 / 0.05);
|
|
2171
|
+
--hairline-under-shadow: 0 0.5px 0 0 rgb(0 0 0 / 0.06);
|
|
2172
|
+
|
|
2173
|
+
/* Specular + curvature — softened for dark backdrops. Disco-grain stays
|
|
2174
|
+
at the same opacity ceiling; the dark grain blend already lifts it. */
|
|
2175
|
+
--glass-specular: inset 0 1.5px 0 0 hsl(0 0% 100% / 0.30);
|
|
2176
|
+
/* AV.W15 M3 — the full-perimeter rim remaps to its dark weight inside
|
|
2177
|
+
`.dark` (mirroring the `--glass-specular` remap above). The lit token
|
|
2178
|
+
resolves to the `-dark` alpha on the deeper canvas. */
|
|
2179
|
+
--glass-edge-light: var(--glass-edge-light-dark);
|
|
2180
|
+
|
|
2181
|
+
/* AW.W23 — the chromatic-fringe + adaptive-tint dark arm. The fringe drops
|
|
2182
|
+
to a lower-luminance warm/cool pair on the deep canvas; `--glass-tint-
|
|
2183
|
+
source` auto-flips with `--card` (no override needed — the default already
|
|
2184
|
+
resolves the dark card). */
|
|
2185
|
+
--glass-fringe-warm: oklch(0.78 0.07 40 / 0.18);
|
|
2186
|
+
--glass-fringe-cool: oklch(0.74 0.06 230 / 0.14);
|
|
2187
|
+
/* AX.W52 D19 — the curvature sheen is genuinely SOFTER on the deep canvas (the
|
|
2188
|
+
prior dark arm re-declared the overlay BYTE-IDENTICAL to light, so it read
|
|
2189
|
+
HARDER over the dark substrate — an unsoftened-dark defect). The `:root`
|
|
2190
|
+
`--glass-curvature-overlay` already reads `var(--glass-curvature-intensity)`,
|
|
2191
|
+
so lowering just the intensity here re-resolves the SAME warm-cream recipe at
|
|
2192
|
+
a softer alpha — no byte-identical re-declaration. */
|
|
2193
|
+
--glass-curvature-intensity: 0.012;
|
|
2194
|
+
|
|
2195
|
+
/* Gold — boosted for dark (oklch; AV.W16 TW2) */
|
|
2196
|
+
--gold: oklch(0.784 0.143 86.0);
|
|
2197
|
+
--gold-light: oklch(0.898 0.182 97.4);
|
|
2198
|
+
--gold-dark: oklch(0.678 0.150 63.8);
|
|
2199
|
+
/* D6.b — the dark-arm gilt ink. `--gold-rim` auto-re-resolves (its color-mix
|
|
2200
|
+
reads the dark `--gold` above — no override). `--gold-ink` MUST lift L for
|
|
2201
|
+
the dark `--card` (hsl 24 8% 10%): a deep gold-dark ink would vanish into
|
|
2202
|
+
the near-black plate, so the dark ink is a BRIGHT gold —
|
|
2203
|
+
oklch(0.860 0.158 90) → |Lc| 77.1 on the dark `--card` (cream-law ②;
|
|
2204
|
+
verified by proof:gold-ink-contrast). */
|
|
2205
|
+
--gold-ink: oklch(0.860 0.158 90);
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2208
|
+
/* ═══════════════════════════════════════════════
|
|
2209
|
+
§18 TYPED CSS PROPERTIES — Houdini @property registrations
|
|
2210
|
+
(AI.W4 grammar — adjacent to §2.C tokens above)
|
|
2211
|
+
|
|
2212
|
+
Three typed custom properties register with the CSS Houdini @property
|
|
2213
|
+
API so transitions interpolate VALUES (percentage / length) rather
|
|
2214
|
+
than the textual representation. Unregistered fallback is safe — the
|
|
2215
|
+
`initial-value` provides a sensible default for any consumer that
|
|
2216
|
+
imports this stylesheet on a browser that doesn't yet support the
|
|
2217
|
+
typed @property registration (the cross-fade collapses to the
|
|
2218
|
+
initial value, then re-paints at the new state).
|
|
2219
|
+
|
|
2220
|
+
Browser support: Chromium 85+, Safari 16.4+, Firefox 128+. The
|
|
2221
|
+
speedtest deployment target sits well within the floor.
|
|
2222
|
+
|
|
2223
|
+
• --progress-crescendo (percentage) — the leading-edge brightness
|
|
2224
|
+
ramp on `<Progress variant="gradient">` past 85% modelValue.
|
|
2225
|
+
`inherits: false` because the value is consumed at one
|
|
2226
|
+
declaration only (the gradient stop calculation); inheriting
|
|
2227
|
+
would let an unrelated ancestor accidentally drive a sibling
|
|
2228
|
+
progress bar.
|
|
2229
|
+
|
|
2230
|
+
• --phase-tint-amount (percentage) — the chassis depth-of-tint
|
|
2231
|
+
companion to `--phase-color`. `inherits: true` because the
|
|
2232
|
+
value cascades from the chassis root through every region
|
|
2233
|
+
wrapper that reads it for a sympathetic tint (matches the
|
|
2234
|
+
`--phase-color` inheritance pattern).
|
|
2235
|
+
|
|
2236
|
+
• --ripple-radius (length) — the `btn-audacious` press ripple
|
|
2237
|
+
radial. `inherits: false` because each button owns its own
|
|
2238
|
+
ripple state (a hovered parent must not push a ripple-radius
|
|
2239
|
+
onto a non-pressed child).
|
|
2240
|
+
═══════════════════════════════════════════════ */
|
|
2241
|
+
|
|
2242
|
+
@property --progress-crescendo {
|
|
2243
|
+
syntax: "<percentage>";
|
|
2244
|
+
inherits: false;
|
|
2245
|
+
initial-value: 0%;
|
|
2246
|
+
}
|
|
2247
|
+
|
|
2248
|
+
@property --phase-tint-amount {
|
|
2249
|
+
syntax: "<percentage>";
|
|
2250
|
+
inherits: true;
|
|
2251
|
+
initial-value: 0%;
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
@property --ripple-radius {
|
|
2255
|
+
syntax: "<length>";
|
|
2256
|
+
inherits: false;
|
|
2257
|
+
initial-value: 0px;
|
|
2258
|
+
}
|
|
2259
|
+
|
|
2260
|
+
/* ═══════════════════════════════════════════════
|
|
2261
|
+
§11b POINTER-ANCHORED MOVING SPECULAR (AV.W15)
|
|
2262
|
+
|
|
2263
|
+
The iOS-26 Liquid Glass "light travels around the material /
|
|
2264
|
+
illuminate under your fingertip" behaviour. A masked radial-gradient
|
|
2265
|
+
catch-light rides the surface at (--specular-x, --specular-y), driven
|
|
2266
|
+
by the consumer's pointer-tracked --mouse-x/--mouse-y write. Registered
|
|
2267
|
+
as typed custom properties so the position INTERPOLATES smoothly between
|
|
2268
|
+
pointer samples (a bare unregistered var() snaps; the @property reg lets
|
|
2269
|
+
the engine animate the percentage stop).
|
|
2270
|
+
|
|
2271
|
+
• --specular-x / --specular-y (percentage) — the catch-light centre.
|
|
2272
|
+
`inherits: false` because each glass surface owns its own pointer
|
|
2273
|
+
position (a hovered parent must not push its specular onto a child —
|
|
2274
|
+
the no-glass-on-glass discipline made mechanical).
|
|
2275
|
+
|
|
2276
|
+
• --specular-intensity (number) — the catch-light alpha multiplier.
|
|
2277
|
+
`inherits: false` for the same per-surface-ownership reason; rises on
|
|
2278
|
+
hover/active, settles to its rest floor on leave.
|
|
2279
|
+
|
|
2280
|
+
@property crosses Baseline 2024-07-09. The consumption (the masked
|
|
2281
|
+
radial + the reduced-motion static bracket + the var() fallback) lives
|
|
2282
|
+
in glass-specular-track.css; the registrations live here alongside the
|
|
2283
|
+
other three regs so the typed-property tier has one home.
|
|
2284
|
+
═══════════════════════════════════════════════ */
|
|
2285
|
+
|
|
2286
|
+
@property --specular-x {
|
|
2287
|
+
syntax: "<percentage>";
|
|
2288
|
+
inherits: false;
|
|
2289
|
+
initial-value: 50%;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
@property --specular-y {
|
|
2293
|
+
syntax: "<percentage>";
|
|
2294
|
+
inherits: false;
|
|
2295
|
+
initial-value: 50%;
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
@property --specular-intensity {
|
|
2299
|
+
syntax: "<number>";
|
|
2300
|
+
inherits: false;
|
|
2301
|
+
initial-value: 0;
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
/* AX.W54 — the GLASS-FIRST single knob. `--glass-level` is the ONE clarity
|
|
2305
|
+
scalar threaded through BOTH glass ladders at their single sites (the
|
|
2306
|
+
`--glass-bg-*` opacity recipe + the `--glass-blur-*` radii). It is a typed,
|
|
2307
|
+
INHERITING <number> so a host setting it on any ancestor retunes every
|
|
2308
|
+
descendant glass surface (the @container-free cascade path) — and so it
|
|
2309
|
+
animates smoothly rather than snapping. The level acts as a clarity multiplier
|
|
2310
|
+
that PRESERVES level=1 (byte-identical to the hand-tuned ladder):
|
|
2311
|
+
• level 1 — the calibrated glass (today's surfaces, unchanged).
|
|
2312
|
+
• level 0 — the OPAQUE escape: solid `--card` + `blur(0)` through the SAME
|
|
2313
|
+
machinery (the `.glass-opaque` rung + the a11y brackets ride it).
|
|
2314
|
+
• level >1 — clearer (more transparent + more diffuse) in lockstep.
|
|
2315
|
+
Glass is the DEFAULT surface register for EVERY band (USER-DECIDED MAXIMAL);
|
|
2316
|
+
the opaque level-0 rung is the explicit opt-out. W55 carries the over-light
|
|
2317
|
+
legibility on the SEPARATE `--glass-tint-*` axis (the `--glass-backdrop` probe
|
|
2318
|
+
lifts the tint toward ink — level = opacity+blur, tint = darken-over-light, the
|
|
2319
|
+
two axes coordinate but never collapse: the a11y Clear↔Tinted escape rides
|
|
2320
|
+
level-up here AND tint-toward-ink under `prefers-contrast: more`). */
|
|
2321
|
+
@property --glass-level {
|
|
2322
|
+
syntax: "<number>";
|
|
2323
|
+
inherits: true;
|
|
2324
|
+
initial-value: 1;
|
|
2325
|
+
}
|
|
2326
|
+
|
|
2327
|
+
/* AX.W51 D18 — the master comfortable-sizing scalar registered typed. The
|
|
2328
|
+
`<number>` syntax guarantees `calc(<base> * var(--ui-scale))` is always valid (a
|
|
2329
|
+
malformed override CLAMPS to the initial value 1, not an invalidated calc — the
|
|
2330
|
+
fail-safe); `inherits: true` (unlike the per-element specular @property cohort)
|
|
2331
|
+
so a SCOPED override (a dense data-table region) cascades to every descendant
|
|
2332
|
+
control without a per-element set; the type makes it animatable (a density
|
|
2333
|
+
toggle COULD spring it). Mirrors the `--glass-level` registration above (the
|
|
2334
|
+
cascading-scalar idiom), distinct from the per-element specular @property cohort
|
|
2335
|
+
(those are `inherits: false`). */
|
|
2336
|
+
@property --ui-scale {
|
|
2337
|
+
syntax: "<number>";
|
|
2338
|
+
inherits: true;
|
|
2339
|
+
initial-value: 1;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
/* ── The specular-intensity magnitude cohort (AX.W09) ──────────────────────
|
|
2343
|
+
The catch-light alpha multiplier at each interaction state, as a SINGLE
|
|
2344
|
+
overridable token cohort (was three buried literals across glass.css —
|
|
2345
|
+
`0.35` rest floor / `0.6` hover / `0.85` active — and the `.dark` arm's
|
|
2346
|
+
`0.22`). `glass.css`'s `.glass-material::before` rest/hover/active rules READ
|
|
2347
|
+
these, so the subtle-vs-extreme magnitude is a knob a consumer (or the dark
|
|
2348
|
+
arm) retunes ON THE CASCADE — never a re-buried literal. Override on `:root`
|
|
2349
|
+
to retune library-wide; the cartoon-shadow override contract is the precedent.
|
|
2350
|
+
|
|
2351
|
+
Re-baselined AGAIN at AX.W52 D19 — with the central screen-disc replaced by a
|
|
2352
|
+
BOUNDED plus-lighter edge gleam (glass.css), the gleam is a whisper at every
|
|
2353
|
+
rung, so the cohort drops further (the W09 0.22/0.32 ceiling still lifted the
|
|
2354
|
+
whole-tile disc on hover):
|
|
2355
|
+
• rest 0 — static, unwired surfaces are CLEAN; the gleam wakes only on
|
|
2356
|
+
hover/active or on a pointer-wired surface. Aligns the painted
|
|
2357
|
+
rest with the @property `--specular-intensity { initial-value:
|
|
2358
|
+
0 }` dormancy.
|
|
2359
|
+
• hover 0.10 — a whisper edge gleam, not a bloom.
|
|
2360
|
+
• active 0.16 — the press whisper. */
|
|
2361
|
+
:root {
|
|
2362
|
+
--glass-specular-intensity-rest: 0;
|
|
2363
|
+
--glass-specular-intensity-hover: 0.1;
|
|
2364
|
+
--glass-specular-intensity-active: 0.16;
|
|
2365
|
+
}
|
|
2366
|
+
|
|
2367
|
+
/* Over the deep canvas `plus-lighter` still lifts, so the dark arm runs a touch
|
|
2368
|
+
softer on the interaction rungs (rest already 0). */
|
|
2369
|
+
.dark {
|
|
2370
|
+
--glass-specular-intensity-hover: 0.08;
|
|
2371
|
+
--glass-specular-intensity-active: 0.12;
|
|
2372
|
+
}
|