@vegastack/design-tokens 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/base.css CHANGED
@@ -55,17 +55,38 @@
55
55
  outline-color: Highlight;
56
56
  }
57
57
 
58
- /* Composite text-entry surfaces (TextEdit) put their focus affordance on a WRAPPER via
59
- `focus-within:border-ring/…` — a border TINT. The wrapper itself never matches
60
- `:focus-visible` (the contenteditable inside it does), and forced-colors replaces
61
- border-color outright, so in forced-colors mode that surface had NO visible focus indicator
62
- at all. A real outline is the only affordance the forced palette preserves.
63
- Simple fields (Input/Textarea/Select) need no equivalent: there the focused element IS the
64
- control, so the `:focus-visible` rule above already covers them. */
65
- [data-slot="text-edit"]:focus-within {
58
+ /* Text-entry focus (B1-01, 2026-09-07). Every text-entry control signals focus with the
59
+ border TINT (`focus:border-ring/(--alpha-tint-border)`) and strips the outline
60
+ (`outline-none`), because a raw text field cannot tell mouse from keyboard. Forced colours
61
+ replaces `border-color` outright, so the tint vanishes and `outline-style: none` stays in
62
+ force a Windows High Contrast user had no caret location at all. This block is UNLAYERED
63
+ on purpose: it beats the component's `outline-none` (a layered utility) regardless of
64
+ specificity, so the fallback is written ONCE here, never per component.
65
+ - `input`/`textarea` at `:focus` (not `:focus-visible`, matching the tint's trigger);
66
+ - composite editors (TextEdit's contenteditable) at `:focus`;
67
+ - wrapper-tinted surfaces (`data-slot="text-edit"`, and every `data-field-group`) at
68
+ `:focus-within`. */
69
+ input:focus,
70
+ textarea:focus,
71
+ [contenteditable="true"]:focus,
72
+ [data-slot="text-edit"]:focus-within,
73
+ [data-field-group]:focus-within {
66
74
  outline: 2px solid Highlight;
67
75
  outline-offset: 1px;
68
76
  }
77
+
78
+ /* …and only ONE of them paints (Fo1, 2026-09-07). A bordered field GROUP — Input's prefix/suffix
79
+ wrapper, NumberField's stepper group, ChipInput, the Combobox input-group — clips with
80
+ `overflow-hidden` so its addons follow the rounded corner. The inner input's own outline is
81
+ offset outward INTO that clip, so it was drawn and then cut, which is how an addon field ended
82
+ up with no visible focus at all under the forced palette. The group carries the outline (it is
83
+ the element whose border the tint would have moved); the control inside it stands down, so the
84
+ two never paint a double ring. `data-field-group` is set by every consumer of
85
+ `fieldControlGroup` in `@vegastack/design` — the attribute IS the contract. */
86
+ [data-field-group] input:focus,
87
+ [data-field-group] textarea:focus {
88
+ outline: none;
89
+ }
69
90
  }
70
91
 
71
92
  /* ───────────────────────────────────────────────────────────────────────────────────────────────
@@ -85,7 +106,15 @@
85
106
  ::after {
86
107
  animation-duration: 0.01ms !important;
87
108
  animation-iteration-count: 1 !important;
109
+ /* A zeroed DURATION alone is not enough: a staggered entrance schedules its
110
+ * per-item `animation-delay` in real time, so the items would still appear
111
+ * one after another (each instantly) over the full stagger window. Zeroing
112
+ * the delay too is what makes "reduced motion" a static end state — and it
113
+ * is why no component needs its own `motion-reduce:` restatement (audit
114
+ * batch Di1 / B2-06). */
115
+ animation-delay: 0s !important;
88
116
  transition-duration: 0.01ms !important;
117
+ transition-delay: 0s !important;
89
118
  scroll-behavior: auto !important;
90
119
  }
91
120
 
package/dist/theme.css CHANGED
@@ -8,42 +8,46 @@
8
8
  color-scheme: light;
9
9
  --background: oklch(0.994 0.002 75);
10
10
  --foreground: oklch(0.145 0.003 75);
11
- --card: oklch(0.985 0.003 75);
11
+ --card: oklch(0.994 0.002 75); /** Light cards are PAGE-COLOURED and separated by the alpha hairline alone (surface-ladder decision 2026-09-07, P1): no reference system lifts or sinks a light card. Dark keeps the one-step lift (neutral.900). */
12
12
  --card-foreground: oklch(0.145 0.003 75);
13
- --popover: oklch(0.994 0.002 75);
13
+ --popover: oklch(0.994 0.002 75); /** Every floating surface is the card surface + shadow-overlay; never a lighter or darker rung of its own. */
14
14
  --popover-foreground: oklch(0.145 0.003 75);
15
+ --surface-1: oklch(0.97 0.003 75); /** Surface ladder rung 1 — the REST fill of a filled control (secondary/soft button, kbd, chip, segmented rail, tab-list pill) and the sunken well (code block, skeleton, disabled field, slider/progress track). `secondary` and `muted` are aliases of this rung. */
16
+ --surface-2: oklch(0.945 0.003 75); /** Surface ladder rung 2 — the HOVER step: a transparent row/item/ghost control hovers to it, a rung-1 control hovers to it. `accent` and `sidebar-accent` are aliases. Alpha twin: bg-foreground/(--alpha-hover). */
17
+ --surface-3: oklch(0.922 0.003 75); /** Surface ladder rung 3 — the PRESSED / SELECTED step (active:, data-selected, the active sidebar row, the switch off-track). Alpha twin: bg-foreground/(--alpha-pressed). */
15
18
  --primary: oklch(0.353 0.003 75);
16
19
  --primary-foreground: oklch(0.985 0.003 75);
17
20
  --primary-hover: oklch(0.269 0.003 75);
18
21
  --primary-active: oklch(0.236 0.003 75);
