diff --git a/CHANGELOG.md b/CHANGELOG.md index e4953ff7..3c1fa20b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), ## Unreleased +### ⚠️ Breaking Changes +- **tokens:** remove the six `base` relative shade aliases (`--sf-color-base-superlight`, `-xlight`, `-lighter`, `-darker`, `-xdark`, `-superdark`). `base` is an absolute scale, so direction-named aliases were misleading (e.g. `-lighter` resolved darker than a near-white base in light mode). Use the numeric ramp (`--sf-color-base-50`…`-950`) for fixed shades, or the surface tokens (`--sf-color-bg` / `-inset` / `-raised`) for mode-adaptive elevation. See `docs/migration.md`. + ## [0.6.25] - 2026-06-29 ### Features diff --git a/badges/badge-optimal.json b/badges/badge-optimal.json index 18209ea4..1536a71b 100644 --- a/badges/badge-optimal.json +++ b/badges/badge-optimal.json @@ -1,7 +1,7 @@ { "schemaVersion": 1, "label": "optimal", - "message": "17.6 kB gzip", + "message": "17.5 kB gzip", "color": "brightgreen", "namedLogo": "css3" } diff --git a/configurator/src/data/api-index.generated.json b/configurator/src/data/api-index.generated.json index 254517b6..5a9af307 100644 --- a/configurator/src/data/api-index.generated.json +++ b/configurator/src/data/api-index.generated.json @@ -2,7 +2,7 @@ "_sync": { "generatedBy": "configurator/scripts/sync-api.mjs", "source": "docs/api-index.json", - "tokensHash": "99d86a47c17a", + "tokensHash": "a6a2fe9aab66", "bundles": [ "full", "optimal", @@ -10,15 +10,15 @@ "optimal-utilities" ], "counts": { - "tokens": 691, + "tokens": 685, "byTier": { - "PUBLIC": 635, + "PUBLIC": 629, "PUBLIC-ADVANCED": 55, "INTERNAL": 1 }, "byCategory": { "Layout tokens": 54, - "Core tokens": 608, + "Core tokens": 602, "Macro tokens": 23, "Component tokens": 6 } @@ -2236,8 +2236,8 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Base color at pressed/active brightness.", - "value": "var(--sf-color-base-xdark)", - "aliasOf": "--sf-color-base-xdark", + "value": "oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.08 + var(--sf-is-dark) * 0.16), 0.99) c h)", + "aliasOf": null, "registered": false, "syntax": null, "fallbackOnly": false, @@ -2259,8 +2259,8 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Base color at hover brightness.", - "value": "var(--sf-color-base-darker)", - "aliasOf": "--sf-color-base-darker", + "value": "oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.04 + var(--sf-is-dark) * 0.08), 0.99) c h)", + "aliasOf": null, "registered": false, "syntax": null, "fallbackOnly": false, @@ -2282,7 +2282,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Very light base shade. Hover fills, badge backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-100), var(--sf-color-base))", + "value": "oklch(from var(--sf-color-base) 0.94 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2305,7 +2305,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Light base shade.", - "value": "color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-200), var(--sf-color-base))", + "value": "oklch(from var(--sf-color-base) 0.88 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2328,7 +2328,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Light-mid base shade. Borders on light backgrounds.", - "value": "color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-300), var(--sf-color-base))", + "value": "oklch(from var(--sf-color-base) 0.78 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2351,7 +2351,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Mid-light base shade. Disabled fills.", - "value": "color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-400), var(--sf-color-base))", + "value": "oklch(from var(--sf-color-base) 0.65 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2374,7 +2374,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Lightest base tint.", - "value": "color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-50), var(--sf-color-base))", + "value": "oklch(from var(--sf-color-base) 0.97 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2397,8 +2397,8 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Mid base shade — the 'pure' hue.", - "value": "var(--sf-color-base)", - "aliasOf": "--sf-color-base", + "value": "oklch(from var(--sf-color-base) 0.50 c h)", + "aliasOf": null, "registered": false, "syntax": null, "fallbackOnly": false, @@ -2420,7 +2420,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Mid-dark base shade. Text on light surfaces.", - "value": "color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-600), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-base) 0.37 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2443,7 +2443,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Dark base shade.", - "value": "color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-700), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-base) 0.27 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2466,7 +2466,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Very dark base shade.", - "value": "color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-800), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-base) 0.17 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2489,7 +2489,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Near-black base shade.", - "value": "color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-900), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-base) 0.11 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2512,7 +2512,7 @@ "group": "base", "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", "note": "Darkest base tint.", - "value": "color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-950), var(--sf-color-text))", + "value": "oklch(from var(--sf-color-base) 0.06 c h)", "aliasOf": null, "registered": false, "syntax": null, @@ -2641,29 +2641,6 @@ "optimal-utilities" ] }, - { - "name": "--sf-color-base-darker", - "tier": "PUBLIC", - "role": "consumption", - "namespace": "color", - "category": "Core tokens", - "group": "base", - "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", - "note": "Deep base shade.", - "value": "var(--sf-color-base-600)", - "aliasOf": "--sf-color-base-600", - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal", - "optimal-components", - "optimal-utilities" - ] - }, { "name": "--sf-color-base-ghost", "tier": "PUBLIC", @@ -2687,29 +2664,6 @@ "optimal-utilities" ] }, - { - "name": "--sf-color-base-lighter", - "tier": "PUBLIC", - "role": "consumption", - "namespace": "color", - "category": "Core tokens", - "group": "base", - "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", - "note": "Light base shade.", - "value": "var(--sf-color-base-400)", - "aliasOf": "--sf-color-base-400", - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal", - "optimal-components", - "optimal-utilities" - ] - }, { "name": "--sf-color-base-muted", "tier": "PUBLIC", @@ -2802,98 +2756,6 @@ "optimal-utilities" ] }, - { - "name": "--sf-color-base-superdark", - "tier": "PUBLIC", - "role": "consumption", - "namespace": "color", - "category": "Core tokens", - "group": "base", - "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", - "note": "Near-black base shade.", - "value": "var(--sf-color-base-950)", - "aliasOf": "--sf-color-base-950", - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal", - "optimal-components", - "optimal-utilities" - ] - }, - { - "name": "--sf-color-base-superlight", - "tier": "PUBLIC", - "role": "consumption", - "namespace": "color", - "category": "Core tokens", - "group": "base", - "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", - "note": "Near-white base shade.", - "value": "var(--sf-color-base-50)", - "aliasOf": "--sf-color-base-50", - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal", - "optimal-components", - "optimal-utilities" - ] - }, - { - "name": "--sf-color-base-xdark", - "tier": "PUBLIC", - "role": "consumption", - "namespace": "color", - "category": "Core tokens", - "group": "base", - "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", - "note": "Extra-dark base shade.", - "value": "var(--sf-color-base-800)", - "aliasOf": "--sf-color-base-800", - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal", - "optimal-components", - "optimal-utilities" - ] - }, - { - "name": "--sf-color-base-xlight", - "tier": "PUBLIC", - "role": "consumption", - "namespace": "color", - "category": "Core tokens", - "group": "base", - "description": "Semantic base-color scale derived from --sf-color-base. Covers fills, hover/active states, and ghost variants for secondary interactive elements.", - "note": "Extra-light base shade.", - "value": "var(--sf-color-base-200)", - "aliasOf": "--sf-color-base-200", - "registered": false, - "syntax": null, - "fallbackOnly": false, - "optional": false, - "layer": "slashed.tokens", - "bundles": [ - "full", - "optimal", - "optimal-components", - "optimal-utilities" - ] - }, { "name": "--sf-color-bg", "tier": "PUBLIC", diff --git a/configurator/src/data/token-registry.generated.json b/configurator/src/data/token-registry.generated.json index f9969d68..35fa0783 100644 --- a/configurator/src/data/token-registry.generated.json +++ b/configurator/src/data/token-registry.generated.json @@ -449,7 +449,8 @@ }, { "id": 110, - "name": "--sf-color-base-darker" + "name": "--sf-color-base-darker", + "removed": true }, { "id": 111, @@ -461,7 +462,8 @@ }, { "id": 113, - "name": "--sf-color-base-lighter" + "name": "--sf-color-base-lighter", + "removed": true }, { "id": 114, @@ -473,19 +475,23 @@ }, { "id": 116, - "name": "--sf-color-base-superdark" + "name": "--sf-color-base-superdark", + "removed": true }, { "id": 117, - "name": "--sf-color-base-superlight" + "name": "--sf-color-base-superlight", + "removed": true }, { "id": 118, - "name": "--sf-color-base-xdark" + "name": "--sf-color-base-xdark", + "removed": true }, { "id": 119, - "name": "--sf-color-base-xlight" + "name": "--sf-color-base-xlight", + "removed": true }, { "id": 120, diff --git a/core/tokens.css b/core/tokens.css index 3c87633f..4bc09994 100644 --- a/core/tokens.css +++ b/core/tokens.css @@ -834,56 +834,43 @@ /* ---------------------------------------------------------- - base — V-shaped ramp (inverted tint direction) + base — fixed-lightness ramp (mode-independent, monotonic) ──────────────────────────────────────────────────────── - Unlike every other family, base is a near-white (light mode) - or near-black (dark mode) surface token, not a mid-lightness - brand colour. There is nowhere "lighter" to go from near-white, - so the tint direction is inverted: steps 50-400 mix --sf-color-text - INTO base (progressively darker in light mode, progressively - lighter in dark mode). Steps 600-950 mix base INTO text in both - modes (the same direction as other families' shades). - - Approximate OKLCH L values — default palette, light mode: - base-50 ≈ 0.946 barely off-surface (dividers, zebra rows) - base-100 ≈ 0.931 subtle surface variant - base-200 ≈ 0.900 light gray (well / inset areas) - base-300 ≈ 0.840 medium-light gray - base-400 ≈ 0.748 medium gray (secondary UI elements) - base-500 ≈ 0.960 base itself (source token) - base-600 ≈ 0.850 medium-light (toward text, from 500) - base-700 ≈ 0.762 - base-800 ≈ 0.630 - base-900 ≈ 0.337 - base-950 ≈ 0.170 near-black - - Dark mode reverses the visual: base-50 becomes near-white-ish, - base-950 becomes near-black-ish, base-500 is the dark surface. - - SEMANTIC ALIAS MAPPING (consistent position in ramp, not absolute L): - superlight = base-50 (closest to surface — barely distinguishable) - xlight = base-200 (light gray) - lighter = base-400 (medium gray — "lighter contrast" toward text) - darker = base-600 (one step past base toward text from shade side) - xdark = base-800 - superdark = base-950 (near ink color) - - When you need surface-level differentiation, prefer - --sf-color-inset / --sf-color-raised / --sf-color-bg over the - numbered scale. For overlays, prefer the alpha variants (-a10…-a80) - which are mode-safe by transparency and compose cleanly on any bg. + base is a surface-elevation family, not a mid-lightness brand + colour. The ramp uses oklch() relative syntax with fixed L steps + spanning 0.97 → 0.06, preserving the base source's hue and chroma. + 50 is always near-white; 950 is always near-black regardless of + light/dark mode or the source colour's position. + + OKLCH L values (fixed, mode-independent): + base-50 = 0.97 near-white + base-100 = 0.94 very light gray + base-200 = 0.88 light gray + base-300 = 0.78 medium-light gray + base-400 = 0.65 medium gray + base-500 = 0.50 mid gray + base-600 = 0.37 medium-dark gray + base-700 = 0.27 dark gray + base-800 = 0.17 very dark gray + base-900 = 0.11 near-black + base-950 = 0.06 near-black + + For mode-adaptive surface differentiation use the surface tokens + (--sf-color-inset / --sf-color-raised / --sf-color-bg) which derive + from --sf-color-base via relative oklch and adapt to light/dark mode. + For overlays use alpha variants (-a10…-a80). ---------------------------------------------------------- */ - --sf-color-base-50: color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-50), var(--sf-color-base)); - --sf-color-base-100: color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-100), var(--sf-color-base)); - --sf-color-base-200: color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-200), var(--sf-color-base)); - --sf-color-base-300: color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-300), var(--sf-color-base)); - --sf-color-base-400: color-mix(in oklab, var(--sf-color-text) var(--sf-palette-mix-400), var(--sf-color-base)); - --sf-color-base-500: var(--sf-color-base); - --sf-color-base-600: color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-600), var(--sf-color-text)); - --sf-color-base-700: color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-700), var(--sf-color-text)); - --sf-color-base-800: color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-800), var(--sf-color-text)); - --sf-color-base-900: color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-900), var(--sf-color-text)); - --sf-color-base-950: color-mix(in oklab, var(--sf-color-base) var(--sf-palette-mix-950), var(--sf-color-text)); + --sf-color-base-50: oklch(from var(--sf-color-base) 0.97 c h); + --sf-color-base-100: oklch(from var(--sf-color-base) 0.94 c h); + --sf-color-base-200: oklch(from var(--sf-color-base) 0.88 c h); + --sf-color-base-300: oklch(from var(--sf-color-base) 0.78 c h); + --sf-color-base-400: oklch(from var(--sf-color-base) 0.65 c h); + --sf-color-base-500: oklch(from var(--sf-color-base) 0.50 c h); + --sf-color-base-600: oklch(from var(--sf-color-base) 0.37 c h); + --sf-color-base-700: oklch(from var(--sf-color-base) 0.27 c h); + --sf-color-base-800: oklch(from var(--sf-color-base) 0.17 c h); + --sf-color-base-900: oklch(from var(--sf-color-base) 0.11 c h); + --sf-color-base-950: oklch(from var(--sf-color-base) 0.06 c h); --sf-color-base-a5: oklch(from var(--sf-color-base) l c h / 0.05); --sf-color-base-a10: oklch(from var(--sf-color-base) l c h / 0.10); @@ -891,14 +878,13 @@ --sf-color-base-a50: oklch(from var(--sf-color-base) l c h / 0.50); --sf-color-base-a80: oklch(from var(--sf-color-base) l c h / 0.80); - --sf-color-base-superlight: var(--sf-color-base-50); - --sf-color-base-xlight: var(--sf-color-base-200); - --sf-color-base-lighter: var(--sf-color-base-400); - --sf-color-base-darker: var(--sf-color-base-600); - --sf-color-base-xdark: var(--sf-color-base-800); - --sf-color-base-superdark: var(--sf-color-base-950); - --sf-color-base--hover: var(--sf-color-base-darker); - --sf-color-base--active: var(--sf-color-base-xdark); + /* No relative aliases (lighter/darker/xlight/…) on base: it is an + absolute scale, so a step's name would lie depending on where the + source sits (e.g. "lighter" would be darker than a near-white base + in light mode). For relative, mode-adaptive surface elevation use + --sf-color-bg / --sf-color-inset / --sf-color-raised instead. */ + --sf-color-base--hover: oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.04 + var(--sf-is-dark) * 0.08), 0.99) c h); + --sf-color-base--active: oklch(from var(--sf-color-base) clamp(0.01, calc(l - 0.08 + var(--sf-is-dark) * 0.16), 0.99) c h); --sf-color-base-subtle: var(--sf-color-base-a10); --sf-color-base-muted: var(--sf-color-base-a30); --sf-color-base-ghost: var(--sf-color-base-a5); diff --git a/demos/full-api-demo-with-overrides.html b/demos/full-api-demo-with-overrides.html index 1c113fd8..766204c9 100644 --- a/demos/full-api-demo-with-overrides.html +++ b/demos/full-api-demo-with-overrides.html @@ -4,7 +4,7 @@ SLASHED — Full API Demo (overridden) - +