/**
 * Color parsing + WCAG contrast.
 *
 * Accent colors are stored either as a preset name (resolved elsewhere) or as
 * a raw CSS color string. To validate contrast we need a real luminance, so we
 * parse both `#rgb`/`#rrggbb` and `oklch(L C H)` into LINEAR sRGB and apply the
 * WCAG relative-luminance + contrast-ratio formulas. Linear RGB is exactly what
 * the luminance formula wants, so the hex path linearizes gamma sRGB and the
 * oklch path (via OKLab→linear sRGB, per Björn Ottosson) is already linear.
 */
function clamp01(v) {
    return v < 0 ? 0 : v > 1 ? 1 : v;
}
/** sRGB gamma channel (0..1) → linear (0..1). */
function srgbToLinear(c) {
    return c <= 0.04045 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
}
function parseHex(input) {
    let hex = input.trim().replace(/^#/, '');
    if (hex.length === 3) {
        hex = hex
            .split('')
            .map((ch) => ch + ch)
            .join('');
    }
    if (!/^[0-9a-fA-F]{6}$/.test(hex))
        return null;
    const r = parseInt(hex.slice(0, 2), 16) / 255;
    const g = parseInt(hex.slice(2, 4), 16) / 255;
    const b = parseInt(hex.slice(4, 6), 16) / 255;
    return { r: srgbToLinear(r), g: srgbToLinear(g), b: srgbToLinear(b) };
}
/** Parse `oklch(L C H)` (L 0..1 or 0%..100%, C ≥ 0, H degrees) → linear sRGB. */
function parseOklch(input) {
    const m = input.trim().match(/^oklch\(\s*([\d.]+%?)\s+([\d.]+)\s+([\d.]+)\s*\)$/i);
    if (!m)
        return null;
    let L = parseFloat(m[1]);
    if (m[1].endsWith('%'))
        L /= 100;
    const C = parseFloat(m[2]);
    const Hdeg = parseFloat(m[3]);
    if (!Number.isFinite(L) || !Number.isFinite(C) || !Number.isFinite(Hdeg))
        return null;
    const h = (Hdeg * Math.PI) / 180;
    const a = C * Math.cos(h);
    const b = C * Math.sin(h);
    const l_ = L + 0.3963377774 * a + 0.2158037573 * b;
    const m_ = L - 0.1055613458 * a - 0.0638541728 * b;
    const s_ = L - 0.0894841775 * a - 1.291485548 * b;
    const l = l_ * l_ * l_;
    const mm = m_ * m_ * m_;
    const s = s_ * s_ * s_;
    const r = 4.0767416621 * l - 3.3077115913 * mm + 0.2309699292 * s;
    const g = -1.2684380046 * l + 2.6097574011 * mm - 0.3413193965 * s;
    const bl = -0.0041960863 * l - 0.7034186147 * mm + 1.707614701 * s;
    return { r: clamp01(r), g: clamp01(g), b: clamp01(bl) };
}
/** Parse a supported color string (`#hex` or `oklch(...)`) into linear sRGB. */
export function parseColorToLinear(input) {
    if (!input)
        return null;
    const trimmed = input.trim();
    if (trimmed.startsWith('#'))
        return parseHex(trimmed);
    if (/^oklch\(/i.test(trimmed))
        return parseOklch(trimmed);
    return null;
}
/** WCAG relative luminance from linear sRGB. */
export function relativeLuminance(rgb) {
    return 0.2126 * rgb.r + 0.7152 * rgb.g + 0.0722 * rgb.b;
}
/** WCAG contrast ratio (1..21) between two colors. Returns 0 if unparseable. */
export function contrastRatio(a, b) {
    const ca = parseColorToLinear(a);
    const cb = parseColorToLinear(b);
    if (!ca || !cb)
        return 0;
    const la = relativeLuminance(ca);
    const lb = relativeLuminance(cb);
    const lighter = Math.max(la, lb);
    const darker = Math.min(la, lb);
    return (lighter + 0.05) / (darker + 0.05);
}
/** True when the color string is a parseable `#hex` or `oklch(...)` value. */
export function isParseableColor(input) {
    return parseColorToLinear(input) !== null;
}
//# sourceMappingURL=color.js.map