{"version":3,"file":"color.cjs","names":[],"sources":["../../src/theme/color.ts"],"sourcesContent":["/**\n * @tempest-limits file-lines — OKLCH ↔ sRGB with the gamut mapping in between: the\n * transfer function, the LMS matrices, the chroma search that finds the nearest in-\n * gamut colour and the contrast ratio used to check it. Matrices split across files\n * are matrices that get edited one half at a time.\n */\n/**\n * Color math behind {@link createTheme} — OKLab/OKLCH conversions, tint scale\n * generation and WCAG contrast picking.\n *\n * Everything here is pure and dependency-free: the SDK generates brand ramps at\n * runtime in the browser, so a color library would be a disproportionate cost\n * for ~150 lines of well-specified math. OKLCH is used instead of HSL because\n * HSL lightness is not perceptual — an HSL ramp of a yellow and of a blue at the\n * same `L` read as wildly different brightness, which is exactly what breaks a\n * generated palette.\n */\n\n/** A color in the OKLCH space: perceptual lightness, chroma and hue. */\nexport interface Oklch {\n    /** Perceptual lightness, `0` (black) to `1` (white). */\n    l: number;\n    /** Chroma (colorfulness). `0` is gray; sRGB rarely exceeds `~0.37`. */\n    c: number;\n    /** Hue angle in degrees, `0`–`360`. */\n    h: number;\n}\n\n/** The ten steps of a Tempest tint scale, lightest to darkest. */\nexport type ScaleStep = 50 | 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;\n\n/** A generated tint scale, keyed by step. */\nexport type ColorScale = Record<ScaleStep, string>;\n\nconst SCALE_STEPS: ScaleStep[] = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900];\n\n/**\n * Target lightness per step for a **brand** ramp in light mode.\n *\n * These are the measured OKLCH lightnesses of the hand-written `--tempest-primary-*`\n * scale in `colors.css`, so a generated brand ramp lands in the same visual range\n * as the built-in one instead of merely near it.\n */\nconst LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n    50: 0.966,\n    100: 0.923,\n    200: 0.844,\n    300: 0.743,\n    400: 0.642,\n    500: 0.563,\n    600: 0.48,\n    700: 0.391,\n    800: 0.325,\n    900: 0.251,\n};\n\n/**\n * Target lightness per step for a **neutral** ramp in light mode — measured from\n * the hand-written `--tempest-gray-*` scale.\n *\n * Deliberately **wider** than the brand curve at both ends (`0.982` → `0.210` vs\n * `0.966` → `0.251`): a neutral carries surfaces that must read as near-white and\n * text that must read as near-black, and the pair `text-muted` on `surface-3` has\n * to clear AA. Reusing the brand curve for neutrals is what dropped that pair to\n * 3.5:1 and made the browser axe sweep fail on every generated theme.\n */\nconst NEUTRAL_LIGHT_LIGHTNESS: Record<ScaleStep, number> = {\n    50: 0.982,\n    100: 0.963,\n    200: 0.927,\n    300: 0.872,\n    400: 0.71,\n    500: 0.544,\n    600: 0.442,\n    700: 0.369,\n    800: 0.278,\n    900: 0.21,\n};\n\n/**\n * Neutral ramp for dark mode, measured from the `[data-tempest-theme=\"dark\"]`\n * surface/text tokens: `50` is the page background and `900` is text-grade.\n */\nconst NEUTRAL_DARK_LIGHTNESS: Record<ScaleStep, number> = {\n    50: 0.159,\n    100: 0.205,\n    200: 0.254,\n    300: 0.314,\n    400: 0.381,\n    500: 0.5,\n    600: 0.571,\n    700: 0.762,\n    800: 0.86,\n    900: 0.964,\n};\n\n/**\n * Target lightness for a dark-theme ramp — the ramp is **inverted**: `50` is the\n * darkest tint (a surface) and `900` the lightest (text-grade), matching the\n * `[data-tempest-theme=\"dark\"]` block in `colors.css`.\n */\nconst DARK_LIGHTNESS: Record<ScaleStep, number> = {\n    50: 0.238,\n    100: 0.288,\n    200: 0.362,\n    300: 0.452,\n    400: 0.544,\n    500: 0.632,\n    600: 0.712,\n    700: 0.788,\n    800: 0.862,\n    900: 0.928,\n};\n\n/**\n * Chroma multiplier per step, relative to the input color's chroma.\n *\n * Peaks around `500`–`600` and falls off at both ends: near-white and near-black\n * tints hold very little chroma before they look muddy or leave the sRGB gamut.\n */\nconst CHROMA_CURVE: Record<ScaleStep, number> = {\n    50: 0.18,\n    100: 0.34,\n    200: 0.6,\n    300: 0.82,\n    400: 0.95,\n    500: 1,\n    600: 0.98,\n    700: 0.88,\n    800: 0.74,\n    900: 0.58,\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n    return Math.min(max, Math.max(min, value));\n}\n\n/** Expand `#abc` to `#aabbcc` and normalize to a lowercase 6-digit hex. */\nfunction normalizeHex(hex: string): string {\n    const raw = hex.trim().replace(/^#/, \"\");\n    const expanded =\n        raw.length === 3 || raw.length === 4\n            ? raw\n                  .slice(0, 3)\n                  .split(\"\")\n                  .map((char) => char + char)\n                  .join(\"\")\n            : raw.slice(0, 6);\n    if (!/^[0-9a-fA-F]{6}$/.test(expanded)) {\n        throw new Error(`Invalid hex color: \"${hex}\"`);\n    }\n    return `#${expanded.toLowerCase()}`;\n}\n\n/** Parse a hex color into sRGB channels in the `0`–`1` range. */\nexport function hexToRgb(hex: string): { r: number; g: number; b: number } {\n    const normalized = normalizeHex(hex).slice(1);\n    return {\n        r: parseInt(normalized.slice(0, 2), 16) / 255,\n        g: parseInt(normalized.slice(2, 4), 16) / 255,\n        b: parseInt(normalized.slice(4, 6), 16) / 255,\n    };\n}\n\n/** Serialize sRGB channels (`0`–`1`, clamped) back to a `#rrggbb` string. */\nexport function rgbToHex(r: number, g: number, b: number): string {\n    const channel = (value: number): string =>\n        Math.round(clamp(value, 0, 1) * 255)\n            .toString(16)\n            .padStart(2, \"0\");\n    return `#${channel(r)}${channel(g)}${channel(b)}`;\n}\n\nfunction srgbToLinear(channel: number): number {\n    return channel <= 0.04045 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);\n}\n\nfunction linearToSrgb(channel: number): number {\n    return channel <= 0.0031308 ? channel * 12.92 : 1.055 * Math.pow(channel, 1 / 2.4) - 0.055;\n}\n\n/** Convert a hex color to OKLCH. */\nexport function hexToOklch(hex: string): Oklch {\n    const { r, g, b } = hexToRgb(hex);\n    const lr = srgbToLinear(r);\n    const lg = srgbToLinear(g);\n    const lb = srgbToLinear(b);\n\n    const long = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);\n    const medium = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);\n    const short = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);\n\n    const l = 0.2104542553 * long + 0.793617785 * medium - 0.0040720468 * short;\n    const a = 1.9779984951 * long - 2.428592205 * medium + 0.4505937099 * short;\n    const bAxis = 0.0259040371 * long + 0.7827717662 * medium - 0.808675766 * short;\n\n    const c = Math.sqrt(a * a + bAxis * bAxis);\n    const hue = c < 1e-6 ? 0 : (Math.atan2(bAxis, a) * 180) / Math.PI;\n\n    return { l, c, h: hue < 0 ? hue + 360 : hue };\n}\n\n/** Convert OKLCH to linear-light sRGB, without gamut clamping. */\nfunction oklchToLinearRgb({ l, c, h }: Oklch): { r: number; g: number; b: number } {\n    const hRad = (h * Math.PI) / 180;\n    const a = Math.cos(hRad) * c;\n    const bAxis = Math.sin(hRad) * c;\n\n    const long = (l + 0.3963377774 * a + 0.2158037573 * bAxis) ** 3;\n    const medium = (l - 0.1055613458 * a - 0.0638541728 * bAxis) ** 3;\n    const short = (l - 0.0894841775 * a - 1.291485548 * bAxis) ** 3;\n\n    return {\n        r: 4.0767416621 * long - 3.3077115913 * medium + 0.2309699292 * short,\n        g: -1.2684380046 * long + 2.6097574011 * medium - 0.3413193965 * short,\n        b: -0.0041960863 * long - 0.7034186147 * medium + 1.707614701 * short,\n    };\n}\n\nfunction inGamut({ r, g, b }: { r: number; g: number; b: number }): boolean {\n    const epsilon = 1e-4;\n    return (\n        r >= -epsilon &&\n        r <= 1 + epsilon &&\n        g >= -epsilon &&\n        g <= 1 + epsilon &&\n        b >= -epsilon &&\n        b <= 1 + epsilon\n    );\n}\n\n/**\n * Convert OKLCH to a hex color, reducing chroma until the result fits sRGB.\n *\n * Lightness and hue are preserved: desaturating is far less noticeable than\n * shifting either of them, and a naive channel clamp would do both.\n */\nexport function oklchToHex(color: Oklch): string {\n    let chroma = Math.max(0, color.c);\n    let rgb = oklchToLinearRgb({ ...color, c: chroma });\n\n    for (let i = 0; i < 24 && !inGamut(rgb); i += 1) {\n        chroma *= 0.9;\n        rgb = oklchToLinearRgb({ ...color, c: chroma });\n    }\n\n    return rgbToHex(linearToSrgb(rgb.r), linearToSrgb(rgb.g), linearToSrgb(rgb.b));\n}\n\n/** Options for {@link createColorScale}. */\nexport interface ColorScaleOptions {\n    /**\n     * Pin step `500` to the input color's exact lightness. Default `true`.\n     *\n     * Right for a **brand** color: the hex a designer hands over is the one the\n     * buttons must be. Wrong for a **neutral**: nobody checks that `gray-500` is\n     * exactly the input, while everybody notices that a surface stopped being\n     * near-white — anchoring rescales both halves around the input and compresses\n     * exactly the range a neutral needs wide. With `false`, the ramp keeps the\n     * tuned lightness curve and the input only contributes hue and chroma (a warm\n     * or cool neutral, as asked).\n     */\n    anchor?: boolean;\n    /**\n     * Use the neutral lightness curve instead of the brand one. Default `false`.\n     *\n     * The neutral curve is wider at both ends, which is what keeps\n     * `text-muted`-on-`surface-3` above AA. Implies the ramp is meant for\n     * surfaces, borders and text rather than for an action color.\n     */\n    neutral?: boolean;\n}\n\n/**\n * Build a ten-step tint scale from a single color.\n *\n * The input color's hue is kept throughout and its chroma sets the intensity of\n * the whole ramp, so a muted brand color yields a muted scale instead of being\n * \"corrected\" into something the brand never approved.\n *\n * @param hex - Any hex color (`#abc` or `#aabbcc`), the intended `500` step.\n * @param mode - `\"light\"` for a light→dark ramp, `\"dark\"` for the inverted ramp\n *   used under `[data-tempest-theme=\"dark\"]`.\n * @param options - See {@link ColorScaleOptions}.\n */\nexport function createColorScale(\n    hex: string,\n    mode: \"light\" | \"dark\" = \"light\",\n    options: ColorScaleOptions = {},\n): ColorScale {\n    const base = hexToOklch(hex);\n    const targets = options.neutral\n        ? mode === \"dark\"\n            ? NEUTRAL_DARK_LIGHTNESS\n            : NEUTRAL_LIGHT_LIGHTNESS\n        : mode === \"dark\"\n          ? DARK_LIGHTNESS\n          : LIGHT_LIGHTNESS;\n    const lightness =\n        options.anchor === false ? targets : anchorLightnessAt500(targets, base.l, mode);\n    const scale = {} as ColorScale;\n\n    for (const step of SCALE_STEPS) {\n        scale[step] = oklchToHex({\n            l: lightness[step],\n            c: base.c * CHROMA_CURVE[step],\n            h: base.h,\n        });\n    }\n\n    return scale;\n}\n\n/** Widest lightness band a generated ramp may span, so both ends stay usable. */\nconst LIGHTNESS_CEILING = 0.985;\nconst LIGHTNESS_FLOOR = 0.12;\n\n/**\n * Re-anchor a lightness ramp so step `500` lands on the brand color exactly.\n *\n * Without this, `500` is forced onto the ramp's own target lightness: a brand\n * `#7c3aed` came back as `#9161fe` — same hue, same chroma, *re-lightened*. It\n * looks fine in isolation and is wrong anyway, because the one color a designer\n * hands over is the one the buttons must actually be.\n *\n * Each half of the ramp is scaled independently around the anchor, so the shape\n * of the original curve survives and the ramp stays monotonic even for a very\n * light brand (yellow) or a very dark one (navy) — those simply get a shorter\n * run on the crowded side.\n *\n * @param targets - The default per-step lightness for this scheme.\n * @param anchor - Lightness of the brand color, used verbatim at step `500`.\n * @param mode - `\"dark\"` inverts which side of the ramp is the light one.\n */\nfunction anchorLightnessAt500(\n    targets: Record<ScaleStep, number>,\n    anchor: number,\n    mode: \"light\" | \"dark\",\n): Record<ScaleStep, number> {\n    const anchored = {} as Record<ScaleStep, number>;\n    const base = targets[500];\n    const lightEnd = mode === \"dark\" ? targets[900] : targets[50];\n    const darkEnd = mode === \"dark\" ? targets[50] : targets[900];\n\n    const top = Math.min(LIGHTNESS_CEILING, Math.max(lightEnd, anchor + 0.05));\n    const bottom = Math.max(LIGHTNESS_FLOOR, Math.min(darkEnd, anchor - 0.05));\n\n    for (const step of SCALE_STEPS) {\n        const target = targets[step];\n        if (target === base) {\n            anchored[step] = anchor;\n        } else if (target > base) {\n            const ratio = (target - base) / (lightEnd - base);\n            anchored[step] = anchor + ratio * (top - anchor);\n        } else {\n            const ratio = (base - target) / (base - darkEnd);\n            anchored[step] = anchor - ratio * (anchor - bottom);\n        }\n    }\n\n    return anchored;\n}\n\n/** WCAG 2.x relative luminance of a hex color. */\nexport function relativeLuminance(hex: string): number {\n    const { r, g, b } = hexToRgb(hex);\n    return 0.2126 * srgbToLinear(r) + 0.7152 * srgbToLinear(g) + 0.0722 * srgbToLinear(b);\n}\n\n/** WCAG 2.x contrast ratio between two hex colors, from `1` to `21`. */\nexport function contrastRatio(a: string, b: string): number {\n    const la = relativeLuminance(a);\n    const lb = relativeLuminance(b);\n    const lighter = Math.max(la, lb);\n    const darker = Math.min(la, lb);\n    return (lighter + 0.05) / (darker + 0.05);\n}\n\n/**\n * Pick the readable foreground for a background, by contrast ratio.\n *\n * Used for `--tempest-primary-foreground`: a generated brand color can land\n * anywhere on the lightness axis, and hardcoding white would silently produce\n * unreadable buttons for light brands (yellow, lime, cyan).\n */\nexport function readableForeground(\n    background: string,\n    light = \"#ffffff\",\n    dark = \"#101828\",\n): string {\n    return contrastRatio(background, light) >= contrastRatio(background, dark) ? light : dark;\n}\n\n/** Format a hex color as `rgb(r g b / alpha)`, for focus rings and overlays. */\nexport function hexToRgbaString(hex: string, alpha: number): string {\n    const { r, g, b } = hexToRgb(hex);\n    const channel = (value: number): number => Math.round(clamp(value, 0, 1) * 255);\n    return `rgb(${channel(r)} ${channel(g)} ${channel(b)} / ${clamp(alpha, 0, 1)})`;\n}\n"],"mappings":"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"}