From 6d51c4e3b6328bc2446a61a0158a9f8cd619ea59 Mon Sep 17 00:00:00 2001 From: Austin McShan Date: Sun, 1 Feb 2026 09:09:16 -0600 Subject: [PATCH 1/3] chore(core): refine color manipulation functions --- packages/core/src/utils/functions.css | 68 ++++++++++++++++++--------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/packages/core/src/utils/functions.css b/packages/core/src/utils/functions.css index cfe1b9d..500a3a2 100644 --- a/packages/core/src/utils/functions.css +++ b/packages/core/src/utils/functions.css @@ -45,21 +45,25 @@ } /** - * --s-saturate: Increase chroma/saturation + * --s-saturate: Increase chroma/saturation (gamut-aware) + * Boosts the C (Chroma) channel while clamping to prevent gamut overflow. + * Colors are pushed toward P3 space limits when hardware supports it. * @param --color: The base color * @param --amount: Amount to increase (0-0.4) */ @function --s-saturate(--color, --amount) { - result: oklch(from var(--color) l calc(c + var(--amount)) h); + result: oklch(from var(--color) l min(0.4, calc(c + var(--amount))) h); } /** * --s-desaturate: Decrease chroma/saturation + * Pulls the C (Chroma) channel toward zero, creating muted/grayscale versions + * while retaining the same perceived brightness. Clamped to prevent negatives. * @param --color: The base color * @param --amount: Amount to decrease (0-0.4) */ @function --s-desaturate(--color, --amount) { - result: oklch(from var(--color) l calc(c - var(--amount)) h); + result: oklch(from var(--color) l max(0, calc(c - var(--amount))) h); } /** @@ -84,24 +88,30 @@ ============================================================================= */ /** - * --s-glow: Generate a glowing box-shadow + * --s-glow: Generate a glowing box-shadow simulating light emission + * Uses boosted chroma in inner layers for vibrant "light source" effect, + * fading to softer outer layers. The high-chroma core simulates photon emission. * @param --color: The glow color * @param --intensity: Intensity multiplier (1-5) */ @function --s-glow(--color, --intensity) { - result: 0 0 calc(var(--intensity) * 10px) oklch(from var(--color) l c h / 0.5), - 0 0 calc(var(--intensity) * 20px) oklch(from var(--color) l c h / 0.3), - 0 0 calc(var(--intensity) * 30px) oklch(from var(--color) l c h / 0.1); + result: 0 0 calc(var(--intensity) * 10px) oklch(from var(--color) l min(0.4, calc(c * 1.3)) h / 0.6), + 0 0 calc(var(--intensity) * 20px) oklch(from var(--color) l min(0.35, calc(c * 1.15)) h / 0.35), + 0 0 calc(var(--intensity) * 30px) oklch(from var(--color) l c h / 0.15); } /** - * --s-text-shadow-glow: Generate a text glow effect + * --s-text-shadow-glow: Generate a text glow effect for enhanced legibility + * Three-layer system: crisp edge (1px) preserves letter shapes, mid-layer provides + * the visible glow, outer layer adds atmospheric diffusion. Optimized for + * dark backgrounds without blurring text readability. * @param --color: The glow color * @param --intensity: Intensity multiplier (1-3) */ @function --s-text-shadow-glow(--color, --intensity) { - result: 0 0 calc(var(--intensity) * 5px) oklch(from var(--color) l c h / 0.8), - 0 0 calc(var(--intensity) * 10px) oklch(from var(--color) l c h / 0.5); + result: 0 0 1px oklch(from var(--color) l c h / 0.9), + 0 0 calc(var(--intensity) * 4px) oklch(from var(--color) l c h / 0.7), + 0 0 calc(var(--intensity) * 12px) oklch(from var(--color) l c h / 0.35); } /* ============================================================================= @@ -109,27 +119,36 @@ ============================================================================= */ /** - * --s-contrast-text: Return black or white based on background lightness - * Uses 0.6 OKLCH lightness threshold (pragmatic heuristic, not WCAG luminance) + * --s-contrast-text: Auto-pick accessible text color using WCAG 2.2 contrast + * Uses native color-contrast() to let the browser calculate true luminance + * and select the highest-contrast option between white and black. * @param --bg: The background color */ @function --s-contrast-text(--bg) { + result: color-contrast(var(--bg) vs oklch(0.98 0 0), oklch(0.15 0 0)); +} + +/** + * Legacy fallback for browsers without color-contrast() support + * Uses 0.6 OKLCH lightness threshold as pragmatic approximation + */ +@function --s-contrast-text-fallback(--bg) { result: oklch(from var(--bg) clamp(0.15, calc((0.6 - l) * 1000 + 0.15), 0.95) 0 0); } /** - * --s-readable-on: Ensure text is readable on a given background - * Shifts text lightness based on background: dark bg → lighter text, light bg → darker text + * --s-readable-on: Return accessible version of a brand color on any background + * Preserves the text color's hue and chroma while aggressively adjusting lightness + * to ensure readability. Dark backgrounds push text lighter, light backgrounds push + * text darker. The 50/50 mix ensures strong contrast while retaining brand identity. * @param --bg: The background color - * @param --text: The desired text color + * @param --text: The desired text color (brand hue to preserve) */ @function --s-readable-on(--bg, --text) { - /* Mix text with inverted bg lightness (achromatic) to push toward contrast */ - /* Dark bg (l≈0) → mix with light (1-l≈1), Light bg (l≈1) → mix with dark (1-l≈0) */ result: color-mix( in oklch, - var(--text) 60%, - oklch(from var(--bg) clamp(0.2, calc(1 - l), 0.9) 0 0) + var(--text) 50%, + oklch(from var(--bg) clamp(0.15, calc(1.1 - l), 0.95) 0 0) ); } @@ -151,12 +170,15 @@ } /** - * --s-space-scale: Multiply a spacing value - * @param --base: Base spacing value - * @param --factor: Multiplication factor + * --s-space-scale: Generate rhythm-aligned spacing with quantized snapping + * Calculates base × factor, then snaps the result to the nearest multiple + * of the base unit. This "quantize" approach prevents sub-pixel jitter and + * ensures all spacing aligns to the global grid (e.g., 4px rhythm → 4, 8, 12, 16px). + * @param --base: Base spacing unit (e.g., 4px for a 4px grid) + * @param --factor: Multiplication factor (any number, output will snap) */ @function --s-space-scale(--base, --factor) { - result: calc(var(--base) * var(--factor)); + result: round(nearest, calc(var(--base) * var(--factor)), var(--base)); } /* ============================================================================= From aac1b4d0f4a32bace15087958e37ea2d97cf1fb1 Mon Sep 17 00:00:00 2001 From: Austin McShan Date: Sun, 1 Feb 2026 09:14:52 -0600 Subject: [PATCH 2/3] fix(core): update fallback lightness threshold --- packages/core/src/utils/functions.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/core/src/utils/functions.css b/packages/core/src/utils/functions.css index 500a3a2..d06e797 100644 --- a/packages/core/src/utils/functions.css +++ b/packages/core/src/utils/functions.css @@ -130,10 +130,10 @@ /** * Legacy fallback for browsers without color-contrast() support - * Uses 0.6 OKLCH lightness threshold as pragmatic approximation + * Uses 0.55 OKLCH lightness threshold (consistent with s-dark-aware) */ @function --s-contrast-text-fallback(--bg) { - result: oklch(from var(--bg) clamp(0.15, calc((0.6 - l) * 1000 + 0.15), 0.95) 0 0); + result: oklch(from var(--bg) clamp(0.15, calc((0.55 - l) * 1000 + 0.15), 0.95) 0 0); } /** From 3e3a6250f8057a3c81ceab5492e8278545dbc7bd Mon Sep 17 00:00:00 2001 From: Austin McShan Date: Sun, 1 Feb 2026 09:24:54 -0600 Subject: [PATCH 3/3] chore(css): refine --s-contrast-text function --- packages/core/src/utils/functions.css | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/packages/core/src/utils/functions.css b/packages/core/src/utils/functions.css index d06e797..fb9bb3d 100644 --- a/packages/core/src/utils/functions.css +++ b/packages/core/src/utils/functions.css @@ -119,20 +119,18 @@ ============================================================================= */ /** - * --s-contrast-text: Auto-pick accessible text color using WCAG 2.2 contrast - * Uses native color-contrast() to let the browser calculate true luminance - * and select the highest-contrast option between white and black. + * --s-contrast-text: Auto-pick accessible text color based on background + * Uses 0.55 OKLCH lightness threshold (consistent with s-dark-aware). + * Returns near-black (L=0.15) for light backgrounds, near-white (L=0.95) for dark. + * + * For native WCAG 2.2 contrast calculation, use contrast-color() at rule level: + * @supports (color: contrast-color(red)) { + * color: contrast-color(var(--bg)); + * } + * * @param --bg: The background color */ @function --s-contrast-text(--bg) { - result: color-contrast(var(--bg) vs oklch(0.98 0 0), oklch(0.15 0 0)); -} - -/** - * Legacy fallback for browsers without color-contrast() support - * Uses 0.55 OKLCH lightness threshold (consistent with s-dark-aware) - */ -@function --s-contrast-text-fallback(--bg) { result: oklch(from var(--bg) clamp(0.15, calc((0.55 - l) * 1000 + 0.15), 0.95) 0 0); }