19
- --track: oklch(0.87 0.003 75);
20
- --secondary: oklch(0.97 0.003 75);
21
- --secondary-foreground: oklch(0.205 0.003 75);
22
- --muted: oklch(0.97 0.003 75);
22
+ --secondary: oklch(0.97 0.003 75); /** ALIAS of surface-1 (kept so shadcn-shaped code keeps compiling). Never retune independently. */
23
+ --secondary-foreground: oklch(0.145 0.003 75); /** ALIAS of foreground — one ink on every neutral rung. */
24
+ --muted: oklch(0.97 0.003 75); /** ALIAS of surface-1 (shadcn name). muted-foreground stays a real text role. */
23
25
  --muted-foreground: oklch(0.439 0.003 75);
24
26
  --muted-foreground-faint: oklch(0.63 0.003 75);
25
- --accent: oklch(0.97 0.003 75);
26
- --accent-foreground: oklch(0.205 0.003 75);
27
+ --accent: oklch(0.945 0.003 75); /** ALIAS of surface-2, the hover/highlight rung (shadcn's `accent` — a NEUTRAL, never a hue). Menu/select/command `data-highlighted` rides on it. */
28
+ --accent-foreground: oklch(0.145 0.003 75); /** ALIAS of foreground. */
27
29
  --destructive: oklch(0.505 0.213 27.52);
28
30
  --destructive-foreground: oklch(0.985 0.003 75);
29
31
  --destructive-subtle: oklch(0.949 0.022 24);
30
- --destructive-text: oklch(0.521 0.2 25);
32
+ --destructive-text: oklch(0.496 0.2 25); /** Page-readable red ink (was red.650, L 0.521). Re-tuned -0.025 L on 2026-09-07 so the soft PRESSED rung (`destructive-subtle-active`, fill @12% over subtle) still clears 4.5:1 — at the old ink the soft family sat at the AA edge on hover (4.60:1) and had no room for a pressed step. Every other pair only gains contrast. */
31
33
  --destructive-border: oklch(0.505 0.213 27.52); /** Invalid-state border ink, composited at --alpha-tint-border. A DEDICATED role because the fill hue cannot serve both: on the dark ground, destructive at 70% measures 1.92:1, far under the 3:1 WCAG 1.4.11 floor for a non-text UI indicator, and lightening `destructive` itself would drop destructive-foreground on the solid button below 4.5:1. Light keeps the fill hue (4.24:1); dark re-grounds to red.400 (4.00:1). */
32
34
  --success: oklch(0.5 0.16 150);
33
35
  --success-foreground: oklch(0.985 0.003 75);
34
36
  --success-subtle: oklch(0.951 0.051 150);
35
- --success-text: oklch(0.5 0.13 150);
37
+ --success-text: oklch(0.48 0.13 150); /** Page-readable green ink (was green.650, L 0.5); -0.02 L for the soft pressed rung — see destructive-text. */
36
38
  --warning: oklch(0.52 0.145 52);
37
39
  --warning-foreground: oklch(0.985 0.003 75);
38
40
  --warning-subtle: oklch(0.96 0.019 42);
39
- --warning-text: oklch(0.52 0.139 42);
41
+ --warning-text: oklch(0.505 0.139 42); /** Page-readable amber ink (was amber.650, L 0.52); -0.015 L for the soft pressed rung — see destructive-text. */
40
42
  --info: oklch(0.531 0.182 256);
41
43
  --info-foreground: oklch(0.985 0.003 75);
42
44
  --info-subtle: oklch(0.961 0.018 253);
43
- --info-text: oklch(0.52 0.171 256);
44
- --overlay: oklch(0.13 0.002 75 / 0.28); /** Modal scrim — the ONE sanctioned alpha-composite literal (a translucent wash has no primitive step; alpha is intrinsic to the role). */
45
- --border: oklch(0.922 0.003 75);
46
- --input: oklch(0.922 0.003 75);
45
+ --info-text: oklch(0.5 0.171 256); /** Link / informational blue ink (was blue.650, L 0.52); -0.02 L for the soft pressed rung — see destructive-text. */
46
+ --overlay: oklch(0.13 0.002 75 / 0.28); /** Modal scrim — an alpha-composite literal (a translucent wash has no primitive step; alpha is intrinsic to the role). Theme-split: the dark scrim is deeper. */
47
+ --media-scrim: oklch(0.13 0.002 75 / 0.6); /** THEME-INVARIANT media chrome scrim (B4-01): the gradient/backdrop behind controls laid over video or imagery. Always a warm-black alpha, never a theme token, so the chrome reads dark-scrim + light-ink in both themes (`primary` flips with the theme and inverted the chrome in dark). TEXT IS PERMITTED on this scrim: media-foreground clears 5.2:1 on it over a white worst-case backdrop, and tooling/contrast-check.mjs gates the pair at the AA TEXT floor (4.5:1), not the 3:1 non-text floor — so a retune that thins this scrim under AA fails the build rather than silently demoting its labels. */
48
+ --media-scrim-strong: oklch(0.13 0.002 75 / 0.8); /** Theme-invariant strong scrim for opaque media pills (volume popover, time badge) — 11:1 for media-foreground over a white worst case. Use it for any block of media text that needs headroom beyond the soft scrim's ~5.2:1, and for text over unusually bright or busy frames. */
49
+ --media-foreground: oklch(0.985 0.003 75); /** Theme-invariant media chrome ink: the warm off-white used for every icon, label and track drawn over media-scrim or media-scrim-strong. Labels are allowed on EITHER scrim — both are gated at the AA text floor (4.5:1) against this ink over the white worst case. Not overridden in dark on purpose. */
50
+ --input: oklch(0.145 0.003 75 / 0.08); /** ALIAS of border (the alpha hairline). `border` itself is DERIVED by the SD preprocessor: foreground at --alpha-border (D14) so one hairline survives on page, card, well and dark band alike. */
47
51
  --ring: oklch(0.353 0.003 75);
48
52
  --chart-1: oklch(0.546 0.245 262.88);
49
53
  --chart-2: oklch(0.6 0.118 184.7);
@@ -53,7 +57,9 @@
53
57
  --chart-6: oklch(0.505 0.213 27.52);
54
58
  --chart-7: oklch(0.6 0.127 104.2); /** Olive (hue 104) — reassigned from green.600, which collided with the brand phosphor hue (CX-9). */
55
59
  --chart-8: oklch(0.531 0.182 256);
56
- --brand: oklch(0.6 0.17 148); /** The phosphor-green brand accent, LIGHT half (theme-split per CX-9): marker roles ONLY (live/AI-state dot, sparkline endpoint, eyebrow highlight, terminal prompt glyph). 3.5:1 on card/background — meaningful glyphs pass WCAG 1.4.11. Never fills, borders-at-rest, headlines, or buttons. */
60
+ --chart-single: oklch(0.145 0.003 75); /** Single-series chart ink (D29): one series is drawn in foreground ink; the categorical chart-1…8 hues start at two series. */
61
+ --brand: oklch(0.6 0.17 148); /** The phosphor-green brand accent, LIGHT half (theme-split per CX-9): MARKER roles (live/AI-state dot, sparkline endpoint, eyebrow highlight, terminal prompt glyph) plus the `cta` Button's faint wash and its accent outline — the one sanctioned button, D17/D18. 3.5:1 on card/background — meaningful glyphs pass WCAG 1.4.11, and it is NOT a text ink: brand LABELS take `brand-text`. Never a headline colour, a full-strength surface, or a decorative wash beyond one radial. */
62
+ --brand-text: oklch(0.46 0.17 148); /** The PAGE-READABLE brand ink, LIGHT half — the same role every chromatic family ships as `<family>-text`. `brand` itself is a 3.5:1 marker and fails WCAG 1.4.3 as a label (measured 3.41:1 for the `cta` Button's mono label over its own faint wash, 2026-09-09), so any brand-coloured TEXT reads through this token instead. Gated at 4.5:1 by contrast-check over background/card/popover/surface-1–3 and over the brand wash at alpha-surface-faint/hover/pressed. */
57
63
  --tag-blue: oklch(0.6 0.16 256); /** Tag palette (Attio-teardown Wave 1): 10 chromatic hues x base/subtle/text mirroring the family/family-subtle/family-text shape. base = dots/accents (>=3:1 non-text vs background), subtle = chip fill, text = chip text (>=4.5:1 on subtle AND page). Neutral tags use muted/muted-foreground. AA-validated fail-closed in contrast-check.mjs. */
58
64
  --tag-blue-subtle: oklch(0.955 0.02 256);
59
65
  --tag-blue-text: oklch(0.51 0.15 256);
@@ -84,13 +90,13 @@
84
90
  --tag-purple: oklch(0.6 0.16 295);
85
91
  --tag-purple-subtle: oklch(0.955 0.02 295);
86
92
  --tag-purple-text: oklch(0.51 0.15 295);
87
- --sidebar: oklch(0.985 0.003 75);
88
- --sidebar-foreground: oklch(0.269 0.003 75);
89
- --sidebar-primary: oklch(0.145 0.003 75);
93
+ --sidebar: oklch(0.994 0.002 75); /** The sidebar-* family is ALIASES ONLY (B6-01): the rail is a card surface on the ladder, not a second palette. Names kept for shadcn-shaped code. */
94
+ --sidebar-foreground: oklch(0.145 0.003 75);
95
+ --sidebar-primary: oklch(0.353 0.003 75);
90
96
  --sidebar-primary-foreground: oklch(0.985 0.003 75);
91
- --sidebar-accent: oklch(0.955 0.003 75);
97
+ --sidebar-accent: oklch(0.945 0.003 75); /** ALIAS of surface-2 — the rail's hover rung; the active row sits one rung higher on surface-3 so active+hover still moves (SP-06). */
92
98
  --sidebar-accent-foreground: oklch(0.145 0.003 75);
93
- --sidebar-border: oklch(0.922 0.003 75);
99
+ --sidebar-border: oklch(0.145 0.003 75 / 0.08);
94
100
  --sidebar-ring: oklch(0.353 0.003 75);
95
101
  --radius: 0.75rem;
96
102
  --radius-xs: 0.125rem; /** Micro radius — caret/arrow triangles and other sub-control geometry (was a silent Tailwind fallback, register P1-10). */
@@ -109,35 +115,39 @@
109
115
  --icon-feature: 1.5rem; /** 24px icon — feature/empty-state glyphs (design.md 'feature'). */
110
116
  --sidebar-width: 15rem; /** Expanded sidebar rail width (was a JS constant invisible to design-lint, register P2-13). */
111
117
  --sidebar-width-icon: 3rem; /** Collapsed icon-only rail width. */
118
+ --sidebar-width-mobile: 18rem; /** Width of the sidebar when it renders as an off-canvas sheet below the md breakpoint (was an inline `18rem` fallback, B6-08). */
119
+ --layout-header-height: 3.5rem; /** 56px app-shell header band (was a raw `h-14`, B6-08). Sticky/fixed content below the header offsets by this. */
120
+ --layout-overlay-max-height: calc(100dvh - 16rem); /** The tallest a scrolling overlay body (Command list, Board column, ShortcutOverlay) may grow: the dynamic viewport minus a 16rem chrome allowance. DTCG 2025.10 has no calc expression type, so this dimension is authored as the CSS string it resolves to and passed through verbatim (the same precedent as the `easing` linear() token). */
121
+ --panel-width-sm: 14rem; /** 224px floating panel (compact popover, small menu, single-value date trigger). */
122
+ --panel-width-md: 18rem; /** 288px floating panel — the default Popover, EmojiPicker, checklist card, range date trigger. */
123
+ --panel-width-lg: 20rem; /** 320px floating panel (rich HoverCard previews). */
112
124
  --shadow-overlay: 0 4px 14px -4px oklch(0.13 0.002 75 / 0.1), 0 2px 4px -2px oklch(0.13 0.002 75 / 0.06);
113
- --shadow-lit: inset 0 1px 0 0 oklch(1 0 0 / 0.12), 0 1px 2px 0 oklch(0.13 0.002 75 / 0.18), 0 2px 6px -2px oklch(0.13 0.002 75 / 0.14); /** Wave 2 'lit' action finish (MK-approved amendment to flat-by-default): a 1px on-fill top-light + warm-ink ambient pair for PRIMARY actions only. Attio-calibrated, warm-adapted. Never on cards/surfaces — the flat elevation model stands everywhere else. */
114
- --effect-blur-glass: 8px; /** Backdrop blur for the existing glass Button finish. Matches Tailwind v4's shipped blur-sm value while exposing the effect through a semantic contract. */
125
+ --effect-blur-glass: 8px; /** Backdrop blur for chrome that floats over content (the Attachment upload veil). The Button `glass` variant it was introduced for was deleted 2026-09-07 (audit D16). */
115
126
  --z-raised: 10; /** Local raise WITHIN a component's own stacking context (focused OTP slot / segmented item, floating label, bubble reactions, select scroll arrows). Never for portaled surfaces. */
116
- --z-overlay: 50; /** The single portal band: every portaled floating surface (dialog, sheet, popover, menu, select, tooltip, hover-card). Nesting resolves by DOM order — Base UI appends portals to <body>, so a Select inside a Dialog mounts later and stacks above within the same band. Toasts (sonner) are the documented exemption ABOVE this band (library-managed z; a toast must outrank a modal regardless of mount order). */
127
+ --z-overlay: 50; /** The portal band: every portaled floating surface (dialog, sheet, popover, menu, select, tooltip, hover-card). Nesting resolves by DOM order — Base UI appends portals to <body>, so a Select inside a Dialog mounts later and stacks above within the same band. Toasts are the ONE surface above it, on their own `z-toast` band. */
128
+ --z-toast: 60; /** The toast band, one step above `z-overlay`. A toast is the only surface that must outrank a modal REGARDLESS of mount order — the viewport mounts with the app provider, so DOM order would otherwise put every later-opened dialog on top of it. Within the band the stack counts DOWN from this value by `--toast-index`, so the frontmost toast is the highest. Nothing else may claim this band. */
117
129
  --opacity-dim: 50%; /** Element opacity for disabled controls and dimmed affordances (outside-month days, decorative chevrons). */
118
130
  --opacity-hint-soft: 60%; /** Element opacity for hover-revealed hints (e.g. sort affordance on row hover). */
119
131
  --opacity-hint: 70%; /** Element opacity for resting secondary controls that reach 100% on hover (e.g. alert close). */
120
132
  --opacity-track: 25%; /** Element opacity of the circular progress track ring. */
133
+ --alpha-hover: 7%; /** The alpha twin of surface-2: `bg-<ink>/(--alpha-hover)` composites the hover rung onto ANY backdrop (a kbd inside a hovered row, a chip on a well, a control over media). foreground at 7% over the page measures L 0.943 light / 0.267 dark over card — within 0.003 of the opaque rung. Theme-invariant. */
134
+ --alpha-pressed: 10%; /** The alpha twin of surface-3 (pressed/selected): foreground at 10% measures L 0.921 light / 0.292 dark over card. Theme-invariant. */
135
+ --alpha-border: 8%; /** The hairline alpha (D14): `border` is DERIVED as foreground at this alpha, so one hairline reads on page, card, well and dark band. 8% light (L 0.936, Geist gray-400 territory) / 14% dark (L 0.325 over card). */
121
136
  --alpha-tint-border: 70%; /** Border tint for focus (ring) and error (destructive) borders — design.md's ring/70 pattern. */
122
137
  --alpha-outline-border: 50%; /** Resting border of the outline button family (border-<family>). */
123
138
  --alpha-border-subtle: 20%; /** Alert variant border tint (border-<family>). */
124
- --alpha-border-soft: 30%; /** Toast (sonner) status border tint (border-<family>). */
139
+ --alpha-border-soft: 30%; /** The softer of the two border-tint steps. Introduced for the sonner toast surface; since the Base UI Toast migration (O2) the toast tint uses `alpha-border-subtle` like Alert, so this step currently has NO in-repo caller. Kept because it is published token surface — retiring it is a token-batch decision, not a component one. */
125
140
  --alpha-surface-faint: 5%; /** Resting wash of the outline button family (bg-<family>). */
126
- --alpha-surface-subtle: 10%; /** Hover wash of the outline button family (bg-<family>). */
127
141
  --alpha-ink-tint: 10%; /** Neutral pressed/hover ink tint (bg-foreground) — toggle pressed, chip remove hover. */
128
142
  --alpha-ink-tint-strong: 15%; /** Hovered pressed-state ink tint (bg-foreground). */
129
- --alpha-soft-hover: 20%; /** Hover wash of soft (subtle-filled) status surfaces. Theme-split: 30% in dark. */
130
- --alpha-soft-surface: 10%; /** Resting wash of soft status surfaces (chat destructive bubble). Theme-split: 20% in dark. */
131
143
  --alpha-input: 30%; /** Dark-theme input fill tint (bg-input) — see the dark-tint scoping note. */
132
- --alpha-input-hover: 50%; /** Dark-theme input fill tint on hover (bg-input). */
133
- --alpha-fill-hover: 80%; /** Hover dim of an interactive solid fill (bg-primary/secondary/muted/accent on chat bubbles, secondary button). */
134
144
  --alpha-wash-faint: 40%; /** Faint neutral wash (bg-muted) — rich-text toolbar. */
135
145
  --alpha-wash: 50%; /** Neutral wash (bg-muted) — card/table footers, ghost dark hover. */
136
146
  --alpha-wash-strong: 60%; /** Stronger neutral wash (bg-muted) — line-tab hover. */
137
147
  --alpha-backdrop-soft: 60%; /** Translucent surface backdrop (bg-background) — pill tab list. */
138
148
  --alpha-glass: 90%; /** Glass button surface (bg-background + backdrop-blur). */
139
149
  --alpha-glass-hover: 95%; /** Glass button surface on hover. */
140
- --alpha-link-hover: 80%; /** Hovered link text dim (text-info-text) in rendered rich text. */
150
+ --alpha-link-hover: 88%; /** Hovered link text dim, applied to a `<family>-text` ink in rendered rich text and on the `link` Button. 88%, not 80%: at 80% the light composites measured 4.03–4.11:1 for success/info/warning (2026-09-09) — a hover state that drops the link below WCAG 1.4.3 AA. contrast-check gates the composite, not just the solid ink. */
141
151
  --alpha-outline-soft: 50%; /** Soft neutral outline/ring (base outline default, date-picker today ring). */
142
152
  --font-family-sans: Geist, sans-serif;
143
153
  --font-family-mono: 'Geist Mono', monospace;
@@ -147,23 +157,29 @@
147
157
  --duration-fast: 150ms;
148
158
  --duration-base: 200ms;
149
159
  --duration-slow: 300ms;
160
+ --duration-indeterminate: 1200ms; /** 1200ms — the loop cadence of the ONE sanctioned looping utility, `motion-indeterminate` (an indeterminate Progress sweep; audit M-06). Not an interaction duration: interactions use fast/base/slow. */
150
161
  --motion-ease-standard: cubic-bezier(0.2, 0, 0, 1);
151
162
  --motion-ease-emphasized: cubic-bezier(0.3, 0, 0, 1);
152
163
  --motion-ease-exit: cubic-bezier(0.4, 0, 1, 1);
153
164
  --motion-ease-spring: linear(0, 0.5 60%, 1.05 80%, 0.98 90%, 1); /** CSS linear() spring with a very small overshoot — the success-bounce/appear curve for state-feedback micro-interactions (Phase M). Subtle by design: dense dev-tool aesthetic, not playful. */
154
165
  --motion-blur: 2px; /** Motion-blur amount for blur-fade entrances (Phase M text/element reveals). */
166
+ --border: oklch(0.145 0.003 75 / 0.08); /** DERIVED: foreground at 8% (alpha-border) — the one alpha hairline (D14). */
155
167
  --destructive-hover: oklch(0.455 0.213 27.52); /** DERIVED: destructive fill at L-0.05 (hover step). */
156
168
  --destructive-active: oklch(0.415 0.213 27.52); /** DERIVED: destructive fill at L-0.09 (active step). */
157
169
  --destructive-subtle-hover: oklch(0.91 0.036 20.4); /** DERIVED: destructive fill @7.000000000000001% composited over destructive-subtle (soft-hover surface, AA-gated against destructive-text). */
170
+ --destructive-subtle-active: oklch(0.883 0.046 19.3); /** DERIVED: destructive fill @12% composited over destructive-subtle (soft-pressed surface, AA-gated against destructive-text). */
158
171
  --success-hover: oklch(0.45 0.16 150); /** DERIVED: success fill at L-0.05 (hover step). */
159
172
  --success-active: oklch(0.41 0.16 150); /** DERIVED: success fill at L-0.09 (active step). */
160
173
  --success-subtle-hover: oklch(0.919 0.059 151.1); /** DERIVED: success fill @7.000000000000001% composited over success-subtle (soft-hover surface, AA-gated against success-text). */
174
+ --success-subtle-active: oklch(0.896 0.065 151.7); /** DERIVED: success fill @12% composited over success-subtle (soft-pressed surface, AA-gated against success-text). */
161
175
  --warning-hover: oklch(0.47 0.145 52); /** DERIVED: warning fill at L-0.05 (hover step). */
162
176
  --warning-active: oklch(0.43 0.145 52); /** DERIVED: warning fill at L-0.09 (active step). */
163
177
  --warning-subtle-hover: oklch(0.929 0.027 48.8); /** DERIVED: warning fill @7.000000000000001% composited over warning-subtle (soft-hover surface, AA-gated against warning-text). */
178
+ --warning-subtle-active: oklch(0.906 0.034 51.5); /** DERIVED: warning fill @12% composited over warning-subtle (soft-pressed surface, AA-gated against warning-text). */
164
179
  --info-hover: oklch(0.481 0.182 256); /** DERIVED: info fill at L-0.05 (hover step). */
165
180
  --info-active: oklch(0.441 0.182 256); /** DERIVED: info fill at L-0.09 (active step). */
166
181
  --info-subtle-hover: oklch(0.929 0.03 251.1); /** DERIVED: info fill @7.000000000000001% composited over info-subtle (soft-hover surface, AA-gated against info-text). */
182
+ --info-subtle-active: oklch(0.906 0.038 250.5); /** DERIVED: info fill @12% composited over info-subtle (soft-pressed surface, AA-gated against info-text). */
167
183
  }
168
184
 
169
185
  /**
@@ -182,26 +198,27 @@
182
198
  --primary-foreground: oklch(0.145 0.003 75);
183
199
  --primary-hover: oklch(0.97 0.003 75);
184
200
  --primary-active: oklch(0.994 0.002 75);
185
- --track: oklch(0.439 0.003 75);
186
- --secondary: oklch(0.269 0.003 75);
201
+ --surface-1: oklch(0.236 0.003 75); /** Dark ladder: card 0.205 -> surface-1 0.236 -> surface-2 0.269 -> surface-3 0.29 (lighter = higher, ~0.03 L per rung, the Radix/Linear dark step). */
202
+ --surface-2: oklch(0.269 0.003 75);
203
+ --surface-3: oklch(0.29 0.003 75);
204
+ --secondary: oklch(0.236 0.003 75);
187
205
  --secondary-foreground: oklch(0.922 0.003 75);
188
- --muted: oklch(0.269 0.003 75);
206
+ --muted: oklch(0.236 0.003 75);
189
207
  --muted-foreground: oklch(0.66 0.003 75);
190
208
  --muted-foreground-faint: oklch(0.559 0.003 75);
191
209
  --accent: oklch(0.269 0.003 75);
192
- --accent-foreground: oklch(0.967 0.003 75);
210
+ --accent-foreground: oklch(0.922 0.003 75);
193
211
  --destructive-subtle: oklch(0.275 0.07 25);
194
- --destructive-text: oklch(0.72 0.16 25);
212
+ --destructive-text: oklch(0.74 0.16 25); /** Dark red ink (was red.400, L 0.72); +0.02 L so the soft pressed rung (fill @40% over subtle) clears 4.5:1 — see the light destructive-text note. */
195
213
  --destructive-border: oklch(0.72 0.16 25); /** Dark-ground invalid-state border ink. red.400 at --alpha-tint-border measures 4.00:1 on background and 3.86:1 on card, clearing the 3:1 WCAG 1.4.11 floor the shared destructive fill misses (1.92:1). */
196
214
  --success-subtle: oklch(0.276 0.061 150);
197
- --success-text: oklch(0.72 0.17 150);
215
+ --success-text: oklch(0.74 0.17 150); /** Dark green ink (was green.500, L 0.72); +0.02 L for the soft pressed rung. */
198
216
  --warning-subtle: oklch(0.28 0.069 42);
199
217
  --warning-text: oklch(0.769 0.188 70.08);
200
218
  --info-subtle: oklch(0.275 0.059 255);
201
- --info-text: oklch(0.72 0.13 256);
219
+ --info-text: oklch(0.76 0.13 256); /** Dark link / informational blue ink (was blue.400, L 0.72); +0.04 L for the soft pressed rung — blue had the least headroom (4.50:1 at hover). */
202
220
  --overlay: oklch(0 0 0 / 0.55);
203
- --border: oklch(0.269 0.003 75);
204
- --input: oklch(0.269 0.003 75);
221
+ --input: oklch(0.922 0.003 75 / 0.14);
205
222
  --ring: oklch(0.922 0.003 75);
206
223
  --chart-1: oklch(0.623 0.214 259.81);
207
224
  --chart-2: oklch(0.696 0.17 162.48);
@@ -211,6 +228,7 @@
211
228
  --chart-6: oklch(0.69 0.21 25);
212
229
  --chart-7: oklch(0.72 0.15 103.9);
213
230
  --chart-8: oklch(0.72 0.13 256);
231
+ --chart-single: oklch(0.922 0.003 75); /** Repeated here on purpose: an alias is resolved per run, so a light-only alias would leak the LIGHT ink into `.dark` through the cascade (the contrast gate caught exactly that). */
214
232
  --tag-blue: oklch(0.72 0.14 256);
215
233
  --tag-blue-subtle: oklch(0.275 0.05 256);
216
234
  --tag-blue-text: oklch(0.75 0.13 256);
@@ -241,23 +259,27 @@
241
259
  --tag-purple: oklch(0.72 0.15 295);
242
260
  --tag-purple-subtle: oklch(0.275 0.05 295);
243
261
  --tag-purple-text: oklch(0.75 0.13 295);
244
- --sidebar: oklch(0.145 0.003 75);
245
- --sidebar-foreground: oklch(0.87 0.003 75);
262
+ --sidebar: oklch(0.205 0.003 75);
263
+ --sidebar-foreground: oklch(0.922 0.003 75);
246
264
  --sidebar-primary: oklch(0.922 0.003 75);
247
265
  --sidebar-primary-foreground: oklch(0.145 0.003 75);
248
- --sidebar-accent: oklch(0.205 0.003 75);
266
+ --sidebar-accent: oklch(0.269 0.003 75);
249
267
  --sidebar-accent-foreground: oklch(0.922 0.003 75);
250
- --sidebar-border: oklch(0.269 0.003 75);
268
+ --sidebar-border: oklch(0.922 0.003 75 / 0.14);
251
269
  --sidebar-ring: oklch(0.922 0.003 75);
252
- --brand: oklch(0.86 0.21 148); /** The phosphor-green brand accent, DARK half — MK's pick (13.3:1 on the dark canvas). Marker roles only. */
253
- --alpha-soft-hover: 30%; /** Dark half of the theme-split soft-surface hover wash. */
254
- --alpha-soft-surface: 20%; /** Dark half of the theme-split soft-surface resting wash. */
270
+ --brand: oklch(0.86 0.21 148); /** The phosphor-green brand accent, DARK half — MK's pick (13.3:1 on the dark canvas). Marker roles plus the `cta` Button's wash/outline. */
271
+ --brand-text: oklch(0.86 0.21 148); /** The page-readable brand ink, DARK half. On the dark and marketing grounds the marker value already measures 12.2:1 as a label, so brand-text and brand carry the SAME value here — the split exists because the light half cannot. */
272
+ --alpha-border: 14%; /** Dark half of the hairline alpha (D14): near-white ink needs more alpha than near-black to read as a line — foreground at 14% over card measures L 0.325, over the page 0.302. */
255
273
  --shadow-overlay: 0 8px 28px -6px oklch(0 0 0 / 0.48), 0 2px 8px -2px oklch(0 0 0 / 0.4); /** DARK overlay shadow, strengthened (Wave 1 — Attio-calibrated): the old single 24px layer was near-invisible on the dark canvas; this two-layer ramp restores the floating cue while staying below Attio's 88px maximal ramp. */
256
- --shadow-lit: inset 0 1px 0 0 oklch(1 0 0 / 0.35), 0 2px 6px -2px oklch(0 0 0 / 0.5);
274
+ --border: oklch(0.922 0.003 75 / 0.14); /** DERIVED: foreground at 14% (alpha-border) the one alpha hairline (D14). */
257
275
  --destructive-subtle-hover: oklch(0.34 0.123 26.3); /** DERIVED: destructive fill @30% composited over destructive-subtle (soft-hover surface, AA-gated against destructive-text). */
276
+ --destructive-subtle-active: oklch(0.364 0.137 26.9); /** DERIVED: destructive fill @40% composited over destructive-subtle (soft-pressed surface, AA-gated against destructive-text). */
258
277
  --success-subtle-hover: oklch(0.348 0.092 148.9); /** DERIVED: success fill @30% composited over success-subtle (soft-hover surface, AA-gated against success-text). */
278
+ --success-subtle-active: oklch(0.371 0.101 148.5); /** DERIVED: success fill @40% composited over success-subtle (soft-pressed surface, AA-gated against success-text). */
259
279
  --warning-subtle-hover: oklch(0.356 0.093 46.6); /** DERIVED: warning fill @30% composited over warning-subtle (soft-hover surface, AA-gated against warning-text). */
280
+ --warning-subtle-active: oklch(0.381 0.1 47.3); /** DERIVED: warning fill @40% composited over warning-subtle (soft-pressed surface, AA-gated against warning-text). */
260
281
  --info-subtle-hover: oklch(0.354 0.101 254.3); /** DERIVED: info fill @30% composited over info-subtle (soft-hover surface, AA-gated against info-text). */
282
+ --info-subtle-active: oklch(0.38 0.114 254.5); /** DERIVED: info fill @40% composited over info-subtle (soft-pressed surface, AA-gated against info-text). */
261
283
  }
262
284
 
263
285
  /**
@@ -276,26 +298,27 @@
276
298
  --primary-foreground: oklch(0.145 0.003 75);
277
299
  --primary-hover: oklch(0.97 0.003 75);
278
300
  --primary-active: oklch(0.994 0.002 75);
279
- --track: oklch(0.439 0.003 75);
280
- --secondary: oklch(0.269 0.003 75);
301
+ --surface-1: oklch(0.236 0.003 75); /** Dark ladder: card 0.205 -> surface-1 0.236 -> surface-2 0.269 -> surface-3 0.29 (lighter = higher, ~0.03 L per rung, the Radix/Linear dark step). */
302
+ --surface-2: oklch(0.269 0.003 75);
303
+ --surface-3: oklch(0.29 0.003 75);
304
+ --secondary: oklch(0.236 0.003 75);
281
305
  --secondary-foreground: oklch(0.922 0.003 75);
282
- --muted: oklch(0.269 0.003 75);
306
+ --muted: oklch(0.236 0.003 75);
283
307
  --muted-foreground: oklch(0.66 0.003 75);
284
308
  --muted-foreground-faint: oklch(0.559 0.003 75);
285
309
  --accent: oklch(0.269 0.003 75);
286
- --accent-foreground: oklch(0.967 0.003 75);
310
+ --accent-foreground: oklch(0.922 0.003 75);
287
311
  --destructive-subtle: oklch(0.275 0.07 25);
288
- --destructive-text: oklch(0.72 0.16 25);
312
+ --destructive-text: oklch(0.74 0.16 25); /** Dark red ink (was red.400, L 0.72); +0.02 L so the soft pressed rung (fill @40% over subtle) clears 4.5:1 — see the light destructive-text note. */
289
313
  --destructive-border: oklch(0.72 0.16 25); /** Dark-ground invalid-state border ink. red.400 at --alpha-tint-border measures 4.00:1 on background and 3.86:1 on card, clearing the 3:1 WCAG 1.4.11 floor the shared destructive fill misses (1.92:1). */
290
314
  --success-subtle: oklch(0.276 0.061 150);
291
- --success-text: oklch(0.72 0.17 150);
315
+ --success-text: oklch(0.74 0.17 150); /** Dark green ink (was green.500, L 0.72); +0.02 L for the soft pressed rung. */
292
316
  --warning-subtle: oklch(0.28 0.069 42);
293
317
  --warning-text: oklch(0.769 0.188 70.08);
294
318
  --info-subtle: oklch(0.275 0.059 255);
295
- --info-text: oklch(0.72 0.13 256);
319
+ --info-text: oklch(0.76 0.13 256); /** Dark link / informational blue ink (was blue.400, L 0.72); +0.04 L for the soft pressed rung — blue had the least headroom (4.50:1 at hover). */
296
320
  --overlay: oklch(0 0 0 / 0.55);
297
- --border: oklch(0.269 0.003 75);
298
- --input: oklch(0.269 0.003 75);
321
+ --input: oklch(0.922 0.003 75 / 0.14);
299
322
  --ring: oklch(0.922 0.003 75);
300
323
  --chart-1: oklch(0.623 0.214 259.81);
301
324
  --chart-2: oklch(0.696 0.17 162.48);
@@ -305,6 +328,7 @@
305
328
  --chart-6: oklch(0.69 0.21 25);
306
329
  --chart-7: oklch(0.72 0.15 103.9);
307
330
  --chart-8: oklch(0.72 0.13 256);
331
+ --chart-single: oklch(0.922 0.003 75); /** Repeated here on purpose: an alias is resolved per run, so a light-only alias would leak the LIGHT ink into `.dark` through the cascade (the contrast gate caught exactly that). */
308
332
  --tag-blue: oklch(0.72 0.14 256);
309
333
  --tag-blue-subtle: oklch(0.275 0.05 256);
310
334
  --tag-blue-text: oklch(0.75 0.13 256);
@@ -335,23 +359,27 @@
335
359
  --tag-purple: oklch(0.72 0.15 295);
336
360
  --tag-purple-subtle: oklch(0.275 0.05 295);
337
361
  --tag-purple-text: oklch(0.75 0.13 295);
338
- --sidebar: oklch(0.145 0.003 75);
339
- --sidebar-foreground: oklch(0.87 0.003 75);
362
+ --sidebar: oklch(0.205 0.003 75);
363
+ --sidebar-foreground: oklch(0.922 0.003 75);
340
364
  --sidebar-primary: oklch(0.922 0.003 75);
341
365
  --sidebar-primary-foreground: oklch(0.145 0.003 75);
342
- --sidebar-accent: oklch(0.205 0.003 75);
366
+ --sidebar-accent: oklch(0.269 0.003 75);
343
367
  --sidebar-accent-foreground: oklch(0.922 0.003 75);
344
- --sidebar-border: oklch(0.269 0.003 75);
368
+ --sidebar-border: oklch(0.922 0.003 75 / 0.14);
345
369
  --sidebar-ring: oklch(0.922 0.003 75);
346
- --brand: oklch(0.86 0.21 148); /** The phosphor-green brand accent, DARK half — MK's pick (13.3:1 on the dark canvas). Marker roles only. */
347
- --alpha-soft-hover: 30%; /** Dark half of the theme-split soft-surface hover wash. */
348
- --alpha-soft-surface: 20%; /** Dark half of the theme-split soft-surface resting wash. */
370
+ --brand: oklch(0.86 0.21 148); /** The phosphor-green brand accent, DARK half — MK's pick (13.3:1 on the dark canvas). Marker roles plus the `cta` Button's wash/outline. */
371
+ --brand-text: oklch(0.86 0.21 148); /** The page-readable brand ink, DARK half. On the dark and marketing grounds the marker value already measures 12.2:1 as a label, so brand-text and brand carry the SAME value here — the split exists because the light half cannot. */
372
+ --alpha-border: 14%; /** Dark half of the hairline alpha (D14): near-white ink needs more alpha than near-black to read as a line — foreground at 14% over card measures L 0.325, over the page 0.302. */
349
373
  --shadow-overlay: 0 8px 28px -6px oklch(0 0 0 / 0.48), 0 2px 8px -2px oklch(0 0 0 / 0.4); /** DARK overlay shadow, strengthened (Wave 1 — Attio-calibrated): the old single 24px layer was near-invisible on the dark canvas; this two-layer ramp restores the floating cue while staying below Attio's 88px maximal ramp. */
350
- --shadow-lit: inset 0 1px 0 0 oklch(1 0 0 / 0.35), 0 2px 6px -2px oklch(0 0 0 / 0.5);
374
+ --border: oklch(0.922 0.003 75 / 0.14); /** DERIVED: foreground at 14% (alpha-border) the one alpha hairline (D14). */
351
375
  --destructive-subtle-hover: oklch(0.34 0.123 26.3); /** DERIVED: destructive fill @30% composited over destructive-subtle (soft-hover surface, AA-gated against destructive-text). */
376
+ --destructive-subtle-active: oklch(0.364 0.137 26.9); /** DERIVED: destructive fill @40% composited over destructive-subtle (soft-pressed surface, AA-gated against destructive-text). */
352
377
  --success-subtle-hover: oklch(0.348 0.092 148.9); /** DERIVED: success fill @30% composited over success-subtle (soft-hover surface, AA-gated against success-text). */
378
+ --success-subtle-active: oklch(0.371 0.101 148.5); /** DERIVED: success fill @40% composited over success-subtle (soft-pressed surface, AA-gated against success-text). */
353
379
  --warning-subtle-hover: oklch(0.356 0.093 46.6); /** DERIVED: warning fill @30% composited over warning-subtle (soft-hover surface, AA-gated against warning-text). */
380
+ --warning-subtle-active: oklch(0.381 0.1 47.3); /** DERIVED: warning fill @40% composited over warning-subtle (soft-pressed surface, AA-gated against warning-text). */
354
381
  --info-subtle-hover: oklch(0.354 0.101 254.3); /** DERIVED: info fill @30% composited over info-subtle (soft-hover surface, AA-gated against info-text). */
382
+ --info-subtle-active: oklch(0.38 0.114 254.5); /** DERIVED: info fill @40% composited over info-subtle (soft-pressed surface, AA-gated against info-text). */
355
383
  }
356
384
 
357
385
  /* Two-layer type scale (T1): both ladders + the active binding (product by default). */
@@ -407,11 +435,13 @@
407
435
  --color-card-foreground: var(--card-foreground);
408
436
  --color-popover: var(--popover);
409
437
  --color-popover-foreground: var(--popover-foreground);
438
+ --color-surface-1: var(--surface-1);
439
+ --color-surface-2: var(--surface-2);
440
+ --color-surface-3: var(--surface-3);
410
441
  --color-primary: var(--primary);
411
442
  --color-primary-foreground: var(--primary-foreground);
412
443
  --color-primary-hover: var(--primary-hover);
413
444
  --color-primary-active: var(--primary-active);
414
- --color-track: var(--track);
415
445
  --color-secondary: var(--secondary);
416
446
  --color-secondary-foreground: var(--secondary-foreground);
417
447
  --color-muted: var(--muted);
@@ -437,7 +467,9 @@
437
467
  --color-info-subtle: var(--info-subtle);
438
468
  --color-info-text: var(--info-text);
439
469
  --color-overlay: var(--overlay);
440
- --color-border: var(--border);
470
+ --color-media-scrim: var(--media-scrim);
471
+ --color-media-scrim-strong: var(--media-scrim-strong);
472
+ --color-media-foreground: var(--media-foreground);
441
473
  --color-input: var(--input);
442
474
  --color-ring: var(--ring);
443
475
  --color-chart-1: var(--chart-1);
@@ -448,7 +480,9 @@
448
480
  --color-chart-6: var(--chart-6);
449
481
  --color-chart-7: var(--chart-7);
450
482
  --color-chart-8: var(--chart-8);
483
+ --color-chart-single: var(--chart-single);
451
484
  --color-brand: var(--brand);
485
+ --color-brand-text: var(--brand-text);
452
486
  --color-tag-blue: var(--tag-blue);
453
487
  --color-tag-blue-subtle: var(--tag-blue-subtle);
454
488
  --color-tag-blue-text: var(--tag-blue-text);
@@ -487,18 +521,23 @@
487
521
  --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
488
522
  --color-sidebar-border: var(--sidebar-border);
489
523
  --color-sidebar-ring: var(--sidebar-ring);
524
+ --color-border: var(--border);
490
525
  --color-destructive-hover: var(--destructive-hover);
491
526
  --color-destructive-active: var(--destructive-active);
492
527
  --color-destructive-subtle-hover: var(--destructive-subtle-hover);
528
+ --color-destructive-subtle-active: var(--destructive-subtle-active);
493
529
  --color-success-hover: var(--success-hover);
494
530
  --color-success-active: var(--success-active);
495
531
  --color-success-subtle-hover: var(--success-subtle-hover);
532
+ --color-success-subtle-active: var(--success-subtle-active);
496
533
  --color-warning-hover: var(--warning-hover);
497
534
  --color-warning-active: var(--warning-active);
498
535
  --color-warning-subtle-hover: var(--warning-subtle-hover);
536
+ --color-warning-subtle-active: var(--warning-subtle-active);
499
537
  --color-info-hover: var(--info-hover);
500
538
  --color-info-active: var(--info-active);
501
539
  --color-info-subtle-hover: var(--info-subtle-hover);
540
+ --color-info-subtle-active: var(--info-subtle-active);
502
541
  /* text-* remap — utilities resolve through the scoped --type-* binding (CX-6) */
503
542
  --text-xs: var(--type-xs);
504
543
  --text-xs--line-height: var(--type-xs--line-height);
@@ -577,6 +616,8 @@
577
616
  --font-sans: var(--font-family-sans);
578
617
  --font-mono: var(--font-family-mono);
579
618
  --font-serif: var(--font-family-serif);
619
+ --font-display: var(--font-family-display);
620
+ --font-pixel: var(--font-family-pixel);
580
621
  --ease-standard: var(--motion-ease-standard);
581
622
  --ease-emphasized: var(--motion-ease-emphasized);
582
623
  --ease-exit: var(--motion-ease-exit);