diff --git a/.github/skills/update-docs/SKILL.md b/.github/skills/update-docs/SKILL.md new file mode 100644 index 00000000..28d088bd --- /dev/null +++ b/.github/skills/update-docs/SKILL.md @@ -0,0 +1,82 @@ +--- +name: update-docs +description: Audit and update all rampa project documentation after code changes. Use when adding features, changing defaults, modifying APIs, or before a release. +metadata: + author: ismael.fyi + version: "1.0.0" +--- + +# Update Documentation + +Audit and update all project documentation to reflect current code. + +## Doc Files to Update + +| File | Purpose | +|------|---------| +| `sdk/README.md` | SDK user-facing docs — transforms, palette API, value ranges, type exports | +| `cli/README.md` | CLI user-facing docs — all subcommand flag tables, examples, defaults | +| `cli/src/palette.ts` | CLI palette `showHelp()` function and `parseArgs()` defaults | +| `cli/src/index.ts` | Main `rampa --help` text — subcommand list, IMAGE PALETTE section | +| `cli/src/color.ts` | CLI color subcommand help text and transform flags | +| `AGENTS.md` | Architecture guide — build commands, file map, conventions | + +## Source Files to Read + +| File | What to check | +|------|---------------| +| `sdk/src/index.ts` | All SDK exports — types and classes | +| `sdk/src/palette.ts` | PaletteResult API surface, options interfaces, defaults | +| `sdk/src/types.ts` | All public type definitions | +| `sdk/src/color-result.ts` | Color transform methods, value ranges | +| `src/engine/PaletteEngine.ts` | Engine defaults — sampleSize, tolerance, bucket counts | +| `cli/src/palette.ts` | CLI palette `parseArgs()` defaults, flag list | +| `cli/src/color.ts` | CLI color transform flags | + +## Audit Process + +1. **Read source files** to understand current API surface and defaults +2. **Read doc files** to see what's documented +3. **Diff** — find stale defaults, missing features, removed APIs +4. **Update** — make surgical edits to fix gaps +5. **Verify** — CLI help text defaults must match `parseArgs()` defaults in the same file + +## Defaults to Track + +These change occasionally and must be consistent across all docs: + +| Setting | Source of truth | Also appears in | +|---------|----------------|-----------------| +| Sample size | `PaletteEngine.ts` `samplePixels` default | `sdk/palette.ts`, `cli/palette.ts` parseArgs, SDK README, CLI README, CLI help | +| K-means tolerance | `PaletteEngine.ts` `kMeansClustering` default | `sdk/palette.ts` DominantOptions JSDoc, `cli/palette.ts` parseArgs, SDK README, CLI README, CLI help | +| Raw tolerance | `PaletteEngine.ts` `buildRawPalette` default | `cli/palette.ts` parseArgs, CLI README, CLI help | +| Dominant count | `cli/palette.ts` parseArgs default | CLI README, CLI help | +| ANSI count | `PaletteEngine.ts` `buildAnsiPalette` default | SDK README | +| L bucket count | `PaletteEngine.ts` `DEFAULT_L_BUCKETS` array length | `cli/palette.ts` parseArgs `lBuckets`, CLI README, CLI help | +| C bucket count | `PaletteEngine.ts` `DEFAULT_C_BUCKETS` array length | `cli/palette.ts` parseArgs `cBuckets`, CLI README, CLI help | +| H bucket count | `PaletteEngine.ts` `DEFAULT_H_BUCKETS` array length | `cli/palette.ts` parseArgs `hBuckets`, CLI README, CLI help | +| Contrast mode | `sdk/src/contrast.ts` default mode | SDK README, CLI README | + +## SDK README Sections to Verify + +- Color transforms (lighten, darken, saturate, desaturate, rotate, set, mix, blend) +- Value ranges (HSL s/l and OKLCH l use 0-1 scale, NOT 0-100) +- Ramp introspection (.at(), .colors() on Linear/Plane/CubeColorSpace) +- Palette extraction (palette(), dominant(), raw(), ansi(), group(), sortBy()) +- Output formats (json, css, text) +- Type exports (all public types from `sdk/src/index.ts` should be mentioned) + +## CLI README Sections to Verify + +- `rampa color` flags table (transform flags: --lighten, --darken, etc.) +- `rampa palette` flags table (all flags with correct defaults) +- `rampa palette` usage examples +- `rampa lint` flags +- `rampa colorspace` flags + +## Rules + +- **Release notes**: Only include SDK/CLI changes. Never include site/editor/landing page changes. +- **Site demos**: Only update `site/` if SDK API changes break existing demos. +- **Value ranges**: 0-1 scale for HSL s/l and OKLCH l. Format string output is unchanged. +- **Help text**: CLI `showHelp()` defaults must exactly match `parseArgs()` defaults in the same file. diff --git a/AGENTS.md b/AGENTS.md index 9e1e0afd..7ad6261d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -32,17 +32,21 @@ src/engine/ ← Core math (color mixing, interpolation, ramps) ├── ColorSpaceEngine.ts Linear/Plane/Cube color space generation ├── OklchEngine.ts Color mixing and perceptual uniformity ├── HarmonyEngine.ts Complementary, triadic, analogous, etc. - └── BlendingEngine.ts 16 blend modes for tinting + ├── BlendingEngine.ts 16 blend modes for tinting + ├── PaletteEngine.ts Image palette extraction (k-means, ANSI classification) + └── ImageDecoder.ts PNG/JPEG decoding (fast-png + jpeg-js) sdk/src/ ← npm package (@basiclines/rampa-sdk) ├── builder.ts rampa('#hex').size(10).lightness(10,90) → callable palette + ├── palette.ts palette('image.jpg') → dominant, raw, ansi, average ├── linear-color-space.ts ├── plane-color-space.ts └── cube-color-space.ts cli/src/ ← npm package (@basiclines/rampa) ├── index.ts Main CLI entry (citty framework) - └── colorspace.ts `rampa colorspace` subcommand + ├── colorspace.ts `rampa colorspace` subcommand + └── palette.ts `rampa palette` subcommand src/ ← React web app (rampa.studio) ├── components/ shadcn/ui + @react-three/fiber for 3D viewer @@ -70,6 +74,24 @@ Do NOT use `.hex` property — use template literals or `.valueOf()`. - **CubeColorSpace** — 3D cube (8 corner colors: k, r, g, b, y, m, c, w) All support chainable `.interpolation()`, `.format()`, `.size()`. +All support `.at()` for 0-based Color access and `.colors()` for Color[] arrays. + +### Color Transforms +All transforms on `color()` operate in **OKLCH space** and return a new immutable `Color`: +- `lighten(n)`, `darken(n)` — absolute L delta (0-1 scale) +- `saturate(n)`, `desaturate(n)` — absolute chroma delta +- `rotate(n)` — hue rotation in degrees +- `set({ lightness?, chroma?, hue? })` — absolute OKLCH values +- `mix(color, ratio, space?)` — color space interpolation (oklch/lab/srgb) +- `blend(color, opacity, mode)` — compositing modes (multiply/screen/overlay etc.) + +### Value Ranges +All structured property values use **0-1 normalized ranges** (CSS-spec aligned): +- `hsl.s`, `hsl.l` — 0 to 1 (not 0-100) +- `oklch.l` — 0 to 1 (not 0-100) +- `oklch.c` — 0 to ~0.4 (native OKLCH) +- Hue values are always 0-360 degrees +- `.format()` string output uses CSS conventions (percentages where appropriate) ### SDK Type Declarations When adding new types, interfaces, or classes to the SDK: @@ -107,3 +129,9 @@ CLI uses manual argument parsing (not a framework for `colorspace` subcommand). **Always include release notes** when creating a GitHub release. Summarize new features, fixes, and breaking changes. Use the PR descriptions and commit messages as source material. **Always ask the user before committing and pushing.** + +## Development Skills + +Internal skills for rampa development live in `.github/skills/`: + +- **`update-docs`** — Audit and update all documentation after code changes. Lists every doc file, source file, and default value that must stay in sync. Use after adding features or changing defaults. diff --git a/bun.lockb b/bun.lockb index c5755440..8b0204b8 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/cli/README.md b/cli/README.md index 724f33b5..0a0ea54f 100644 --- a/cli/README.md +++ b/cli/README.md @@ -267,7 +267,7 @@ rampa lint --fg '#fff' --bg '#000' --output json ### Color -Inspect a color in all supported formats (hex, hsl, rgb, oklch). +Inspect, transform, mix, and export a single color. All transforms operate in OKLCH space. ```bash rampa color '#ff6600' @@ -277,9 +277,31 @@ rampa color '#1e1e2e' -O css --prefix brand | Flag | Alias | Description | |------|-------|-------------| -| `` | `-c` | Color to inspect (positional or flag) | +| `` | `-c` | Color to inspect/transform (positional or flag) | | `--output ` | `-O` | Output format (default: text) | | `--prefix ` | | Prefix for CSS variable names (default: color) | +| `--lighten ` | | Increase OKLCH lightness by n (0-1 scale) | +| `--darken ` | | Decrease OKLCH lightness by n | +| `--saturate ` | | Increase OKLCH chroma by n | +| `--desaturate ` | | Decrease OKLCH chroma by n | +| `--rotate ` | | Rotate hue by n degrees | +| `--set-lightness ` | | Set OKLCH lightness to n | +| `--set-chroma ` | | Set OKLCH chroma to n | +| `--set-hue ` | | Set hue to n degrees | +| `--mix ` | | Mix with target color (use --ratio, --space) | +| `--blend ` | | Blend with target color (use --ratio, --mode) | +| `--ratio ` | | Mix/blend ratio 0-1 (default: 0.5) | +| `--space ` | | Color space for --mix (default: oklch) | +| `--mode ` | | Blend mode for --blend (multiply, screen, overlay, etc.) | + +Transforms are applied left-to-right, matching SDK chaining order: + +```bash +rampa color '#66b172' --lighten 0.1 --desaturate 0.05 +rampa color '#ff0000' --mix '#0000ff' --ratio 0.5 --space lab +rampa color '#ff8800' --blend '#0088ff' --ratio 0.5 --mode multiply +rampa color '#66b172' --lighten 0.1 --desaturate 0.05 -O css --prefix brand +``` ### Other @@ -288,6 +310,38 @@ rampa color '#1e1e2e' -O css --prefix brand | `--help` | `-h` | Show help | | `--version` | `-v` | Show version | +### Image Palette + +Extract color palettes from PNG and JPEG images. + +```bash +rampa palette photo.jpg +rampa palette photo.jpg --count 5 +rampa palette photo.jpg --ansi --count 3 +rampa palette photo.jpg --group C --sort L +rampa palette photo.jpg --output json +``` + +| Flag | Alias | Description | +|------|-------|-------------| +| `` | | Image file path (PNG or JPEG) | +| `--count ` | | Number of dominant colors (default: 10) | +| `--tolerance ` | | DeltaE clustering radius (default: 4) | +| `--raw` | | Show all unique colors | +| `--raw-tolerance ` | | DeltaE threshold for raw dedup (default: 2) | +| `--max-colors ` | | Max colors for raw output (default: 1000) | +| `--ansi` | | Classify into ANSI color categories | +| `--group ` | | Group by lightness, chroma, or hue | +| `--l-buckets ` | | Number of lightness buckets (default: 5) | +| `--c-buckets ` | | Number of chroma buckets (default: 4) | +| `--h-buckets ` | | Number of hue buckets (default: 8) | +| `--sort ` | | Sort order (default: frequency) | +| `--average` | | Show average color only | +| `--temperature` | | Show color temperature only | +| `--sample-size ` | | Pixels to sample (default: 50000) | +| `--output ` | `-O` | Output format (default: text) | +| `--prefix ` | | CSS variable prefix (default: palette) | + ## Examples ### Basic Palette @@ -454,13 +508,63 @@ rampa lint --fg '#fff' --bg '#000' -O css ```bash # View all formats -rampa inspect -c '#ff6600' +rampa color '#ff6600' # JSON output -rampa inspect -c 'rgb(100, 200, 50)' --output json +rampa color 'rgb(100, 200, 50)' --output json # CSS custom properties -rampa inspect -c '#1e1e2e' -O css +rampa color '#1e1e2e' -O css + +# Transform: lighten and desaturate +rampa color '#66b172' --lighten 0.1 --desaturate 0.05 + +# Derive bright variant +rampa color '#06ef48' --lighten 0.1 --desaturate 0.05 + +# Mix two colors in lab space +rampa color '#ff0000' --mix '#0000ff' --ratio 0.5 --space lab + +# Blend with multiply mode +rampa color '#ff8800' --blend '#0088ff' --ratio 0.5 --mode multiply + +# Set absolute OKLCH values +rampa color '#f85149' --set-lightness 0.48 --set-chroma 0.15 +``` + +### Image Palette + +```bash +# Dominant colors from a photo +rampa palette photo.jpg + +# Top 5 with ANSI swatches +rampa palette photo.jpg --count 5 + +# ANSI-classified palette +rampa palette photo.jpg --ansi --count 3 + +# Group by chroma, sorted by lightness (accent discovery) +rampa palette photo.jpg --group C --sort L + +# Group by lightness with 3 buckets +rampa palette photo.jpg --group L --l-buckets 3 + +# Group by hue, sorted dark→light +rampa palette photo.jpg --group H --sort L + +# Raw unique colors +rampa palette photo.jpg --raw --tolerance 5 + +# JSON output for tooling +rampa palette photo.jpg --output json + +# CSS variables +rampa palette photo.jpg --output css --prefix photo + +# Average color and temperature +rampa palette photo.jpg --average +rampa palette photo.jpg --temperature ``` ## Contextual Help diff --git a/cli/bun.lock b/cli/bun.lock index 3bebe9d4..a2ab06b2 100644 --- a/cli/bun.lock +++ b/cli/bun.lock @@ -5,10 +5,10 @@ "": { "name": "rampa-cli", "dependencies": { - "apca-w3": "^0.1.9", "chroma-js": "^3.1.2", "citty": "^0.1.6", - "culori": "^4.0.1", + "fast-png": "^8.0.0", + "jpeg-js": "^0.4.4", }, "devDependencies": { "@github/copilot-sdk": "^0.1.23", @@ -42,19 +42,21 @@ "@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], - "apca-w3": ["apca-w3@0.1.9", "", { "dependencies": { "colorparsley": "^0.1.8" } }, "sha512-Zrf6AeBeQjNe/fxK7U1jCo5zfdjDl6T4/kdw5Xlky3G7u+EJTZkyItjMYQGtwf9pkftsINxcYyOpuLkzKf1ITQ=="], - "bun-types": ["bun-types@1.3.8", "", { "dependencies": { "@types/node": "*" } }, "sha512-fL99nxdOWvV4LqjmC+8Q9kW3M4QTtTR1eePs94v5ctGqU8OeceWrSUaRw3JYb7tU3FkMIAjkueehrHPPPGKi5Q=="], "chroma-js": ["chroma-js@3.2.0", "", {}, "sha512-os/OippSlX1RlWWr+QDPcGUZs0uoqr32urfxESG9U93lhUfbnlyckte84Q8P1UQY/qth983AS1JONKmLS4T0nw=="], "citty": ["citty@0.1.6", "", { "dependencies": { "consola": "^3.2.3" } }, "sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ=="], - "colorparsley": ["colorparsley@0.1.8", "", {}, "sha512-rObESTTTE6G5qO5WFwFxWPggpw4KfpxnLC6Ssl8bITBnNVRhDsyCeTRAUxWQNVTx2pRknKlO2nddYTxjkdNFaw=="], - "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], - "culori": ["culori@4.0.2", "", {}, "sha512-1+BhOB8ahCn4O0cep0Sh2l9KCOfOdY+BXJnKMHFFzDEouSr/el18QwXEMRlOj9UY5nCeA8UN3a/82rUWRBeyBw=="], + "fast-png": ["fast-png@8.0.0", "", { "dependencies": { "fflate": "^0.8.2", "iobuffer": "^6.0.1" } }, "sha512-gCysNasJ8KEMgfdYIKd/wTDo6ENK1PWT0RJO7O+0pgmuHPw2O6tA1WvdxFRJoLf9V8yFYpG0FA1YgI8X97OhJA=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "iobuffer": ["iobuffer@6.0.1", "", {}, "sha512-SZWYkWNfjIXIBYSDpXDYIgshqtbOPsi4lviawAEceR1Kqk+sHDlcQjWrzNQsii80AyBY0q5c8HCTNjqo74ul+Q=="], + + "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], "picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="], diff --git a/cli/package.json b/cli/package.json index cf4694b0..6946da51 100644 --- a/cli/package.json +++ b/cli/package.json @@ -45,7 +45,9 @@ }, "dependencies": { "chroma-js": "^3.1.2", - "citty": "^0.1.6" + "citty": "^0.1.6", + "fast-png": "^8.0.0", + "jpeg-js": "^0.4.4" }, "devDependencies": { "@github/copilot-sdk": "^0.1.23", diff --git a/cli/src/color.ts b/cli/src/color.ts index 0feaf5f3..5d05f681 100644 --- a/cli/src/color.ts +++ b/cli/src/color.ts @@ -1,14 +1,17 @@ #!/usr/bin/env node /** - * rampa color — Inspect a single color in all supported formats + * rampa color — Inspect and transform a single color * * Usage: * rampa color '#fe0000' * rampa color '#fe0000' --output json - * rampa color 'rgb(255, 102, 0)' --output css --prefix brand + * rampa color '#66b172' --lighten 0.1 --desaturate 0.05 + * rampa color '#f85149' --mix '#0000ff' --ratio 0.5 + * rampa color '#f85149' --blend '#000000' --ratio 0.2 --mode multiply */ import { color } from '../../sdk/src/index'; +import type { Color, InterpolationMode, BlendMode } from '../../sdk/src/types'; // ── ANSI helpers ───────────────────────────────────────────────────── @@ -22,32 +25,74 @@ interface ColorArgs { color: string; output: 'text' | 'json' | 'css'; prefix?: string; + transforms: TransformOp[]; } +type TransformOp = + | { type: 'lighten'; value: number } + | { type: 'darken'; value: number } + | { type: 'saturate'; value: number } + | { type: 'desaturate'; value: number } + | { type: 'rotate'; value: number } + | { type: 'set-lightness'; value: number } + | { type: 'set-chroma'; value: number } + | { type: 'set-hue'; value: number } + | { type: 'mix'; target: string; ratio: number; space: InterpolationMode } + | { type: 'blend'; target: string; ratio: number; mode: BlendMode }; + function showColorHelp(): void { const help = ` rampa color -Inspect a color in all supported formats +Inspect and transform a color USAGE - ${cyan}rampa color [options]${reset} + ${cyan}rampa color [transforms] [options]${reset} -OPTIONS +COLOR ${cyan}${reset} ${dim}Color to inspect (positional or -c)${reset} ${cyan}-c, --color ${reset} ${dim}Color to inspect (flag form)${reset} + +TRANSFORMS ${dim}(applied left to right, all OKLCH-based)${reset} + ${cyan}--lighten ${reset} ${dim}Increase lightness (0-1 scale)${reset} + ${cyan}--darken ${reset} ${dim}Decrease lightness (0-1 scale)${reset} + ${cyan}--saturate ${reset} ${dim}Increase chroma (0-0.4 scale)${reset} + ${cyan}--desaturate ${reset} ${dim}Decrease chroma (0-0.4 scale)${reset} + ${cyan}--rotate ${reset} ${dim}Rotate hue (degrees)${reset} + ${cyan}--set-lightness ${reset} ${dim}Set absolute lightness (0-1)${reset} + ${cyan}--set-chroma ${reset} ${dim}Set absolute chroma (0-0.4)${reset} + ${cyan}--set-hue ${reset} ${dim}Set absolute hue (0-360)${reset} + +MIXING + ${cyan}--mix ${reset} ${dim}Mix with color (use --ratio and --space)${reset} + ${cyan}--blend ${reset} ${dim}Blend with color (use --ratio and --mode)${reset} + ${cyan}--ratio <0-1>${reset} ${dim}Mix/blend ratio (default: 0.5)${reset} + ${cyan}--space ${reset} ${dim}Color space for --mix (default: oklch)${reset} + ${cyan}--mode ${reset} ${dim}Blend mode for --blend (e.g. multiply, screen)${reset} + +OUTPUT ${cyan}--output, -O ${reset} ${dim}Output format (default: text)${reset} ${cyan}--prefix ${reset} ${dim}Prefix for CSS variable names (default: color)${reset} ${cyan}--help, -h${reset} ${dim}Show this help${reset} EXAMPLES ${cyan}rampa color '#ff6600'${reset} - ${cyan}rampa color 'rgb(100, 200, 50)' --output json${reset} - ${cyan}rampa color '#1e1e2e' -O css --prefix brand${reset} + ${cyan}rampa color '#66b172' --lighten 0.1 --desaturate 0.05${reset} + ${cyan}rampa color '#f85149' --set-lightness 0.48${reset} + ${cyan}rampa color '#f85149' --mix '#0000ff' --ratio 0.5${reset} + ${cyan}rampa color '#f85149' --blend '#000' --ratio 0.2 --mode multiply${reset} + ${cyan}rampa color '#66b172' --lighten 0.1 -O css --prefix brand${reset} `; console.log(help.trim()); process.exit(0); } +const VALID_BLEND_MODES = [ + 'normal', 'darken', 'multiply', 'plus-darker', 'color-burn', + 'lighten', 'screen', 'plus-lighter', 'color-dodge', + 'overlay', 'soft-light', 'hard-light', + 'difference', 'exclusion', 'hue', 'saturation', 'color', 'luminosity', +]; + export function parseColorArgs(args: string[]): ColorArgs { if (args.length === 0 || args.includes('--help') || args.includes('-h') || args.includes('help')) { showColorHelp(); @@ -56,6 +101,14 @@ export function parseColorArgs(args: string[]): ColorArgs { let colorStr = ''; let output: 'text' | 'json' | 'css' = 'text'; let prefix: string | undefined; + const transforms: TransformOp[] = []; + + // Pending mix/blend state + let pendingMix: string | null = null; + let pendingBlend: string | null = null; + let ratio = 0.5; + let space: InterpolationMode = 'oklch'; + let blendMode: BlendMode | null = null; for (let i = 0; i < args.length; i++) { const arg = args[i]; @@ -72,22 +125,90 @@ export function parseColorArgs(args: string[]): ColorArgs { output = o as 'text' | 'json' | 'css'; i++; } else if (arg === '--prefix' && next) { prefix = next; i++; + } else if (arg === '--lighten' && next) { + transforms.push({ type: 'lighten', value: parseFloat(next) }); i++; + } else if (arg === '--darken' && next) { + transforms.push({ type: 'darken', value: parseFloat(next) }); i++; + } else if (arg === '--saturate' && next) { + transforms.push({ type: 'saturate', value: parseFloat(next) }); i++; + } else if (arg === '--desaturate' && next) { + transforms.push({ type: 'desaturate', value: parseFloat(next) }); i++; + } else if (arg === '--rotate' && next) { + transforms.push({ type: 'rotate', value: parseFloat(next) }); i++; + } else if (arg === '--set-lightness' && next) { + transforms.push({ type: 'set-lightness', value: parseFloat(next) }); i++; + } else if (arg === '--set-chroma' && next) { + transforms.push({ type: 'set-chroma', value: parseFloat(next) }); i++; + } else if (arg === '--set-hue' && next) { + transforms.push({ type: 'set-hue', value: parseFloat(next) }); i++; + } else if (arg === '--mix' && next) { + pendingMix = next; i++; + } else if (arg === '--blend' && next) { + pendingBlend = next; i++; + } else if (arg === '--ratio' && next) { + ratio = parseFloat(next); i++; + } else if (arg === '--space' && next) { + const s = next.toLowerCase(); + if (s !== 'oklch' && s !== 'lab' && s !== 'srgb' && s !== 'rgb') { + console.error(`Error: Invalid space "${next}". Use 'oklch', 'lab', or 'srgb'.`); + process.exit(1); + } + space = (s === 'srgb' ? 'rgb' : s) as InterpolationMode; i++; + } else if (arg === '--mode' && next) { + if (!VALID_BLEND_MODES.includes(next.toLowerCase())) { + console.error(`Error: Invalid blend mode "${next}". Valid modes: ${VALID_BLEND_MODES.join(', ')}`); + process.exit(1); + } + blendMode = next.toLowerCase() as BlendMode; i++; } else if (!arg.startsWith('-') && !colorStr) { colorStr = arg; } } + // Resolve pending mix/blend + if (pendingMix) { + transforms.push({ type: 'mix', target: pendingMix, ratio, space }); + } + if (pendingBlend) { + if (!blendMode) { + console.error('Error: --blend requires --mode .'); + process.exit(1); + } + transforms.push({ type: 'blend', target: pendingBlend, ratio, mode: blendMode! }); + } + if (!colorStr) { console.error('Error: A color argument is required.'); process.exit(1); } - return { color: colorStr, output, prefix }; + return { color: colorStr, output, prefix, transforms }; +} + +// ── Transform Application ──────────────────────────────────────────── + +function applyTransforms(c: Color, transforms: TransformOp[]): Color { + let result = c; + for (const op of transforms) { + switch (op.type) { + case 'lighten': result = result.lighten(op.value); break; + case 'darken': result = result.darken(op.value); break; + case 'saturate': result = result.saturate(op.value); break; + case 'desaturate': result = result.desaturate(op.value); break; + case 'rotate': result = result.rotate(op.value); break; + case 'set-lightness': result = result.set({ lightness: op.value }); break; + case 'set-chroma': result = result.set({ chroma: op.value }); break; + case 'set-hue': result = result.set({ hue: op.value }); break; + case 'mix': result = result.mix(op.target, op.ratio, op.space); break; + case 'blend': result = result.blend(op.target, op.ratio, op.mode); break; + } + } + return result; } // ── Output Formatters ──────────────────────────────────────────────── -function formatText(c: ReturnType): string { +function formatText(c: Color): string { const lines: string[] = []; lines.push(''); lines.push('Color'); @@ -105,7 +226,7 @@ function formatText(c: ReturnType): string { export function runColor(args: string[]): void { const parsed = parseColorArgs(args); - let c: ReturnType; + let c: Color; try { c = color(parsed.color); } catch { @@ -113,6 +234,10 @@ export function runColor(args: string[]): void { process.exit(1); } + if (parsed.transforms.length > 0) { + c = applyTransforms(c, parsed.transforms); + } + switch (parsed.output) { case 'json': console.log(c.output('json')); diff --git a/cli/src/formatters/json.ts b/cli/src/formatters/json.ts index 48934f11..90249b14 100644 --- a/cli/src/formatters/json.ts +++ b/cli/src/formatters/json.ts @@ -11,8 +11,8 @@ function structuredColor(hex: string, format?: ColorFormat) { const all = { hex: c.hex(), rgb: { r, g, b }, - hsl: { h: Math.round(hh || 0), s: Math.round(ss * 100), l: Math.round(ll * 100) }, - oklch: { l: parseFloat((ol * 100).toFixed(1)), c: parseFloat(oc.toFixed(3)), h: Math.round(oh || 0) }, + hsl: { h: Math.round(hh || 0), s: parseFloat(ss.toFixed(2)), l: parseFloat(ll.toFixed(2)) }, + oklch: { l: parseFloat(ol.toFixed(3)), c: parseFloat(oc.toFixed(3)), h: Math.round(oh || 0) }, }; if (format) { return { [format]: all[format] }; diff --git a/cli/src/index.ts b/cli/src/index.ts index 5eb7cb30..842197db 100644 --- a/cli/src/index.ts +++ b/cli/src/index.ts @@ -57,6 +57,13 @@ if (args[0] === 'inspect') { process.exit(0); } +// Intercept palette subcommand +if (args[0] === 'palette') { + const { runPalette } = await import('./palette'); + await runPalette(args.slice(1)); + process.exit(0); +} + if (args.includes('--help') || args.includes('-h') || args.includes('help') || args.length === 0) { showHelp(); } @@ -146,6 +153,10 @@ COLOR INSPECT ${cyan}rampa color${reset} ${dim}Inspect a color in all supported formats${reset} ${dim}Use rampa color --help for details${reset} +IMAGE PALETTE + ${cyan}rampa palette${reset} ${dim}Extract color palettes from images${reset} + ${dim}Use rampa palette --help for details${reset} + OTHER ${cyan}-h, --help${reset} ${dim}Show this help${reset} ${cyan}-v, --version${reset} ${dim}Show version${reset} @@ -165,6 +176,8 @@ EXAMPLES ${cyan}rampa lint --fg '#fff' --bg '#1e1e2e'${reset} ${cyan}rampa lint --fg '#777' --bg '#fff' --mode wcag${reset} ${cyan}rampa inspect -c '#ff6600'${reset} + ${cyan}rampa palette photo.jpg${reset} + ${cyan}rampa palette photo.jpg --ansi --count 3${reset} `; console.log(help.trim()); process.exit(0); diff --git a/cli/src/inspect.ts b/cli/src/inspect.ts index 30cd52d3..bf7ae71c 100644 --- a/cli/src/inspect.ts +++ b/cli/src/inspect.ts @@ -106,12 +106,12 @@ function getColorFormats(input: string): ColorFormats { hsl: { raw: `hsl(${Math.round(h || 0)}, ${Math.round(s * 100)}%, ${Math.round(l * 100)}%)`, h: Math.round(h || 0), - s: Math.round(s * 100), - l: Math.round(l * 100), + s: parseFloat(s.toFixed(2)), + l: parseFloat(l.toFixed(2)), }, oklch: { raw: `oklch(${(ol * 100).toFixed(1)}% ${oc.toFixed(3)} ${Math.round(oh || 0)})`, - l: parseFloat((ol * 100).toFixed(1)), + l: parseFloat(ol.toFixed(3)), c: parseFloat(oc.toFixed(3)), h: Math.round(oh || 0), }, diff --git a/cli/src/palette.ts b/cli/src/palette.ts new file mode 100644 index 00000000..8c32e53d --- /dev/null +++ b/cli/src/palette.ts @@ -0,0 +1,331 @@ +#!/usr/bin/env node +/** + * rampa palette — Extract color palettes from images + * + * Usage: + * rampa palette photo.jpg + * rampa palette photo.jpg --count 5 + * rampa palette photo.jpg --ansi + * rampa palette photo.jpg --raw --tolerance 3 + * rampa palette photo.jpg --output json + */ + +import { palette, type GroupOptions } from '../../sdk/src/palette'; +import { getDefaultBuckets, type GroupBucket, type GroupByProperty } from '../../src/engine/PaletteEngine'; +import { coloredSquare } from './utils/terminal-colors'; + +const reset = '\x1b[0m'; +const dim = '\x1b[2m'; +const bold = '\x1b[1m'; +const cyan = '\x1b[36m'; +const yellow = '\x1b[33m'; +const green = '\x1b[32m'; + +function showHelp(): void { + console.log(` +${bold}rampa palette${reset} — Extract color palettes from images + +${bold}Usage:${reset} + rampa palette ${dim}Top 10 dominant colors${reset} + rampa palette --count 5 ${dim}Top 5 dominant colors${reset} + rampa palette --raw ${dim}All unique colors${reset} + rampa palette --ansi ${dim}ANSI-classified palette${reset} + +${bold}Flags:${reset} + ${cyan}${reset} ${dim}Image file path (PNG or JPEG)${reset} + ${cyan}--count ${reset} ${dim}Number of dominant colors (default: 10)${reset} + ${cyan}--tolerance ${reset} ${dim}DeltaE clustering radius (default: 4)${reset} + ${cyan}--raw${reset} ${dim}Show raw palette (all unique colors)${reset} + ${cyan}--raw-tolerance ${reset} ${dim}DeltaE threshold for raw dedup (default: 2)${reset} + ${cyan}--max-colors ${reset} ${dim}Max colors for raw output (default: 1000)${reset} + ${cyan}--ansi${reset} ${dim}Classify into ANSI color categories${reset} + ${cyan}--group ${reset} ${dim}Group by lightness, chroma, or hue${reset} + ${cyan}--l-buckets ${reset} ${dim}Number of lightness buckets (default: 5)${reset} + ${cyan}--c-buckets ${reset} ${dim}Number of chroma buckets (default: 4)${reset} + ${cyan}--h-buckets ${reset} ${dim}Number of hue buckets (default: 8)${reset} + ${cyan}--average${reset} ${dim}Show average color only${reset} + ${cyan}--temperature${reset} ${dim}Show color temperature only${reset} + ${cyan}--sample-size ${reset} ${dim}Pixels to sample (default: 50000)${reset} + ${cyan}--sort ${reset} ${dim}Sort order (default: frequency)${reset} + ${cyan}--output ${reset} ${dim}-O${reset} ${dim}Output format (default: text)${reset} + ${cyan}--prefix ${reset} ${dim}CSS variable prefix (default: palette)${reset} + ${cyan}--help${reset} ${dim}-h${reset} ${dim}Show this help${reset} +`); +} + +type SortField = 'frequency' | 'L' | 'C' | 'H'; + +interface PaletteArgs { + filePath: string; + mode: 'dominant' | 'raw' | 'ansi' | 'group' | 'average' | 'temperature'; + count: number; + tolerance: number; + rawTolerance: number; + maxColors: number; + sampleSize: number; + sort: SortField; + groupBy: 'L' | 'C' | 'H'; + lBuckets: number; + cBuckets: number; + hBuckets: number; + output: 'text' | 'json' | 'css'; + prefix: string; +} + +function sortEntries( + entries: T[], + field: SortField +): T[] { + const sorted = [...entries]; + switch (field) { + case 'L': return sorted.sort((a, b) => a.color.oklch.l - b.color.oklch.l); + case 'C': return sorted.sort((a, b) => a.color.oklch.c - b.color.oklch.c); + case 'H': return sorted.sort((a, b) => a.color.oklch.h - b.color.oklch.h); + default: return sorted; // already sorted by frequency + } +} + +function parseArgs(args: string[]): PaletteArgs | null { + const result: PaletteArgs = { + filePath: '', + mode: 'dominant', + count: 10, + tolerance: 4, + rawTolerance: 2, + maxColors: 1000, + sampleSize: 50000, + sort: 'frequency', + groupBy: 'L', + lBuckets: 5, + cBuckets: 4, + hBuckets: 8, + output: 'text', + prefix: 'palette', + }; + + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + + if (arg === '--help' || arg === '-h') { + showHelp(); + return null; + } + if (arg === '--raw') { result.mode = 'raw'; continue; } + if (arg === '--ansi') { result.mode = 'ansi'; continue; } + if (arg === '--group' && args[i + 1]) { result.mode = 'group'; result.groupBy = args[++i] as any; continue; } + if (arg === '--average') { result.mode = 'average'; continue; } + if (arg === '--temperature') { result.mode = 'temperature'; continue; } + + if (arg === '--count' && args[i + 1]) { result.count = parseInt(args[++i]); continue; } + if (arg === '--tolerance' && args[i + 1]) { result.tolerance = parseFloat(args[++i]); continue; } + if (arg === '--raw-tolerance' && args[i + 1]) { result.rawTolerance = parseFloat(args[++i]); continue; } + if (arg === '--max-colors' && args[i + 1]) { result.maxColors = parseInt(args[++i]); continue; } + if (arg === '--sample-size' && args[i + 1]) { result.sampleSize = parseInt(args[++i]); continue; } + if (arg === '--sort' && args[i + 1]) { result.sort = args[++i] as SortField; continue; } + if (arg === '--l-buckets' && args[i + 1]) { result.lBuckets = parseInt(args[++i]); continue; } + if (arg === '--c-buckets' && args[i + 1]) { result.cBuckets = parseInt(args[++i]); continue; } + if (arg === '--h-buckets' && args[i + 1]) { result.hBuckets = parseInt(args[++i]); continue; } + if ((arg === '--output' || arg === '-O') && args[i + 1]) { + result.output = args[++i] as any; + continue; + } + if (arg === '--prefix' && args[i + 1]) { result.prefix = args[++i]; continue; } + + // Positional: file path + if (!arg.startsWith('-') && !result.filePath) { + result.filePath = arg; + continue; + } + } + + if (!result.filePath) { + console.error('Error: No image file specified. Usage: rampa palette '); + return null; + } + + return result; +} + +function buildCustomBuckets(property: GroupByProperty, count: number): GroupBucket[] | undefined { + const defaults = getDefaultBuckets(property); + if (count === defaults.length) return undefined; // use defaults + + // Generate evenly-spaced buckets + const ranges: Record string }> = { + L: { max: 1, names: (i, n) => { + if (n <= 3) return ['dark', 'mid', 'light'][i]; + if (n <= 5) return ['darkest', 'dark', 'mid', 'light', 'lightest'][i] || `L${i}`; + return `L${i}`; + }}, + C: { max: 0.2, names: (i, n) => { + if (n <= 4) return ['gray', 'muted', 'saturated', 'vivid'][i] || `C${i}`; + return `C${i}`; + }}, + H: { max: 360, names: (i, n) => { + if (n <= 8) return ['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'pink'][i] || `H${i}`; + return `H${i}`; + }}, + }; + + const { max, names } = ranges[property]; + const step = max / count; + return Array.from({ length: count }, (_, i) => ({ + name: names(i, count), + min: i * step, + max: i === count - 1 ? (property === 'C' ? Infinity : max) : (i + 1) * step, + })); +} + +function hexToRgb(hex: string): [number, number, number] { + const h = hex.replace('#', ''); + return [parseInt(h.slice(0, 2), 16), parseInt(h.slice(2, 4), 16), parseInt(h.slice(4, 6), 16)]; +} + +function swatch(hex: string): string { + const [r, g, b] = hexToRgb(hex); + return coloredSquare(r, g, b); +} + +function padRight(s: string, len: number): string { + return s + ' '.repeat(Math.max(0, len - s.length)); +} + +export async function runPalette(args: string[]): Promise { + const parsed = parseArgs(args); + if (!parsed) return; + + try { + const p = await palette(parsed.filePath, { sampleSize: parsed.sampleSize }); + + // JSON/CSS output delegates to SDK + if (parsed.output === 'json' && parsed.mode === 'dominant') { + console.log(p.output('json')); + return; + } + if (parsed.output === 'css') { + console.log(p.output('css', parsed.prefix)); + return; + } + + switch (parsed.mode) { + case 'dominant': { + const dom = sortEntries(p.dominant({ count: parsed.count, tolerance: parsed.tolerance }), parsed.sort); + if (parsed.output === 'json') { + console.log(JSON.stringify(dom.map(d => ({ + hex: d.color.hex, frequency: Math.round(d.frequency * 10000) / 10000, + oklch: d.color.oklch, + })), null, 2)); + return; + } + console.log(`\n${bold}Dominant colors${reset} ${dim}(${dom.length})${reset}\n`); + for (let i = 0; i < dom.length; i++) { + const d = dom[i]; + const pct = (d.frequency * 100).toFixed(1); + console.log(` ${swatch(d.color.hex)} ${padRight(d.color.hex, 9)} ${dim}${padRight(pct + '%', 7)}${reset} ${dim}L=${d.color.oklch.l.toFixed(2)} C=${d.color.oklch.c.toFixed(3)} H=${Math.round(d.color.oklch.h)}°${reset}`); + } + console.log(`\n ${dim}Average:${reset} ${swatch(p.average().hex)} ${p.average().hex}`); + console.log(` ${dim}Temperature:${reset} ${p.temperature()}\n`); + break; + } + + case 'raw': { + const raw = sortEntries(p.raw({ tolerance: parsed.rawTolerance, maxColors: parsed.maxColors }), parsed.sort); + if (parsed.output === 'json') { + console.log(JSON.stringify(raw.map(r => ({ + hex: r.color.hex, frequency: Math.round(r.frequency * 10000) / 10000, + })), null, 2)); + return; + } + console.log(`\n${bold}Raw palette${reset} ${dim}(${raw.length} colors)${reset}\n`); + for (const r of raw.slice(0, 50)) { // limit text display + const pct = (r.frequency * 100).toFixed(2); + console.log(` ${swatch(r.color.hex)} ${padRight(r.color.hex, 9)} ${dim}${padRight(pct + '%', 7)}${reset} ${dim}L=${r.color.oklch.l.toFixed(2)} C=${r.color.oklch.c.toFixed(3)} H=${Math.round(r.color.oklch.h)}°${reset}`); + } + if (raw.length > 50) console.log(` ${dim}... and ${raw.length - 50} more (use --output json for full list)${reset}`); + console.log(''); + break; + } + + case 'ansi': { + const ansi = p.ansi({ count: parsed.count, tolerance: parsed.tolerance }); + if (parsed.output === 'json') { + console.log(JSON.stringify(Object.fromEntries( + Object.entries(ansi).map(([name, entries]) => [ + name, entries.map(e => ({ hex: e.color.hex, frequency: Math.round(e.frequency * 10000) / 10000 })), + ]) + ), null, 2)); + return; + } + console.log(`\n${bold}ANSI palette${reset}\n`); + const names: string[] = ['black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white']; + for (const name of names) { + const entries = (ansi as any)[name] || []; + if (entries.length === 0) { + console.log(` ${padRight(name, 9)} ${dim}(none)${reset}`); + } else { + const sorted = sortEntries(entries, parsed.sort); + const swatches = sorted.map((e: any) => `${swatch(e.color.hex)} ${e.color.hex}`).join(' '); + console.log(` ${padRight(name, 9)} ${swatches}`); + } + } + console.log(''); + break; + } + + case 'group': { + const bucketCount = { L: parsed.lBuckets, C: parsed.cBuckets, H: parsed.hBuckets }[parsed.groupBy]; + const customBuckets = buildCustomBuckets(parsed.groupBy, bucketCount); + const groupOpts: GroupOptions = { + by: parsed.groupBy, + count: parsed.count, + tolerance: parsed.tolerance, + ...(customBuckets ? { buckets: customBuckets } : {}), + }; + const grouped = p.group(groupOpts); + if (parsed.output === 'json') { + console.log(JSON.stringify(Object.fromEntries( + Object.entries(grouped).map(([name, entries]) => [ + name, entries.map(e => ({ hex: e.color.hex, frequency: Math.round(e.frequency * 10000) / 10000 })), + ]) + ), null, 2)); + return; + } + console.log(`\n${bold}Group by ${parsed.groupBy}${reset}\n`); + for (const [name, entries] of Object.entries(grouped)) { + if (entries.length === 0) { + console.log(` ${padRight(name, 11)} ${dim}(none)${reset}`); + } else { + const sorted = sortEntries(entries, parsed.sort); + const swatches = sorted.map((e: any) => `${swatch(e.color.hex)} ${e.color.hex}`).join(' '); + console.log(` ${padRight(name, 11)} ${swatches}`); + } + } + console.log(''); + break; + } + + case 'average': { + const avg = p.average(); + if (parsed.output === 'json') { + console.log(JSON.stringify({ hex: avg.hex, oklch: avg.oklch })); + return; + } + console.log(`\n ${swatch(avg.hex)} ${bold}${avg.hex}${reset} ${dim}oklch(${avg.oklch.l.toFixed(2)} ${avg.oklch.c.toFixed(3)} ${avg.oklch.h})${reset}\n`); + break; + } + + case 'temperature': { + const temp = p.temperature(); + if (parsed.output === 'json') { + console.log(JSON.stringify({ temperature: temp })); + return; + } + console.log(`\n Temperature: ${bold}${temp}${reset}\n`); + break; + } + } + } catch (err: any) { + console.error(`Error: ${err.message}`); + process.exit(1); + } +} diff --git a/cli/tests/color-transforms.test.ts b/cli/tests/color-transforms.test.ts new file mode 100644 index 00000000..faf5a75f --- /dev/null +++ b/cli/tests/color-transforms.test.ts @@ -0,0 +1,109 @@ +import { describe, it, expect } from 'bun:test'; + +const CLI_CMD = `cd "${import.meta.dir}/.." && bun run src/index.ts`; + +async function runCli(args: string): Promise { + const proc = Bun.spawn(['bash', '-c', `${CLI_CMD} color ${args}`], { + stdout: 'pipe', + stderr: 'pipe', + }); + const text = await new Response(proc.stdout).text(); + await proc.exited; + return text.trim(); +} + +async function runCliJson(args: string): Promise { + const text = await runCli(`${args} --output json`); + return JSON.parse(text); +} + +describe('CLI color transforms', () => { + describe('lighten / darken', () => { + it('--lighten increases lightness', async () => { + const original = await runCliJson("'#666666'"); + const lightened = await runCliJson("'#666666' --lighten 0.1"); + expect(lightened.oklch.l).toBeGreaterThan(original.oklch.l); + }); + + it('--darken decreases lightness', async () => { + const original = await runCliJson("'#666666'"); + const darkened = await runCliJson("'#666666' --darken 0.1"); + expect(darkened.oklch.l).toBeLessThan(original.oklch.l); + }); + }); + + describe('saturate / desaturate', () => { + it('--saturate increases chroma', async () => { + const original = await runCliJson("'#996666'"); + const saturated = await runCliJson("'#996666' --saturate 0.05"); + expect(saturated.oklch.c).toBeGreaterThan(original.oklch.c); + }); + + it('--desaturate decreases chroma', async () => { + const original = await runCliJson("'#ff0000'"); + const desaturated = await runCliJson("'#ff0000' --desaturate 0.05"); + expect(desaturated.oklch.c).toBeLessThan(original.oklch.c); + }); + }); + + describe('rotate', () => { + it('--rotate changes hue', async () => { + const original = await runCliJson("'#ff0000'"); + const rotated = await runCliJson("'#ff0000' --rotate 120"); + expect(rotated.oklch.h).not.toBeCloseTo(original.oklch.h, 0); + }); + }); + + describe('set', () => { + it('--set-lightness sets absolute lightness', async () => { + const result = await runCliJson("'#ff0000' --set-lightness 0.5"); + expect(result.oklch.l).toBeCloseTo(0.5, 1); + }); + + it('--set-chroma sets absolute chroma', async () => { + const result = await runCliJson("'#ff0000' --set-chroma 0.1"); + expect(result.oklch.c).toBeCloseTo(0.1, 1); + }); + + it('--set-hue sets absolute hue', async () => { + const result = await runCliJson("'#ff0000' --set-hue 180"); + expect(result.oklch.h).toBeCloseTo(180, 0); + }); + }); + + describe('mix', () => { + it('--mix blends two colors', async () => { + const result = await runCliJson("'#ff0000' --mix '#0000ff' --ratio 0.5"); + expect(result.hex).not.toBe('#ff0000'); + expect(result.hex).not.toBe('#0000ff'); + }); + + it('--mix with --space uses different color space', async () => { + const oklch = await runCliJson("'#ff0000' --mix '#0000ff' --ratio 0.5"); + const lab = await runCliJson("'#ff0000' --mix '#0000ff' --ratio 0.5 --space lab"); + expect(oklch.hex).not.toBe(lab.hex); + }); + }); + + describe('blend', () => { + it('--blend with --mode applies blend mode', async () => { + const result = await runCliJson("'#ff8800' --blend '#0088ff' --ratio 0.5 --mode multiply"); + expect(result.hex).toBeDefined(); + expect(result.hex).not.toBe('#ff8800'); + }); + }); + + describe('chaining', () => { + it('multiple transforms applied left to right', async () => { + const result = await runCliJson("'#66b172' --lighten 0.1 --desaturate 0.05"); + const original = await runCliJson("'#66b172'"); + expect(result.oklch.l).toBeGreaterThan(original.oklch.l); + }); + + it('transforms with CSS output', async () => { + const css = await runCli("'#66b172' --lighten 0.1 --desaturate 0.05 -O css --prefix brand"); + expect(css).toContain(':root {'); + expect(css).toContain('--brand-'); + }); + }); +}); diff --git a/cli/tests/palette.test.ts b/cli/tests/palette.test.ts new file mode 100644 index 00000000..1d25bbeb --- /dev/null +++ b/cli/tests/palette.test.ts @@ -0,0 +1,161 @@ +import { describe, it, expect } from 'bun:test'; +import { resolve } from 'path'; + +const CLI_CMD = `cd "${resolve(__dirname, '..')}" && bun run src/index.ts`; +const TEST_PNG = resolve(__dirname, '../../tests/fixtures/test-palette.png'); +const TEST_JPEG = '/Users/basiclines/Downloads/IMG_6588.jpeg'; + +async function runCli(...args: string[]): Promise { + const proc = Bun.spawn(['bash', '-c', `${CLI_CMD} palette ${args.join(' ')}`], { + stdout: 'pipe', + stderr: 'pipe', + }); + const text = await new Response(proc.stdout).text(); + await proc.exited; + return text.trim(); +} + +describe('CLI palette subcommand', () => { + describe('dominant (default)', () => { + it('shows dominant colors from PNG', async () => { + const out = await runCli(TEST_PNG); + expect(out).toContain('Dominant colors'); + expect(out).toContain('#ff0000'); + }); + + it('respects --count', async () => { + const out = await runCli(`${TEST_PNG} --count 2`); + // Should show 2 entries + const hexMatches = out.match(/#[0-9a-f]{6}/g) || []; + // At least 2 from dominant + 1 from average + expect(hexMatches.length).toBeGreaterThanOrEqual(3); + }); + }); + + describe('--raw', () => { + it('shows raw palette', async () => { + const out = await runCli(`${TEST_PNG} --raw`); + expect(out).toContain('Raw palette'); + }); + }); + + describe('--ansi', () => { + it('shows ANSI categories', async () => { + const out = await runCli(`${TEST_PNG} --ansi`); + expect(out).toContain('ANSI palette'); + expect(out).toContain('red'); + expect(out).toContain('green'); + expect(out).toContain('blue'); + }); + }); + + describe('--average', () => { + it('shows average color', async () => { + const out = await runCli(`${TEST_PNG} --average`); + expect(out).toContain('#'); + expect(out).toContain('oklch'); + }); + }); + + describe('--temperature', () => { + it('shows temperature', async () => { + const out = await runCli(`${TEST_PNG} --temperature`); + expect(out).toContain('Temperature:'); + }); + }); + + describe('output formats', () => { + it('--output json returns valid JSON', async () => { + const out = await runCli(`${TEST_PNG} --output json`); + const parsed = JSON.parse(out); + expect(parsed.dominant).toBeDefined(); + expect(parsed.average).toBeDefined(); + expect(parsed.temperature).toBeDefined(); + }); + + it('--output css returns CSS', async () => { + const out = await runCli(`${TEST_PNG} --output css --prefix img`); + expect(out).toContain(':root {'); + expect(out).toContain('--img-1:'); + expect(out).toContain('--img-avg:'); + }); + + it('--ansi --output json returns ANSI JSON', async () => { + const out = await runCli(`${TEST_PNG} --ansi --output json`); + const parsed = JSON.parse(out); + expect(parsed.red).toBeDefined(); + expect(parsed.blue).toBeDefined(); + }); + }); + + describe('JPEG files', () => { + it('loads JPEG and shows dominant colors', async () => { + const out = await runCli(`${TEST_JPEG} --count 3`); + expect(out).toContain('Dominant colors'); + }); + }); + + describe('help', () => { + it('shows help with --help', async () => { + const out = await runCli('--help'); + expect(out).toContain('rampa palette'); + expect(out).toContain('--count'); + expect(out).toContain('--ansi'); + expect(out).toContain('--group'); + expect(out).toContain('--sort'); + }); + }); + + describe('--sort', () => { + it('--sort L sorts dominant by lightness', async () => { + const out = await runCli(TEST_PNG, '--sort', 'L'); + const lines = out.split('\n').filter(l => l.includes('L=')); + const lValues = lines.map(l => { + const match = l.match(/L=([\d.]+)/); + return match ? parseFloat(match[1]) : -1; + }).filter(v => v >= 0); + for (let i = 1; i < lValues.length; i++) { + expect(lValues[i]).toBeGreaterThanOrEqual(lValues[i - 1]); + } + }); + }); + + describe('--group', () => { + it('--group L shows lightness buckets', async () => { + const out = await runCli(TEST_PNG, '--group', 'L'); + expect(out).toContain('Group by L'); + expect(out).toContain('darkest'); + expect(out).toContain('lightest'); + }); + + it('--group C shows chroma buckets', async () => { + const out = await runCli(TEST_PNG, '--group', 'C'); + expect(out).toContain('Group by C'); + expect(out).toContain('gray'); + expect(out).toContain('vivid'); + }); + + it('--group H shows hue buckets', async () => { + const out = await runCli(TEST_PNG, '--group', 'H'); + expect(out).toContain('Group by H'); + expect(out).toContain('red'); + expect(out).toContain('green'); + expect(out).toContain('blue'); + }); + + it('--group L --output json returns valid JSON', async () => { + const out = await runCli(TEST_PNG, '--group', 'L', '--output', 'json'); + const parsed = JSON.parse(out); + expect(parsed).toHaveProperty('darkest'); + expect(parsed).toHaveProperty('lightest'); + }); + + it('--group L --l-buckets 3 creates 3 buckets', async () => { + const out = await runCli(TEST_PNG, '--group', 'L', '--l-buckets', '3'); + expect(out).toContain('dark'); + expect(out).toContain('mid'); + expect(out).toContain('light'); + expect(out).not.toContain('darkest'); + }); + }); +}); diff --git a/package.json b/package.json index 4c11e74b..664f9203 100644 --- a/package.json +++ b/package.json @@ -58,7 +58,9 @@ "cmdk": "^1.1.1", "date-fns": "^4.1.0", "embla-carousel-react": "^8.6.0", + "fast-png": "^8.0.0", "input-otp": "^1.4.2", + "jpeg-js": "^0.4.4", "lucide-react": "^0.525.0", "netlify-cli": "^22.1.3", "next-themes": "^0.4.6", diff --git a/sdk/README.md b/sdk/README.md index 37fb07e0..aba76642 100644 --- a/sdk/README.md +++ b/sdk/README.md @@ -237,7 +237,17 @@ result.ramps[1].colors // complementary ramp colors ### `color(input)` -Inspect a single color — get all format representations, format conversion, and export. Equivalent to `rampa color` in the CLI. +Inspect, transform, mix, and export a single color. Equivalent to `rampa color` in the CLI. + +All property values use **0-1 normalized ranges** to match CSS spec conventions: + +| Property | Range | +|----------|-------| +| `hsl.h` | 0–360 (degrees) | +| `hsl.s`, `hsl.l` | 0–1 | +| `oklch.l` | 0–1 | +| `oklch.c` | 0–0.4 (native OKLCH scale) | +| `oklch.h` | 0–360 (degrees) | ```typescript import { color } from '@basiclines/rampa-sdk'; @@ -245,11 +255,11 @@ import { color } from '@basiclines/rampa-sdk'; const c = color('#fe0000'); c.hex // '#fe0000' c.rgb // { r: 254, g: 0, b: 0 } -c.hsl // { h: 0, s: 100, l: 50 } -c.oklch // { l: 62.8, c: 0.258, h: 29 } +c.hsl // { h: 0, s: 1.0, l: 0.5 } +c.oklch // { l: 0.628, c: 0.258, h: 29 } c.luminance // 0.628 -// Format conversion +// Format conversion (string output uses CSS conventions: percentages) c.format('hsl') // 'hsl(0, 100%, 50%)' c.format('rgb') // 'rgb(254, 0, 0)' c.format('oklch') // 'oklch(62.8% 0.258 29)' @@ -263,6 +273,51 @@ c.output('text') // plain hex string `${c}` // '#fe0000' ``` +#### Color Transforms + +All transforms operate in **OKLCH space** and return a new immutable `Color`. Chain freely. + +```typescript +// Absolute deltas — clamped to valid range +c.lighten(0.1) // L += 0.1 (OKLCH lightness, 0-1) +c.darken(0.1) // L -= 0.1 +c.saturate(0.05) // C += 0.05 (OKLCH chroma) +c.desaturate(0.05) // C -= 0.05 +c.rotate(30) // H += 30° (hue rotation) + +// All accept negative values: lighten(-0.1) === darken(0.1) + +// Set absolute OKLCH values +c.set({ lightness: 0.48 }) // set L +c.set({ chroma: 0.15, hue: 200 }) // batch set + +// Chain transforms +color('#66b172').lighten(0.1).desaturate(0.05).hex +// → bright desaturated green, no throwaway converters +``` + +#### Mix (color space interpolation) + +Like CSS `color-mix()` — interpolates between two colors in a chosen color space. + +```typescript +c.mix('#0000ff', 0.5) // 50% mix in oklch (default) +c.mix('#0000ff', 0.18, 'lab') // explicit color space +c.mix('#0000ff', 0.18, 'srgb') // sRGB interpolation +``` + +#### Blend (compositing modes) + +Like Photoshop/CSS blend modes — composites two colors with an opacity and a blend mode. + +```typescript +c.blend('#0000ff', 0.15, 'multiply') +c.blend('#0000ff', 0.15, 'screen') +c.blend('#0000ff', 0.15, 'overlay') +``` + +Available blend modes: `normal`, `multiply`, `screen`, `overlay`, `darken`, `lighten`, `color-dodge`, `color-burn`, `hard-light`, `soft-light`, `difference`, `exclusion`, `hue`, `saturation`, `color`, `luminosity` + ### `rampa.convert(color, format)` Standalone utility to convert a color to a different format. @@ -335,8 +390,9 @@ import type { RampResult, // { name, baseColor, colors } RampaResult, // { ramps: RampResult[] } RampaFn, // callable palette returned by rampa() - Color, // { hex, rgb, hsl, oklch, luminance, format(), output() } + Color, // { hex, rgb, hsl, oklch, luminance, format(), output(), lighten(), ... } ColorInfo, // { hex, rgb, hsl, oklch } + OklchSetValues, // { lightness?, chroma?, hue? } for color.set() InterpolationMode, // 'oklch' | 'lab' | 'rgb' LinearColorSpaceFn, // callable function returned by LinearColorSpace.size() CubeColorSpaceFn, // callable function returned by CubeColorSpace.size() @@ -453,6 +509,23 @@ neutral(12).hsl() // → 'hsl(0, 0%, 40%)' neutral.palette // → string[24] ``` +#### Ramp introspection + +Access individual steps as full `Color` objects with `.at()`, or get all steps with `.colors()`: + +```typescript +const ramp = new LinearColorSpace('#000', '#fff').size(12); + +ramp.at(3) // → Color (0-based index) +ramp.at(3).oklch.c // → chroma at step 3 +ramp.at(3).lighten(0.1).hex // → transform a ramp step + +ramp.colors() // → Color[] +ramp.colors().map(c => c.oklch.c) // → chroma curve across ramp +``` + +**`.at()` is 0-based** (like `Array.at()`), while the callable `ramp(n)` remains 1-based for backward compatibility. + #### Lookup table mode Set `.interpolation(false)` for a plain lookup table — no interpolation, just indexed access to the exact colors you provide: @@ -497,6 +570,11 @@ red(5, 5) // → full hue color red(0, 0) // → dark anchor red.palette // → string[36] (6²) +// Ramp introspection +red.at(3, 5) // → Color at (saturation=3, lightness=5) +red.at(3, 5).oklch.c // → chroma at that coordinate +red.colors() // → Color[] (flat, row-major) + // Template literals and concatenation work directly `background: ${red(3, 5)};` // → 'background: #ab34cd;' @@ -526,6 +604,10 @@ const { r, b, tint } = new CubeColorSpace({ r(4) // → strong red tint({ r: 4, b: 2 }) // → red-blue blend tint({ w: 3 }) // → mid-white (all axes at 3) + +// Ramp introspection +cube.at(2, 3, 1) // → Color at (x=2, y=3, z=1) +cube.colors() // → Color[] ``` #### Custom vocabulary @@ -635,6 +717,128 @@ const rgbSpace = new PlaneColorSpace('#000', '#fff', '#f00').format('rgb').size( rgbSpace(3, 5).hex() // → '#ff8080' (still available) ``` +## Image Palette Extraction + +Extract color palettes from images with three tiers of analysis: raw unique colors, dominant color clusters, and ANSI-classified palettes. + +Requires `fast-png` and `jpeg-js` (installed as dependencies). Supports PNG and JPEG files. + +### `palette(filePath)` + +```typescript +import { palette } from '@basiclines/rampa-sdk'; + +const p = await palette('photo.jpg'); +``` + +### Dominant Colors + +Top N color groups via k-means clustering in OKLCH space: + +```typescript +p.dominant() // → PaletteEntry[] (top 10) +p.dominant({ count: 5 }) // top 5 +p.dominant({ tolerance: 10 }) // wider clustering (default: 4) + +// Shortcut with .at() (0-based, like ramp.at()) +p.at(0) // most dominant color +p.at(0).color.hex // → '#2d2a18' +p.at(0).frequency // → 0.278 (27.8% of pixels) +p.at(0).color.lighten(0.1).hex // chain transforms +``` + +### Raw Palette + +All unique colors with near-duplicates merged: + +```typescript +p.raw() // → PaletteEntry[] +p.raw({ tolerance: 3 }) // deltaE merge threshold (default: 2) +p.raw({ maxColors: 500 }) // cap output (default: 1000) +``` + +### ANSI Palette + +Colors classified into terminal color categories: + +```typescript +p.ansi() +// → { red: PaletteEntry[], green: [...], blue: [...], ... } + +p.ansi({ count: 3 }) // max 3 per category (default: 5) +``` + +Categories: `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, `white` + +### Group by OKLCH Property + +Group colors into buckets by lightness, chroma, or hue: + +```typescript +p.group({ by: 'L' }) // → { darkest, dark, mid, light, lightest } +p.group({ by: 'C' }) // → { gray, muted, saturated, vivid } +p.group({ by: 'H' }) // → { red, orange, yellow, green, cyan, blue, purple, pink } + +p.group({ by: 'L', count: 3 }) // max 3 colors per bucket +p.group({ by: 'L', tolerance: 10 }) // wider dedup within buckets +``` + +Custom bucket boundaries: + +```typescript +p.group({ + by: 'L', + buckets: [ + { name: 'dark', min: 0, max: 0.3 }, + { name: 'mid', min: 0.3, max: 0.7 }, + { name: 'light', min: 0.7, max: 1.0 }, + ], +}) +``` + +### Sorting with `.sortBy()` + +All array and grouped results support `.sortBy()` for reordering: + +```typescript +// Sort dominant colors by lightness (dark → light) +p.dominant({ count: 5 }).sortBy('L') + +// Sort within each group bucket +p.group({ by: 'C' }).sortBy('L') // chroma groups, each sorted dark→light +p.ansi().sortBy('L') // ANSI categories, each sorted dark→light + +// Sort fields: 'L' (lightness), 'C' (chroma), 'H' (hue), 'frequency' +p.raw().sortBy('H') // all colors sorted by hue angle + +// Chainable — returns a new sorted result +p.dominant().sortBy('L').sortBy('C') +``` + +### Extras + +```typescript +p.average() // → Color (weighted OKLCH average) +p.temperature() // → 'warm' | 'cool' | 'neutral' +``` + +### Output + +```typescript +p.output('json') // full analysis as JSON +p.output('css', 'photo') // CSS custom properties +p.output('text') // readable text +``` + +### PaletteEntry Shape + +```typescript +interface PaletteEntry { + color: Color; // full Color with transforms + frequency: number; // 0-1, percentage of sampled pixels +} +``` + ## Development ```bash diff --git a/sdk/bun.lock b/sdk/bun.lock index 249a30d3..190a13d2 100644 --- a/sdk/bun.lock +++ b/sdk/bun.lock @@ -6,20 +6,14 @@ "name": "@basiclines/rampa-sdk", "dependencies": { "chroma-js": "^3.1.2", - "culori": "^4.0.1", + "fast-png": "^8.0.0", + "jpeg-js": "^0.4.4", }, "devDependencies": { "@types/bun": "^1.2.17", "@types/chroma-js": "^3.1.1", - "apca-w3": "^0.1.9", "typescript": "^5.5.3", }, - "peerDependencies": { - "apca-w3": "^0.1.9", - }, - "optionalPeers": [ - "apca-w3", - ], }, }, "packages": { @@ -29,15 +23,17 @@ "@types/node": ["@types/node@25.3.0", "", { "dependencies": { "undici-types": "~7.18.0" } }, "sha512-4K3bqJpXpqfg2XKGK9bpDTc6xO/xoUP/RBWS7AtRMug6zZFaRekiLzjVtAoZMquxoAbzBvy5nxQ7veS5eYzf8A=="], - "apca-w3": ["apca-w3@0.1.9", "", { "dependencies": { "colorparsley": "^0.1.8" } }, "sha512-Zrf6AeBeQjNe/fxK7U1jCo5zfdjDl6T4/kdw5Xlky3G7u+EJTZkyItjMYQGtwf9pkftsINxcYyOpuLkzKf1ITQ=="], - "bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="], "chroma-js": ["chroma-js@3.2.0", "", {}, "sha512-os/OippSlX1RlWWr+QDPcGUZs0uoqr32urfxESG9U93lhUfbnlyckte84Q8P1UQY/qth983AS1JONKmLS4T0nw=="], - "colorparsley": ["colorparsley@0.1.8", "", {}, "sha512-rObESTTTE6G5qO5WFwFxWPggpw4KfpxnLC6Ssl8bITBnNVRhDsyCeTRAUxWQNVTx2pRknKlO2nddYTxjkdNFaw=="], + "fast-png": ["fast-png@8.0.0", "", { "dependencies": { "fflate": "^0.8.2", "iobuffer": "^6.0.1" } }, "sha512-gCysNasJ8KEMgfdYIKd/wTDo6ENK1PWT0RJO7O+0pgmuHPw2O6tA1WvdxFRJoLf9V8yFYpG0FA1YgI8X97OhJA=="], + + "fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="], + + "iobuffer": ["iobuffer@6.0.1", "", {}, "sha512-SZWYkWNfjIXIBYSDpXDYIgshqtbOPsi4lviawAEceR1Kqk+sHDlcQjWrzNQsii80AyBY0q5c8HCTNjqo74ul+Q=="], - "culori": ["culori@4.0.2", "", {}, "sha512-1+BhOB8ahCn4O0cep0Sh2l9KCOfOdY+BXJnKMHFFzDEouSr/el18QwXEMRlOj9UY5nCeA8UN3a/82rUWRBeyBw=="], + "jpeg-js": ["jpeg-js@0.4.4", "", {}, "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], diff --git a/sdk/package.json b/sdk/package.json index e84eb683..68d175e5 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -32,7 +32,9 @@ "provenance": true }, "dependencies": { - "chroma-js": "^3.1.2" + "chroma-js": "^3.1.2", + "fast-png": "^8.0.0", + "jpeg-js": "^0.4.4" }, "devDependencies": { "@types/bun": "^1.2.17", diff --git a/sdk/src/color-result.ts b/sdk/src/color-result.ts index 68450be9..241384a9 100644 --- a/sdk/src/color-result.ts +++ b/sdk/src/color-result.ts @@ -1,5 +1,8 @@ import chroma from 'chroma-js'; -import type { ColorFormat, Color, ColorAccessor, RampaOutputFormat } from './types'; +import { convertToOklch, convertFromOklch, constrainOklchValues } from '../../src/engine/OklchEngine'; +import { mixWithMode } from '../../src/engine/ColorSpaceEngine'; +import { applyBlendMode } from '../../src/engine/BlendingEngine'; +import type { ColorFormat, Color, ColorAccessor, RampaOutputFormat, BlendMode, InterpolationMode, OklchSetValues } from './types'; /** * Detect the format of a color string. @@ -91,13 +94,13 @@ export function createColor(input: string): Color { const [ol, oc, oh] = c.oklch(); const rgb = { r, g, b }; - const hsl = { h: Math.round(hh || 0), s: Math.round(ss * 100), l: Math.round(ll * 100) }; - const oklch = { l: parseFloat((ol * 100).toFixed(1)), c: parseFloat(oc.toFixed(3)), h: Math.round(oh || 0) }; + const hsl = { h: Math.round(hh || 0), s: parseFloat(ss.toFixed(2)), l: parseFloat(ll.toFixed(2)) }; + const oklch = { l: parseFloat(ol.toFixed(3)), c: parseFloat(oc.toFixed(3)), h: Math.round(oh || 0) }; const formatColor = (fmt: ColorFormat): string => { switch (fmt) { case 'hsl': - return `hsl(${hsl.h}, ${hsl.s}%, ${hsl.l}%)`; + return `hsl(${hsl.h}, ${Math.round(hsl.s * 100)}%, ${Math.round(hsl.l * 100)}%)`; case 'rgb': return `rgb(${r}, ${g}, ${b})`; case 'oklch': @@ -114,6 +117,51 @@ export function createColor(input: string): Color { oklch, luminance: ol, + lighten(delta: number): Color { + const o = convertToOklch(hex); + o.l = Math.max(0, Math.min(1, o.l + delta)); + return createColor(convertFromOklch(constrainOklchValues(o))); + }, + + darken(delta: number): Color { + return this.lighten(-delta); + }, + + saturate(delta: number): Color { + const o = convertToOklch(hex); + o.c = Math.max(0, o.c + delta); + return createColor(convertFromOklch(constrainOklchValues(o))); + }, + + desaturate(delta: number): Color { + return this.saturate(-delta); + }, + + rotate(degrees: number): Color { + const o = convertToOklch(hex); + o.h = ((o.h + degrees) % 360 + 360) % 360; + return createColor(convertFromOklch(constrainOklchValues(o))); + }, + + set(values: OklchSetValues): Color { + const o = convertToOklch(hex); + if (values.lightness !== undefined) o.l = Math.max(0, Math.min(1, values.lightness)); + if (values.chroma !== undefined) o.c = Math.max(0, values.chroma); + if (values.hue !== undefined) o.h = ((values.hue % 360) + 360) % 360; + return createColor(convertFromOklch(constrainOklchValues(o))); + }, + + mix(target: string, ratio: number, space: InterpolationMode = 'oklch'): Color { + const engineSpace = space === 'srgb' ? 'rgb' : space; + const mixed = mixWithMode(hex, chroma(target).hex(), ratio, engineSpace as InterpolationMode); + return createColor(mixed); + }, + + blend(target: string, opacity: number, mode: BlendMode): Color { + const blended = applyBlendMode(chroma(hex), chroma(target), opacity, mode); + return createColor(blended.hex()); + }, + format(fmt: ColorFormat): string { return formatColor(fmt); }, diff --git a/sdk/src/cube-color-space.ts b/sdk/src/cube-color-space.ts index 59af00c0..06607f74 100644 --- a/sdk/src/cube-color-space.ts +++ b/sdk/src/cube-color-space.ts @@ -1,9 +1,9 @@ import { generateCubeSpace, mixWithMode } from '../../src/engine/ColorSpaceEngine'; import { calculateScalePosition } from '../../src/engine/HarmonyEngine'; -import { createColorAccessor, validateSameFormat } from './color-result'; +import { createColorAccessor, validateSameFormat, createColor } from './color-result'; import { cubeToCSS, cubeToJSON } from './formatters/color-space'; import chroma from 'chroma-js'; -import type { ColorFormat, InterpolationMode, CubeColorSpaceResult, ColorAccessor, ScaleType, RampaOutputFormat } from './types'; +import type { ColorFormat, InterpolationMode, CubeColorSpaceResult, ColorAccessor, ScaleType, RampaOutputFormat, Color } from './types'; // The 8 cube corner positions in binary order. // Constructor keys map to these positions by their insertion order. @@ -175,6 +175,14 @@ export class CubeColorSpace { default: throw new Error(`Unknown output format: ${format}`); } }, + at: (x: number, y: number, z: number): Color => { + const cx = Math.max(0, Math.min(max, Math.round(x))); + const cy = Math.max(0, Math.min(max, Math.round(y))); + const cz = Math.max(0, Math.min(max, Math.round(z))); + const index = cx * stepsPerAxis * stepsPerAxis + cy * stepsPerAxis + cz; + return createColor(palette[index]); + }, + colors: (): Color[] => palette.map(hex => createColor(hex)), }; // Add per-corner shortcut: e.g. result.r = (index) => tint({ r: index }) diff --git a/sdk/src/index.ts b/sdk/src/index.ts index 5b133167..4831d314 100644 --- a/sdk/src/index.ts +++ b/sdk/src/index.ts @@ -28,6 +28,7 @@ import type { ContrastLevelResult, ContrastResult, LintResult, + OklchSetValues, } from './types'; /** @@ -103,6 +104,8 @@ export function color(input: string): Color { } export { lint, RampaBuilder, createRampaFn, LintBuilder, LinearColorSpace, CubeColorSpace, PlaneColorSpace }; +export { palette } from './palette'; +export type { PaletteEntry, PaletteResult, PaletteOptions, RawOptions, DominantOptions, AnsiOptions, GroupOptions, SortField, SortablePaletteEntries, SortablePaletteGroups } from './palette'; export type { ColorFormat, OutputMode, @@ -126,4 +129,5 @@ export type { ContrastLevelResult, ContrastResult, LintResult, + OklchSetValues, }; diff --git a/sdk/src/linear-color-space.ts b/sdk/src/linear-color-space.ts index d246eef9..cdde882c 100644 --- a/sdk/src/linear-color-space.ts +++ b/sdk/src/linear-color-space.ts @@ -1,9 +1,9 @@ import { generateLinearSpace, mixWithMode } from '../../src/engine/ColorSpaceEngine'; import { calculateScalePosition } from '../../src/engine/HarmonyEngine'; -import { createColorAccessor, validateSameFormat } from './color-result'; +import { createColorAccessor, validateSameFormat, createColor } from './color-result'; import { linearToCSS, linearToJSON } from './formatters/color-space'; import chroma from 'chroma-js'; -import type { ColorFormat, InterpolationMode, LinearColorSpaceFn, ColorAccessor, ScaleType, RampaOutputFormat } from './types'; +import type { ColorFormat, InterpolationMode, LinearColorSpaceFn, ColorAccessor, ScaleType, RampaOutputFormat, Color } from './types'; /** * Create a linear color space. @@ -117,6 +117,11 @@ function buildFn(palette: string[], outputFormat: ColorFormat): LinearColorSpace default: throw new Error(`Unknown output format: ${format}`); } }; + fn.at = (index: number): Color => { + const i = Math.max(0, Math.min(palette.length - 1, index)); + return createColor(palette[i]); + }; + fn.colors = (): Color[] => palette.map(hex => createColor(hex)); return fn; } diff --git a/sdk/src/palette.ts b/sdk/src/palette.ts new file mode 100644 index 00000000..2113aaeb --- /dev/null +++ b/sdk/src/palette.ts @@ -0,0 +1,275 @@ +import { decodeImage } from '../../src/engine/ImageDecoder'; +import { + samplePixels, + buildFrequencyMap, + buildRawPalette, + kMeansClustering, + buildAnsiPalette, + buildGroupPalette, + getDefaultBuckets, + computeAverage, + classifyTemperature, + type PaletteEngineEntry, + type AnsiColorName, + type GroupByProperty, + type GroupBucket, +} from '../../src/engine/PaletteEngine'; +import { oklchToHex } from '../../src/engine/OklchMathEngine'; +import { createColor } from './color-result'; +import type { Color, RampaOutputFormat } from './types'; + +export interface PaletteEntry { + color: Color; + frequency: number; +} + +export interface PaletteOptions { + /** Number of pixels to sample (default: 50000) */ + sampleSize?: number; +} + +export interface RawOptions { + /** DeltaE tolerance for merging near-duplicates (default: 2) */ + tolerance?: number; + /** Maximum colors to return (default: 1000) */ + maxColors?: number; +} + +export interface DominantOptions { + /** Number of dominant colors to return (default: 10) */ + count?: number; + /** DeltaE tolerance for clustering radius (default: 4) */ + tolerance?: number; +} + +export interface AnsiOptions { + /** Max colors per ANSI category (default: 5) */ + count?: number; + /** DeltaE tolerance for dedup within each category (default: 4) */ + tolerance?: number; +} + +export interface GroupOptions { + /** OKLCH property to group by */ + by: GroupByProperty; + /** Max colors per bucket (default: 5) */ + count?: number; + /** DeltaE tolerance for dedup within each bucket (default: 4) */ + tolerance?: number; + /** Custom bucket boundaries (overrides defaults) */ + buckets?: GroupBucket[]; +} + +export type SortField = 'frequency' | 'L' | 'C' | 'H'; + +export interface SortablePaletteEntries extends Array { + sortBy(field: SortField): SortablePaletteEntries; +} + +export interface SortablePaletteGroups extends Record { + sortBy(field: SortField): SortablePaletteGroups; +} + +export interface PaletteResult { + /** All unique colors, most frequent first, near-duplicates merged */ + raw(options?: RawOptions): SortablePaletteEntries; + /** Top N dominant color groups via k-means clustering */ + dominant(options?: DominantOptions): SortablePaletteEntries; + /** Shortcut into dominant results (0-based index) */ + at(index: number): PaletteEntry; + /** Colors classified into ANSI categories */ + ansi(options?: AnsiOptions): SortablePaletteGroups; + /** Colors grouped by OKLCH property (L, C, or H) */ + group(options: GroupOptions): SortablePaletteGroups; + /** Weighted average color of the image */ + average(): Color; + /** Overall color temperature */ + temperature(): 'warm' | 'cool' | 'neutral'; + /** Export as json, css, or text */ + output(format: RampaOutputFormat, prefix?: string): string; +} + +function sortEntriesByField(entries: PaletteEntry[], field: SortField): PaletteEntry[] { + const sorted = [...entries]; + switch (field) { + case 'L': return sorted.sort((a, b) => a.color.oklch.l - b.color.oklch.l); + case 'C': return sorted.sort((a, b) => a.color.oklch.c - b.color.oklch.c); + case 'H': return sorted.sort((a, b) => a.color.oklch.h - b.color.oklch.h); + default: return sorted.sort((a, b) => b.frequency - a.frequency); + } +} + +function makeSortableEntries(entries: PaletteEntry[]): SortablePaletteEntries { + const arr = [...entries] as SortablePaletteEntries; + Object.defineProperty(arr, 'sortBy', { + enumerable: false, + value(field: SortField): SortablePaletteEntries { + return makeSortableEntries(sortEntriesByField(arr, field)); + }, + }); + return arr; +} + +function makeSortableGroups(groups: Record): SortablePaletteGroups { + const result = { ...groups } as SortablePaletteGroups; + Object.defineProperty(result, 'sortBy', { + enumerable: false, + value(field: SortField): SortablePaletteGroups { + const sorted: Record = {}; + for (const [key, entries] of Object.entries(result)) { + sorted[key] = sortEntriesByField(entries, field); + } + return makeSortableGroups(sorted); + }, + }); + return result; +} + +function engineToEntry(e: PaletteEngineEntry): PaletteEntry { + return { color: createColor(e.hex), frequency: e.frequency }; +} + +function engineArrayToEntries(arr: PaletteEngineEntry[]): PaletteEntry[] { + return arr.map(engineToEntry); +} + +export async function palette(filePath: string, options?: PaletteOptions): Promise { + const { sampleSize = 50000 } = options || {}; + + const image = decodeImage(filePath); + const pixels = samplePixels(image.data, image.width, image.height, sampleSize); + const freqMap = buildFrequencyMap(pixels); + + // Cache results for repeated calls with same options + let cachedRaw: Map = new Map(); + let cachedDominant: Map = new Map(); + let cachedAnsi: Map = new Map(); + let cachedGroup: Map = new Map(); + let cachedAverage: Color | null = null; + let cachedTemp: string | null = null; + + const result: PaletteResult = { + raw(opts?: RawOptions): SortablePaletteEntries { + const key = JSON.stringify(opts || {}); + if (cachedRaw.has(key)) return cachedRaw.get(key)!; + const raw = buildRawPalette(freqMap, opts?.tolerance, opts?.maxColors); + const entries = makeSortableEntries(engineArrayToEntries(raw)); + cachedRaw.set(key, entries); + return entries; + }, + + dominant(opts?: DominantOptions): SortablePaletteEntries { + const key = JSON.stringify(opts || {}); + if (cachedDominant.has(key)) return cachedDominant.get(key)!; + const raw = buildRawPalette(freqMap, 2, 1000); + const clusters = kMeansClustering(raw, opts?.count, opts?.tolerance); + const entries = makeSortableEntries(engineArrayToEntries(clusters)); + cachedDominant.set(key, entries); + return entries; + }, + + at(index: number): PaletteEntry { + const dom = result.dominant(); + if (index < 0 || index >= dom.length) { + throw new RangeError(`Index ${index} out of range (0-${dom.length - 1})`); + } + return dom[index]; + }, + + ansi(opts?: AnsiOptions): SortablePaletteGroups { + const key = JSON.stringify(opts || {}); + if (cachedAnsi.has(key)) return cachedAnsi.get(key)!; + const raw = buildRawPalette(freqMap, 2, 1000); + const ansiMap = buildAnsiPalette(raw, opts?.count, opts?.tolerance); + const entries: Record = {}; + for (const [name, arr] of Object.entries(ansiMap)) { + entries[name] = engineArrayToEntries(arr); + } + const sortable = makeSortableGroups(entries); + cachedAnsi.set(key, sortable); + return sortable; + }, + + group(opts: GroupOptions): SortablePaletteGroups { + const key = JSON.stringify(opts); + if (cachedGroup.has(key)) return cachedGroup.get(key)!; + const raw = buildRawPalette(freqMap, 2, 1000); + const buckets = opts.buckets || getDefaultBuckets(opts.by); + const grouped = buildGroupPalette(raw, opts.by, buckets, opts.count, opts.tolerance); + const entries: Record = {}; + for (const [name, arr] of Object.entries(grouped)) { + entries[name] = engineArrayToEntries(arr); + } + const sortable = makeSortableGroups(entries); + cachedGroup.set(key, sortable); + return sortable; + }, + + average(): Color { + if (cachedAverage) return cachedAverage; + const raw = buildRawPalette(freqMap, 2, 1000); + const avg = computeAverage(raw); + const hex = oklchToHex(avg.l, avg.c, avg.h); + cachedAverage = createColor(hex); + return cachedAverage; + }, + + temperature(): 'warm' | 'cool' | 'neutral' { + if (cachedTemp) return cachedTemp as any; + const raw = buildRawPalette(freqMap, 2, 1000); + cachedTemp = classifyTemperature(raw); + return cachedTemp as any; + }, + + output(format: RampaOutputFormat, prefix: string = 'palette'): string { + const dom = result.dominant(); + const avg = result.average(); + const temp = result.temperature(); + const ansiData = result.ansi(); + + if (format === 'json') { + return JSON.stringify({ + dominant: dom.map(d => ({ + hex: d.color.hex, + oklch: d.color.oklch, + frequency: Math.round(d.frequency * 10000) / 10000, + })), + average: { hex: avg.hex, oklch: avg.oklch }, + temperature: temp, + ansi: Object.fromEntries( + Object.entries(ansiData).map(([name, entries]) => [ + name, + entries.map(e => ({ + hex: e.color.hex, + frequency: Math.round(e.frequency * 10000) / 10000, + })), + ]) + ), + }, null, 2); + } + + if (format === 'css') { + const lines = [':root {']; + dom.forEach((d, i) => { + lines.push(` --${prefix}-${i + 1}: ${d.color.hex};`); + }); + lines.push(` --${prefix}-avg: ${avg.hex};`); + lines.push('}'); + return lines.join('\n'); + } + + // text format + const lines: string[] = []; + lines.push('Dominant colors:'); + dom.forEach((d, i) => { + const pct = (d.frequency * 100).toFixed(1); + lines.push(` ${i + 1}. ${d.color.hex} ${pct}%`); + }); + lines.push(`\nAverage: ${avg.hex}`); + lines.push(`Temperature: ${temp}`); + return lines.join('\n'); + }, + }; + + return result; +} diff --git a/sdk/src/plane-color-space.ts b/sdk/src/plane-color-space.ts index 0cb45fa4..bd37fe23 100644 --- a/sdk/src/plane-color-space.ts +++ b/sdk/src/plane-color-space.ts @@ -1,9 +1,9 @@ import { generatePlaneSpace, mixWithMode } from '../../src/engine/ColorSpaceEngine'; import { calculateScalePosition } from '../../src/engine/HarmonyEngine'; -import { createColorAccessor, validateSameFormat } from './color-result'; +import { createColorAccessor, validateSameFormat, createColor } from './color-result'; import { planeToCSS, planeToJSON } from './formatters/color-space'; import chroma from 'chroma-js'; -import type { ColorFormat, InterpolationMode, PlaneColorSpaceResult, ColorAccessor, ScaleType, RampaOutputFormat } from './types'; +import type { ColorFormat, InterpolationMode, PlaneColorSpaceResult, ColorAccessor, ScaleType, RampaOutputFormat, Color } from './types'; /** * Create a 2D color plane from dark, light, and hue anchors. @@ -114,6 +114,13 @@ export class PlaneColorSpace { default: throw new Error(`Unknown output format: ${format}`); } }, enumerable: false }, + at: { value: (saturation: number, lightness: number): Color => { + const sx = Math.max(0, Math.min(stepsPerAxis - 1, saturation)); + const ly = Math.max(0, Math.min(stepsPerAxis - 1, lightness)); + const idx = sx * stepsPerAxis + ly; + return createColor(palette[idx]); + }, enumerable: false }, + colors: { value: (): Color[] => palette.map(hex => createColor(hex)), enumerable: false }, }); return result; diff --git a/sdk/src/types.ts b/sdk/src/types.ts index 7d6858b3..c1b6e033 100644 --- a/sdk/src/types.ts +++ b/sdk/src/types.ts @@ -58,21 +58,57 @@ export interface ColorInfo { oklch: { l: number; c: number; h: number }; } +/** + * OKLCH values for absolute color setting via .set(). + */ +export interface OklchSetValues { + /** Lightness (0-1) */ + lightness?: number; + /** Chroma (0-0.4) */ + chroma?: number; + /** Hue (0-360) */ + hue?: number; +} + /** * A color primitive with all format representations and export support. * Returned by the standalone `color()` function. + * + * All transforms are OKLCH-based and return a new immutable Color. */ export interface Color { /** Hex color string */ hex: string; - /** RGB components (0-255) */ + /** RGB components (r: 0-255, g: 0-255, b: 0-255) */ rgb: { r: number; g: number; b: number }; - /** HSL components (h: 0-360, s: 0-100, l: 0-100) */ + /** HSL components (h: 0-360, s: 0-1, l: 0-1) */ hsl: { h: number; s: number; l: number }; - /** OKLCH components (l: 0-100, c: 0-0.4, h: 0-360) */ + /** OKLCH components (l: 0-1, c: 0-0.4, h: 0-360) */ oklch: { l: number; c: number; h: number }; - /** Perceptual luminance (0-1) using OKLCH lightness */ + /** Perceptual luminance (0-1), same as oklch.l */ luminance: number; + + // ── Transforms (OKLCH, return new Color) ────────────── + + /** Increase OKLCH lightness by delta (0-1 scale). Returns new Color. */ + lighten(delta: number): Color; + /** Decrease OKLCH lightness by delta (0-1 scale). Sugar for lighten(-delta). Returns new Color. */ + darken(delta: number): Color; + /** Increase OKLCH chroma by delta (0-0.4 scale). Returns new Color. */ + saturate(delta: number): Color; + /** Decrease OKLCH chroma by delta (0-0.4 scale). Sugar for saturate(-delta). Returns new Color. */ + desaturate(delta: number): Color; + /** Rotate OKLCH hue by degrees. Returns new Color. */ + rotate(degrees: number): Color; + /** Set absolute OKLCH values. Returns new Color. */ + set(values: OklchSetValues): Color; + /** Mix with another color via color space interpolation. Returns new Color. */ + mix(target: string, ratio: number, space?: InterpolationMode): Color; + /** Blend with another color using a compositing mode. Returns new Color. */ + blend(target: string, opacity: number, mode: BlendMode): Color; + + // ── Format & Output ─────────────────────────────────── + /** Format the color as a string in the given format */ format(fmt: ColorFormat): string; /** Export as css, json, or text. Optional prefix for CSS variable names. */ @@ -83,7 +119,7 @@ export interface Color { // ── Color Space Types ────────────────────────────────────────────────── -export type InterpolationMode = 'oklch' | 'lab' | 'rgb'; +export type InterpolationMode = 'oklch' | 'lab' | 'rgb' | 'srgb'; export interface ColorSpaceOptions { interpolation?: InterpolationMode; @@ -171,6 +207,10 @@ export interface LinearColorSpaceFn { size: number; /** Export as css, json, or text. Optional prefix for variable names. */ output(format: RampaOutputFormat, prefix?: string): string; + /** Get a Color at a 0-based index. Returns a full Color with transforms. */ + at(index: number): Color; + /** Get all colors as Color objects. */ + colors(): Color[]; } /** @@ -192,8 +232,12 @@ export interface CubeColorSpaceResult { size: number; /** Export as css, json, or text. Optional prefix for variable names. */ output(format: RampaOutputFormat, prefix?: string): string; + /** Get a Color at 3D coordinates (0-based). Returns a full Color with transforms. */ + at(x: number, y: number, z: number): Color; + /** Get all colors as Color objects. */ + colors(): Color[]; /** Per-corner shortcut functions, keyed by constructor key names */ - [key: string]: ((index: number) => ColorAccessor) | string[] | number | ((query: Record) => ColorAccessor) | ((x: number, y: number, z: number) => ColorAccessor) | ((format: RampaOutputFormat, prefix?: string) => string); + [key: string]: ((index: number) => ColorAccessor) | string[] | number | ((query: Record) => ColorAccessor) | ((x: number, y: number, z: number) => ColorAccessor) | ((x: number, y: number, z: number) => Color) | ((format: RampaOutputFormat, prefix?: string) => string) | (() => Color[]); } /** @@ -209,6 +253,10 @@ export interface PlaneColorSpaceResult { size: number; /** Export as css, json, or text. Optional prefix for variable names. */ output(format: RampaOutputFormat, prefix?: string): string; + /** Get a Color at 2D coordinates (0-based). Returns a full Color with transforms. */ + at(saturation: number, lightness: number): Color; + /** Get all colors as Color objects. */ + colors(): Color[]; } // ── Contrast / Lint Types ────────────────────────────────────────────── diff --git a/sdk/tests/cli-parity.test.ts b/sdk/tests/cli-parity.test.ts index 5b61c32f..6b79e807 100644 --- a/sdk/tests/cli-parity.test.ts +++ b/sdk/tests/cli-parity.test.ts @@ -148,7 +148,7 @@ describe('SDK ↔ CLI parity', () => { // CLI JSON with --format hsl returns structured {hsl: {h,s,l}} objects. // SDK returns formatted hsl() strings. Compare by converting CLI structured to strings. const cliHslStrings = cliResult.ramps.map(r => - r.colors.map((c: any) => `hsl(${c.hsl.h}, ${c.hsl.s}%, ${c.hsl.l}%)`) + r.colors.map((c: any) => `hsl(${c.hsl.h}, ${Math.round(c.hsl.s * 100)}%, ${Math.round(c.hsl.l * 100)}%)`) ); const sdkColors = sdk.ramps.map(r => r.colors); @@ -172,7 +172,7 @@ describe('SDK ↔ CLI parity', () => { const sdk = rampa('#3b82f6').size(5).format('oklch'); const cliOklchStrings = cliResult.ramps.map(r => - r.colors.map((c: any) => `oklch(${c.oklch.l.toFixed(1)}% ${c.oklch.c.toFixed(3)} ${c.oklch.h})`) + r.colors.map((c: any) => `oklch(${(c.oklch.l * 100).toFixed(1)}% ${c.oklch.c.toFixed(3)} ${c.oklch.h})`) ); const sdkColors = sdk.ramps.map(r => r.colors); diff --git a/sdk/tests/color-transforms.test.ts b/sdk/tests/color-transforms.test.ts new file mode 100644 index 00000000..bc9a7ba2 --- /dev/null +++ b/sdk/tests/color-transforms.test.ts @@ -0,0 +1,214 @@ +import { describe, it, expect } from 'bun:test'; +import { color } from '../src/index'; + +describe('Color transforms', () => { + describe('lighten / darken', () => { + it('lighten increases OKLCH lightness', () => { + const c = color('#666666'); + const lighter = c.lighten(0.1); + expect(lighter.oklch.l).toBeGreaterThan(c.oklch.l); + }); + + it('darken decreases OKLCH lightness', () => { + const c = color('#666666'); + const darker = c.darken(0.1); + expect(darker.oklch.l).toBeLessThan(c.oklch.l); + }); + + it('darken is sugar for lighten(-delta)', () => { + const c = color('#ff6600'); + expect(c.darken(0.1).hex).toBe(c.lighten(-0.1).hex); + }); + + it('clamps lightness to [0, 1]', () => { + const white = color('#ffffff').lighten(0.5); + expect(white.oklch.l).toBeLessThanOrEqual(1); + + const black = color('#000000').darken(0.5); + expect(black.oklch.l).toBeGreaterThanOrEqual(0); + }); + + it('returns a new Color (immutable)', () => { + const c = color('#ff0000'); + const lighter = c.lighten(0.1); + expect(lighter.hex).not.toBe(c.hex); + expect(c.hex).toBe('#ff0000'); + }); + }); + + describe('saturate / desaturate', () => { + it('saturate increases OKLCH chroma in a meaningful way', () => { + const c = color('#996666'); + const saturated = c.saturate(0.05); + expect(saturated.oklch.c).toBeGreaterThan(c.oklch.c); + }); + + it('desaturate decreases OKLCH chroma', () => { + const c = color('#ff0000'); + const desaturated = c.desaturate(0.05); + expect(desaturated.oklch.c).toBeLessThan(c.oklch.c); + }); + + it('desaturate is sugar for saturate(-delta)', () => { + const c = color('#ff6600'); + expect(c.desaturate(0.05).hex).toBe(c.saturate(-0.05).hex); + }); + + it('clamps chroma to >= 0', () => { + const gray = color('#808080').desaturate(1); + expect(gray.oklch.c).toBeGreaterThanOrEqual(0); + }); + }); + + describe('rotate', () => { + it('rotates hue by degrees', () => { + const c = color('#ff0000'); + const rotated = c.rotate(120); + // Red (~29° in OKLCH) + 120° ≈ 149° — roughly green territory + expect(rotated.oklch.h).not.toBe(c.oklch.h); + }); + + it('handles negative rotation', () => { + const c = color('#ff0000'); + const rotated = c.rotate(-30); + expect(rotated.oklch.h).toBeDefined(); + }); + + it('wraps around 360°', () => { + const c = color('#ff0000'); + const full = c.rotate(360); + expect(full.oklch.h).toBeCloseTo(c.oklch.h, 0); + }); + }); + + describe('set', () => { + it('sets absolute lightness', () => { + const c = color('#ff0000').set({ lightness: 0.5 }); + expect(c.oklch.l).toBeCloseTo(0.5, 1); + }); + + it('sets absolute chroma', () => { + const c = color('#ff0000').set({ chroma: 0.1 }); + expect(c.oklch.c).toBeCloseTo(0.1, 2); + }); + + it('sets absolute hue', () => { + const c = color('#ff0000').set({ hue: 180 }); + expect(c.oklch.h).toBeCloseTo(180, 0); + }); + + it('sets multiple values at once', () => { + const c = color('#ff0000').set({ lightness: 0.5, chroma: 0.1, hue: 180 }); + expect(c.oklch.l).toBeCloseTo(0.5, 1); + expect(c.oklch.c).toBeCloseTo(0.1, 1); + expect(c.oklch.h).toBeCloseTo(180, 0); + }); + + it('clamps lightness to [0, 1]', () => { + const c = color('#ff0000').set({ lightness: 1.5 }); + expect(c.oklch.l).toBeLessThanOrEqual(1); + }); + }); + + describe('mix', () => { + it('mixes two colors at 50% in oklch', () => { + const c = color('#ff0000').mix('#0000ff', 0.5); + // Midpoint should differ from both endpoints + expect(c.hex).not.toBe('#ff0000'); + expect(c.hex).not.toBe('#0000ff'); + }); + + it('ratio 0 returns original color', () => { + const c = color('#ff0000').mix('#0000ff', 0); + // OKLCH round-trip may introduce tiny differences + expect(c.oklch.l).toBeCloseTo(color('#ff0000').oklch.l, 1); + }); + + it('ratio 1 returns target color', () => { + const c = color('#ff0000').mix('#0000ff', 1); + expect(c.oklch.l).toBeCloseTo(color('#0000ff').oklch.l, 1); + }); + + it('supports lab color space', () => { + const oklch = color('#ff0000').mix('#0000ff', 0.5, 'oklch'); + const lab = color('#ff0000').mix('#0000ff', 0.5, 'lab'); + // Different spaces produce different midpoints + expect(oklch.hex).not.toBe(lab.hex); + }); + + it('supports rgb color space', () => { + const c = color('#ff0000').mix('#0000ff', 0.5, 'rgb'); + expect(c.hex).toBeDefined(); + }); + }); + + describe('blend', () => { + it('applies multiply blend mode', () => { + const c = color('#ff8800').blend('#0088ff', 0.5, 'multiply'); + expect(c.hex).toBeDefined(); + expect(c.hex).not.toBe('#ff8800'); + }); + + it('applies screen blend mode', () => { + const c = color('#333333').blend('#ffffff', 0.5, 'screen'); + // Screen lightens + expect(c.oklch.l).toBeGreaterThan(color('#333333').oklch.l); + }); + + it('applies overlay blend mode', () => { + const c = color('#ff0000').blend('#00ff00', 0.5, 'overlay'); + expect(c.hex).toBeDefined(); + }); + }); + + describe('chaining', () => { + it('chains multiple transforms', () => { + const c = color('#66b172') + .lighten(0.1) + .desaturate(0.05) + .rotate(10); + expect(c.hex).toBeDefined(); + expect(typeof c.hex).toBe('string'); + }); + + it('chains transform with mix', () => { + const c = color('#ff0000') + .lighten(0.1) + .mix('#0000ff', 0.3); + expect(c.hex).toBeDefined(); + }); + + it('chains transform with blend', () => { + const c = color('#ff0000') + .darken(0.1) + .blend('#000000', 0.2, 'multiply'); + expect(c.hex).toBeDefined(); + }); + + it('bright variant pattern works', () => { + const base = color('#06ef48'); + const bright = base.lighten(0.1).desaturate(0.05); + expect(bright.oklch.l).toBeGreaterThan(base.oklch.l); + expect(bright.hex).not.toBe(base.hex); + }); + + it('result has all Color properties', () => { + const c = color('#ff0000').lighten(0.1); + expect(c.hex).toBeDefined(); + expect(c.rgb).toBeDefined(); + expect(c.hsl).toBeDefined(); + expect(c.oklch).toBeDefined(); + expect(c.luminance).toBeDefined(); + expect(typeof c.format).toBe('function'); + expect(typeof c.output).toBe('function'); + expect(typeof c.lighten).toBe('function'); + expect(typeof c.mix).toBe('function'); + expect(typeof c.blend).toBe('function'); + }); + + it('toString still returns hex after transforms', () => { + const c = color('#ff0000').lighten(0.1); + expect(`${c}`).toMatch(/^#[0-9a-f]{6}$/); + }); + }); +}); diff --git a/sdk/tests/palette.test.ts b/sdk/tests/palette.test.ts new file mode 100644 index 00000000..0c0421a8 --- /dev/null +++ b/sdk/tests/palette.test.ts @@ -0,0 +1,312 @@ +import { describe, it, expect } from 'bun:test'; +import { palette } from '../src/index'; +import { resolve } from 'path'; + +const TEST_PNG = resolve(__dirname, '../../tests/fixtures/test-palette.png'); +// Use a real JPEG from Downloads for JPEG decoding tests +const TEST_JPEG = '/Users/basiclines/Downloads/IMG_6588.jpeg'; + +describe('palette()', () => { + describe('PNG decoding', () => { + it('loads a PNG file', async () => { + const p = await palette(TEST_PNG); + expect(p).toBeDefined(); + }); + + it('detects dominant colors from simple image', async () => { + const p = await palette(TEST_PNG); + const dom = p.dominant({ count: 3 }); + expect(dom.length).toBe(3); + + // Red should be most dominant (60% of pixels) + const hexes = dom.map(d => d.color.hex); + expect(hexes[0]).toBe('#ff0000'); + }); + + it('frequencies sum to ~1', async () => { + const p = await palette(TEST_PNG); + const dom = p.dominant({ count: 3 }); + const total = dom.reduce((s, d) => s + d.frequency, 0); + expect(total).toBeCloseTo(1, 1); + }); + + it('frequency order matches expected ratios', async () => { + const p = await palette(TEST_PNG); + const dom = p.dominant({ count: 3 }); + // Red=60%, Blue=30%, Green=10% + expect(dom[0].frequency).toBeGreaterThan(dom[1].frequency); + expect(dom[1].frequency).toBeGreaterThan(dom[2].frequency); + }); + }); + + describe('JPEG decoding', () => { + it('loads a JPEG file', async () => { + const p = await palette(TEST_JPEG); + expect(p).toBeDefined(); + }); + + it('returns dominant colors', async () => { + const p = await palette(TEST_JPEG); + const dom = p.dominant(); + expect(dom.length).toBeGreaterThan(0); + expect(dom.length).toBeLessThanOrEqual(10); // may merge close clusters + expect(dom[0].frequency).toBeGreaterThan(0); + }); + }); + + describe('.at()', () => { + it('returns the Nth dominant color (0-based)', async () => { + const p = await palette(TEST_PNG); + const first = p.at(0); + const dom = p.dominant(); + expect(first.color.hex).toBe(dom[0].color.hex); + expect(first.frequency).toBe(dom[0].frequency); + }); + + it('throws RangeError for out-of-bounds index', async () => { + const p = await palette(TEST_PNG); + expect(() => p.at(100)).toThrow(RangeError); + expect(() => p.at(-1)).toThrow(RangeError); + }); + + it('returns Color with transform methods', async () => { + const p = await palette(TEST_PNG); + const lightened = p.at(0).color.lighten(0.1); + expect(lightened.hex).toBeDefined(); + expect(lightened.hex).not.toBe(p.at(0).color.hex); + }); + }); + + describe('.raw()', () => { + it('returns all unique colors', async () => { + const p = await palette(TEST_PNG); + const raw = p.raw(); + expect(raw.length).toBeGreaterThan(0); + expect(raw.length).toBeLessThanOrEqual(1000); + }); + + it('respects tolerance option', async () => { + const p = await palette(TEST_JPEG); + const tight = p.raw({ tolerance: 1 }); + const loose = p.raw({ tolerance: 10 }); + expect(tight.length).toBeGreaterThanOrEqual(loose.length); + }); + + it('respects maxColors option', async () => { + const p = await palette(TEST_JPEG); + const limited = p.raw({ maxColors: 5 }); + expect(limited.length).toBeLessThanOrEqual(5); + }); + }); + + describe('.ansi()', () => { + it('returns all 8 ANSI categories', async () => { + const p = await palette(TEST_PNG); + const ansi = p.ansi(); + const keys = Object.keys(ansi); + expect(keys).toContain('red'); + expect(keys).toContain('green'); + expect(keys).toContain('blue'); + expect(keys).toContain('yellow'); + expect(keys).toContain('magenta'); + expect(keys).toContain('cyan'); + expect(keys).toContain('black'); + expect(keys).toContain('white'); + }); + + it('classifies pure red as red', async () => { + const p = await palette(TEST_PNG); + const ansi = p.ansi(); + expect(ansi.red.length).toBeGreaterThan(0); + expect(ansi.red[0].color.hex).toBe('#ff0000'); + }); + + it('respects count option', async () => { + const p = await palette(TEST_JPEG); + const ansi = p.ansi({ count: 2 }); + for (const entries of Object.values(ansi)) { + expect(entries.length).toBeLessThanOrEqual(2); + } + }); + }); + + describe('.average()', () => { + it('returns a Color', async () => { + const p = await palette(TEST_PNG); + const avg = p.average(); + expect(avg.hex).toBeDefined(); + expect(avg.oklch).toBeDefined(); + }); + }); + + describe('.temperature()', () => { + it('returns warm, cool, or neutral', async () => { + const p = await palette(TEST_PNG); + const temp = p.temperature(); + expect(['warm', 'cool', 'neutral']).toContain(temp); + }); + }); + + describe('.output()', () => { + it('generates JSON output', async () => { + const p = await palette(TEST_PNG); + const json = p.output('json'); + const parsed = JSON.parse(json); + expect(parsed.dominant).toBeDefined(); + expect(parsed.average).toBeDefined(); + expect(parsed.temperature).toBeDefined(); + expect(parsed.ansi).toBeDefined(); + }); + + it('generates CSS output', async () => { + const p = await palette(TEST_PNG); + const css = p.output('css', 'test'); + expect(css).toContain(':root {'); + expect(css).toContain('--test-1:'); + expect(css).toContain('--test-avg:'); + }); + + it('generates text output', async () => { + const p = await palette(TEST_PNG); + const text = p.output('text'); + expect(text).toContain('Dominant colors:'); + expect(text).toContain('Average:'); + expect(text).toContain('Temperature:'); + }); + }); + + describe('PaletteEntry shape', () => { + it('has color and frequency properties', async () => { + const p = await palette(TEST_PNG); + const entry = p.at(0); + expect(entry).toHaveProperty('color'); + expect(entry).toHaveProperty('frequency'); + expect(typeof entry.frequency).toBe('number'); + expect(entry.frequency).toBeGreaterThan(0); + expect(entry.frequency).toBeLessThanOrEqual(1); + expect(entry.color.hex).toBeDefined(); + expect(entry.color.oklch).toBeDefined(); + }); + }); + + describe('.sortBy()', () => { + it('sorts dominant by lightness ascending', async () => { + const p = await palette(TEST_PNG); + const sorted = p.dominant().sortBy('L'); + for (let i = 1; i < sorted.length; i++) { + expect(sorted[i].color.oklch.l).toBeGreaterThanOrEqual(sorted[i - 1].color.oklch.l); + } + }); + + it('sorts dominant by chroma ascending', async () => { + const p = await palette(TEST_PNG); + const sorted = p.dominant().sortBy('C'); + for (let i = 1; i < sorted.length; i++) { + expect(sorted[i].color.oklch.c).toBeGreaterThanOrEqual(sorted[i - 1].color.oklch.c); + } + }); + + it('sorts dominant by hue ascending', async () => { + const p = await palette(TEST_PNG); + const sorted = p.dominant().sortBy('H'); + for (let i = 1; i < sorted.length; i++) { + expect(sorted[i].color.oklch.h).toBeGreaterThanOrEqual(sorted[i - 1].color.oklch.h); + } + }); + + it('returns a new array (does not mutate)', async () => { + const p = await palette(TEST_PNG); + const original = p.dominant(); + const sorted = original.sortBy('L'); + expect(sorted).not.toBe(original); + expect(sorted.length).toBe(original.length); + }); + + it('sortBy is chainable', async () => { + const p = await palette(TEST_PNG); + const sorted = p.dominant().sortBy('L').sortBy('C'); + expect(sorted.length).toBeGreaterThan(0); + }); + + it('sorts group buckets internally by L', async () => { + const p = await palette(TEST_JPEG); + const grouped = p.group({ by: 'C' }).sortBy('L'); + for (const [, entries] of Object.entries(grouped)) { + for (let i = 1; i < entries.length; i++) { + expect(entries[i].color.oklch.l).toBeGreaterThanOrEqual(entries[i - 1].color.oklch.l); + } + } + }); + + it('sorts ansi buckets internally', async () => { + const p = await palette(TEST_PNG); + const ansi = p.ansi().sortBy('L'); + for (const [, entries] of Object.entries(ansi)) { + for (let i = 1; i < entries.length; i++) { + expect(entries[i].color.oklch.l).toBeGreaterThanOrEqual(entries[i - 1].color.oklch.l); + } + } + }); + }); + + describe('.group()', () => { + it('groups by lightness with default buckets', async () => { + const p = await palette(TEST_PNG); + const grouped = p.group({ by: 'L' }); + const keys = Object.keys(grouped); + expect(keys).toEqual(['darkest', 'dark', 'mid', 'light', 'lightest']); + }); + + it('groups by chroma with default buckets', async () => { + const p = await palette(TEST_PNG); + const grouped = p.group({ by: 'C' }); + const keys = Object.keys(grouped); + expect(keys).toEqual(['gray', 'muted', 'saturated', 'vivid']); + }); + + it('groups by hue with default buckets', async () => { + const p = await palette(TEST_PNG); + const grouped = p.group({ by: 'H' }); + const keys = Object.keys(grouped); + expect(keys).toEqual(['red', 'orange', 'yellow', 'green', 'cyan', 'blue', 'purple', 'pink']); + }); + + it('respects count per bucket', async () => { + const p = await palette(TEST_JPEG); + const grouped = p.group({ by: 'L', count: 2 }); + for (const entries of Object.values(grouped)) { + expect(entries.length).toBeLessThanOrEqual(2); + } + }); + + it('respects tolerance for dedup', async () => { + const p = await palette(TEST_JPEG); + const tight = p.group({ by: 'L', tolerance: 2, count: 20 }); + const wide = p.group({ by: 'L', tolerance: 10, count: 20 }); + const tightTotal = Object.values(tight).reduce((s, e) => s + e.length, 0); + const wideTotal = Object.values(wide).reduce((s, e) => s + e.length, 0); + expect(tightTotal).toBeGreaterThanOrEqual(wideTotal); + }); + + it('result has sortBy method', async () => { + const p = await palette(TEST_PNG); + const grouped = p.group({ by: 'C' }); + expect(typeof grouped.sortBy).toBe('function'); + }); + }); + + describe('k-means++ clustering', () => { + it('post-merges close clusters with tolerance', async () => { + const p = await palette(TEST_JPEG); + const loose = p.dominant({ count: 10, tolerance: 15 }); + const tight = p.dominant({ count: 10, tolerance: 2 }); + expect(loose.length).toBeLessThanOrEqual(tight.length); + }); + + it('dominant result has sortBy method', async () => { + const p = await palette(TEST_PNG); + const dom = p.dominant(); + expect(typeof dom.sortBy).toBe('function'); + }); + }); +}); diff --git a/sdk/tests/ramp-introspection.test.ts b/sdk/tests/ramp-introspection.test.ts new file mode 100644 index 00000000..aecb7c3b --- /dev/null +++ b/sdk/tests/ramp-introspection.test.ts @@ -0,0 +1,135 @@ +import { describe, it, expect } from 'bun:test'; +import { LinearColorSpace, PlaneColorSpace, CubeColorSpace } from '../src/index'; + +describe('Ramp introspection', () => { + describe('LinearColorSpace', () => { + const ramp = new LinearColorSpace('#000000', '#ffffff').size(12); + + it('.at(n) returns a Color object', () => { + const c = ramp.at(0); + expect(c.hex).toBeDefined(); + expect(c.oklch).toBeDefined(); + expect(c.hsl).toBeDefined(); + expect(c.rgb).toBeDefined(); + expect(typeof c.lighten).toBe('function'); + }); + + it('.at(n) is 0-based', () => { + const first = ramp.at(0); + const last = ramp.at(11); + expect(first.oklch.l).toBeLessThan(last.oklch.l); + }); + + it('.at(n) clamps to valid range', () => { + const underflow = ramp.at(-5); + const overflow = ramp.at(100); + expect(underflow.hex).toBe(ramp.at(0).hex); + expect(overflow.hex).toBe(ramp.at(11).hex); + }); + + it('.colors() returns Color[]', () => { + const colors = ramp.colors(); + expect(colors).toHaveLength(12); + expect(colors[0].hex).toBeDefined(); + expect(typeof colors[0].lighten).toBe('function'); + }); + + it('.colors() matches .palette', () => { + const colors = ramp.colors(); + expect(colors.map(c => c.hex)).toEqual(ramp.palette); + }); + + it('Color from .at() has oklch components', () => { + const c = ramp.at(6); + expect(typeof c.oklch.l).toBe('number'); + expect(typeof c.oklch.c).toBe('number'); + expect(typeof c.oklch.h).toBe('number'); + }); + + it('Color from .at() supports transforms', () => { + const c = ramp.at(3); + const lighter = c.lighten(0.1); + expect(lighter.oklch.l).toBeGreaterThan(c.oklch.l); + expect(lighter.hex).not.toBe(c.hex); + }); + + it('transforms on .at() do not mutate the ramp', () => { + const before = ramp.at(3).hex; + ramp.at(3).lighten(0.1); + expect(ramp.at(3).hex).toBe(before); + }); + + it('.colors() enables chroma curve extraction', () => { + const chromaValues = ramp.colors().map(c => c.oklch.c); + expect(chromaValues).toHaveLength(12); + chromaValues.forEach(v => expect(typeof v).toBe('number')); + }); + }); + + describe('PlaneColorSpace', () => { + const plane = new PlaneColorSpace('#1e1e2e', '#cdd6f4', '#f38ba8').size(6); + + it('.at(sat, lgt) returns a Color object', () => { + const c = plane.at(3, 5); + expect(c.hex).toBeDefined(); + expect(c.oklch).toBeDefined(); + expect(typeof c.lighten).toBe('function'); + }); + + it('.at() clamps to valid range', () => { + const c = plane.at(-1, 100); + expect(c.hex).toBeDefined(); + }); + + it('.colors() returns Color[] of size²', () => { + const colors = plane.colors(); + expect(colors).toHaveLength(36); + }); + + it('.colors() matches .palette', () => { + const colors = plane.colors(); + expect(colors.map(c => c.hex)).toEqual(plane.palette); + }); + + it('Color from .at() supports transforms', () => { + const c = plane.at(3, 5); + const rotated = c.rotate(90); + expect(rotated.hex).not.toBe(c.hex); + }); + }); + + describe('CubeColorSpace', () => { + const cube = new CubeColorSpace({ + k: '#1e1e2e', r: '#f38ba8', g: '#a6e3a1', b: '#89b4fa', + y: '#f9e2af', m: '#cba6f7', c: '#94e2d5', w: '#cdd6f4', + }).size(4); + + it('.at(x, y, z) returns a Color object', () => { + const c = cube.at(2, 3, 1); + expect(c.hex).toBeDefined(); + expect(c.oklch).toBeDefined(); + expect(typeof c.lighten).toBe('function'); + }); + + it('.at() clamps to valid range', () => { + const c = cube.at(-1, 100, 2); + expect(c.hex).toBeDefined(); + }); + + it('.colors() returns Color[] of size³', () => { + const colors = cube.colors(); + expect(colors).toHaveLength(64); + }); + + it('.colors() matches .palette', () => { + const colors = cube.colors(); + expect(colors.map(c => c.hex)).toEqual(cube.palette); + }); + + it('Color from .at() supports transforms', () => { + const c = cube.at(1, 1, 1); + const desaturated = c.desaturate(0.05); + expect(desaturated.oklch.c).toBeLessThan(c.oklch.c); + }); + }); +}); diff --git a/sdk/tests/sdk.test.ts b/sdk/tests/sdk.test.ts index e73ec64a..61a5186f 100644 --- a/sdk/tests/sdk.test.ts +++ b/sdk/tests/sdk.test.ts @@ -202,7 +202,7 @@ describe('color()', () => { const c = color('#fe0000'); expect(c.hex).toBe('#fe0000'); expect(c.rgb).toEqual({ r: 254, g: 0, b: 0 }); - expect(c.hsl).toEqual({ h: 0, s: 100, l: 50 }); + expect(c.hsl).toEqual({ h: 0, s: 1, l: 0.5 }); expect(c.oklch).toHaveProperty('l'); expect(c.oklch).toHaveProperty('c'); expect(c.oklch).toHaveProperty('h'); @@ -234,7 +234,7 @@ describe('color()', () => { const json = JSON.parse(c.output('json')); expect(json.hex).toBe('#fe0000'); expect(json.rgb).toEqual({ r: 254, g: 0, b: 0 }); - expect(json.hsl).toEqual({ h: 0, s: 100, l: 50 }); + expect(json.hsl).toEqual({ h: 0, s: 1, l: 0.5 }); expect(json.oklch).toHaveProperty('l'); }); diff --git a/site/index.html b/site/index.html index dad4dc56..6587f56c 100644 --- a/site/index.html +++ b/site/index.html @@ -1106,6 +1106,10 @@

Color spaces
Linear, plane, and cube interpolation
+ +
diff --git a/site/js/demos.js b/site/js/demos.js index f2e15f5f..865d8d18 100644 --- a/site/js/demos.js +++ b/site/js/demos.js @@ -38,11 +38,13 @@ harmony: { title: 'Harmonies', run: runHarmony }, contrast: { title: 'Contrast lint', run: runContrast }, colorspace: { title: 'Color space', run: runColorspace }, + 'cli-transforms': { title: 'Color transforms', run: runCliTransforms }, // SDK demos 'sdk-ramp': { title: 'Builder API', run: runSdkRamp }, 'sdk-linear': { title: 'Linear space', run: runSdkLinear }, 'sdk-plane': { title: 'Plane space', run: runSdkPlane }, 'sdk-contrast': { title: 'Contrast', run: runSdkContrast }, + 'sdk-transforms': { title: 'Color transforms', run: runSdkTransforms }, }; // Wire up nav buttons + intersection observer BEFORE hero animation @@ -264,6 +266,71 @@ tt.cursor(); } + async function runCliTransforms(tt) { + await tt.line([dim('$ '), cmd('rampa'), dim(' color '), val("'#66b172'"), dim(' '), flag('--lighten'), dim(' '), num('0.1'), dim(' '), flag('--desaturate'), dim(' '), num('0.05')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line([comment('# Bright variant — no hand-written converters')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('hex '), val('#8cd69a')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('oklch '), val('oklch(81.2% 0.103 150)')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line('', { instant: true }); + await tt.line([dim('$ '), cmd('rampa'), dim(' color '), val("'#f85149'"), dim(' '), flag('--set-lightness'), dim(' '), num('0.48'), dim(' '), flag('--set-chroma'), dim(' '), num('0.15')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line([comment('# Absolute OKLCH positioning')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('hex '), val('#c73d51')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line('', { instant: true }); + await tt.line([dim('$ '), cmd('rampa'), dim(' color '), val("'#ff0000'"), dim(' '), flag('--mix'), dim(' '), val("'#0000ff'"), dim(' '), flag('--ratio'), dim(' '), num('0.5'), dim(' '), flag('--space'), dim(' '), val('lab')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line([comment('# color-mix in lab space')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('hex '), val('#c10078')], { instant: true }); + tt.cursor(); + } + + async function runSdkTransforms(tt) { + await tt.line([kw('import'), dim(' { '), val('color'), dim(', '), val('LinearColorSpace'), dim(' } '), kw('from'), val(' "@basiclines/rampa-sdk"')], { instant: true }); + await tt.wait(TICK); + await tt.line('', { instant: true }); + await tt.line([comment('// OKLCH transforms — all return new Color')], { instant: true }); + await tt.wait(TICK); + await tt.line([kw('const'), dim(' c = '), cmd('color'), dim('('), val('"#66b172"'), dim(')')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('c.'), prop('lighten'), dim('('), num('0.1'), dim(').'), prop('desaturate'), dim('('), num('0.05'), dim(').'), prop('hex')], { instant: true }); + await tt.wait(TICK); + await tt.line([comment('// → "#8cd69a" bright variant, no throwaway converters')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line([comment('// Mix — like CSS color-mix()')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('c.'), prop('mix'), dim('('), val('"#0000ff"'), dim(', '), num('0.5'), dim(', '), val('"lab"'), dim(')'), dim('.'), prop('hex')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line([comment('// Set absolute OKLCH values')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('c.'), prop('set'), dim('({ '), prop('lightness'), dim(': '), num('0.48'), dim(', '), prop('chroma'), dim(': '), num('0.15'), dim(' })'), dim('.'), prop('hex')], { instant: true }); + await tt.wait(300); + await tt.line('', { instant: true }); + await tt.line([comment('// Ramp introspection — .at() returns Color')], { instant: true }); + await tt.wait(TICK); + await tt.line([kw('const'), dim(' ramp = '), kw('new'), cmd(' LinearColorSpace'), dim('('), val('"#000"'), dim(', '), val('"#fff"'), dim(')'), dim('.'), prop('size'), dim('('), num('12'), dim(')')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('ramp.'), prop('at'), dim('('), num('3'), dim(').'), prop('oklch'), dim('.'), prop('c'), dim(' '), comment('// chroma at step 3')], { instant: true }); + await tt.wait(TICK); + await tt.line([dim('ramp.'), prop('colors'), dim('().'), prop('map'), dim('('), val('c'), dim(' => c.'), prop('oklch'), dim('.'), prop('l'), dim(')')], { instant: true }); + await tt.wait(TICK); + await tt.line([comment('// → [0, 0.09, 0.18, ... 1] lightness curve')], { instant: true }); + tt.cursor(); + } + // --- Tab switching --- function switchTab(tab) { if (activeTab === tab) return; diff --git a/site/js/rampa-sdk.min.js b/site/js/rampa-sdk.min.js index 83f90ba0..fae26e0a 100644 --- a/site/js/rampa-sdk.min.js +++ b/site/js/rampa-sdk.min.js @@ -1,14 +1,14 @@ -(()=>{var{min:z8,max:O8}=Math,J0=(f,$=0,Q=1)=>{return z8(O8($,f),Q)};var g0=(f)=>{f._clipped=!1,f._unclipped=f.slice(0);for(let $=0;$<=3;$++)if($<3){if(f[$]<0||f[$]>255)f._clipped=!0;f[$]=J0(f[$],0,255)}else if($===3)f[$]=J0(f[$],0,1);return f};var H2={};for(let f of["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"])H2[`[object ${f}]`]=f.toLowerCase();function T(f){return H2[Object.prototype.toString.call(f)]||"object"}var O=(f,$=null)=>{if(f.length>=3)return Array.prototype.slice.call(f);if(T(f[0])=="object"&&$)return $.split("").filter((Q)=>f[0][Q]!==void 0).map((Q)=>f[0][Q]);return f[0].slice(0)};var Q0=(f)=>{if(f.length<2)return null;let $=f.length-1;if(T(f[$])=="string")return f[$].toLowerCase();return null};var{PI:Tf,min:vf,max:Lf}=Math,l=(f)=>Math.round(f*100)/100,Ef=(f)=>Math.round(f*100)/100,N0=Tf*2,jf=Tf/3,S2=Tf/180,p2=180/Tf;function Rf(f){return[...f.slice(0,3).reverse(),...f.slice(3)]}var j={format:{},autodetect:[]};class M2{constructor(...f){let $=this;if(T(f[0])==="object"&&f[0].constructor&&f[0].constructor===this.constructor)return f[0];let Q=Q0(f),U=!1;if(!Q){if(U=!0,!j.sorted)j.autodetect=j.autodetect.sort((J,N)=>N.p-J.p),j.sorted=!0;for(let J of j.autodetect)if(Q=J.test(...f),Q)break}if(j.format[Q]){let J=j.format[Q].apply(null,U?f:f.slice(0,-1));$._rgb=g0(J)}else throw Error("unknown format: "+f);if($._rgb.length===3)$._rgb.push(1)}toString(){if(T(this.hex)=="function")return this.hex();return`[${this._rgb.join(",")}]`}}var W=M2;var P2="3.2.0";var T2=(...f)=>{return new W(...f)};T2.version=P2;var _=T2;var H8={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},v0=H8;var S8=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,p8=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,M8=(f)=>{if(f.match(S8)){if(f.length===4||f.length===7)f=f.substr(1);if(f.length===3)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2];let $=parseInt(f,16),Q=$>>16,U=$>>8&255,J=$&255;return[Q,U,J,1]}if(f.match(p8)){if(f.length===5||f.length===9)f=f.substr(1);if(f.length===4)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2]+f[3]+f[3];let $=parseInt(f,16),Q=$>>24&255,U=$>>16&255,J=$>>8&255,N=Math.round(($&255)/255*100)/100;return[Q,U,J,N]}throw Error(`unknown hex color: ${f}`)},Af=M8;var{round:mf}=Math,P8=(...f)=>{let[$,Q,U,J]=O(f,"rgba"),N=Q0(f)||"auto";if(J===void 0)J=1;if(N==="auto")N=J<1?"rgba":"rgb";$=mf($),Q=mf(Q),U=mf(U);let Z="000000"+($<<16|Q<<8|U).toString(16);Z=Z.substr(Z.length-6);let D="0"+mf(J*255).toString(16);switch(D=D.substr(D.length-2),N.toLowerCase()){case"rgba":return`#${Z}${D}`;case"argb":return`#${D}${Z}`;default:return`#${Z}`}},_f=P8;W.prototype.name=function(){let f=_f(this._rgb,"rgb");for(let $ of Object.keys(v0))if(v0[$]===f)return $.toLowerCase();return f};j.format.named=(f)=>{if(f=f.toLowerCase(),v0[f])return Af(v0[f]);throw Error("unknown color name: "+f)};j.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&T(f)==="string"&&v0[f.toLowerCase()])return"named"}});W.prototype.alpha=function(f,$=!1){if(f!==void 0&&T(f)==="number"){if($)return this._rgb[3]=f,this;return new W([this._rgb[0],this._rgb[1],this._rgb[2],f],"rgb")}return this._rgb[3]};W.prototype.clipped=function(){return this._rgb._clipped||!1};var kf={Kn:18,labWhitePoint:"d65",Xn:0.95047,Yn:1,Zn:1.08883,t0:0.137931034,t1:0.206896552,t2:0.12841855,t3:0.008856452,kE:0.008856451679035631,kKE:8,kK:903.2962962962963,RefWhiteRGB:{X:0.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:0.4124564390896922,m01:0.21267285140562253,m02:0.0193338955823293,m10:0.357576077643909,m11:0.715152155287818,m12:0.11919202588130297,m20:0.18043748326639894,m21:0.07217499330655958,m22:0.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-0.9692660305051868,m02:0.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-0.2040259135167538,m20:-0.498531409556016,m21:0.041556017530349834,m22:1.0572251882231791},As:0.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:0.8951,m01:-0.7502,m02:0.0389,m10:0.2664,m11:1.7135,m12:-0.0685,m20:-0.1614,m21:0.0367,m22:1.0296},MtxAdaptMaI:{m00:0.9869929054667123,m01:0.43230526972339456,m02:-0.008528664575177328,m10:-0.14705425642099013,m11:0.5183602715367776,m12:0.04004282165408487,m20:0.15996265166373125,m21:0.0492912282128556,m22:0.9684866957875502}},E0=kf,T8=new Map([["a",[1.0985,0.35585]],["b",[1.0985,0.35585]],["c",[0.98074,1.18232]],["d50",[0.96422,0.82521]],["d55",[0.95682,0.92149]],["d65",[0.95047,1.08883]],["e",[1,1,1]],["f2",[0.99186,0.67393]],["f7",[0.95041,1.08747]],["f11",[1.00962,0.6435]],["icc",[0.96422,0.82521]]]);function q0(f){let $=T8.get(String(f).toLowerCase());if(!$)throw Error("unknown Lab illuminant "+f);kf.labWhitePoint=f,kf.Xn=$[0],kf.Zn=$[1]}function L0(){return kf.labWhitePoint}var v8=(...f)=>{f=O(f,"lab");let[$,Q,U]=f,[J,N,q]=L8($,Q,U),[Z,D,X]=M1(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},L8=(f,$,Q)=>{let{kE:U,kK:J,kKE:N,Xn:q,Yn:Z,Zn:D}=E0,X=(f+16)/116,K=0.002*$+X,F=X-0.005*Q,V=K*K*K,G=F*F*F,B=V>U?V:(116*K-16)/J,S=f>N?Math.pow((f+16)/116,3):f/J,u=G>U?G:(116*F-16)/J,w=B*q,m=S*Z,L=u*D;return[w,m,L]},p1=(f)=>{let $=Math.sign(f);return f=Math.abs(f),(f<=0.0031308?f*12.92:1.055*Math.pow(f,0.4166666666666667)-0.055)*$},M1=(f,$,Q)=>{let{MtxAdaptMa:U,MtxAdaptMaI:J,MtxXYZ2RGB:N,RefWhiteRGB:q,Xn:Z,Yn:D,Zn:X}=E0,K=Z*U.m00+D*U.m10+X*U.m20,F=Z*U.m01+D*U.m11+X*U.m21,V=Z*U.m02+D*U.m12+X*U.m22,G=q.X*U.m00+q.Y*U.m10+q.Z*U.m20,B=q.X*U.m01+q.Y*U.m11+q.Z*U.m21,S=q.X*U.m02+q.Y*U.m12+q.Z*U.m22,u=(f*U.m00+$*U.m10+Q*U.m20)*(G/K),w=(f*U.m01+$*U.m11+Q*U.m21)*(B/F),m=(f*U.m02+$*U.m12+Q*U.m22)*(S/V),L=u*J.m00+w*J.m10+m*J.m20,p=u*J.m01+w*J.m11+m*J.m21,n=u*J.m02+w*J.m12+m*J.m22,A=p1(L*N.m00+p*N.m10+n*N.m20),I=p1(L*N.m01+p*N.m11+n*N.m21),y=p1(L*N.m02+p*N.m12+n*N.m22);return[A*255,I*255,y*255]},l0=v8;var j8=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),[N,q,Z]=T1($,Q,U),[D,X,K]=R8(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function R8(f,$,Q){let{Xn:U,Yn:J,Zn:N,kE:q,kK:Z}=E0,D=f/U,X=$/J,K=Q/N,F=D>q?Math.pow(D,0.3333333333333333):(Z*D+16)/116,V=X>q?Math.pow(X,0.3333333333333333):(Z*X+16)/116,G=K>q?Math.pow(K,0.3333333333333333):(Z*K+16)/116;return[116*V-16,500*(F-V),200*(V-G)]}function P1(f){let $=Math.sign(f);return f=Math.abs(f),(f<=0.04045?f/12.92:Math.pow((f+0.055)/1.055,2.4))*$}var T1=(f,$,Q)=>{f=P1(f/255),$=P1($/255),Q=P1(Q/255);let{MtxRGB2XYZ:U,MtxAdaptMa:J,MtxAdaptMaI:N,Xn:q,Yn:Z,Zn:D,As:X,Bs:K,Cs:F}=E0,V=f*U.m00+$*U.m10+Q*U.m20,G=f*U.m01+$*U.m11+Q*U.m21,B=f*U.m02+$*U.m12+Q*U.m22,S=q*J.m00+Z*J.m10+D*J.m20,u=q*J.m01+Z*J.m11+D*J.m21,w=q*J.m02+Z*J.m12+D*J.m22,m=V*J.m00+G*J.m10+B*J.m20,L=V*J.m01+G*J.m11+B*J.m21,p=V*J.m02+G*J.m12+B*J.m22;return m*=S/X,L*=u/K,p*=w/F,V=m*N.m00+L*N.m10+p*N.m20,G=m*N.m01+L*N.m11+p*N.m21,B=m*N.m02+L*N.m12+p*N.m22,[V,G,B]},a0=j8;W.prototype.lab=function(){return a0(this._rgb)};var A8=(...f)=>new W(...f,"lab");Object.assign(_,{lab:A8,getLabWhitePoint:L0,setLabWhitePoint:q0});j.format.lab=l0;j.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"lab"),T(f)==="array"&&f.length===3)return"lab"}});W.prototype.darken=function(f=1){let $=this,Q=$.lab();return Q[0]-=E0.Kn*f,new W(Q,"lab").alpha($.alpha(),!0)};W.prototype.brighten=function(f=1){return this.darken(-f)};W.prototype.darker=W.prototype.darken;W.prototype.brighter=W.prototype.brighten;W.prototype.get=function(f){let[$,Q]=f.split("."),U=this[$]();if(Q){let J=$.indexOf(Q)-($.substr(0,2)==="ok"?2:0);if(J>-1)return U[J];throw Error(`unknown channel ${Q} in mode ${$}`)}else return U};var{pow:m8}=Math,_8=0.0000001,C8=20;W.prototype.luminance=function(f,$="rgb"){if(f!==void 0&&T(f)==="number"){if(f===0)return new W([0,0,0,this._rgb[3]],"rgb");if(f===1)return new W([255,255,255,this._rgb[3]],"rgb");let Q=this.luminance(),U=C8,J=(q,Z)=>{let D=q.interpolate(Z,0.5,$),X=D.luminance();if(Math.abs(f-X)<_8||!U--)return D;return X>f?J(q,D):J(D,Z)},N=(Q>f?J(new W([0,0,0]),this):J(this,new W([255,255,255]))).rgb();return new W([...N,this._rgb[3]])}return n8(...this._rgb.slice(0,3))};var n8=(f,$,Q)=>{return f=v1(f),$=v1($),Q=v1(Q),0.2126*f+0.7152*$+0.0722*Q},v1=(f)=>{return f/=255,f<=0.03928?f/12.92:m8((f+0.055)/1.055,2.4)};var d={};var k0=(f,$,Q=0.5,...U)=>{let J=U[0]||"lrgb";if(!d[J]&&!U.length)J=Object.keys(d)[0];if(!d[J])throw Error(`interpolation mode ${J} is not defined`);if(T(f)!=="object")f=new W(f);if(T($)!=="object")$=new W($);return d[J](f,$,Q).alpha(f.alpha()+Q*($.alpha()-f.alpha()))};W.prototype.mix=W.prototype.interpolate=function(f,$=0.5,...Q){return k0(this,f,$,...Q)};W.prototype.premultiply=function(f=!1){let $=this._rgb,Q=$[3];if(f)return this._rgb=[$[0]*Q,$[1]*Q,$[2]*Q,Q],this;else return new W([$[0]*Q,$[1]*Q,$[2]*Q,Q],"rgb")};var{sin:t8,cos:d8}=Math,x8=(...f)=>{let[$,Q,U]=O(f,"lch");if(isNaN(U))U=0;return U=U*S2,[$,d8(U)*Q,t8(U)*Q]},Cf=x8;var h8=(...f)=>{f=O(f,"lch");let[$,Q,U]=f,[J,N,q]=Cf($,Q,U),[Z,D,X]=l0(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},s0=h8;var b8=(...f)=>{let $=Rf(O(f,"hcl"));return s0(...$)},v2=b8;var{sqrt:r8,atan2:g8,round:i8}=Math,c8=(...f)=>{let[$,Q,U]=O(f,"lab"),J=r8(Q*Q+U*U),N=(g8(U,Q)*p2+360)%360;if(i8(J*1e4)===0)N=Number.NaN;return[$,J,N]},nf=c8;var o8=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),[N,q,Z]=a0($,Q,U),[D,X,K]=nf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},zf=o8;W.prototype.lch=function(){return zf(this._rgb)};W.prototype.hcl=function(){return Rf(zf(this._rgb))};var e8=(...f)=>new W(...f,"lch"),l8=(...f)=>new W(...f,"hcl");Object.assign(_,{lch:e8,hcl:l8});j.format.lch=s0;j.format.hcl=v2;["lch","hcl"].forEach((f)=>j.autodetect.push({p:2,test:(...$)=>{if($=O($,f),T($)==="array"&&$.length===3)return f}}));W.prototype.saturate=function(f=1){let $=this,Q=$.lch();if(Q[1]+=E0.Kn*f,Q[1]<0)Q[1]=0;return new W(Q,"lch").alpha($.alpha(),!0)};W.prototype.desaturate=function(f=1){return this.saturate(-f)};W.prototype.set=function(f,$,Q=!1){let[U,J]=f.split("."),N=this[U]();if(J){let q=U.indexOf(J)-(U.substr(0,2)==="ok"?2:0);if(q>-1){if(T($)=="string")switch($.charAt(0)){case"+":N[q]+=+$;break;case"-":N[q]+=+$;break;case"*":N[q]*=+$.substr(1);break;case"/":N[q]/=+$.substr(1);break;default:N[q]=+$}else if(T($)==="number")N[q]=$;else throw Error("unsupported value for Color.set");let Z=new W(N,U);if(Q)return this._rgb=Z._rgb,this;return Z}throw Error(`unknown channel ${J} in mode ${U}`)}else return N};W.prototype.tint=function(f=0.5,...$){return k0(this,"white",f,...$)};W.prototype.shade=function(f=0.5,...$){return k0(this,"black",f,...$)};var a8=(f,$,Q)=>{let U=f._rgb,J=$._rgb;return new W(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"rgb")};d.rgb=a8;var{sqrt:L1,pow:ff}=Math,s8=(f,$,Q)=>{let[U,J,N]=f._rgb,[q,Z,D]=$._rgb;return new W(L1(ff(U,2)*(1-Q)+ff(q,2)*Q),L1(ff(J,2)*(1-Q)+ff(Z,2)*Q),L1(ff(N,2)*(1-Q)+ff(D,2)*Q),"rgb")};d.lrgb=s8;var f9=(f,$,Q)=>{let U=f.lab(),J=$.lab();return new W(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"lab")};d.lab=f9;var Z0=(f,$,Q,U)=>{let J,N;if(U==="hsl")J=f.hsl(),N=$.hsl();else if(U==="hsv")J=f.hsv(),N=$.hsv();else if(U==="hcg")J=f.hcg(),N=$.hcg();else if(U==="hsi")J=f.hsi(),N=$.hsi();else if(U==="lch"||U==="hcl")U="hcl",J=f.hcl(),N=$.hcl();else if(U==="oklch")J=f.oklch().reverse(),N=$.oklch().reverse();let q,Z,D,X,K,F;if(U.substr(0,1)==="h"||U==="oklch")[q,D,K]=J,[Z,X,F]=N;let V,G,B,S;if(!isNaN(q)&&!isNaN(Z)){if(Z>q&&Z-q>180)S=Z-(q+360);else if(Z180)S=Z+360-q;else S=Z-q;G=q+Q*S}else if(!isNaN(q)){if(G=q,(F==1||F==0)&&U!="hsv")V=D}else if(!isNaN(Z)){if(G=Z,(K==1||K==0)&&U!="hsv")V=X}else G=Number.NaN;if(V===void 0)V=D+Q*(X-D);return B=K+Q*(F-K),U==="oklch"?new W([B,V,G],U):new W([G,V,B],U)};var L2=(f,$,Q)=>{return Z0(f,$,Q,"lch")};d.lch=L2;d.hcl=L2;var $9=(f)=>{if(T(f)=="number"&&f>=0&&f<=16777215){let $=f>>16,Q=f>>8&255,U=f&255;return[$,Q,U,1]}throw Error("unknown num color: "+f)},j2=$9;var Q9=(...f)=>{let[$,Q,U]=O(f,"rgb");return($<<16)+(Q<<8)+U},R2=Q9;W.prototype.num=function(){return R2(this._rgb)};var U9=(...f)=>new W(...f,"num");Object.assign(_,{num:U9});j.format.num=j2;j.autodetect.push({p:5,test:(...f)=>{if(f.length===1&&T(f[0])==="number"&&f[0]>=0&&f[0]<=16777215)return"num"}});var J9=(f,$,Q)=>{let U=f.num(),J=$.num();return new W(U+Q*(J-U),"num")};d.num=J9;var{floor:N9}=Math,q9=(...f)=>{f=O(f,"hcg");let[$,Q,U]=f,J,N,q;U=U*255;let Z=Q*255;if(Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let D=N9($),X=$-D,K=U*(1-Q),F=K+Z*(1-X),V=K+Z*X,G=K+Z;switch(D){case 0:[J,N,q]=[G,V,K];break;case 1:[J,N,q]=[F,G,K];break;case 2:[J,N,q]=[K,G,V];break;case 3:[J,N,q]=[K,F,G];break;case 4:[J,N,q]=[V,K,G];break;case 5:[J,N,q]=[G,K,F];break}}return[J,N,q,f.length>3?f[3]:1]},A2=q9;var Z9=(...f)=>{let[$,Q,U]=O(f,"rgb"),J=vf($,Q,U),N=Lf($,Q,U),q=N-J,Z=q*100/255,D=J/(255-q)*100,X;if(q===0)X=Number.NaN;else{if($===N)X=(Q-U)/q;if(Q===N)X=2+(U-$)/q;if(U===N)X=4+($-Q)/q;if(X*=60,X<0)X+=360}return[X,Z,D]},m2=Z9;W.prototype.hcg=function(){return m2(this._rgb)};var D9=(...f)=>new W(...f,"hcg");_.hcg=D9;j.format.hcg=A2;j.autodetect.push({p:1,test:(...f)=>{if(f=O(f,"hcg"),T(f)==="array"&&f.length===3)return"hcg"}});var X9=(f,$,Q)=>{return Z0(f,$,Q,"hcg")};d.hcg=X9;var{cos:$f}=Math,K9=(...f)=>{f=O(f,"hsi");let[$,Q,U]=f,J,N,q;if(isNaN($))$=0;if(isNaN(Q))Q=0;if($>360)$-=360;if($<0)$+=360;if($/=360,$<0.3333333333333333)q=(1-Q)/3,J=(1+Q*$f(N0*$)/$f(jf-N0*$))/3,N=1-(q+J);else if($<0.6666666666666666)$-=0.3333333333333333,J=(1-Q)/3,N=(1+Q*$f(N0*$)/$f(jf-N0*$))/3,q=1-(J+N);else $-=0.6666666666666666,N=(1-Q)/3,q=(1+Q*$f(N0*$)/$f(jf-N0*$))/3,J=1-(N+q);return J=J0(U*J*3),N=J0(U*N*3),q=J0(U*q*3),[J*255,N*255,q*255,f.length>3?f[3]:1]},_2=K9;var{min:F9,sqrt:V9,acos:y9}=Math,W9=(...f)=>{let[$,Q,U]=O(f,"rgb");$/=255,Q/=255,U/=255;let J,N=F9($,Q,U),q=($+Q+U)/3,Z=q>0?1-N/q:0;if(Z===0)J=NaN;else{if(J=($-Q+($-U))/2,J/=V9(($-Q)*($-Q)+($-U)*(Q-U)),J=y9(J),U>Q)J=N0-J;J/=N0}return[J*360,Z,q]},C2=W9;W.prototype.hsi=function(){return C2(this._rgb)};var Y9=(...f)=>new W(...f,"hsi");_.hsi=Y9;j.format.hsi=_2;j.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"hsi"),T(f)==="array"&&f.length===3)return"hsi"}});var G9=(f,$,Q)=>{return Z0(f,$,Q,"hsi")};d.hsi=G9;var I9=(...f)=>{f=O(f,"hsl");let[$,Q,U]=f,J,N,q;if(Q===0)J=N=q=U*255;else{let Z=[0,0,0],D=[0,0,0],X=U<0.5?U*(1+Q):U+Q-U*Q,K=2*U-X,F=$/360;Z[0]=F+0.3333333333333333,Z[1]=F,Z[2]=F-0.3333333333333333;for(let V=0;V<3;V++){if(Z[V]<0)Z[V]+=1;if(Z[V]>1)Z[V]-=1;if(6*Z[V]<1)D[V]=K+(X-K)*6*Z[V];else if(2*Z[V]<1)D[V]=X;else if(3*Z[V]<2)D[V]=K+(X-K)*(0.6666666666666666-Z[V])*6;else D[V]=K}[J,N,q]=[D[0]*255,D[1]*255,D[2]*255]}if(f.length>3)return[J,N,q,f[3]];return[J,N,q,1]},Of=I9;var w9=(...f)=>{f=O(f,"rgba");let[$,Q,U]=f;$/=255,Q/=255,U/=255;let J=vf($,Q,U),N=Lf($,Q,U),q=(N+J)/2,Z,D;if(N===J)Z=0,D=Number.NaN;else Z=q<0.5?(N-J)/(N+J):(N-J)/(2-N-J);if($==N)D=(Q-U)/(N-J);else if(Q==N)D=2+(U-$)/(N-J);else if(U==N)D=4+($-Q)/(N-J);if(D*=60,D<0)D+=360;if(f.length>3&&f[3]!==void 0)return[D,Z,q,f[3]];return[D,Z,q]},tf=w9;W.prototype.hsl=function(){return tf(this._rgb)};var u9=(...f)=>new W(...f,"hsl");_.hsl=u9;j.format.hsl=Of;j.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"hsl"),T(f)==="array"&&f.length===3)return"hsl"}});var B9=(f,$,Q)=>{return Z0(f,$,Q,"hsl")};d.hsl=B9;var{floor:E9}=Math,k9=(...f)=>{f=O(f,"hsv");let[$,Q,U]=f,J,N,q;if(U*=255,Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let Z=E9($),D=$-Z,X=U*(1-Q),K=U*(1-Q*D),F=U*(1-Q*(1-D));switch(Z){case 0:[J,N,q]=[U,F,X];break;case 1:[J,N,q]=[K,U,X];break;case 2:[J,N,q]=[X,U,F];break;case 3:[J,N,q]=[X,K,U];break;case 4:[J,N,q]=[F,X,U];break;case 5:[J,N,q]=[U,X,K];break}}return[J,N,q,f.length>3?f[3]:1]},n2=k9;var{min:z9,max:O9}=Math,H9=(...f)=>{f=O(f,"rgb");let[$,Q,U]=f,J=z9($,Q,U),N=O9($,Q,U),q=N-J,Z,D,X;if(X=N/255,N===0)Z=Number.NaN,D=0;else{if(D=q/N,$===N)Z=(Q-U)/q;if(Q===N)Z=2+(U-$)/q;if(U===N)Z=4+($-Q)/q;if(Z*=60,Z<0)Z+=360}return[Z,D,X]},t2=H9;W.prototype.hsv=function(){return t2(this._rgb)};var S9=(...f)=>new W(...f,"hsv");_.hsv=S9;j.format.hsv=n2;j.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"hsv"),T(f)==="array"&&f.length===3)return"hsv"}});var p9=(f,$,Q)=>{return Z0(f,$,Q,"hsv")};d.hsv=p9;function i0(f,$){let Q=f.length;if(!Array.isArray(f[0]))f=[f];if(!Array.isArray($[0]))$=$.map((q)=>[q]);let U=$[0].length,J=$[0].map((q,Z)=>$.map((D)=>D[Z])),N=f.map((q)=>J.map((Z)=>{if(!Array.isArray(q))return Z.reduce((D,X)=>D+X*q,0);return q.reduce((D,X,K)=>D+X*(Z[K]||0),0)}));if(Q===1)N=N[0];if(U===1)return N.map((q)=>q[0]);return N}var M9=(...f)=>{f=O(f,"lab");let[$,Q,U,...J]=f,[N,q,Z]=P9([$,Q,U]),[D,X,K]=M1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function P9(f){var $=[[1.2268798758459243,-0.5578149944602171,0.2813910456659647],[-0.0405757452148008,1.112286803280317,-0.0717110580655164],[-0.0763729366746601,-0.4214933324022432,1.5869240198367816]],Q=[[1,0.3963377773761749,0.2158037573099136],[1,-0.1055613458156586,-0.0638541728258133],[1,-0.0894841775298119,-1.2914855480194092]],U=i0(Q,f);return i0($,U.map((J)=>J**3))}var Qf=M9;var T9=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),N=T1($,Q,U);return[...v9(N),...J.length>0&&J[0]<1?[J[0]]:[]]};function v9(f){let $=[[0.819022437996703,0.3619062600528904,-0.1288737815209879],[0.0329836539323885,0.9292868615863434,0.0361446663506424],[0.0481771893596242,0.2642395317527308,0.6335478284694309]],Q=[[0.210454268309314,0.7936177747023054,-0.0040720430116193],[1.9779985324311684,-2.42859224204858,0.450593709617411],[0.0259040424655478,0.7827717124575296,-0.8086757549230774]],U=i0($,f);return i0(Q,U.map((J)=>Math.cbrt(J)))}var Uf=T9;W.prototype.oklab=function(){return Uf(this._rgb)};var L9=(...f)=>new W(...f,"oklab");Object.assign(_,{oklab:L9});j.format.oklab=Qf;j.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"oklab"),T(f)==="array"&&f.length===3)return"oklab"}});var j9=(f,$,Q)=>{let U=f.oklab(),J=$.oklab();return new W(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"oklab")};d.oklab=j9;var R9=(f,$,Q)=>{return Z0(f,$,Q,"oklch")};d.oklch=R9;var{pow:j1,sqrt:R1,PI:A1,cos:d2,sin:x2,atan2:A9}=Math,h2=(f,$="lrgb",Q=null)=>{let U=f.length;if(!Q)Q=Array.from(Array(U)).map(()=>1);let J=U/Q.reduce(function(F,V){return F+V});if(Q.forEach((F,V)=>{Q[V]*=J}),f=f.map((F)=>new W(F)),$==="lrgb")return m9(f,Q);let N=f.shift(),q=N.get($),Z=[],D=0,X=0;for(let F=0;F{let G=F.get($);K+=F.alpha()*Q[V+1];for(let B=0;B=360)V-=360;q[F]=V}else q[F]=q[F]/Z[F];return K/=U,new W(q,$).alpha(K>0.99999?1:K,!0)},m9=(f,$)=>{let Q=f.length,U=[0,0,0,0];for(let J=0;J0.9999999)U[3]=1;return new W(g0(U))};var{pow:_9}=Math;function j0(f){let $="rgb",Q=_("#ccc"),U=0,J=[0,1],N=[0,1],q=[],Z=[0,0],D=!1,X=[],K=!1,F=0,V=1,G=!1,B={},S=!0,u=1,w=function(y){if(y=y||["#fff","#000"],y&&T(y)==="string"&&_.brewer&&_.brewer[y.toLowerCase()])y=_.brewer[y.toLowerCase()];if(T(y)==="array"){if(y.length===1)y=[y[0],y[0]];y=y.slice(0);for(let E=0;E=D[k])k++;return k-1}return 0},L=(y)=>y,p=(y)=>y,n=function(y,E){let k,z;if(E==null)E=!1;if(isNaN(y)||y===null)return Q;if(!E)if(D&&D.length>2)z=m(y)/(D.length-2);else if(V!==F)z=(y-F)/(V-F);else z=1;else z=y;if(z=p(z),!E)z=L(z);if(u!==1)z=_9(z,u);z=Z[0]+z*(1-Z[0]-Z[1]),z=J0(z,0,1);let P=Math.floor(z*1e4);if(S&&B[P])k=B[P];else{if(T(X)==="array")for(let M=0;M=b&&M===q.length-1){k=X[M];break}if(z>b&&zB={};w(f);let I=function(y){let E=_(n(y));if(K&&E[K])return E[K]();else return E};return I.classes=function(y){if(y!=null){if(T(y)==="array")D=y,J=[y[0],y[y.length-1]];else{let E=_.analyze(J);if(y===0)D=[E.min,E.max];else D=_.limits(E,"e",y)}return I}return D},I.domain=function(y){if(!arguments.length)return N;N=y.slice(0),F=y[0],V=y[y.length-1],q=[];let E=X.length;if(y.length===E&&F!==V)for(let k of Array.from(y))q.push((k-F)/(V-F));else{for(let k=0;k2){let k=y.map((P,M)=>M/(y.length-1)),z=y.map((P)=>(P-F)/(V-F));if(!z.every((P,M)=>k[M]===P))p=(P)=>{if(P<=0||P>=1)return P;let M=0;while(P>=z[M+1])M++;let b=(P-z[M])/(z[M+1]-z[M]);return k[M]+b*(k[M+1]-k[M])}}}return J=[F,V],I},I.mode=function(y){if(!arguments.length)return $;return $=y,A(),I},I.range=function(y,E){return w(y,E),I},I.out=function(y){return K=y,I},I.spread=function(y){if(!arguments.length)return U;return U=y,I},I.correctLightness=function(y){if(y==null)y=!0;if(G=y,A(),G)L=function(E){let k=n(0,!0).lab()[0],z=n(1,!0).lab()[0],P=k>z,M=n(E,!0).lab()[0],b=k+(z-k)*E,e=M-b,Y0=0,B0=1,b0=20;while(Math.abs(e)>0.01&&b0-- >0)(function(){if(P)e*=-1;if(e<0)Y0=E,E+=(B0-E)*0.5;else B0=E,E+=(Y0-E)*0.5;return M=n(E,!0).lab()[0],e=M-b})();return E};else L=(E)=>E;return I},I.padding=function(y){if(y!=null){if(T(y)==="number")y=[y,y];return Z=y,I}else return Z},I.colors=function(y,E){if(arguments.length<2)E="hex";let k=[];if(arguments.length===0)k=X.slice(0);else if(y===1)k=[I(0.5)];else if(y>1){let z=J[0],P=J[1]-z;k=C9(0,y,!1).map((M)=>I(z+M/(y-1)*P))}else{f=[];let z=[];if(D&&D.length>2)for(let P=1,M=D.length,b=1<=M;b?PM;b?P++:P--)z.push((D[P-1]+D[P])*0.5);else z=J;k=z.map((P)=>I(P))}if(_[E])k=k.map((z)=>z[E]());return k},I.cache=function(y){if(y!=null)return S=y,I;else return S},I.gamma=function(y){if(y!=null)return u=y,I;else return u},I.nodata=function(y){if(y!=null)return Q=_(y),I;else return Q},I}function C9(f,$,Q){let U=[],J=f<$,N=!Q?$:J?$+1:$-1;for(let q=f;J?qN;J?q++:q--)U.push(q);return U}var n9=function(f){let $=[1,1];for(let Q=1;Qnew W(N)),f.length===2)[Q,U]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>Q[Z]+N*(U[Z]-Q[Z]));return new W(q,"lab")};else if(f.length===3)[Q,U,J]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>(1-N)*(1-N)*Q[Z]+2*(1-N)*N*U[Z]+N*N*J[Z]);return new W(q,"lab")};else if(f.length===4){let N;[Q,U,J,N]=f.map((q)=>q.lab()),$=function(q){let Z=[0,1,2].map((D)=>(1-q)*(1-q)*(1-q)*Q[D]+3*(1-q)*(1-q)*q*U[D]+3*(1-q)*q*q*J[D]+q*q*q*N[D]);return new W(Z,"lab")}}else if(f.length>=5){let N,q,Z;N=f.map((D)=>D.lab()),Z=f.length-1,q=n9(Z),$=function(D){let X=1-D,K=[0,1,2].map((F)=>N.reduce((V,G,B)=>V+q[B]*X**(Z-B)*D**B*G[F],0));return new W(K,"lab")}}else throw RangeError("No point in running bezier with only one color.");return $},b2=(f)=>{let $=t9(f);return $.scale=()=>j0($),$};var{round:r2}=Math;W.prototype.rgb=function(f=!0){if(f===!1)return this._rgb.slice(0,3);return this._rgb.slice(0,3).map(r2)};W.prototype.rgba=function(f=!0){return this._rgb.slice(0,4).map(($,Q)=>{return Q<3?f===!1?$:r2($):$})};var d9=(...f)=>new W(...f,"rgb");Object.assign(_,{rgb:d9});j.format.rgb=(...f)=>{let $=O(f,"rgba");if($[3]===void 0)$[3]=1;return $};j.autodetect.push({p:3,test:(...f)=>{if(f=O(f,"rgba"),T(f)==="array"&&(f.length===3||f.length===4&&T(f[3])=="number"&&f[3]>=0&&f[3]<=1))return"rgb"}});var G0=(f,$,Q)=>{if(!G0[Q])throw Error("unknown blend mode "+Q);return G0[Q](f,$)},R0=(f)=>($,Q)=>{let U=_(Q).rgb(),J=_($).rgb();return _.rgb(f(U,J))},A0=(f)=>($,Q)=>{let U=[];return U[0]=f($[0],Q[0]),U[1]=f($[1],Q[1]),U[2]=f($[2],Q[2]),U},x9=(f)=>f,h9=(f,$)=>f*$/255,b9=(f,$)=>f>$?$:f,r9=(f,$)=>f>$?f:$,g9=(f,$)=>255*(1-(1-f/255)*(1-$/255)),i9=(f,$)=>$<128?2*f*$/255:255*(1-2*(1-f/255)*(1-$/255)),c9=(f,$)=>255*(1-(1-$/255)/(f/255)),o9=(f,$)=>{if(f===255)return 255;return f=255*($/255)/(1-f/255),f>255?255:f};G0.normal=R0(A0(x9));G0.multiply=R0(A0(h9));G0.screen=R0(A0(g9));G0.overlay=R0(A0(i9));G0.darken=R0(A0(b9));G0.lighten=R0(A0(r9));G0.dodge=R0(A0(o9));G0.burn=R0(A0(c9));var g2=G0;var{pow:e9,sin:l9,cos:a9}=Math;function m1(f=300,$=-1.5,Q=1,U=1,J=[0,1]){let N=0,q;if(T(J)==="array")q=J[1]-J[0];else q=0,J=[J,J];let Z=function(D){let X=N0*((f+120)/360+$*D),K=e9(J[0]+q*D,U),V=(N!==0?Q[0]+D*N:Q)*K*(1-K)/2,G=a9(X),B=l9(X),S=K+V*(-0.14861*G+1.78277*B),u=K+V*(-0.29227*G-0.90649*B),w=K+V*(1.97294*G);return _(g0([S*255,u*255,w*255,1]))};return Z.start=function(D){if(D==null)return f;return f=D,Z},Z.rotations=function(D){if(D==null)return $;return $=D,Z},Z.gamma=function(D){if(D==null)return U;return U=D,Z},Z.hue=function(D){if(D==null)return Q;if(Q=D,T(Q)==="array"){if(N=Q[1]-Q[0],N===0)Q=Q[1]}else N=0;return Z},Z.lightness=function(D){if(D==null)return J;if(T(D)==="array")J=D,q=D[1]-D[0];else J=[D,D],q=0;return Z},Z.scale=()=>_.scale(Z),Z.hue(Q),Z}var s9="0123456789abcdef",{floor:f7,random:$7}=Math,i2=(f=$7)=>{let $="#";for(let Q=0;Q<6;Q++)$+=s9.charAt(f7(f()*16));return new W($,"hex")};var{log:c2,pow:Q7,floor:U7,abs:J7}=Math;function _1(f,$=null){let Q={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};if(T(f)==="object")f=Object.values(f);return f.forEach((U)=>{if($&&T(U)==="object")U=U[$];if(U!==void 0&&U!==null&&!isNaN(U)){if(Q.values.push(U),Q.sum+=U,UQ.max)Q.max=U;Q.count+=1}}),Q.domain=[Q.min,Q.max],Q.limits=(U,J)=>C1(Q,U,J),Q}function C1(f,$="equal",Q=7){if(T(f)=="array")f=_1(f);let{min:U,max:J}=f,N=f.values.sort((Z,D)=>Z-D);if(Q===1)return[U,J];let q=[];if($.substr(0,1)==="c")q.push(U),q.push(J);if($.substr(0,1)==="e"){q.push(U);for(let Z=1;Z 0");let Z=Math.LOG10E*c2(U),D=Math.LOG10E*c2(J);q.push(U);for(let X=1;X200)F=!1}let B={};for(let u=0;uu-w),q.push(S[0]);for(let u=1;u{f=new W(f),$=new W($);let Q=f.luminance(),U=$.luminance();return Q>U?(Q+0.05)/(U+0.05):(U+0.05)/(Q+0.05)};var e2=0.027,N7=0.0005,q7=0.1,l2=1.14,df=0.022,a2=1.414,f5=(f,$)=>{if(f=new W(f),$=new W($),f.alpha()<1)f=k0($,f,f.alpha(),"rgb");let Q=s2(...f.rgb()),U=s2(...$.rgb()),J=Q>=df?Q:Q+Math.pow(df-Q,a2),N=U>=df?U:U+Math.pow(df-U,a2),q=Math.pow(N,0.56)-Math.pow(J,0.57),Z=Math.pow(N,0.65)-Math.pow(J,0.62),D=Math.abs(N-J)0?D-e2:D+e2)*100};function s2(f,$,Q){return 0.2126729*Math.pow(f/255,2.4)+0.7151522*Math.pow($/255,2.4)+0.072175*Math.pow(Q/255,2.4)}var{sqrt:S0,pow:g,min:Z7,max:D7,atan2:$5,abs:Q5,cos:xf,sin:U5,exp:X7,PI:J5}=Math;function n1(f,$,Q=1,U=1,J=1){var N=function(r0){return 360*r0/(2*J5)},q=function(r0){return 2*J5*r0/360};f=new W(f),$=new W($);let[Z,D,X]=Array.from(f.lab()),[K,F,V]=Array.from($.lab()),G=(Z+K)/2,B=S0(g(D,2)+g(X,2)),S=S0(g(F,2)+g(V,2)),u=(B+S)/2,w=0.5*(1-S0(g(u,7)/(g(u,7)+g(25,7)))),m=D*(1+w),L=F*(1+w),p=S0(g(m,2)+g(X,2)),n=S0(g(L,2)+g(V,2)),A=(p+n)/2,I=N($5(X,m)),y=N($5(V,L)),E=I>=0?I:I+360,k=y>=0?y:y+360,z=Q5(E-k)>180?(E+k+360)/2:(E+k)/2,P=1-0.17*xf(q(z-30))+0.24*xf(q(2*z))+0.32*xf(q(3*z+6))-0.2*xf(q(4*z-63)),M=k-E;M=Q5(M)<=180?M:k<=E?M+360:M-360,M=2*S0(p*n)*U5(q(M)/2);let b=K-Z,e=n-p,Y0=1+0.015*g(G-50,2)/S0(20+g(G-50,2)),B0=1+0.045*A,b0=1+0.015*A*P,O1=30*X7(-g((z-275)/25,2)),H1=-(2*S0(g(A,7)/(g(A,7)+g(25,7))))*U5(2*q(O1)),S1=S0(g(b/(Q*Y0),2)+g(e/(U*B0),2)+g(M/(J*b0),2)+H1*(e/(U*B0))*(M/(J*b0)));return D7(0,Z7(100,S1))}function t1(f,$,Q="lab"){f=new W(f),$=new W($);let U=f.get(Q),J=$.get(Q),N=0;for(let q in U){let Z=(U[q]||0)-(J[q]||0);N+=Z*Z}return Math.sqrt(N)}var N5=(...f)=>{try{return new W(...f),!0}catch($){return!1}};var q5={cool(){return j0([_.hsl(180,1,0.9),_.hsl(250,0.7,0.4)])},hot(){return j0(["#000","#f00","#ff0","#fff"],[0,0.25,0.75,1]).mode("rgb")}};var d1={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Viridis:["#440154","#482777","#3f4a8a","#31678e","#26838f","#1f9d8a","#6cce5a","#b6de2b","#fee825"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]},D5=Object.keys(d1),Z5=new Map(D5.map((f)=>[f.toLowerCase(),f])),K7=typeof Proxy==="function"?new Proxy(d1,{get(f,$){let Q=$.toLowerCase();if(Z5.has(Q))return f[Z5.get(Q)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(D5)}}):d1,X5=K7;var F7=(...f)=>{f=O(f,"cmyk");let[$,Q,U,J]=f,N=f.length>4?f[4]:1;if(J===1)return[0,0,0,N];return[$>=1?0:255*(1-$)*(1-J),Q>=1?0:255*(1-Q)*(1-J),U>=1?0:255*(1-U)*(1-J),N]},K5=F7;var{max:F5}=Math,V7=(...f)=>{let[$,Q,U]=O(f,"rgb");$=$/255,Q=Q/255,U=U/255;let J=1-F5($,F5(Q,U)),N=J<1?1/(1-J):0,q=(1-$-J)*N,Z=(1-Q-J)*N,D=(1-U-J)*N;return[q,Z,D,J]},V5=V7;W.prototype.cmyk=function(){return V5(this._rgb)};var y7=(...f)=>new W(...f,"cmyk");Object.assign(_,{cmyk:y7});j.format.cmyk=K5;j.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"cmyk"),T(f)==="array"&&f.length===4)return"cmyk"}});var W7=(...f)=>{let $=O(f,"hsla"),Q=Q0(f)||"lsa";if($[0]=l($[0]||0)+"deg",$[1]=l($[1]*100)+"%",$[2]=l($[2]*100)+"%",Q==="hsla"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="hsla";else $.length=3;return`${Q.substr(0,3)}(${$.join(" ")})`},y5=W7;var Y7=(...f)=>{let $=O(f,"lab"),Q=Q0(f)||"lab";if($[0]=l($[0])+"%",$[1]=l($[1]),$[2]=l($[2]),Q==="laba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lab(${$.join(" ")})`},W5=Y7;var G7=(...f)=>{let $=O(f,"lch"),Q=Q0(f)||"lab";if($[0]=l($[0])+"%",$[1]=l($[1]),$[2]=isNaN($[2])?"none":l($[2])+"deg",Q==="lcha"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lch(${$.join(" ")})`},Y5=G7;var I7=(...f)=>{let $=O(f,"lab");if($[0]=l($[0]*100)+"%",$[1]=Ef($[1]),$[2]=Ef($[2]),$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklab(${$.join(" ")})`},G5=I7;var w7=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),[N,q,Z]=Uf($,Q,U),[D,X,K]=nf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},hf=w7;var u7=(...f)=>{let $=O(f,"lch");if($[0]=l($[0]*100)+"%",$[1]=Ef($[1]),$[2]=isNaN($[2])?"none":l($[2])+"deg",$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklch(${$.join(" ")})`},I5=u7;var{round:x1}=Math,B7=(...f)=>{let $=O(f,"rgba"),Q=Q0(f)||"rgb";if(Q.substr(0,3)==="hsl")return y5(tf($),Q);if(Q.substr(0,3)==="lab"){let U=L0();q0("d50");let J=W5(a0($),Q);return q0(U),J}if(Q.substr(0,3)==="lch"){let U=L0();q0("d50");let J=Y5(zf($),Q);return q0(U),J}if(Q.substr(0,5)==="oklab")return G5(Uf($));if(Q.substr(0,5)==="oklch")return I5(hf($));if($[0]=x1($[0]),$[1]=x1($[1]),$[2]=x1($[2]),Q==="rgba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="rgba";return`${Q.substr(0,3)}(${$.slice(0,Q==="rgb"?3:4).join(" ")})`},w5=B7;var E7=(...f)=>{f=O(f,"lch");let[$,Q,U,...J]=f,[N,q,Z]=Cf($,Q,U),[D,X,K]=Qf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},bf=E7;var p0=/((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source,I0=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source,rf=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source,D0=/\s*/.source,Nf=/\s+/.source,h1=/\s*,\s*/.source,gf=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source,qf=/\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source,u5=new RegExp("^rgba?\\("+D0+[p0,p0,p0].join(Nf)+qf+"\\)$"),B5=new RegExp("^rgb\\("+D0+[p0,p0,p0].join(h1)+D0+"\\)$"),E5=new RegExp("^rgba\\("+D0+[p0,p0,p0,I0].join(h1)+D0+"\\)$"),k5=new RegExp("^hsla?\\("+D0+[gf,rf,rf].join(Nf)+qf+"\\)$"),z5=new RegExp("^hsl?\\("+D0+[gf,rf,rf].join(h1)+D0+"\\)$"),O5=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,H5=new RegExp("^lab\\("+D0+[I0,I0,I0].join(Nf)+qf+"\\)$"),S5=new RegExp("^lch\\("+D0+[I0,I0,gf].join(Nf)+qf+"\\)$"),p5=new RegExp("^oklab\\("+D0+[I0,I0,I0].join(Nf)+qf+"\\)$"),M5=new RegExp("^oklch\\("+D0+[I0,I0,gf].join(Nf)+qf+"\\)$"),{round:P5}=Math,Jf=(f)=>{return f.map(($,Q)=>Q<=2?J0(P5($),0,255):$)},i=(f,$=0,Q=100,U=!1)=>{if(typeof f==="string"&&f.endsWith("%"))if(f=parseFloat(f.substring(0,f.length-1))/100,U)f=$+(f+1)*0.5*(Q-$);else f=$+f*(Q-$);return+f},f0=(f,$)=>{return f==="none"?$:f},T5=(f)=>{if(f=f.toLowerCase().trim(),f==="transparent")return[0,0,0,0];let $;if(j.format.named)try{return j.format.named(f)}catch(Q){}if(($=f.match(u5))||($=f.match(B5))){let Q=$.slice(1,4);for(let J=0;J<3;J++)Q[J]=+i(f0(Q[J],0),0,255);Q=Jf(Q);let U=$[4]!==void 0?+i($[4],0,1):1;return Q[3]=U,Q}if($=f.match(E5)){let Q=$.slice(1,5);for(let U=0;U<4;U++)Q[U]=+i(Q[U],0,255);return Q}if(($=f.match(k5))||($=f.match(z5))){let Q=$.slice(1,4);Q[0]=+f0(Q[0].replace("deg",""),0),Q[1]=+i(f0(Q[1],0),0,100)*0.01,Q[2]=+i(f0(Q[2],0),0,100)*0.01;let U=Jf(Of(Q)),J=$[4]!==void 0?+i($[4],0,1):1;return U[3]=J,U}if($=f.match(O5)){let Q=$.slice(1,4);Q[1]*=0.01,Q[2]*=0.01;let U=Of(Q);for(let J=0;J<3;J++)U[J]=P5(U[J]);return U[3]=+$[4],U}if($=f.match(H5)){let Q=$.slice(1,4);Q[0]=i(f0(Q[0],0),0,100),Q[1]=i(f0(Q[1],0),-125,125,!0),Q[2]=i(f0(Q[2],0),-125,125,!0);let U=L0();q0("d50");let J=Jf(l0(Q));q0(U);let N=$[4]!==void 0?+i($[4],0,1):1;return J[3]=N,J}if($=f.match(S5)){let Q=$.slice(1,4);Q[0]=i(Q[0],0,100),Q[1]=i(f0(Q[1],0),0,150,!1),Q[2]=+f0(Q[2].replace("deg",""),0);let U=L0();q0("d50");let J=Jf(s0(Q));q0(U);let N=$[4]!==void 0?+i($[4],0,1):1;return J[3]=N,J}if($=f.match(p5)){let Q=$.slice(1,4);Q[0]=i(f0(Q[0],0),0,1),Q[1]=i(f0(Q[1],0),-0.4,0.4,!0),Q[2]=i(f0(Q[2],0),-0.4,0.4,!0);let U=Jf(Qf(Q)),J=$[4]!==void 0?+i($[4],0,1):1;return U[3]=J,U}if($=f.match(M5)){let Q=$.slice(1,4);Q[0]=i(f0(Q[0],0),0,1),Q[1]=i(f0(Q[1],0),0,0.4,!1),Q[2]=+f0(Q[2].replace("deg",""),0);let U=Jf(bf(Q)),J=$[4]!==void 0?+i($[4],0,1):1;return U[3]=J,U}};T5.test=(f)=>{return u5.test(f)||k5.test(f)||H5.test(f)||S5.test(f)||p5.test(f)||M5.test(f)||B5.test(f)||E5.test(f)||z5.test(f)||O5.test(f)||f==="transparent"};var b1=T5;W.prototype.css=function(f){return w5(this._rgb,f)};var k7=(...f)=>new W(...f,"css");_.css=k7;j.format.css=b1;j.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&T(f)==="string"&&b1.test(f))return"css"}});j.format.gl=(...f)=>{let $=O(f,"rgba");return $[0]*=255,$[1]*=255,$[2]*=255,$};var z7=(...f)=>new W(...f,"gl");_.gl=z7;W.prototype.gl=function(){let f=this._rgb;return[f[0]/255,f[1]/255,f[2]/255,f[3]]};W.prototype.hex=function(f){return _f(this._rgb,f)};var O7=(...f)=>new W(...f,"hex");_.hex=O7;j.format.hex=Af;j.autodetect.push({p:4,test:(f,...$)=>{if(!$.length&&T(f)==="string"&&[3,4,5,6,7,8,9].indexOf(f.length)>=0)return"hex"}});var{log:cf}=Math,H7=(f)=>{let $=f/100,Q,U,J;if($<66)Q=255,U=$<6?0:-155.25485562709179-0.44596950469579133*(U=$-2)+104.49216199393888*cf(U),J=$<20?0:-254.76935184120902+0.8274096064007395*(J=$-10)+115.67994401066147*cf(J);else Q=351.97690566805693+0.114206453784165*(Q=$-55)-40.25366309332127*cf(Q),U=325.4494125711974+0.07943456536662342*(U=$-50)-28.0852963507957*cf(U),J=255;return[Q,U,J,1]},of=H7;var{round:S7}=Math,p7=(...f)=>{let $=O(f,"rgb"),Q=$[0],U=$[2],J=1000,N=40000,q=0.4,Z;while(N-J>q){Z=(N+J)*0.5;let D=of(Z);if(D[2]/D[0]>=U/Q)N=Z;else J=Z}return S7(Z)},v5=p7;W.prototype.temp=W.prototype.kelvin=W.prototype.temperature=function(){return v5(this._rgb)};var r1=(...f)=>new W(...f,"temp");Object.assign(_,{temp:r1,kelvin:r1,temperature:r1});j.format.temp=j.format.kelvin=j.format.temperature=of;W.prototype.oklch=function(){return hf(this._rgb)};var M7=(...f)=>new W(...f,"oklch");Object.assign(_,{oklch:M7});j.format.oklch=bf;j.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"oklch"),T(f)==="array"&&f.length===3)return"oklch"}});Object.assign(_,{analyze:_1,average:h2,bezier:b2,blend:g2,brewer:X5,Color:W,colors:v0,contrast:o2,contrastAPCA:f5,cubehelix:m1,deltaE:n1,distance:t1,input:j,interpolate:k0,limits:C1,mix:k0,random:i2,scale:j0,scales:q5,valid:N5});var h=_;var{min:P7,max:T7}=Math,X0=(f,$=0,Q=1)=>{return P7(T7($,f),Q)};var c0=(f)=>{f._clipped=!1,f._unclipped=f.slice(0);for(let $=0;$<=3;$++)if($<3){if(f[$]<0||f[$]>255)f._clipped=!0;f[$]=X0(f[$],0,255)}else if($===3)f[$]=X0(f[$],0,1);return f};var L5={};for(let f of["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"])L5[`[object ${f}]`]=f.toLowerCase();function v(f){return L5[Object.prototype.toString.call(f)]||"object"}var H=(f,$=null)=>{if(f.length>=3)return Array.prototype.slice.call(f);if(v(f[0])=="object"&&$)return $.split("").filter((Q)=>f[0][Q]!==void 0).map((Q)=>f[0][Q]);return f[0].slice(0)};var U0=(f)=>{if(f.length<2)return null;let $=f.length-1;if(v(f[$])=="string")return f[$].toLowerCase();return null};var{PI:ef,min:lf,max:af}=Math,a=(f)=>Math.round(f*100)/100,Hf=(f)=>Math.round(f*100)/100,K0=ef*2,sf=ef/3,j5=ef/180,R5=180/ef;function f1(f){return[...f.slice(0,3).reverse(),...f.slice(3)]}var R={format:{},autodetect:[]};class A5{constructor(...f){let $=this;if(v(f[0])==="object"&&f[0].constructor&&f[0].constructor===this.constructor)return f[0];let Q=U0(f),U=!1;if(!Q){if(U=!0,!R.sorted)R.autodetect=R.autodetect.sort((J,N)=>N.p-J.p),R.sorted=!0;for(let J of R.autodetect)if(Q=J.test(...f),Q)break}if(R.format[Q]){let J=R.format[Q].apply(null,U?f:f.slice(0,-1));$._rgb=c0(J)}else throw Error("unknown format: "+f);if($._rgb.length===3)$._rgb.push(1)}toString(){if(v(this.hex)=="function")return this.hex();return`[${this._rgb.join(",")}]`}}var Y=A5;var m5="3.1.2";var _5=(...f)=>{return new Y(...f)};_5.version=m5;var C=_5;var v7={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},m0=v7;var L7=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,j7=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,R7=(f)=>{if(f.match(L7)){if(f.length===4||f.length===7)f=f.substr(1);if(f.length===3)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2];let $=parseInt(f,16),Q=$>>16,U=$>>8&255,J=$&255;return[Q,U,J,1]}if(f.match(j7)){if(f.length===5||f.length===9)f=f.substr(1);if(f.length===4)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2]+f[3]+f[3];let $=parseInt(f,16),Q=$>>24&255,U=$>>16&255,J=$>>8&255,N=Math.round(($&255)/255*100)/100;return[Q,U,J,N]}throw Error(`unknown hex color: ${f}`)},$1=R7;var{round:Q1}=Math,A7=(...f)=>{let[$,Q,U,J]=H(f,"rgba"),N=U0(f)||"auto";if(J===void 0)J=1;if(N==="auto")N=J<1?"rgba":"rgb";$=Q1($),Q=Q1(Q),U=Q1(U);let Z="000000"+($<<16|Q<<8|U).toString(16);Z=Z.substr(Z.length-6);let D="0"+Q1(J*255).toString(16);switch(D=D.substr(D.length-2),N.toLowerCase()){case"rgba":return`#${Z}${D}`;case"argb":return`#${D}${Z}`;default:return`#${Z}`}},U1=A7;Y.prototype.name=function(){let f=U1(this._rgb,"rgb");for(let $ of Object.keys(m0))if(m0[$]===f)return $.toLowerCase();return f};R.format.named=(f)=>{if(f=f.toLowerCase(),m0[f])return $1(m0[f]);throw Error("unknown color name: "+f)};R.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&v(f)==="string"&&m0[f.toLowerCase()])return"named"}});Y.prototype.alpha=function(f,$=!1){if(f!==void 0&&v(f)==="number"){if($)return this._rgb[3]=f,this;return new Y([this._rgb[0],this._rgb[1],this._rgb[2],f],"rgb")}return this._rgb[3]};Y.prototype.clipped=function(){return this._rgb._clipped||!1};var Sf={Kn:18,labWhitePoint:"d65",Xn:0.95047,Yn:1,Zn:1.08883,t0:0.137931034,t1:0.206896552,t2:0.12841855,t3:0.008856452,kE:0.008856451679035631,kKE:8,kK:903.2962962962963,RefWhiteRGB:{X:0.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:0.4124564390896922,m01:0.21267285140562253,m02:0.0193338955823293,m10:0.357576077643909,m11:0.715152155287818,m12:0.11919202588130297,m20:0.18043748326639894,m21:0.07217499330655958,m22:0.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-0.9692660305051868,m02:0.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-0.2040259135167538,m20:-0.498531409556016,m21:0.041556017530349834,m22:1.0572251882231791},As:0.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:0.8951,m01:-0.7502,m02:0.0389,m10:0.2664,m11:1.7135,m12:-0.0685,m20:-0.1614,m21:0.0367,m22:1.0296},MtxAdaptMaI:{m00:0.9869929054667123,m01:0.43230526972339456,m02:-0.008528664575177328,m10:-0.14705425642099013,m11:0.5183602715367776,m12:0.04004282165408487,m20:0.15996265166373125,m21:0.0492912282128556,m22:0.9684866957875502}},z0=Sf,m7=new Map([["a",[1.0985,0.35585]],["b",[1.0985,0.35585]],["c",[0.98074,1.18232]],["d50",[0.96422,0.82521]],["d55",[0.95682,0.92149]],["d65",[0.95047,1.08883]],["e",[1,1,1]],["f2",[0.99186,0.67393]],["f7",[0.95041,1.08747]],["f11",[1.00962,0.6435]],["icc",[0.96422,0.82521]]]);function F0(f){let $=m7.get(String(f).toLowerCase());if(!$)throw Error("unknown Lab illuminant "+f);Sf.labWhitePoint=f,Sf.Xn=$[0],Sf.Zn=$[1]}function _0(){return Sf.labWhitePoint}var _7=(...f)=>{f=H(f,"lab");let[$,Q,U]=f,[J,N,q]=C7($,Q,U),[Z,D,X]=i1(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},C7=(f,$,Q)=>{let{kE:U,kK:J,kKE:N,Xn:q,Yn:Z,Zn:D}=z0,X=(f+16)/116,K=0.002*$+X,F=X-0.005*Q,V=K*K*K,G=F*F*F,B=V>U?V:(116*K-16)/J,S=f>N?Math.pow((f+16)/116,3):f/J,u=G>U?G:(116*F-16)/J,w=B*q,m=S*Z,L=u*D;return[w,m,L]},g1=(f)=>{let $=Math.sign(f);return f=Math.abs(f),(f<=0.0031308?f*12.92:1.055*Math.pow(f,0.4166666666666667)-0.055)*$},i1=(f,$,Q)=>{let{MtxAdaptMa:U,MtxAdaptMaI:J,MtxXYZ2RGB:N,RefWhiteRGB:q,Xn:Z,Yn:D,Zn:X}=z0,K=Z*U.m00+D*U.m10+X*U.m20,F=Z*U.m01+D*U.m11+X*U.m21,V=Z*U.m02+D*U.m12+X*U.m22,G=q.X*U.m00+q.Y*U.m10+q.Z*U.m20,B=q.X*U.m01+q.Y*U.m11+q.Z*U.m21,S=q.X*U.m02+q.Y*U.m12+q.Z*U.m22,u=(f*U.m00+$*U.m10+Q*U.m20)*(G/K),w=(f*U.m01+$*U.m11+Q*U.m21)*(B/F),m=(f*U.m02+$*U.m12+Q*U.m22)*(S/V),L=u*J.m00+w*J.m10+m*J.m20,p=u*J.m01+w*J.m11+m*J.m21,n=u*J.m02+w*J.m12+m*J.m22,A=g1(L*N.m00+p*N.m10+n*N.m20),I=g1(L*N.m01+p*N.m11+n*N.m21),y=g1(L*N.m02+p*N.m12+n*N.m22);return[A*255,I*255,y*255]},Zf=_7;var n7=(...f)=>{let[$,Q,U,...J]=H(f,"rgb"),[N,q,Z]=o1($,Q,U),[D,X,K]=t7(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function t7(f,$,Q){let{Xn:U,Yn:J,Zn:N,kE:q,kK:Z}=z0,D=f/U,X=$/J,K=Q/N,F=D>q?Math.pow(D,0.3333333333333333):(Z*D+16)/116,V=X>q?Math.pow(X,0.3333333333333333):(Z*X+16)/116,G=K>q?Math.pow(K,0.3333333333333333):(Z*K+16)/116;return[116*V-16,500*(F-V),200*(V-G)]}function c1(f){let $=Math.sign(f);return f=Math.abs(f),(f<=0.04045?f/12.92:Math.pow((f+0.055)/1.055,2.4))*$}var o1=(f,$,Q)=>{f=c1(f/255),$=c1($/255),Q=c1(Q/255);let{MtxRGB2XYZ:U,MtxAdaptMa:J,MtxAdaptMaI:N,Xn:q,Yn:Z,Zn:D,As:X,Bs:K,Cs:F}=z0,V=f*U.m00+$*U.m10+Q*U.m20,G=f*U.m01+$*U.m11+Q*U.m21,B=f*U.m02+$*U.m12+Q*U.m22,S=q*J.m00+Z*J.m10+D*J.m20,u=q*J.m01+Z*J.m11+D*J.m21,w=q*J.m02+Z*J.m12+D*J.m22,m=V*J.m00+G*J.m10+B*J.m20,L=V*J.m01+G*J.m11+B*J.m21,p=V*J.m02+G*J.m12+B*J.m22;return m*=S/X,L*=u/K,p*=w/F,V=m*N.m00+L*N.m10+p*N.m20,G=m*N.m01+L*N.m11+p*N.m21,B=m*N.m02+L*N.m12+p*N.m22,[V,G,B]},Df=n7;Y.prototype.lab=function(){return Df(this._rgb)};var d7=(...f)=>new Y(...f,"lab");Object.assign(C,{lab:d7,getLabWhitePoint:_0,setLabWhitePoint:F0});R.format.lab=Zf;R.autodetect.push({p:2,test:(...f)=>{if(f=H(f,"lab"),v(f)==="array"&&f.length===3)return"lab"}});Y.prototype.darken=function(f=1){let $=this,Q=$.lab();return Q[0]-=z0.Kn*f,new Y(Q,"lab").alpha($.alpha(),!0)};Y.prototype.brighten=function(f=1){return this.darken(-f)};Y.prototype.darker=Y.prototype.darken;Y.prototype.brighter=Y.prototype.brighten;Y.prototype.get=function(f){let[$,Q]=f.split("."),U=this[$]();if(Q){let J=$.indexOf(Q)-($.substr(0,2)==="ok"?2:0);if(J>-1)return U[J];throw Error(`unknown channel ${Q} in mode ${$}`)}else return U};var{pow:x7}=Math,h7=0.0000001,b7=20;Y.prototype.luminance=function(f,$="rgb"){if(f!==void 0&&v(f)==="number"){if(f===0)return new Y([0,0,0,this._rgb[3]],"rgb");if(f===1)return new Y([255,255,255,this._rgb[3]],"rgb");let Q=this.luminance(),U=b7,J=(q,Z)=>{let D=q.interpolate(Z,0.5,$),X=D.luminance();if(Math.abs(f-X)f?J(q,D):J(D,Z)},N=(Q>f?J(new Y([0,0,0]),this):J(this,new Y([255,255,255]))).rgb();return new Y([...N,this._rgb[3]])}return r7(...this._rgb.slice(0,3))};var r7=(f,$,Q)=>{return f=e1(f),$=e1($),Q=e1(Q),0.2126*f+0.7152*$+0.0722*Q},e1=(f)=>{return f/=255,f<=0.03928?f/12.92:x7((f+0.055)/1.055,2.4)};var x={};var O0=(f,$,Q=0.5,...U)=>{let J=U[0]||"lrgb";if(!x[J]&&!U.length)J=Object.keys(x)[0];if(!x[J])throw Error(`interpolation mode ${J} is not defined`);if(v(f)!=="object")f=new Y(f);if(v($)!=="object")$=new Y($);return x[J](f,$,Q).alpha(f.alpha()+Q*($.alpha()-f.alpha()))};Y.prototype.mix=Y.prototype.interpolate=function(f,$=0.5,...Q){return O0(this,f,$,...Q)};Y.prototype.premultiply=function(f=!1){let $=this._rgb,Q=$[3];if(f)return this._rgb=[$[0]*Q,$[1]*Q,$[2]*Q,Q],this;else return new Y([$[0]*Q,$[1]*Q,$[2]*Q,Q],"rgb")};var{sin:g7,cos:i7}=Math,c7=(...f)=>{let[$,Q,U]=H(f,"lch");if(isNaN(U))U=0;return U=U*j5,[$,i7(U)*Q,g7(U)*Q]},J1=c7;var o7=(...f)=>{f=H(f,"lch");let[$,Q,U]=f,[J,N,q]=J1($,Q,U),[Z,D,X]=Zf(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},Xf=o7;var e7=(...f)=>{let $=f1(H(f,"hcl"));return Xf(...$)},C5=e7;var{sqrt:l7,atan2:a7,round:s7}=Math,f4=(...f)=>{let[$,Q,U]=H(f,"lab"),J=l7(Q*Q+U*U),N=(a7(U,Q)*R5+360)%360;if(s7(J*1e4)===0)N=Number.NaN;return[$,J,N]},N1=f4;var $4=(...f)=>{let[$,Q,U,...J]=H(f,"rgb"),[N,q,Z]=Df($,Q,U),[D,X,K]=N1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},pf=$4;Y.prototype.lch=function(){return pf(this._rgb)};Y.prototype.hcl=function(){return f1(pf(this._rgb))};var Q4=(...f)=>new Y(...f,"lch"),U4=(...f)=>new Y(...f,"hcl");Object.assign(C,{lch:Q4,hcl:U4});R.format.lch=Xf;R.format.hcl=C5;["lch","hcl"].forEach((f)=>R.autodetect.push({p:2,test:(...$)=>{if($=H($,f),v($)==="array"&&$.length===3)return f}}));Y.prototype.saturate=function(f=1){let $=this,Q=$.lch();if(Q[1]+=z0.Kn*f,Q[1]<0)Q[1]=0;return new Y(Q,"lch").alpha($.alpha(),!0)};Y.prototype.desaturate=function(f=1){return this.saturate(-f)};Y.prototype.set=function(f,$,Q=!1){let[U,J]=f.split("."),N=this[U]();if(J){let q=U.indexOf(J)-(U.substr(0,2)==="ok"?2:0);if(q>-1){if(v($)=="string")switch($.charAt(0)){case"+":N[q]+=+$;break;case"-":N[q]+=+$;break;case"*":N[q]*=+$.substr(1);break;case"/":N[q]/=+$.substr(1);break;default:N[q]=+$}else if(v($)==="number")N[q]=$;else throw Error("unsupported value for Color.set");let Z=new Y(N,U);if(Q)return this._rgb=Z._rgb,this;return Z}throw Error(`unknown channel ${J} in mode ${U}`)}else return N};Y.prototype.tint=function(f=0.5,...$){return O0(this,"white",f,...$)};Y.prototype.shade=function(f=0.5,...$){return O0(this,"black",f,...$)};var J4=(f,$,Q)=>{let U=f._rgb,J=$._rgb;return new Y(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"rgb")};x.rgb=J4;var{sqrt:l1,pow:Kf}=Math,N4=(f,$,Q)=>{let[U,J,N]=f._rgb,[q,Z,D]=$._rgb;return new Y(l1(Kf(U,2)*(1-Q)+Kf(q,2)*Q),l1(Kf(J,2)*(1-Q)+Kf(Z,2)*Q),l1(Kf(N,2)*(1-Q)+Kf(D,2)*Q),"rgb")};x.lrgb=N4;var q4=(f,$,Q)=>{let U=f.lab(),J=$.lab();return new Y(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"lab")};x.lab=q4;var V0=(f,$,Q,U)=>{let J,N;if(U==="hsl")J=f.hsl(),N=$.hsl();else if(U==="hsv")J=f.hsv(),N=$.hsv();else if(U==="hcg")J=f.hcg(),N=$.hcg();else if(U==="hsi")J=f.hsi(),N=$.hsi();else if(U==="lch"||U==="hcl")U="hcl",J=f.hcl(),N=$.hcl();else if(U==="oklch")J=f.oklch().reverse(),N=$.oklch().reverse();let q,Z,D,X,K,F;if(U.substr(0,1)==="h"||U==="oklch")[q,D,K]=J,[Z,X,F]=N;let V,G,B,S;if(!isNaN(q)&&!isNaN(Z)){if(Z>q&&Z-q>180)S=Z-(q+360);else if(Z180)S=Z+360-q;else S=Z-q;G=q+Q*S}else if(!isNaN(q)){if(G=q,(F==1||F==0)&&U!="hsv")V=D}else if(!isNaN(Z)){if(G=Z,(K==1||K==0)&&U!="hsv")V=X}else G=Number.NaN;if(V===void 0)V=D+Q*(X-D);return B=K+Q*(F-K),U==="oklch"?new Y([B,V,G],U):new Y([G,V,B],U)};var n5=(f,$,Q)=>{return V0(f,$,Q,"lch")};x.lch=n5;x.hcl=n5;var Z4=(f)=>{if(v(f)=="number"&&f>=0&&f<=16777215){let $=f>>16,Q=f>>8&255,U=f&255;return[$,Q,U,1]}throw Error("unknown num color: "+f)},t5=Z4;var D4=(...f)=>{let[$,Q,U]=H(f,"rgb");return($<<16)+(Q<<8)+U},d5=D4;Y.prototype.num=function(){return d5(this._rgb)};var X4=(...f)=>new Y(...f,"num");Object.assign(C,{num:X4});R.format.num=t5;R.autodetect.push({p:5,test:(...f)=>{if(f.length===1&&v(f[0])==="number"&&f[0]>=0&&f[0]<=16777215)return"num"}});var K4=(f,$,Q)=>{let U=f.num(),J=$.num();return new Y(U+Q*(J-U),"num")};x.num=K4;var{floor:F4}=Math,V4=(...f)=>{f=H(f,"hcg");let[$,Q,U]=f,J,N,q;U=U*255;let Z=Q*255;if(Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let D=F4($),X=$-D,K=U*(1-Q),F=K+Z*(1-X),V=K+Z*X,G=K+Z;switch(D){case 0:[J,N,q]=[G,V,K];break;case 1:[J,N,q]=[F,G,K];break;case 2:[J,N,q]=[K,G,V];break;case 3:[J,N,q]=[K,F,G];break;case 4:[J,N,q]=[V,K,G];break;case 5:[J,N,q]=[G,K,F];break}}return[J,N,q,f.length>3?f[3]:1]},x5=V4;var y4=(...f)=>{let[$,Q,U]=H(f,"rgb"),J=lf($,Q,U),N=af($,Q,U),q=N-J,Z=q*100/255,D=J/(255-q)*100,X;if(q===0)X=Number.NaN;else{if($===N)X=(Q-U)/q;if(Q===N)X=2+(U-$)/q;if(U===N)X=4+($-Q)/q;if(X*=60,X<0)X+=360}return[X,Z,D]},h5=y4;Y.prototype.hcg=function(){return h5(this._rgb)};var W4=(...f)=>new Y(...f,"hcg");C.hcg=W4;R.format.hcg=x5;R.autodetect.push({p:1,test:(...f)=>{if(f=H(f,"hcg"),v(f)==="array"&&f.length===3)return"hcg"}});var Y4=(f,$,Q)=>{return V0(f,$,Q,"hcg")};x.hcg=Y4;var{cos:Ff}=Math,G4=(...f)=>{f=H(f,"hsi");let[$,Q,U]=f,J,N,q;if(isNaN($))$=0;if(isNaN(Q))Q=0;if($>360)$-=360;if($<0)$+=360;if($/=360,$<0.3333333333333333)q=(1-Q)/3,J=(1+Q*Ff(K0*$)/Ff(sf-K0*$))/3,N=1-(q+J);else if($<0.6666666666666666)$-=0.3333333333333333,J=(1-Q)/3,N=(1+Q*Ff(K0*$)/Ff(sf-K0*$))/3,q=1-(J+N);else $-=0.6666666666666666,N=(1-Q)/3,q=(1+Q*Ff(K0*$)/Ff(sf-K0*$))/3,J=1-(N+q);return J=X0(U*J*3),N=X0(U*N*3),q=X0(U*q*3),[J*255,N*255,q*255,f.length>3?f[3]:1]},b5=G4;var{min:I4,sqrt:w4,acos:u4}=Math,B4=(...f)=>{let[$,Q,U]=H(f,"rgb");$/=255,Q/=255,U/=255;let J,N=I4($,Q,U),q=($+Q+U)/3,Z=q>0?1-N/q:0;if(Z===0)J=NaN;else{if(J=($-Q+($-U))/2,J/=w4(($-Q)*($-Q)+($-U)*(Q-U)),J=u4(J),U>Q)J=K0-J;J/=K0}return[J*360,Z,q]},r5=B4;Y.prototype.hsi=function(){return r5(this._rgb)};var E4=(...f)=>new Y(...f,"hsi");C.hsi=E4;R.format.hsi=b5;R.autodetect.push({p:2,test:(...f)=>{if(f=H(f,"hsi"),v(f)==="array"&&f.length===3)return"hsi"}});var k4=(f,$,Q)=>{return V0(f,$,Q,"hsi")};x.hsi=k4;var z4=(...f)=>{f=H(f,"hsl");let[$,Q,U]=f,J,N,q;if(Q===0)J=N=q=U*255;else{let Z=[0,0,0],D=[0,0,0],X=U<0.5?U*(1+Q):U+Q-U*Q,K=2*U-X,F=$/360;Z[0]=F+0.3333333333333333,Z[1]=F,Z[2]=F-0.3333333333333333;for(let V=0;V<3;V++){if(Z[V]<0)Z[V]+=1;if(Z[V]>1)Z[V]-=1;if(6*Z[V]<1)D[V]=K+(X-K)*6*Z[V];else if(2*Z[V]<1)D[V]=X;else if(3*Z[V]<2)D[V]=K+(X-K)*(0.6666666666666666-Z[V])*6;else D[V]=K}[J,N,q]=[D[0]*255,D[1]*255,D[2]*255]}if(f.length>3)return[J,N,q,f[3]];return[J,N,q,1]},Mf=z4;var O4=(...f)=>{f=H(f,"rgba");let[$,Q,U]=f;$/=255,Q/=255,U/=255;let J=lf($,Q,U),N=af($,Q,U),q=(N+J)/2,Z,D;if(N===J)Z=0,D=Number.NaN;else Z=q<0.5?(N-J)/(N+J):(N-J)/(2-N-J);if($==N)D=(Q-U)/(N-J);else if(Q==N)D=2+(U-$)/(N-J);else if(U==N)D=4+($-Q)/(N-J);if(D*=60,D<0)D+=360;if(f.length>3&&f[3]!==void 0)return[D,Z,q,f[3]];return[D,Z,q]},q1=O4;Y.prototype.hsl=function(){return q1(this._rgb)};var H4=(...f)=>new Y(...f,"hsl");C.hsl=H4;R.format.hsl=Mf;R.autodetect.push({p:2,test:(...f)=>{if(f=H(f,"hsl"),v(f)==="array"&&f.length===3)return"hsl"}});var S4=(f,$,Q)=>{return V0(f,$,Q,"hsl")};x.hsl=S4;var{floor:p4}=Math,M4=(...f)=>{f=H(f,"hsv");let[$,Q,U]=f,J,N,q;if(U*=255,Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let Z=p4($),D=$-Z,X=U*(1-Q),K=U*(1-Q*D),F=U*(1-Q*(1-D));switch(Z){case 0:[J,N,q]=[U,F,X];break;case 1:[J,N,q]=[K,U,X];break;case 2:[J,N,q]=[X,U,F];break;case 3:[J,N,q]=[X,K,U];break;case 4:[J,N,q]=[F,X,U];break;case 5:[J,N,q]=[U,X,K];break}}return[J,N,q,f.length>3?f[3]:1]},g5=M4;var{min:P4,max:T4}=Math,v4=(...f)=>{f=H(f,"rgb");let[$,Q,U]=f,J=P4($,Q,U),N=T4($,Q,U),q=N-J,Z,D,X;if(X=N/255,N===0)Z=Number.NaN,D=0;else{if(D=q/N,$===N)Z=(Q-U)/q;if(Q===N)Z=2+(U-$)/q;if(U===N)Z=4+($-Q)/q;if(Z*=60,Z<0)Z+=360}return[Z,D,X]},i5=v4;Y.prototype.hsv=function(){return i5(this._rgb)};var L4=(...f)=>new Y(...f,"hsv");C.hsv=L4;R.format.hsv=g5;R.autodetect.push({p:2,test:(...f)=>{if(f=H(f,"hsv"),v(f)==="array"&&f.length===3)return"hsv"}});var j4=(f,$,Q)=>{return V0(f,$,Q,"hsv")};x.hsv=j4;function o0(f,$){let Q=f.length;if(!Array.isArray(f[0]))f=[f];if(!Array.isArray($[0]))$=$.map((q)=>[q]);let U=$[0].length,J=$[0].map((q,Z)=>$.map((D)=>D[Z])),N=f.map((q)=>J.map((Z)=>{if(!Array.isArray(q))return Z.reduce((D,X)=>D+X*q,0);return q.reduce((D,X,K)=>D+X*(Z[K]||0),0)}));if(Q===1)N=N[0];if(U===1)return N.map((q)=>q[0]);return N}var R4=(...f)=>{f=H(f,"lab");let[$,Q,U,...J]=f,[N,q,Z]=A4([$,Q,U]),[D,X,K]=i1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function A4(f){var $=[[1.2268798758459243,-0.5578149944602171,0.2813910456659647],[-0.0405757452148008,1.112286803280317,-0.0717110580655164],[-0.0763729366746601,-0.4214933324022432,1.5869240198367816]],Q=[[1,0.3963377773761749,0.2158037573099136],[1,-0.1055613458156586,-0.0638541728258133],[1,-0.0894841775298119,-1.2914855480194092]],U=o0(Q,f);return o0($,U.map((J)=>J**3))}var Vf=R4;var m4=(...f)=>{let[$,Q,U,...J]=H(f,"rgb"),N=o1($,Q,U);return[..._4(N),...J.length>0&&J[0]<1?[J[0]]:[]]};function _4(f){let $=[[0.819022437996703,0.3619062600528904,-0.1288737815209879],[0.0329836539323885,0.9292868615863434,0.0361446663506424],[0.0481771893596242,0.2642395317527308,0.6335478284694309]],Q=[[0.210454268309314,0.7936177747023054,-0.0040720430116193],[1.9779985324311684,-2.42859224204858,0.450593709617411],[0.0259040424655478,0.7827717124575296,-0.8086757549230774]],U=o0($,f);return o0(Q,U.map((J)=>Math.cbrt(J)))}var yf=m4;Y.prototype.oklab=function(){return yf(this._rgb)};var C4=(...f)=>new Y(...f,"oklab");Object.assign(C,{oklab:C4});R.format.oklab=Vf;R.autodetect.push({p:2,test:(...f)=>{if(f=H(f,"oklab"),v(f)==="array"&&f.length===3)return"oklab"}});var n4=(f,$,Q)=>{let U=f.oklab(),J=$.oklab();return new Y(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"oklab")};x.oklab=n4;var t4=(f,$,Q)=>{return V0(f,$,Q,"oklch")};x.oklch=t4;var{pow:a1,sqrt:s1,PI:f2,cos:c5,sin:o5,atan2:d4}=Math,e5=(f,$="lrgb",Q=null)=>{let U=f.length;if(!Q)Q=Array.from(Array(U)).map(()=>1);let J=U/Q.reduce(function(F,V){return F+V});if(Q.forEach((F,V)=>{Q[V]*=J}),f=f.map((F)=>new Y(F)),$==="lrgb")return x4(f,Q);let N=f.shift(),q=N.get($),Z=[],D=0,X=0;for(let F=0;F{let G=F.get($);K+=F.alpha()*Q[V+1];for(let B=0;B=360)V-=360;q[F]=V}else q[F]=q[F]/Z[F];return K/=U,new Y(q,$).alpha(K>0.99999?1:K,!0)},x4=(f,$)=>{let Q=f.length,U=[0,0,0,0];for(let J=0;J0.9999999)U[3]=1;return new Y(c0(U))};var{pow:h4}=Math;function C0(f){let $="rgb",Q=C("#ccc"),U=0,J=[0,1],N=[],q=[0,0],Z=!1,D=[],X=!1,K=0,F=1,V=!1,G={},B=!0,S=1,u=function(I){if(I=I||["#fff","#000"],I&&v(I)==="string"&&C.brewer&&C.brewer[I.toLowerCase()])I=C.brewer[I.toLowerCase()];if(v(I)==="array"){if(I.length===1)I=[I[0],I[0]];I=I.slice(0);for(let y=0;y=Z[E])E++;return E-1}return 0},m=(I)=>I,L=(I)=>I,p=function(I,y){let E,k;if(y==null)y=!1;if(isNaN(I)||I===null)return Q;if(!y)if(Z&&Z.length>2)k=w(I)/(Z.length-2);else if(F!==K)k=(I-K)/(F-K);else k=1;else k=I;if(k=L(k),!y)k=m(k);if(S!==1)k=h4(k,S);k=q[0]+k*(1-q[0]-q[1]),k=X0(k,0,1);let z=Math.floor(k*1e4);if(B&&G[z])E=G[z];else{if(v(D)==="array")for(let P=0;P=M&&P===N.length-1){E=D[P];break}if(k>M&&kG={};u(f);let A=function(I){let y=C(p(I));if(X&&y[X])return y[X]();else return y};return A.classes=function(I){if(I!=null){if(v(I)==="array")Z=I,J=[I[0],I[I.length-1]];else{let y=C.analyze(J);if(I===0)Z=[y.min,y.max];else Z=C.limits(y,"e",I)}return A}return Z},A.domain=function(I){if(!arguments.length)return J;K=I[0],F=I[I.length-1],N=[];let y=D.length;if(I.length===y&&K!==F)for(let E of Array.from(I))N.push((E-K)/(F-K));else{for(let E=0;E2){let E=I.map((z,P)=>P/(I.length-1)),k=I.map((z)=>(z-K)/(F-K));if(!k.every((z,P)=>E[P]===z))L=(z)=>{if(z<=0||z>=1)return z;let P=0;while(z>=k[P+1])P++;let M=(z-k[P])/(k[P+1]-k[P]);return E[P]+M*(E[P+1]-E[P])}}}return J=[K,F],A},A.mode=function(I){if(!arguments.length)return $;return $=I,n(),A},A.range=function(I,y){return u(I,y),A},A.out=function(I){return X=I,A},A.spread=function(I){if(!arguments.length)return U;return U=I,A},A.correctLightness=function(I){if(I==null)I=!0;if(V=I,n(),V)m=function(y){let E=p(0,!0).lab()[0],k=p(1,!0).lab()[0],z=E>k,P=p(y,!0).lab()[0],M=E+(k-E)*y,b=P-M,e=0,Y0=1,B0=20;while(Math.abs(b)>0.01&&B0-- >0)(function(){if(z)b*=-1;if(b<0)e=y,y+=(Y0-y)*0.5;else Y0=y,y+=(e-y)*0.5;return P=p(y,!0).lab()[0],b=P-M})();return y};else m=(y)=>y;return A},A.padding=function(I){if(I!=null){if(v(I)==="number")I=[I,I];return q=I,A}else return q},A.colors=function(I,y){if(arguments.length<2)y="hex";let E=[];if(arguments.length===0)E=D.slice(0);else if(I===1)E=[A(0.5)];else if(I>1){let k=J[0],z=J[1]-k;E=b4(0,I,!1).map((P)=>A(k+P/(I-1)*z))}else{f=[];let k=[];if(Z&&Z.length>2)for(let z=1,P=Z.length,M=1<=P;M?zP;M?z++:z--)k.push((Z[z-1]+Z[z])*0.5);else k=J;E=k.map((z)=>A(z))}if(C[y])E=E.map((k)=>k[y]());return E},A.cache=function(I){if(I!=null)return B=I,A;else return B},A.gamma=function(I){if(I!=null)return S=I,A;else return S},A.nodata=function(I){if(I!=null)return Q=C(I),A;else return Q},A}function b4(f,$,Q){let U=[],J=f<$,N=!Q?$:J?$+1:$-1;for(let q=f;J?qN;J?q++:q--)U.push(q);return U}var r4=function(f){let $=[1,1];for(let Q=1;Qnew Y(N)),f.length===2)[Q,U]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>Q[Z]+N*(U[Z]-Q[Z]));return new Y(q,"lab")};else if(f.length===3)[Q,U,J]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>(1-N)*(1-N)*Q[Z]+2*(1-N)*N*U[Z]+N*N*J[Z]);return new Y(q,"lab")};else if(f.length===4){let N;[Q,U,J,N]=f.map((q)=>q.lab()),$=function(q){let Z=[0,1,2].map((D)=>(1-q)*(1-q)*(1-q)*Q[D]+3*(1-q)*(1-q)*q*U[D]+3*(1-q)*q*q*J[D]+q*q*q*N[D]);return new Y(Z,"lab")}}else if(f.length>=5){let N,q,Z;N=f.map((D)=>D.lab()),Z=f.length-1,q=r4(Z),$=function(D){let X=1-D,K=[0,1,2].map((F)=>N.reduce((V,G,B)=>V+q[B]*X**(Z-B)*D**B*G[F],0));return new Y(K,"lab")}}else throw RangeError("No point in running bezier with only one color.");return $},l5=(f)=>{let $=g4(f);return $.scale=()=>C0($),$};var{round:a5}=Math;Y.prototype.rgb=function(f=!0){if(f===!1)return this._rgb.slice(0,3);return this._rgb.slice(0,3).map(a5)};Y.prototype.rgba=function(f=!0){return this._rgb.slice(0,4).map(($,Q)=>{return Q<3?f===!1?$:a5($):$})};var i4=(...f)=>new Y(...f,"rgb");Object.assign(C,{rgb:i4});R.format.rgb=(...f)=>{let $=H(f,"rgba");if($[3]===void 0)$[3]=1;return $};R.autodetect.push({p:3,test:(...f)=>{if(f=H(f,"rgba"),v(f)==="array"&&(f.length===3||f.length===4&&v(f[3])=="number"&&f[3]>=0&&f[3]<=1))return"rgb"}});var w0=(f,$,Q)=>{if(!w0[Q])throw Error("unknown blend mode "+Q);return w0[Q](f,$)},n0=(f)=>($,Q)=>{let U=C(Q).rgb(),J=C($).rgb();return C.rgb(f(U,J))},t0=(f)=>($,Q)=>{let U=[];return U[0]=f($[0],Q[0]),U[1]=f($[1],Q[1]),U[2]=f($[2],Q[2]),U},c4=(f)=>f,o4=(f,$)=>f*$/255,e4=(f,$)=>f>$?$:f,l4=(f,$)=>f>$?f:$,a4=(f,$)=>255*(1-(1-f/255)*(1-$/255)),s4=(f,$)=>$<128?2*f*$/255:255*(1-2*(1-f/255)*(1-$/255)),f$=(f,$)=>255*(1-(1-$/255)/(f/255)),$$=(f,$)=>{if(f===255)return 255;return f=255*($/255)/(1-f/255),f>255?255:f};w0.normal=n0(t0(c4));w0.multiply=n0(t0(o4));w0.screen=n0(t0(a4));w0.overlay=n0(t0(s4));w0.darken=n0(t0(e4));w0.lighten=n0(t0(l4));w0.dodge=n0(t0($$));w0.burn=n0(t0(f$));var s5=w0;var{pow:Q$,sin:U$,cos:J$}=Math;function $2(f=300,$=-1.5,Q=1,U=1,J=[0,1]){let N=0,q;if(v(J)==="array")q=J[1]-J[0];else q=0,J=[J,J];let Z=function(D){let X=K0*((f+120)/360+$*D),K=Q$(J[0]+q*D,U),V=(N!==0?Q[0]+D*N:Q)*K*(1-K)/2,G=J$(X),B=U$(X),S=K+V*(-0.14861*G+1.78277*B),u=K+V*(-0.29227*G-0.90649*B),w=K+V*(1.97294*G);return C(c0([S*255,u*255,w*255,1]))};return Z.start=function(D){if(D==null)return f;return f=D,Z},Z.rotations=function(D){if(D==null)return $;return $=D,Z},Z.gamma=function(D){if(D==null)return U;return U=D,Z},Z.hue=function(D){if(D==null)return Q;if(Q=D,v(Q)==="array"){if(N=Q[1]-Q[0],N===0)Q=Q[1]}else N=0;return Z},Z.lightness=function(D){if(D==null)return J;if(v(D)==="array")J=D,q=D[1]-D[0];else J=[D,D],q=0;return Z},Z.scale=()=>C.scale(Z),Z.hue(Q),Z}var N$="0123456789abcdef",{floor:q$,random:Z$}=Math,f6=()=>{let f="#";for(let $=0;$<6;$++)f+=N$.charAt(q$(Z$()*16));return new Y(f,"hex")};var{log:$6,pow:D$,floor:X$,abs:K$}=Math;function Q2(f,$=null){let Q={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};if(v(f)==="object")f=Object.values(f);return f.forEach((U)=>{if($&&v(U)==="object")U=U[$];if(U!==void 0&&U!==null&&!isNaN(U)){if(Q.values.push(U),Q.sum+=U,UQ.max)Q.max=U;Q.count+=1}}),Q.domain=[Q.min,Q.max],Q.limits=(U,J)=>U2(Q,U,J),Q}function U2(f,$="equal",Q=7){if(v(f)=="array")f=Q2(f);let{min:U,max:J}=f,N=f.values.sort((Z,D)=>Z-D);if(Q===1)return[U,J];let q=[];if($.substr(0,1)==="c")q.push(U),q.push(J);if($.substr(0,1)==="e"){q.push(U);for(let Z=1;Z 0");let Z=Math.LOG10E*$6(U),D=Math.LOG10E*$6(J);q.push(U);for(let X=1;X200)F=!1}let B={};for(let u=0;uu-w),q.push(S[0]);for(let u=1;u{f=new Y(f),$=new Y($);let Q=f.luminance(),U=$.luminance();return Q>U?(Q+0.05)/(U+0.05):(U+0.05)/(Q+0.05)};var U6=0.027,F$=0.0005,V$=0.1,J6=1.14,Z1=0.022,N6=1.414,Z6=(f,$)=>{if(f=new Y(f),$=new Y($),f.alpha()<1)f=O0($,f,f.alpha(),"rgb");let Q=q6(...f.rgb()),U=q6(...$.rgb()),J=Q>=Z1?Q:Q+Math.pow(Z1-Q,N6),N=U>=Z1?U:U+Math.pow(Z1-U,N6),q=Math.pow(N,0.56)-Math.pow(J,0.57),Z=Math.pow(N,0.65)-Math.pow(J,0.62),D=Math.abs(N-J)0?D-U6:D+U6)*100};function q6(f,$,Q){return 0.2126729*Math.pow(f/255,2.4)+0.7151522*Math.pow($/255,2.4)+0.072175*Math.pow(Q/255,2.4)}var{sqrt:M0,pow:c,min:y$,max:W$,atan2:D6,abs:X6,cos:D1,sin:K6,exp:Y$,PI:F6}=Math;function J2(f,$,Q=1,U=1,J=1){var N=function(r0){return 360*r0/(2*F6)},q=function(r0){return 2*F6*r0/360};f=new Y(f),$=new Y($);let[Z,D,X]=Array.from(f.lab()),[K,F,V]=Array.from($.lab()),G=(Z+K)/2,B=M0(c(D,2)+c(X,2)),S=M0(c(F,2)+c(V,2)),u=(B+S)/2,w=0.5*(1-M0(c(u,7)/(c(u,7)+c(25,7)))),m=D*(1+w),L=F*(1+w),p=M0(c(m,2)+c(X,2)),n=M0(c(L,2)+c(V,2)),A=(p+n)/2,I=N(D6(X,m)),y=N(D6(V,L)),E=I>=0?I:I+360,k=y>=0?y:y+360,z=X6(E-k)>180?(E+k+360)/2:(E+k)/2,P=1-0.17*D1(q(z-30))+0.24*D1(q(2*z))+0.32*D1(q(3*z+6))-0.2*D1(q(4*z-63)),M=k-E;M=X6(M)<=180?M:k<=E?M+360:M-360,M=2*M0(p*n)*K6(q(M)/2);let b=K-Z,e=n-p,Y0=1+0.015*c(G-50,2)/M0(20+c(G-50,2)),B0=1+0.045*A,b0=1+0.015*A*P,O1=30*Y$(-c((z-275)/25,2)),H1=-(2*M0(c(A,7)/(c(A,7)+c(25,7))))*K6(2*q(O1)),S1=M0(c(b/(Q*Y0),2)+c(e/(U*B0),2)+c(M/(J*b0),2)+H1*(e/(U*B0))*(M/(J*b0)));return W$(0,y$(100,S1))}function N2(f,$,Q="lab"){f=new Y(f),$=new Y($);let U=f.get(Q),J=$.get(Q),N=0;for(let q in U){let Z=(U[q]||0)-(J[q]||0);N+=Z*Z}return Math.sqrt(N)}var V6=(...f)=>{try{return new Y(...f),!0}catch($){return!1}};var y6={cool(){return C0([C.hsl(180,1,0.9),C.hsl(250,0.7,0.4)])},hot(){return C0(["#000","#f00","#ff0","#fff"],[0,0.25,0.75,1]).mode("rgb")}};var q2={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Viridis:["#440154","#482777","#3f4a8a","#31678e","#26838f","#1f9d8a","#6cce5a","#b6de2b","#fee825"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]},Y6=Object.keys(q2),W6=new Map(Y6.map((f)=>[f.toLowerCase(),f])),G$=typeof Proxy==="function"?new Proxy(q2,{get(f,$){let Q=$.toLowerCase();if(W6.has(Q))return f[W6.get(Q)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(Y6)}}):q2,G6=G$;var I$=(...f)=>{f=H(f,"cmyk");let[$,Q,U,J]=f,N=f.length>4?f[4]:1;if(J===1)return[0,0,0,N];return[$>=1?0:255*(1-$)*(1-J),Q>=1?0:255*(1-Q)*(1-J),U>=1?0:255*(1-U)*(1-J),N]},I6=I$;var{max:w6}=Math,w$=(...f)=>{let[$,Q,U]=H(f,"rgb");$=$/255,Q=Q/255,U=U/255;let J=1-w6($,w6(Q,U)),N=J<1?1/(1-J):0,q=(1-$-J)*N,Z=(1-Q-J)*N,D=(1-U-J)*N;return[q,Z,D,J]},u6=w$;Y.prototype.cmyk=function(){return u6(this._rgb)};var u$=(...f)=>new Y(...f,"cmyk");Object.assign(C,{cmyk:u$});R.format.cmyk=I6;R.autodetect.push({p:2,test:(...f)=>{if(f=H(f,"cmyk"),v(f)==="array"&&f.length===4)return"cmyk"}});var B$=(...f)=>{let $=H(f,"hsla"),Q=U0(f)||"lsa";if($[0]=a($[0]||0)+"deg",$[1]=a($[1]*100)+"%",$[2]=a($[2]*100)+"%",Q==="hsla"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="hsla";else $.length=3;return`${Q.substr(0,3)}(${$.join(" ")})`},B6=B$;var E$=(...f)=>{let $=H(f,"lab"),Q=U0(f)||"lab";if($[0]=a($[0])+"%",$[1]=a($[1]),$[2]=a($[2]),Q==="laba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lab(${$.join(" ")})`},E6=E$;var k$=(...f)=>{let $=H(f,"lch"),Q=U0(f)||"lab";if($[0]=a($[0])+"%",$[1]=a($[1]),$[2]=isNaN($[2])?"none":a($[2])+"deg",Q==="lcha"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lch(${$.join(" ")})`},k6=k$;var z$=(...f)=>{let $=H(f,"lab");if($[0]=a($[0]*100)+"%",$[1]=Hf($[1]),$[2]=Hf($[2]),$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklab(${$.join(" ")})`},z6=z$;var O$=(...f)=>{let[$,Q,U,...J]=H(f,"rgb"),[N,q,Z]=yf($,Q,U),[D,X,K]=N1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},X1=O$;var H$=(...f)=>{let $=H(f,"lch");if($[0]=a($[0]*100)+"%",$[1]=Hf($[1]),$[2]=isNaN($[2])?"none":a($[2])+"deg",$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklch(${$.join(" ")})`},O6=H$;var{round:Z2}=Math,S$=(...f)=>{let $=H(f,"rgba"),Q=U0(f)||"rgb";if(Q.substr(0,3)==="hsl")return B6(q1($),Q);if(Q.substr(0,3)==="lab"){let U=_0();F0("d50");let J=E6(Df($),Q);return F0(U),J}if(Q.substr(0,3)==="lch"){let U=_0();F0("d50");let J=k6(pf($),Q);return F0(U),J}if(Q.substr(0,5)==="oklab")return z6(yf($));if(Q.substr(0,5)==="oklch")return O6(X1($));if($[0]=Z2($[0]),$[1]=Z2($[1]),$[2]=Z2($[2]),Q==="rgba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="rgba";return`${Q.substr(0,3)}(${$.slice(0,Q==="rgb"?3:4).join(" ")})`},H6=S$;var p$=(...f)=>{f=H(f,"lch");let[$,Q,U,...J]=f,[N,q,Z]=J1($,Q,U),[D,X,K]=Vf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},K1=p$;var P0=/((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source,u0=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source,F1=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source,y0=/\s*/.source,Yf=/\s+/.source,D2=/\s*,\s*/.source,V1=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source,Gf=/\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source,S6=new RegExp("^rgba?\\("+y0+[P0,P0,P0].join(Yf)+Gf+"\\)$"),p6=new RegExp("^rgb\\("+y0+[P0,P0,P0].join(D2)+y0+"\\)$"),M6=new RegExp("^rgba\\("+y0+[P0,P0,P0,u0].join(D2)+y0+"\\)$"),P6=new RegExp("^hsla?\\("+y0+[V1,F1,F1].join(Yf)+Gf+"\\)$"),T6=new RegExp("^hsl?\\("+y0+[V1,F1,F1].join(D2)+y0+"\\)$"),v6=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,L6=new RegExp("^lab\\("+y0+[u0,u0,u0].join(Yf)+Gf+"\\)$"),j6=new RegExp("^lch\\("+y0+[u0,u0,V1].join(Yf)+Gf+"\\)$"),R6=new RegExp("^oklab\\("+y0+[u0,u0,u0].join(Yf)+Gf+"\\)$"),A6=new RegExp("^oklch\\("+y0+[u0,u0,V1].join(Yf)+Gf+"\\)$"),{round:m6}=Math,Wf=(f)=>{return f.map(($,Q)=>Q<=2?X0(m6($),0,255):$)},o=(f,$=0,Q=100,U=!1)=>{if(typeof f==="string"&&f.endsWith("%"))if(f=parseFloat(f.substring(0,f.length-1))/100,U)f=$+(f+1)*0.5*(Q-$);else f=$+f*(Q-$);return+f},$0=(f,$)=>{return f==="none"?$:f},_6=(f)=>{if(f=f.toLowerCase().trim(),f==="transparent")return[0,0,0,0];let $;if(R.format.named)try{return R.format.named(f)}catch(Q){}if(($=f.match(S6))||($=f.match(p6))){let Q=$.slice(1,4);for(let J=0;J<3;J++)Q[J]=+o($0(Q[J],0),0,255);Q=Wf(Q);let U=$[4]!==void 0?+o($[4],0,1):1;return Q[3]=U,Q}if($=f.match(M6)){let Q=$.slice(1,5);for(let U=0;U<4;U++)Q[U]=+o(Q[U],0,255);return Q}if(($=f.match(P6))||($=f.match(T6))){let Q=$.slice(1,4);Q[0]=+$0(Q[0].replace("deg",""),0),Q[1]=+o($0(Q[1],0),0,100)*0.01,Q[2]=+o($0(Q[2],0),0,100)*0.01;let U=Wf(Mf(Q)),J=$[4]!==void 0?+o($[4],0,1):1;return U[3]=J,U}if($=f.match(v6)){let Q=$.slice(1,4);Q[1]*=0.01,Q[2]*=0.01;let U=Mf(Q);for(let J=0;J<3;J++)U[J]=m6(U[J]);return U[3]=+$[4],U}if($=f.match(L6)){let Q=$.slice(1,4);Q[0]=o($0(Q[0],0),0,100),Q[1]=o($0(Q[1],0),-125,125,!0),Q[2]=o($0(Q[2],0),-125,125,!0);let U=_0();F0("d50");let J=Wf(Zf(Q));F0(U);let N=$[4]!==void 0?+o($[4],0,1):1;return J[3]=N,J}if($=f.match(j6)){let Q=$.slice(1,4);Q[0]=o(Q[0],0,100),Q[1]=o($0(Q[1],0),0,150,!1),Q[2]=+$0(Q[2].replace("deg",""),0);let U=_0();F0("d50");let J=Wf(Xf(Q));F0(U);let N=$[4]!==void 0?+o($[4],0,1):1;return J[3]=N,J}if($=f.match(R6)){let Q=$.slice(1,4);Q[0]=o($0(Q[0],0),0,1),Q[1]=o($0(Q[1],0),-0.4,0.4,!0),Q[2]=o($0(Q[2],0),-0.4,0.4,!0);let U=Wf(Vf(Q)),J=$[4]!==void 0?+o($[4],0,1):1;return U[3]=J,U}if($=f.match(A6)){let Q=$.slice(1,4);Q[0]=o($0(Q[0],0),0,1),Q[1]=o($0(Q[1],0),0,0.4,!1),Q[2]=+$0(Q[2].replace("deg",""),0);let U=Wf(K1(Q)),J=$[4]!==void 0?+o($[4],0,1):1;return U[3]=J,U}};_6.test=(f)=>{return S6.test(f)||P6.test(f)||L6.test(f)||j6.test(f)||R6.test(f)||A6.test(f)||p6.test(f)||M6.test(f)||T6.test(f)||v6.test(f)||f==="transparent"};var X2=_6;Y.prototype.css=function(f){return H6(this._rgb,f)};var M$=(...f)=>new Y(...f,"css");C.css=M$;R.format.css=X2;R.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&v(f)==="string"&&X2.test(f))return"css"}});R.format.gl=(...f)=>{let $=H(f,"rgba");return $[0]*=255,$[1]*=255,$[2]*=255,$};var P$=(...f)=>new Y(...f,"gl");C.gl=P$;Y.prototype.gl=function(){let f=this._rgb;return[f[0]/255,f[1]/255,f[2]/255,f[3]]};Y.prototype.hex=function(f){return U1(this._rgb,f)};var T$=(...f)=>new Y(...f,"hex");C.hex=T$;R.format.hex=$1;R.autodetect.push({p:4,test:(f,...$)=>{if(!$.length&&v(f)==="string"&&[3,4,5,6,7,8,9].indexOf(f.length)>=0)return"hex"}});var{log:y1}=Math,v$=(f)=>{let $=f/100,Q,U,J;if($<66)Q=255,U=$<6?0:-155.25485562709179-0.44596950469579133*(U=$-2)+104.49216199393888*y1(U),J=$<20?0:-254.76935184120902+0.8274096064007395*(J=$-10)+115.67994401066147*y1(J);else Q=351.97690566805693+0.114206453784165*(Q=$-55)-40.25366309332127*y1(Q),U=325.4494125711974+0.07943456536662342*(U=$-50)-28.0852963507957*y1(U),J=255;return[Q,U,J,1]},W1=v$;var{round:L$}=Math,j$=(...f)=>{let $=H(f,"rgb"),Q=$[0],U=$[2],J=1000,N=40000,q=0.4,Z;while(N-J>q){Z=(N+J)*0.5;let D=W1(Z);if(D[2]/D[0]>=U/Q)N=Z;else J=Z}return L$(Z)},C6=j$;Y.prototype.temp=Y.prototype.kelvin=Y.prototype.temperature=function(){return C6(this._rgb)};var K2=(...f)=>new Y(...f,"temp");Object.assign(C,{temp:K2,kelvin:K2,temperature:K2});R.format.temp=R.format.kelvin=R.format.temperature=W1;Y.prototype.oklch=function(){return X1(this._rgb)};var R$=(...f)=>new Y(...f,"oklch");Object.assign(C,{oklch:R$});R.format.oklch=K1;R.autodetect.push({p:2,test:(...f)=>{if(f=H(f,"oklch"),v(f)==="array"&&f.length===3)return"oklch"}});Object.assign(C,{analyze:Q2,average:e5,bezier:l5,blend:s5,brewer:G6,Color:Y,colors:m0,contrast:Q6,contrastAPCA:Z6,cubehelix:$2,deltaE:J2,distance:N2,input:R,interpolate:O0,limits:U2,mix:O0,random:f6,scale:C0,scales:y6,valid:V6});var t=C;var F2=(f)=>{return typeof f==="number"&&!isNaN(f)&&isFinite(f)},H0=(f,$,Q)=>{if(!F2(f))return $;return Math.max($,Math.min(Q,f))},W0=(f,$,Q)=>{try{if(!F2(f)||!F2($)||$<=0)return 0;let U=f/($-1);switch(Q){case"geometric":return A$(f,$);case"fibonacci":return m$($)[f]||0;case"golden-ratio":return _$($)[f]||0;case"logarithmic":return C$(f,$);case"powers-of-2":return n$(f,$);case"musical-ratio":return t$(f,$);case"cielab-uniform":return d$(f,$);case"ease-in":return x$(f,$);case"ease-out":return h$(f,$);case"ease-in-out":return b$(f,$);default:return U}}catch(U){return console.error("Error calculating scale position:",U),0}},A$=(f,$)=>{try{if($<=1)return 0;let U=1,J=Math.pow(3,$-1),N=(Math.pow(3,f)-U)/(J-U);return H0(N,0,1)}catch(Q){return console.error("Error calculating geometric position:",Q),0}},m$=(f)=>{try{let $=[0,1];for(let J=2;JH0((J-Q)/(U-Q),0,1))}catch($){return console.error("Error calculating Fibonacci positions:",$),Array(f).fill(0)}},_$=(f)=>{try{let Q=[];for(let N=0;NH0((N-U)/(J-U),0,1))}catch($){return console.error("Error calculating golden ratio positions:",$),Array(f).fill(0)}},C$=(f,$)=>{try{let U=$,J=Math.log(1),N=Math.log(U),q=f+1,Z=(Math.log(q)-J)/(N-J);return H0(Z,0,1)}catch(Q){return console.error("Error calculating logarithmic position:",Q),0}},n$=(f,$)=>{try{let U=Math.pow(2,$-1),J=(Math.pow(2,f)-1)/(U-1);return H0(J,0,1)}catch(Q){return console.error("Error calculating powers of 2 position:",Q),0}},t$=(f,$)=>{try{let Q=[1,1.0666666666666667,1.125,1.2,1.25,1.3333333333333333,1.40625,1.5,1.6,1.6666666666666667,1.875,2],U=[];if($<=Q.length)U=Q.slice(0,$);else for(let Z=0;Z<$;Z++)U.push(1*Math.pow(2,Z/($-1)));let J=U[0],N=U[U.length-1],q=(U[f]-J)/(N-J);return H0(q,0,1)}catch(Q){return console.error("Error calculating musical ratio position:",Q),0}},d$=(f,$)=>{try{let Q=f/($-1);return H0(Q,0,1)}catch(Q){return console.error("Error calculating CIELAB uniform position:",Q),0}},x$=(f,$)=>{try{let Q=f/($-1),U=Q*Q;return H0(U,0,1)}catch(Q){return console.error("Error calculating ease-in position:",Q),0}},h$=(f,$)=>{try{let Q=f/($-1),U=1-(1-Q)*(1-Q);return H0(U,0,1)}catch(Q){return console.error("Error calculating ease-out position:",Q),0}},b$=(f,$)=>{try{let Q=f/($-1),U=Q<0.5?2*Q*Q:1-Math.pow(-2*Q+2,2)/2;return H0(U,0,1)}catch(Q){return console.error("Error calculating ease-in-out position:",Q),0}},V2=(f,$)=>{let Q=$.lightnessDistributionType||"linear",U=$.hueDistributionType||"linear",J=$.saturationDistributionType||"linear";return{lightness:W0(f,$.totalSteps,Q),hue:W0(f,$.totalSteps,U),saturation:W0(f,$.totalSteps,J)}};var d0=(f)=>Math.max(0,Math.min(255,f)),y2=(f,$,Q,U)=>{let J=f.rgb(),N=$.rgb(),q;switch(U){case"darken":q=[Math.min(J[0],N[0]),Math.min(J[1],N[1]),Math.min(J[2],N[2])];break;case"multiply":q=[J[0]*N[0]/255,J[1]*N[1]/255,J[2]*N[2]/255];break;case"plus-darker":q=[d0(J[0]+N[0]-255),d0(J[1]+N[1]-255),d0(J[2]+N[2]-255)];break;case"color-burn":q=J.map((u,w)=>{let m=N[w];if(m===0)return 0;return d0(255-(255-u)*255/m)});break;case"lighten":q=[Math.max(J[0],N[0]),Math.max(J[1],N[1]),Math.max(J[2],N[2])];break;case"screen":q=[255-(255-J[0])*(255-N[0])/255,255-(255-J[1])*(255-N[1])/255,255-(255-J[2])*(255-N[2])/255];break;case"plus-lighter":q=[d0(J[0]+N[0]),d0(J[1]+N[1]),d0(J[2]+N[2])];break;case"color-dodge":q=J.map((u,w)=>{let m=N[w];if(m===255)return 255;return d0(u*255/(255-m))});break;case"overlay":q=J.map((u,w)=>{let m=N[w],L=u/255,p=m/255;if(L<0.5)return 2*L*p*255;else return(1-2*(1-L)*(1-p))*255});break;case"soft-light":q=J.map((u,w)=>{let m=N[w],L=u/255,p=m/255;if(p<0.5)return(2*L*p+L*L*(1-2*p))*255;else return(2*L*(1-p)+Math.sqrt(L)*(2*p-1))*255});break;case"hard-light":q=J.map((u,w)=>{let m=N[w],L=u/255,p=m/255;if(p<0.5)return 2*L*p*255;else return(1-2*(1-L)*(1-p))*255});break;case"difference":q=[Math.abs(J[0]-N[0]),Math.abs(J[1]-N[1]),Math.abs(J[2]-N[2])];break;case"exclusion":q=[J[0]+N[0]-2*J[0]*N[0]/255,J[1]+N[1]-2*J[1]*N[1]/255,J[2]+N[2]-2*J[2]*N[2]/255];break;case"hue":let D=f.hsl(),X=$.hsl();return t.hsl(X[0]||0,D[1]||0,D[2]||0);case"saturation":let K=f.hsl(),F=$.hsl();return t.hsl(K[0]||0,F[1]||0,K[2]||0);case"color":let V=f.hsl(),G=$.hsl();return t.hsl(G[0]||0,G[1]||0,V[2]||0);case"luminosity":let B=f.hsl(),S=$.hsl();return t.hsl(B[0]||0,B[1]||0,S[2]||0);case"normal":default:return t.mix(f,$,Q,"rgb")}let Z=t.rgb(...q);return t.mix(f,Z,Q,"rgb")};function W2(f){if(f<=0.04045)return f/12.92;return Math.pow((f+0.055)/1.055,2.4)}function Y2(f){if(f<=0.0031308)return f*12.92;return 1.055*Math.pow(f,0.4166666666666667)-0.055}function n6(f,$,Q){return[W2(f/255),W2($/255),W2(Q/255)]}function t6(f,$,Q){return[Math.round(Math.max(0,Math.min(1,Y2(f)))*255),Math.round(Math.max(0,Math.min(1,Y2($)))*255),Math.round(Math.max(0,Math.min(1,Y2(Q)))*255)]}function d6(f,$,Q){let U=0.4122214708*f+0.5363325363*$+0.0514459929*Q,J=0.2119034982*f+0.6806995451*$+0.1073969566*Q,N=0.0883024619*f+0.2817188376*$+0.6299787005*Q,q=Math.cbrt(U),Z=Math.cbrt(J),D=Math.cbrt(N),X=0.2104542553*q+0.793617785*Z-0.0040720468*D,K=1.9779984951*q-2.428592205*Z+0.4505937099*D,F=0.0259040371*q+0.7827717662*Z-0.808675766*D;return[X,K,F]}function G2(f,$,Q){let U=f+0.3963377774*$+0.2158037573*Q,J=f-0.1055613458*$-0.0638541728*Q,N=f-0.0894841775*$-1.291485548*Q,q=U*U*U,Z=J*J*J,D=N*N*N,X=4.0767416621*q-3.3077115913*Z+0.2309699292*D,K=-1.2684380046*q+2.6097574011*Z-0.3413193965*D,F=-0.0041960863*q-0.7034186147*Z+1.707614701*D;return[X,K,F]}function x6(f,$,Q){let U=Math.sqrt($*$+Q*Q),J=Math.atan2(Q,$)*180/Math.PI;if(J<0)J+=360;return[f,U,J]}function I2(f,$,Q){let U=Q*Math.PI/180;return[f,$*Math.cos(U),$*Math.sin(U)]}function h6(f){let[$,Q,U]=i6(f),[J,N,q]=n6($,Q,U),[Z,D,X]=d6(J,N,q);return x6(Z,D,X)}function b6(f,$,Q){let[,U,J]=I2(f,$,Q),[N,q,Z]=G2(f,U,J),[D,X,K]=t6(N,q,Z);return g$(D,X,K)}function r6(f,$,Q){let[U,J,N]=n6(f,$,Q),[q,Z,D]=d6(U,J,N);return x6(q,Z,D)}function r$(f,$,Q){let[,U,J]=I2(f,$,Q),[N,q,Z]=G2(f,U,J);return t6(N,q,Z)}function g6(f,$,Q){let[,U,J]=I2(f,$,Q),[N,q,Z]=G2(f,U,J),D=0.000001;return N>=-0.000001&&N<=1.000001&&q>=-0.000001&&q<=1.000001&&Z>=-0.000001&&Z<=1.000001}function i6(f){let $=f.replace(/^#/,"");if($.length===3||$.length===4)$=$.split("").map((U)=>U+U).join("");let Q=parseInt($.substring(0,6),16);return[Q>>16&255,Q>>8&255,Q&255]}function g$(f,$,Q){let U=(J)=>Math.max(0,Math.min(255,J)).toString(16).padStart(2,"0");return`#${U(f)}${U($)}${U(Q)}`}function c6(f){let $=f.trim().toLowerCase();if($.startsWith("#"))return i6($);let Q=$.match(/^rgba?\(\s*(\d+(?:\.\d+)?)\s*[,\s]\s*(\d+(?:\.\d+)?)\s*[,\s]\s*(\d+(?:\.\d+)?)/);if(Q)return[Math.round(parseFloat(Q[1])),Math.round(parseFloat(Q[2])),Math.round(parseFloat(Q[3]))];let U=$.match(/^hsla?\(\s*(\d+(?:\.\d+)?)\s*[,\s]\s*(\d+(?:\.\d+)?)%\s*[,\s]\s*(\d+(?:\.\d+)?)%/);if(U){let N=parseFloat(U[1]),q=parseFloat(U[2])/100,Z=parseFloat(U[3])/100;return i$(N,q,Z)}let J=$.match(/^oklch\(\s*(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)/);if(J){let N=parseFloat(J[1]),q=parseFloat(J[2]),Z=parseFloat(J[3]);return r$(N,q,Z)}return null}function i$(f,$,Q){f=(f%360+360)%360;let U=(1-Math.abs(2*Q-1))*$,J=U*(1-Math.abs(f/60%2-1)),N=Q-U/2,q,Z,D;if(f<60)q=U,Z=J,D=0;else if(f<120)q=J,Z=U,D=0;else if(f<180)q=0,Z=U,D=J;else if(f<240)q=0,Z=J,D=U;else if(f<300)q=J,Z=0,D=U;else q=U,Z=0,D=J;return[Math.round((q+N)*255),Math.round((Z+N)*255),Math.round((D+N)*255)]}function Y1(f){let{l:$,c:Q,h:U,alpha:J}=f;return{l:Math.round($*100)/100,c:Math.round(Q*100)/100,h:Math.round(U),alpha:J!==void 0?Math.round(J*100)/100:J}}function c$(f){let{l:$,c:Q,h:U,alpha:J}=f;return{l:Math.round($*1000)/1000,c:Math.round(Q*1000)/1000,h:Math.round(U),alpha:J!==void 0?Math.round(J*1000)/1000:J}}function s(f){try{if(f.startsWith("#")){let[N,q,Z]=h6(f);return{l:N,c:q,h:Z}}let $=c6(f);if(!$)throw Error(`Invalid color: ${f}`);let[Q,U,J]=r6($[0],$[1],$[2]);return{l:Q,c:U,h:J}}catch($){return console.error("Error converting to OKLCH:",$),{l:0.5,c:0,h:0,alpha:1}}}function If(f){try{return b6(f.l,f.c,f.h)}catch($){return console.error("Error converting from OKLCH:",$),"#808080"}}function r(f){let $=Y1(f),{l:Q,c:U,h:J,alpha:N}=$;if(N!==void 0&&N<1)return`oklch(${Q} ${U} ${J} / ${N})`;return`oklch(${Q} ${U} ${J})`}function o6(f){try{return g6(f.l,f.c,f.h)}catch($){return console.error("Error checking sRGB gamut:",$),!1}}function e6(f,$){let Q=0,U=0.5,J=0,N=20;while(J0.001){let q=(Q+U)/2;if(o6({l:f,c:q,h:$}))Q=q;else U=q;J++}return Math.max(0,Q)}function o$(f){let $=e6(f.l,f.h);if(f.c>$)return{...f,c:$};return f}function wf(f,$=!1){let{l:Q,c:U,h:J,alpha:N}=f;if(Q=Math.max(0,Math.min(1,Q)),J=(J%360+360)%360,N!==void 0)N=Math.max(0,Math.min(1,N));if($){let Z=c$({l:Q,c:U,h:J,alpha:N}),D=e6(Z.l,Z.h),X=Math.min(Z.c,D);return{...Z,c:X}}return o$({l:Q,c:U,h:J,alpha:N})}var G1=(f,$)=>{try{if($==="hsl"){let[Q,U,J]=f.hsl(),N=x0(Q,0,360),q=x0(U,0,1),Z=x0(J,0,1);return`hsl(${Math.round(N)}, ${Math.round(q*100)}%, ${Math.round(Z*100)}%)`}if($==="oklch"){let Q=f.hex(),U=s(Q);return r(U)}return f.hex()}catch(Q){return console.error("Error formatting color:",Q),"#000000"}},e0=(f)=>{return typeof f==="number"&&!isNaN(f)&&isFinite(f)},x0=(f,$,Q)=>{if(!e0(f))return $;return Math.max($,Math.min(Q,f))},e$=(f,$,Q,U,J)=>{try{let N=f.lightnessStart/100,q=f.lightnessEnd/100,Z=N+(q-N)*$;return x0(Z,0,1)}catch(N){return console.error("Error calculating lightness:",N),0.5}},l$=(f,$,Q,U,J)=>{try{let N=f.chromaEnd-f.chromaStart,q=(Q+f.chromaStart+N*$)%360;while(q<0)q+=360;return x0(q,0,360)}catch(N){return console.error("Error calculating hue:",N),0}},a$=(f,$,Q,U,J)=>{try{let N=f.saturationStart/100*Q,q=f.saturationEnd/100*Q,Z=N+(q-N)*$;return x0(Z,0,1)}catch(N){return console.error("Error calculating saturation:",N),0.5}},s$=(f,$,Q,U,J)=>{try{let N=f.lightnessStart/100,q=f.lightnessEnd/100,Z=N+(q-N)*$;return x0(Z,0,1)}catch(N){return console.error("Error calculating OKLCH lightness:",N),0.5}},fQ=(f,$,Q,U,J)=>{try{let N=f.chromaEnd-f.chromaStart,q=(Q+f.chromaStart+N*$)%360;while(q<0)q+=360;return x0(q,0,360)}catch(N){return console.error("Error calculating OKLCH hue:",N),0}},$Q=(f,$,Q,U,J)=>{try{let N=f.saturationStart/100*Q,q=f.saturationEnd/100*Q,Z=N+(q-N)*$;return Math.max(0,Z)}catch(N){return console.error("Error calculating OKLCH chroma:",N),0.1}},QQ=(f,$,Q,U)=>{try{let[J,N,q]=Q.hsl(),Z=e0(J)?J:0,D=e0(N)?N:0,X=e0(q)?q:0,K=V2($,f),F=e$(f,K.lightness,X,U,$),V=l$(f,K.hue,Z,U,$),G=a$(f,K.saturation,D,U,$);if(!e0(V)||!e0(G)||!e0(F))return console.warn("Invalid color values detected, using fallback:",{newHue:V,newSaturation:G,newLightness:F}),G1(t.hsl(0,0,0.5),f.colorFormat);let B=t.hsl(V,G,F);if(f.tintColor&&f.tintOpacity&&f.tintOpacity>0)try{let S=t(f.tintColor),u=f.tintOpacity/100,w=f.tintBlendMode||"normal";B=y2(B,S,u,w)}catch(S){console.error("Error applying tint:",S)}return G1(B,f.colorFormat)}catch(J){return console.error("Error generating single color:",J),G1(t.hsl(0,0,0.5),f.colorFormat)}},UQ=(f,$,Q,U)=>{try{let J=V2($,f),N=s$(f,J.lightness,Q.l,U,$),q=fQ(f,J.hue,Q.h,U,$),Z=$Q(f,J.saturation,Q.c,U,$),D={l:N,c:Z,h:q,alpha:Q.alpha};if(D=wf(D),f.tintColor&&f.tintOpacity&&f.tintOpacity>0)try{let X=If(D),K=t(X),F=t(f.tintColor),V=f.tintOpacity/100,G=f.tintBlendMode||"normal";K=y2(K,F,V,G);let B=K.hex();D=s(B)}catch(X){console.error("Error applying tint to OKLCH:",X)}return r(Y1(D))}catch(J){return console.error("Error generating single OKLCH color:",J),r(Y1({l:0.5,c:0.1,h:0,alpha:1}))}},JQ=(f)=>{let $=[];for(let Q=0;Q{try{let $=t(f.baseColor),Q=[],U=Math.floor(f.totalSteps/2);for(let J=0;J{let N=$?f.length===1?w1($):`${w1($)}-${w1(U.name)}`:w1(U.name);if(J>0)Q.push("");Q.push(` /* ${N} */`),U.colors.forEach((q,Z)=>{Q.push(` --${N}-${Z}: ${q};`)})}),Q.push("}"),Q.join(` -`)}function u2(f,$){let Q={ramps:f.map((U)=>({name:$?f.length===1?$:`${$}-${U.name}`:U.name,baseColor:U.baseColor,colors:U.colors}))};return JSON.stringify(Q,null,2)}function B2(f){return f.map(($)=>$.colors.join(` +(()=>{var{min:z8,max:H8}=Math,N0=(f,$=0,Q=1)=>{return z8(H8($,f),Q)};var o0=(f)=>{f._clipped=!1,f._unclipped=f.slice(0);for(let $=0;$<=3;$++)if($<3){if(f[$]<0||f[$]>255)f._clipped=!0;f[$]=N0(f[$],0,255)}else if($===3)f[$]=N0(f[$],0,1);return f};var S2={};for(let f of["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"])S2[`[object ${f}]`]=f.toLowerCase();function v(f){return S2[Object.prototype.toString.call(f)]||"object"}var S=(f,$=null)=>{if(f.length>=3)return Array.prototype.slice.call(f);if(v(f[0])=="object"&&$)return $.split("").filter((Q)=>f[0][Q]!==void 0).map((Q)=>f[0][Q]);return f[0].slice(0)};var U0=(f)=>{if(f.length<2)return null;let $=f.length-1;if(v(f[$])=="string")return f[$].toLowerCase();return null};var{PI:vf,min:jf,max:Rf}=Math,s=(f)=>Math.round(f*100)/100,kf=(f)=>Math.round(f*100)/100,q0=vf*2,Af=vf/3,O2=vf/180,p2=180/vf;function mf(f){return[...f.slice(0,3).reverse(),...f.slice(3)]}var R={format:{},autodetect:[]};class M2{constructor(...f){let $=this;if(v(f[0])==="object"&&f[0].constructor&&f[0].constructor===this.constructor)return f[0];let Q=U0(f),U=!1;if(!Q){if(U=!0,!R.sorted)R.autodetect=R.autodetect.sort((J,N)=>N.p-J.p),R.sorted=!0;for(let J of R.autodetect)if(Q=J.test(...f),Q)break}if(R.format[Q]){let J=R.format[Q].apply(null,U?f:f.slice(0,-1));$._rgb=o0(J)}else throw Error("unknown format: "+f);if($._rgb.length===3)$._rgb.push(1)}toString(){if(v(this.hex)=="function")return this.hex();return`[${this._rgb.join(",")}]`}}var G=M2;var T2="3.2.0";var P2=(...f)=>{return new G(...f)};P2.version=T2;var _=P2;var S8={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},R0=S8;var O8=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,p8=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,M8=(f)=>{if(f.match(O8)){if(f.length===4||f.length===7)f=f.substr(1);if(f.length===3)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2];let $=parseInt(f,16),Q=$>>16,U=$>>8&255,J=$&255;return[Q,U,J,1]}if(f.match(p8)){if(f.length===5||f.length===9)f=f.substr(1);if(f.length===4)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2]+f[3]+f[3];let $=parseInt(f,16),Q=$>>24&255,U=$>>16&255,J=$>>8&255,N=Math.round(($&255)/255*100)/100;return[Q,U,J,N]}throw Error(`unknown hex color: ${f}`)},_f=M8;var{round:Cf}=Math,T8=(...f)=>{let[$,Q,U,J]=S(f,"rgba"),N=U0(f)||"auto";if(J===void 0)J=1;if(N==="auto")N=J<1?"rgba":"rgb";$=Cf($),Q=Cf(Q),U=Cf(U);let Z="000000"+($<<16|Q<<8|U).toString(16);Z=Z.substr(Z.length-6);let D="0"+Cf(J*255).toString(16);switch(D=D.substr(D.length-2),N.toLowerCase()){case"rgba":return`#${Z}${D}`;case"argb":return`#${D}${Z}`;default:return`#${Z}`}},nf=T8;G.prototype.name=function(){let f=nf(this._rgb,"rgb");for(let $ of Object.keys(R0))if(R0[$]===f)return $.toLowerCase();return f};R.format.named=(f)=>{if(f=f.toLowerCase(),R0[f])return _f(R0[f]);throw Error("unknown color name: "+f)};R.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&v(f)==="string"&&R0[f.toLowerCase()])return"named"}});G.prototype.alpha=function(f,$=!1){if(f!==void 0&&v(f)==="number"){if($)return this._rgb[3]=f,this;return new G([this._rgb[0],this._rgb[1],this._rgb[2],f],"rgb")}return this._rgb[3]};G.prototype.clipped=function(){return this._rgb._clipped||!1};var zf={Kn:18,labWhitePoint:"d65",Xn:0.95047,Yn:1,Zn:1.08883,t0:0.137931034,t1:0.206896552,t2:0.12841855,t3:0.008856452,kE:0.008856451679035631,kKE:8,kK:903.2962962962963,RefWhiteRGB:{X:0.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:0.4124564390896922,m01:0.21267285140562253,m02:0.0193338955823293,m10:0.357576077643909,m11:0.715152155287818,m12:0.11919202588130297,m20:0.18043748326639894,m21:0.07217499330655958,m22:0.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-0.9692660305051868,m02:0.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-0.2040259135167538,m20:-0.498531409556016,m21:0.041556017530349834,m22:1.0572251882231791},As:0.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:0.8951,m01:-0.7502,m02:0.0389,m10:0.2664,m11:1.7135,m12:-0.0685,m20:-0.1614,m21:0.0367,m22:1.0296},MtxAdaptMaI:{m00:0.9869929054667123,m01:0.43230526972339456,m02:-0.008528664575177328,m10:-0.14705425642099013,m11:0.5183602715367776,m12:0.04004282165408487,m20:0.15996265166373125,m21:0.0492912282128556,m22:0.9684866957875502}},S0=zf,P8=new Map([["a",[1.0985,0.35585]],["b",[1.0985,0.35585]],["c",[0.98074,1.18232]],["d50",[0.96422,0.82521]],["d55",[0.95682,0.92149]],["d65",[0.95047,1.08883]],["e",[1,1,1]],["f2",[0.99186,0.67393]],["f7",[0.95041,1.08747]],["f11",[1.00962,0.6435]],["icc",[0.96422,0.82521]]]);function Z0(f){let $=P8.get(String(f).toLowerCase());if(!$)throw Error("unknown Lab illuminant "+f);zf.labWhitePoint=f,zf.Xn=$[0],zf.Zn=$[1]}function A0(){return zf.labWhitePoint}var L8=(...f)=>{f=S(f,"lab");let[$,Q,U]=f,[J,N,q]=v8($,Q,U),[Z,D,X]=P1(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},v8=(f,$,Q)=>{let{kE:U,kK:J,kKE:N,Xn:q,Yn:Z,Zn:D}=S0,X=(f+16)/116,K=0.002*$+X,F=X-0.005*Q,V=K*K*K,Y=F*F*F,u=V>U?V:(116*K-16)/J,z=f>N?Math.pow((f+16)/116,3):f/J,B=Y>U?Y:(116*F-16)/J,W=u*q,M=z*Z,L=B*D;return[W,M,L]},T1=(f)=>{let $=Math.sign(f);return f=Math.abs(f),(f<=0.0031308?f*12.92:1.055*Math.pow(f,0.4166666666666667)-0.055)*$},P1=(f,$,Q)=>{let{MtxAdaptMa:U,MtxAdaptMaI:J,MtxXYZ2RGB:N,RefWhiteRGB:q,Xn:Z,Yn:D,Zn:X}=S0,K=Z*U.m00+D*U.m10+X*U.m20,F=Z*U.m01+D*U.m11+X*U.m21,V=Z*U.m02+D*U.m12+X*U.m22,Y=q.X*U.m00+q.Y*U.m10+q.Z*U.m20,u=q.X*U.m01+q.Y*U.m11+q.Z*U.m21,z=q.X*U.m02+q.Y*U.m12+q.Z*U.m22,B=(f*U.m00+$*U.m10+Q*U.m20)*(Y/K),W=(f*U.m01+$*U.m11+Q*U.m21)*(u/F),M=(f*U.m02+$*U.m12+Q*U.m22)*(z/V),L=B*J.m00+W*J.m10+M*J.m20,p=B*J.m01+W*J.m11+M*J.m21,n=B*J.m02+W*J.m12+M*J.m22,m=T1(L*N.m00+p*N.m10+n*N.m20),w=T1(L*N.m01+p*N.m11+n*N.m21),y=T1(L*N.m02+p*N.m12+n*N.m22);return[m*255,w*255,y*255]},ff=L8;var j8=(...f)=>{let[$,Q,U,...J]=S(f,"rgb"),[N,q,Z]=v1($,Q,U),[D,X,K]=R8(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function R8(f,$,Q){let{Xn:U,Yn:J,Zn:N,kE:q,kK:Z}=S0,D=f/U,X=$/J,K=Q/N,F=D>q?Math.pow(D,0.3333333333333333):(Z*D+16)/116,V=X>q?Math.pow(X,0.3333333333333333):(Z*X+16)/116,Y=K>q?Math.pow(K,0.3333333333333333):(Z*K+16)/116;return[116*V-16,500*(F-V),200*(V-Y)]}function L1(f){let $=Math.sign(f);return f=Math.abs(f),(f<=0.04045?f/12.92:Math.pow((f+0.055)/1.055,2.4))*$}var v1=(f,$,Q)=>{f=L1(f/255),$=L1($/255),Q=L1(Q/255);let{MtxRGB2XYZ:U,MtxAdaptMa:J,MtxAdaptMaI:N,Xn:q,Yn:Z,Zn:D,As:X,Bs:K,Cs:F}=S0,V=f*U.m00+$*U.m10+Q*U.m20,Y=f*U.m01+$*U.m11+Q*U.m21,u=f*U.m02+$*U.m12+Q*U.m22,z=q*J.m00+Z*J.m10+D*J.m20,B=q*J.m01+Z*J.m11+D*J.m21,W=q*J.m02+Z*J.m12+D*J.m22,M=V*J.m00+Y*J.m10+u*J.m20,L=V*J.m01+Y*J.m11+u*J.m21,p=V*J.m02+Y*J.m12+u*J.m22;return M*=z/X,L*=B/K,p*=W/F,V=M*N.m00+L*N.m10+p*N.m20,Y=M*N.m01+L*N.m11+p*N.m21,u=M*N.m02+L*N.m12+p*N.m22,[V,Y,u]},$f=j8;G.prototype.lab=function(){return $f(this._rgb)};var A8=(...f)=>new G(...f,"lab");Object.assign(_,{lab:A8,getLabWhitePoint:A0,setLabWhitePoint:Z0});R.format.lab=ff;R.autodetect.push({p:2,test:(...f)=>{if(f=S(f,"lab"),v(f)==="array"&&f.length===3)return"lab"}});G.prototype.darken=function(f=1){let $=this,Q=$.lab();return Q[0]-=S0.Kn*f,new G(Q,"lab").alpha($.alpha(),!0)};G.prototype.brighten=function(f=1){return this.darken(-f)};G.prototype.darker=G.prototype.darken;G.prototype.brighter=G.prototype.brighten;G.prototype.get=function(f){let[$,Q]=f.split("."),U=this[$]();if(Q){let J=$.indexOf(Q)-($.substr(0,2)==="ok"?2:0);if(J>-1)return U[J];throw Error(`unknown channel ${Q} in mode ${$}`)}else return U};var{pow:m8}=Math,_8=0.0000001,C8=20;G.prototype.luminance=function(f,$="rgb"){if(f!==void 0&&v(f)==="number"){if(f===0)return new G([0,0,0,this._rgb[3]],"rgb");if(f===1)return new G([255,255,255,this._rgb[3]],"rgb");let Q=this.luminance(),U=C8,J=(q,Z)=>{let D=q.interpolate(Z,0.5,$),X=D.luminance();if(Math.abs(f-X)<_8||!U--)return D;return X>f?J(q,D):J(D,Z)},N=(Q>f?J(new G([0,0,0]),this):J(this,new G([255,255,255]))).rgb();return new G([...N,this._rgb[3]])}return n8(...this._rgb.slice(0,3))};var n8=(f,$,Q)=>{return f=j1(f),$=j1($),Q=j1(Q),0.2126*f+0.7152*$+0.0722*Q},j1=(f)=>{return f/=255,f<=0.03928?f/12.92:m8((f+0.055)/1.055,2.4)};var x={};var O0=(f,$,Q=0.5,...U)=>{let J=U[0]||"lrgb";if(!x[J]&&!U.length)J=Object.keys(x)[0];if(!x[J])throw Error(`interpolation mode ${J} is not defined`);if(v(f)!=="object")f=new G(f);if(v($)!=="object")$=new G($);return x[J](f,$,Q).alpha(f.alpha()+Q*($.alpha()-f.alpha()))};G.prototype.mix=G.prototype.interpolate=function(f,$=0.5,...Q){return O0(this,f,$,...Q)};G.prototype.premultiply=function(f=!1){let $=this._rgb,Q=$[3];if(f)return this._rgb=[$[0]*Q,$[1]*Q,$[2]*Q,Q],this;else return new G([$[0]*Q,$[1]*Q,$[2]*Q,Q],"rgb")};var{sin:d8,cos:t8}=Math,x8=(...f)=>{let[$,Q,U]=S(f,"lch");if(isNaN(U))U=0;return U=U*O2,[$,t8(U)*Q,d8(U)*Q]},df=x8;var h8=(...f)=>{f=S(f,"lch");let[$,Q,U]=f,[J,N,q]=df($,Q,U),[Z,D,X]=ff(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},Qf=h8;var b8=(...f)=>{let $=mf(S(f,"hcl"));return Qf(...$)},L2=b8;var{sqrt:r8,atan2:g8,round:i8}=Math,c8=(...f)=>{let[$,Q,U]=S(f,"lab"),J=r8(Q*Q+U*U),N=(g8(U,Q)*p2+360)%360;if(i8(J*1e4)===0)N=Number.NaN;return[$,J,N]},tf=c8;var o8=(...f)=>{let[$,Q,U,...J]=S(f,"rgb"),[N,q,Z]=$f($,Q,U),[D,X,K]=tf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},Hf=o8;G.prototype.lch=function(){return Hf(this._rgb)};G.prototype.hcl=function(){return mf(Hf(this._rgb))};var e8=(...f)=>new G(...f,"lch"),l8=(...f)=>new G(...f,"hcl");Object.assign(_,{lch:e8,hcl:l8});R.format.lch=Qf;R.format.hcl=L2;["lch","hcl"].forEach((f)=>R.autodetect.push({p:2,test:(...$)=>{if($=S($,f),v($)==="array"&&$.length===3)return f}}));G.prototype.saturate=function(f=1){let $=this,Q=$.lch();if(Q[1]+=S0.Kn*f,Q[1]<0)Q[1]=0;return new G(Q,"lch").alpha($.alpha(),!0)};G.prototype.desaturate=function(f=1){return this.saturate(-f)};G.prototype.set=function(f,$,Q=!1){let[U,J]=f.split("."),N=this[U]();if(J){let q=U.indexOf(J)-(U.substr(0,2)==="ok"?2:0);if(q>-1){if(v($)=="string")switch($.charAt(0)){case"+":N[q]+=+$;break;case"-":N[q]+=+$;break;case"*":N[q]*=+$.substr(1);break;case"/":N[q]/=+$.substr(1);break;default:N[q]=+$}else if(v($)==="number")N[q]=$;else throw Error("unsupported value for Color.set");let Z=new G(N,U);if(Q)return this._rgb=Z._rgb,this;return Z}throw Error(`unknown channel ${J} in mode ${U}`)}else return N};G.prototype.tint=function(f=0.5,...$){return O0(this,"white",f,...$)};G.prototype.shade=function(f=0.5,...$){return O0(this,"black",f,...$)};var a8=(f,$,Q)=>{let U=f._rgb,J=$._rgb;return new G(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"rgb")};x.rgb=a8;var{sqrt:R1,pow:Uf}=Math,s8=(f,$,Q)=>{let[U,J,N]=f._rgb,[q,Z,D]=$._rgb;return new G(R1(Uf(U,2)*(1-Q)+Uf(q,2)*Q),R1(Uf(J,2)*(1-Q)+Uf(Z,2)*Q),R1(Uf(N,2)*(1-Q)+Uf(D,2)*Q),"rgb")};x.lrgb=s8;var f9=(f,$,Q)=>{let U=f.lab(),J=$.lab();return new G(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"lab")};x.lab=f9;var D0=(f,$,Q,U)=>{let J,N;if(U==="hsl")J=f.hsl(),N=$.hsl();else if(U==="hsv")J=f.hsv(),N=$.hsv();else if(U==="hcg")J=f.hcg(),N=$.hcg();else if(U==="hsi")J=f.hsi(),N=$.hsi();else if(U==="lch"||U==="hcl")U="hcl",J=f.hcl(),N=$.hcl();else if(U==="oklch")J=f.oklch().reverse(),N=$.oklch().reverse();let q,Z,D,X,K,F;if(U.substr(0,1)==="h"||U==="oklch")[q,D,K]=J,[Z,X,F]=N;let V,Y,u,z;if(!isNaN(q)&&!isNaN(Z)){if(Z>q&&Z-q>180)z=Z-(q+360);else if(Z180)z=Z+360-q;else z=Z-q;Y=q+Q*z}else if(!isNaN(q)){if(Y=q,(F==1||F==0)&&U!="hsv")V=D}else if(!isNaN(Z)){if(Y=Z,(K==1||K==0)&&U!="hsv")V=X}else Y=Number.NaN;if(V===void 0)V=D+Q*(X-D);return u=K+Q*(F-K),U==="oklch"?new G([u,V,Y],U):new G([Y,V,u],U)};var v2=(f,$,Q)=>{return D0(f,$,Q,"lch")};x.lch=v2;x.hcl=v2;var $9=(f)=>{if(v(f)=="number"&&f>=0&&f<=16777215){let $=f>>16,Q=f>>8&255,U=f&255;return[$,Q,U,1]}throw Error("unknown num color: "+f)},j2=$9;var Q9=(...f)=>{let[$,Q,U]=S(f,"rgb");return($<<16)+(Q<<8)+U},R2=Q9;G.prototype.num=function(){return R2(this._rgb)};var U9=(...f)=>new G(...f,"num");Object.assign(_,{num:U9});R.format.num=j2;R.autodetect.push({p:5,test:(...f)=>{if(f.length===1&&v(f[0])==="number"&&f[0]>=0&&f[0]<=16777215)return"num"}});var J9=(f,$,Q)=>{let U=f.num(),J=$.num();return new G(U+Q*(J-U),"num")};x.num=J9;var{floor:N9}=Math,q9=(...f)=>{f=S(f,"hcg");let[$,Q,U]=f,J,N,q;U=U*255;let Z=Q*255;if(Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let D=N9($),X=$-D,K=U*(1-Q),F=K+Z*(1-X),V=K+Z*X,Y=K+Z;switch(D){case 0:[J,N,q]=[Y,V,K];break;case 1:[J,N,q]=[F,Y,K];break;case 2:[J,N,q]=[K,Y,V];break;case 3:[J,N,q]=[K,F,Y];break;case 4:[J,N,q]=[V,K,Y];break;case 5:[J,N,q]=[Y,K,F];break}}return[J,N,q,f.length>3?f[3]:1]},A2=q9;var Z9=(...f)=>{let[$,Q,U]=S(f,"rgb"),J=jf($,Q,U),N=Rf($,Q,U),q=N-J,Z=q*100/255,D=J/(255-q)*100,X;if(q===0)X=Number.NaN;else{if($===N)X=(Q-U)/q;if(Q===N)X=2+(U-$)/q;if(U===N)X=4+($-Q)/q;if(X*=60,X<0)X+=360}return[X,Z,D]},m2=Z9;G.prototype.hcg=function(){return m2(this._rgb)};var D9=(...f)=>new G(...f,"hcg");_.hcg=D9;R.format.hcg=A2;R.autodetect.push({p:1,test:(...f)=>{if(f=S(f,"hcg"),v(f)==="array"&&f.length===3)return"hcg"}});var X9=(f,$,Q)=>{return D0(f,$,Q,"hcg")};x.hcg=X9;var{cos:Jf}=Math,K9=(...f)=>{f=S(f,"hsi");let[$,Q,U]=f,J,N,q;if(isNaN($))$=0;if(isNaN(Q))Q=0;if($>360)$-=360;if($<0)$+=360;if($/=360,$<0.3333333333333333)q=(1-Q)/3,J=(1+Q*Jf(q0*$)/Jf(Af-q0*$))/3,N=1-(q+J);else if($<0.6666666666666666)$-=0.3333333333333333,J=(1-Q)/3,N=(1+Q*Jf(q0*$)/Jf(Af-q0*$))/3,q=1-(J+N);else $-=0.6666666666666666,N=(1-Q)/3,q=(1+Q*Jf(q0*$)/Jf(Af-q0*$))/3,J=1-(N+q);return J=N0(U*J*3),N=N0(U*N*3),q=N0(U*q*3),[J*255,N*255,q*255,f.length>3?f[3]:1]},_2=K9;var{min:F9,sqrt:V9,acos:y9}=Math,W9=(...f)=>{let[$,Q,U]=S(f,"rgb");$/=255,Q/=255,U/=255;let J,N=F9($,Q,U),q=($+Q+U)/3,Z=q>0?1-N/q:0;if(Z===0)J=NaN;else{if(J=($-Q+($-U))/2,J/=V9(($-Q)*($-Q)+($-U)*(Q-U)),J=y9(J),U>Q)J=q0-J;J/=q0}return[J*360,Z,q]},C2=W9;G.prototype.hsi=function(){return C2(this._rgb)};var Y9=(...f)=>new G(...f,"hsi");_.hsi=Y9;R.format.hsi=_2;R.autodetect.push({p:2,test:(...f)=>{if(f=S(f,"hsi"),v(f)==="array"&&f.length===3)return"hsi"}});var G9=(f,$,Q)=>{return D0(f,$,Q,"hsi")};x.hsi=G9;var I9=(...f)=>{f=S(f,"hsl");let[$,Q,U]=f,J,N,q;if(Q===0)J=N=q=U*255;else{let Z=[0,0,0],D=[0,0,0],X=U<0.5?U*(1+Q):U+Q-U*Q,K=2*U-X,F=$/360;Z[0]=F+0.3333333333333333,Z[1]=F,Z[2]=F-0.3333333333333333;for(let V=0;V<3;V++){if(Z[V]<0)Z[V]+=1;if(Z[V]>1)Z[V]-=1;if(6*Z[V]<1)D[V]=K+(X-K)*6*Z[V];else if(2*Z[V]<1)D[V]=X;else if(3*Z[V]<2)D[V]=K+(X-K)*(0.6666666666666666-Z[V])*6;else D[V]=K}[J,N,q]=[D[0]*255,D[1]*255,D[2]*255]}if(f.length>3)return[J,N,q,f[3]];return[J,N,q,1]},Sf=I9;var w9=(...f)=>{f=S(f,"rgba");let[$,Q,U]=f;$/=255,Q/=255,U/=255;let J=jf($,Q,U),N=Rf($,Q,U),q=(N+J)/2,Z,D;if(N===J)Z=0,D=Number.NaN;else Z=q<0.5?(N-J)/(N+J):(N-J)/(2-N-J);if($==N)D=(Q-U)/(N-J);else if(Q==N)D=2+(U-$)/(N-J);else if(U==N)D=4+($-Q)/(N-J);if(D*=60,D<0)D+=360;if(f.length>3&&f[3]!==void 0)return[D,Z,q,f[3]];return[D,Z,q]},xf=w9;G.prototype.hsl=function(){return xf(this._rgb)};var B9=(...f)=>new G(...f,"hsl");_.hsl=B9;R.format.hsl=Sf;R.autodetect.push({p:2,test:(...f)=>{if(f=S(f,"hsl"),v(f)==="array"&&f.length===3)return"hsl"}});var u9=(f,$,Q)=>{return D0(f,$,Q,"hsl")};x.hsl=u9;var{floor:E9}=Math,k9=(...f)=>{f=S(f,"hsv");let[$,Q,U]=f,J,N,q;if(U*=255,Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let Z=E9($),D=$-Z,X=U*(1-Q),K=U*(1-Q*D),F=U*(1-Q*(1-D));switch(Z){case 0:[J,N,q]=[U,F,X];break;case 1:[J,N,q]=[K,U,X];break;case 2:[J,N,q]=[X,U,F];break;case 3:[J,N,q]=[X,K,U];break;case 4:[J,N,q]=[F,X,U];break;case 5:[J,N,q]=[U,X,K];break}}return[J,N,q,f.length>3?f[3]:1]},n2=k9;var{min:z9,max:H9}=Math,S9=(...f)=>{f=S(f,"rgb");let[$,Q,U]=f,J=z9($,Q,U),N=H9($,Q,U),q=N-J,Z,D,X;if(X=N/255,N===0)Z=Number.NaN,D=0;else{if(D=q/N,$===N)Z=(Q-U)/q;if(Q===N)Z=2+(U-$)/q;if(U===N)Z=4+($-Q)/q;if(Z*=60,Z<0)Z+=360}return[Z,D,X]},d2=S9;G.prototype.hsv=function(){return d2(this._rgb)};var O9=(...f)=>new G(...f,"hsv");_.hsv=O9;R.format.hsv=n2;R.autodetect.push({p:2,test:(...f)=>{if(f=S(f,"hsv"),v(f)==="array"&&f.length===3)return"hsv"}});var p9=(f,$,Q)=>{return D0(f,$,Q,"hsv")};x.hsv=p9;function e0(f,$){let Q=f.length;if(!Array.isArray(f[0]))f=[f];if(!Array.isArray($[0]))$=$.map((q)=>[q]);let U=$[0].length,J=$[0].map((q,Z)=>$.map((D)=>D[Z])),N=f.map((q)=>J.map((Z)=>{if(!Array.isArray(q))return Z.reduce((D,X)=>D+X*q,0);return q.reduce((D,X,K)=>D+X*(Z[K]||0),0)}));if(Q===1)N=N[0];if(U===1)return N.map((q)=>q[0]);return N}var M9=(...f)=>{f=S(f,"lab");let[$,Q,U,...J]=f,[N,q,Z]=T9([$,Q,U]),[D,X,K]=P1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function T9(f){var $=[[1.2268798758459243,-0.5578149944602171,0.2813910456659647],[-0.0405757452148008,1.112286803280317,-0.0717110580655164],[-0.0763729366746601,-0.4214933324022432,1.5869240198367816]],Q=[[1,0.3963377773761749,0.2158037573099136],[1,-0.1055613458156586,-0.0638541728258133],[1,-0.0894841775298119,-1.2914855480194092]],U=e0(Q,f);return e0($,U.map((J)=>J**3))}var Nf=M9;var P9=(...f)=>{let[$,Q,U,...J]=S(f,"rgb"),N=v1($,Q,U);return[...L9(N),...J.length>0&&J[0]<1?[J[0]]:[]]};function L9(f){let $=[[0.819022437996703,0.3619062600528904,-0.1288737815209879],[0.0329836539323885,0.9292868615863434,0.0361446663506424],[0.0481771893596242,0.2642395317527308,0.6335478284694309]],Q=[[0.210454268309314,0.7936177747023054,-0.0040720430116193],[1.9779985324311684,-2.42859224204858,0.450593709617411],[0.0259040424655478,0.7827717124575296,-0.8086757549230774]],U=e0($,f);return e0(Q,U.map((J)=>Math.cbrt(J)))}var qf=P9;G.prototype.oklab=function(){return qf(this._rgb)};var v9=(...f)=>new G(...f,"oklab");Object.assign(_,{oklab:v9});R.format.oklab=Nf;R.autodetect.push({p:2,test:(...f)=>{if(f=S(f,"oklab"),v(f)==="array"&&f.length===3)return"oklab"}});var j9=(f,$,Q)=>{let U=f.oklab(),J=$.oklab();return new G(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"oklab")};x.oklab=j9;var R9=(f,$,Q)=>{return D0(f,$,Q,"oklch")};x.oklch=R9;var{pow:A1,sqrt:m1,PI:_1,cos:t2,sin:x2,atan2:A9}=Math,h2=(f,$="lrgb",Q=null)=>{let U=f.length;if(!Q)Q=Array.from(Array(U)).map(()=>1);let J=U/Q.reduce(function(F,V){return F+V});if(Q.forEach((F,V)=>{Q[V]*=J}),f=f.map((F)=>new G(F)),$==="lrgb")return m9(f,Q);let N=f.shift(),q=N.get($),Z=[],D=0,X=0;for(let F=0;F{let Y=F.get($);K+=F.alpha()*Q[V+1];for(let u=0;u=360)V-=360;q[F]=V}else q[F]=q[F]/Z[F];return K/=U,new G(q,$).alpha(K>0.99999?1:K,!0)},m9=(f,$)=>{let Q=f.length,U=[0,0,0,0];for(let J=0;J0.9999999)U[3]=1;return new G(o0(U))};var{pow:_9}=Math;function m0(f){let $="rgb",Q=_("#ccc"),U=0,J=[0,1],N=[0,1],q=[],Z=[0,0],D=!1,X=[],K=!1,F=0,V=1,Y=!1,u={},z=!0,B=1,W=function(y){if(y=y||["#fff","#000"],y&&v(y)==="string"&&_.brewer&&_.brewer[y.toLowerCase()])y=_.brewer[y.toLowerCase()];if(v(y)==="array"){if(y.length===1)y=[y[0],y[0]];y=y.slice(0);for(let E=0;E=D[k])k++;return k-1}return 0},L=(y)=>y,p=(y)=>y,n=function(y,E){let k,H;if(E==null)E=!1;if(isNaN(y)||y===null)return Q;if(!E)if(D&&D.length>2)H=M(y)/(D.length-2);else if(V!==F)H=(y-F)/(V-F);else H=1;else H=y;if(H=p(H),!E)H=L(H);if(B!==1)H=_9(H,B);H=Z[0]+H*(1-Z[0]-Z[1]),H=N0(H,0,1);let P=Math.floor(H*1e4);if(z&&u[P])k=u[P];else{if(v(X)==="array")for(let T=0;T=b&&T===q.length-1){k=X[T];break}if(H>b&&Hu={};W(f);let w=function(y){let E=_(n(y));if(K&&E[K])return E[K]();else return E};return w.classes=function(y){if(y!=null){if(v(y)==="array")D=y,J=[y[0],y[y.length-1]];else{let E=_.analyze(J);if(y===0)D=[E.min,E.max];else D=_.limits(E,"e",y)}return w}return D},w.domain=function(y){if(!arguments.length)return N;N=y.slice(0),F=y[0],V=y[y.length-1],q=[];let E=X.length;if(y.length===E&&F!==V)for(let k of Array.from(y))q.push((k-F)/(V-F));else{for(let k=0;k2){let k=y.map((P,T)=>T/(y.length-1)),H=y.map((P)=>(P-F)/(V-F));if(!H.every((P,T)=>k[T]===P))p=(P)=>{if(P<=0||P>=1)return P;let T=0;while(P>=H[T+1])T++;let b=(P-H[T])/(H[T+1]-H[T]);return k[T]+b*(k[T+1]-k[T])}}}return J=[F,V],w},w.mode=function(y){if(!arguments.length)return $;return $=y,m(),w},w.range=function(y,E){return W(y,E),w},w.out=function(y){return K=y,w},w.spread=function(y){if(!arguments.length)return U;return U=y,w},w.correctLightness=function(y){if(y==null)y=!0;if(Y=y,m(),Y)L=function(E){let k=n(0,!0).lab()[0],H=n(1,!0).lab()[0],P=k>H,T=n(E,!0).lab()[0],b=k+(H-k)*E,l=T-b,G0=0,H0=1,i0=20;while(Math.abs(l)>0.01&&i0-- >0)(function(){if(P)l*=-1;if(l<0)G0=E,E+=(H0-E)*0.5;else H0=E,E+=(G0-E)*0.5;return T=n(E,!0).lab()[0],l=T-b})();return E};else L=(E)=>E;return w},w.padding=function(y){if(y!=null){if(v(y)==="number")y=[y,y];return Z=y,w}else return Z},w.colors=function(y,E){if(arguments.length<2)E="hex";let k=[];if(arguments.length===0)k=X.slice(0);else if(y===1)k=[w(0.5)];else if(y>1){let H=J[0],P=J[1]-H;k=C9(0,y,!1).map((T)=>w(H+T/(y-1)*P))}else{f=[];let H=[];if(D&&D.length>2)for(let P=1,T=D.length,b=1<=T;b?PT;b?P++:P--)H.push((D[P-1]+D[P])*0.5);else H=J;k=H.map((P)=>w(P))}if(_[E])k=k.map((H)=>H[E]());return k},w.cache=function(y){if(y!=null)return z=y,w;else return z},w.gamma=function(y){if(y!=null)return B=y,w;else return B},w.nodata=function(y){if(y!=null)return Q=_(y),w;else return Q},w}function C9(f,$,Q){let U=[],J=f<$,N=!Q?$:J?$+1:$-1;for(let q=f;J?qN;J?q++:q--)U.push(q);return U}var n9=function(f){let $=[1,1];for(let Q=1;Qnew G(N)),f.length===2)[Q,U]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>Q[Z]+N*(U[Z]-Q[Z]));return new G(q,"lab")};else if(f.length===3)[Q,U,J]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>(1-N)*(1-N)*Q[Z]+2*(1-N)*N*U[Z]+N*N*J[Z]);return new G(q,"lab")};else if(f.length===4){let N;[Q,U,J,N]=f.map((q)=>q.lab()),$=function(q){let Z=[0,1,2].map((D)=>(1-q)*(1-q)*(1-q)*Q[D]+3*(1-q)*(1-q)*q*U[D]+3*(1-q)*q*q*J[D]+q*q*q*N[D]);return new G(Z,"lab")}}else if(f.length>=5){let N,q,Z;N=f.map((D)=>D.lab()),Z=f.length-1,q=n9(Z),$=function(D){let X=1-D,K=[0,1,2].map((F)=>N.reduce((V,Y,u)=>V+q[u]*X**(Z-u)*D**u*Y[F],0));return new G(K,"lab")}}else throw RangeError("No point in running bezier with only one color.");return $},b2=(f)=>{let $=d9(f);return $.scale=()=>m0($),$};var{round:r2}=Math;G.prototype.rgb=function(f=!0){if(f===!1)return this._rgb.slice(0,3);return this._rgb.slice(0,3).map(r2)};G.prototype.rgba=function(f=!0){return this._rgb.slice(0,4).map(($,Q)=>{return Q<3?f===!1?$:r2($):$})};var t9=(...f)=>new G(...f,"rgb");Object.assign(_,{rgb:t9});R.format.rgb=(...f)=>{let $=S(f,"rgba");if($[3]===void 0)$[3]=1;return $};R.autodetect.push({p:3,test:(...f)=>{if(f=S(f,"rgba"),v(f)==="array"&&(f.length===3||f.length===4&&v(f[3])=="number"&&f[3]>=0&&f[3]<=1))return"rgb"}});var I0=(f,$,Q)=>{if(!I0[Q])throw Error("unknown blend mode "+Q);return I0[Q](f,$)},_0=(f)=>($,Q)=>{let U=_(Q).rgb(),J=_($).rgb();return _.rgb(f(U,J))},C0=(f)=>($,Q)=>{let U=[];return U[0]=f($[0],Q[0]),U[1]=f($[1],Q[1]),U[2]=f($[2],Q[2]),U},x9=(f)=>f,h9=(f,$)=>f*$/255,b9=(f,$)=>f>$?$:f,r9=(f,$)=>f>$?f:$,g9=(f,$)=>255*(1-(1-f/255)*(1-$/255)),i9=(f,$)=>$<128?2*f*$/255:255*(1-2*(1-f/255)*(1-$/255)),c9=(f,$)=>255*(1-(1-$/255)/(f/255)),o9=(f,$)=>{if(f===255)return 255;return f=255*($/255)/(1-f/255),f>255?255:f};I0.normal=_0(C0(x9));I0.multiply=_0(C0(h9));I0.screen=_0(C0(g9));I0.overlay=_0(C0(i9));I0.darken=_0(C0(b9));I0.lighten=_0(C0(r9));I0.dodge=_0(C0(o9));I0.burn=_0(C0(c9));var g2=I0;var{pow:e9,sin:l9,cos:a9}=Math;function C1(f=300,$=-1.5,Q=1,U=1,J=[0,1]){let N=0,q;if(v(J)==="array")q=J[1]-J[0];else q=0,J=[J,J];let Z=function(D){let X=q0*((f+120)/360+$*D),K=e9(J[0]+q*D,U),V=(N!==0?Q[0]+D*N:Q)*K*(1-K)/2,Y=a9(X),u=l9(X),z=K+V*(-0.14861*Y+1.78277*u),B=K+V*(-0.29227*Y-0.90649*u),W=K+V*(1.97294*Y);return _(o0([z*255,B*255,W*255,1]))};return Z.start=function(D){if(D==null)return f;return f=D,Z},Z.rotations=function(D){if(D==null)return $;return $=D,Z},Z.gamma=function(D){if(D==null)return U;return U=D,Z},Z.hue=function(D){if(D==null)return Q;if(Q=D,v(Q)==="array"){if(N=Q[1]-Q[0],N===0)Q=Q[1]}else N=0;return Z},Z.lightness=function(D){if(D==null)return J;if(v(D)==="array")J=D,q=D[1]-D[0];else J=[D,D],q=0;return Z},Z.scale=()=>_.scale(Z),Z.hue(Q),Z}var s9="0123456789abcdef",{floor:f7,random:$7}=Math,i2=(f=$7)=>{let $="#";for(let Q=0;Q<6;Q++)$+=s9.charAt(f7(f()*16));return new G($,"hex")};var{log:c2,pow:Q7,floor:U7,abs:J7}=Math;function n1(f,$=null){let Q={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};if(v(f)==="object")f=Object.values(f);return f.forEach((U)=>{if($&&v(U)==="object")U=U[$];if(U!==void 0&&U!==null&&!isNaN(U)){if(Q.values.push(U),Q.sum+=U,UQ.max)Q.max=U;Q.count+=1}}),Q.domain=[Q.min,Q.max],Q.limits=(U,J)=>d1(Q,U,J),Q}function d1(f,$="equal",Q=7){if(v(f)=="array")f=n1(f);let{min:U,max:J}=f,N=f.values.sort((Z,D)=>Z-D);if(Q===1)return[U,J];let q=[];if($.substr(0,1)==="c")q.push(U),q.push(J);if($.substr(0,1)==="e"){q.push(U);for(let Z=1;Z 0");let Z=Math.LOG10E*c2(U),D=Math.LOG10E*c2(J);q.push(U);for(let X=1;X200)F=!1}let u={};for(let B=0;BB-W),q.push(z[0]);for(let B=1;B{f=new G(f),$=new G($);let Q=f.luminance(),U=$.luminance();return Q>U?(Q+0.05)/(U+0.05):(U+0.05)/(Q+0.05)};var e2=0.027,N7=0.0005,q7=0.1,l2=1.14,hf=0.022,a2=1.414,f5=(f,$)=>{if(f=new G(f),$=new G($),f.alpha()<1)f=O0($,f,f.alpha(),"rgb");let Q=s2(...f.rgb()),U=s2(...$.rgb()),J=Q>=hf?Q:Q+Math.pow(hf-Q,a2),N=U>=hf?U:U+Math.pow(hf-U,a2),q=Math.pow(N,0.56)-Math.pow(J,0.57),Z=Math.pow(N,0.65)-Math.pow(J,0.62),D=Math.abs(N-J)0?D-e2:D+e2)*100};function s2(f,$,Q){return 0.2126729*Math.pow(f/255,2.4)+0.7151522*Math.pow($/255,2.4)+0.072175*Math.pow(Q/255,2.4)}var{sqrt:P0,pow:i,min:Z7,max:D7,atan2:$5,abs:Q5,cos:bf,sin:U5,exp:X7,PI:J5}=Math;function t1(f,$,Q=1,U=1,J=1){var N=function(c0){return 360*c0/(2*J5)},q=function(c0){return 2*J5*c0/360};f=new G(f),$=new G($);let[Z,D,X]=Array.from(f.lab()),[K,F,V]=Array.from($.lab()),Y=(Z+K)/2,u=P0(i(D,2)+i(X,2)),z=P0(i(F,2)+i(V,2)),B=(u+z)/2,W=0.5*(1-P0(i(B,7)/(i(B,7)+i(25,7)))),M=D*(1+W),L=F*(1+W),p=P0(i(M,2)+i(X,2)),n=P0(i(L,2)+i(V,2)),m=(p+n)/2,w=N($5(X,M)),y=N($5(V,L)),E=w>=0?w:w+360,k=y>=0?y:y+360,H=Q5(E-k)>180?(E+k+360)/2:(E+k)/2,P=1-0.17*bf(q(H-30))+0.24*bf(q(2*H))+0.32*bf(q(3*H+6))-0.2*bf(q(4*H-63)),T=k-E;T=Q5(T)<=180?T:k<=E?T+360:T-360,T=2*P0(p*n)*U5(q(T)/2);let b=K-Z,l=n-p,G0=1+0.015*i(Y-50,2)/P0(20+i(Y-50,2)),H0=1+0.045*m,i0=1+0.015*m*P,O1=30*X7(-i((H-275)/25,2)),p1=-(2*P0(i(m,7)/(i(m,7)+i(25,7))))*U5(2*q(O1)),M1=P0(i(b/(Q*G0),2)+i(l/(U*H0),2)+i(T/(J*i0),2)+p1*(l/(U*H0))*(T/(J*i0)));return D7(0,Z7(100,M1))}function x1(f,$,Q="lab"){f=new G(f),$=new G($);let U=f.get(Q),J=$.get(Q),N=0;for(let q in U){let Z=(U[q]||0)-(J[q]||0);N+=Z*Z}return Math.sqrt(N)}var N5=(...f)=>{try{return new G(...f),!0}catch($){return!1}};var q5={cool(){return m0([_.hsl(180,1,0.9),_.hsl(250,0.7,0.4)])},hot(){return m0(["#000","#f00","#ff0","#fff"],[0,0.25,0.75,1]).mode("rgb")}};var h1={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Viridis:["#440154","#482777","#3f4a8a","#31678e","#26838f","#1f9d8a","#6cce5a","#b6de2b","#fee825"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]},D5=Object.keys(h1),Z5=new Map(D5.map((f)=>[f.toLowerCase(),f])),K7=typeof Proxy==="function"?new Proxy(h1,{get(f,$){let Q=$.toLowerCase();if(Z5.has(Q))return f[Z5.get(Q)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(D5)}}):h1,X5=K7;var F7=(...f)=>{f=S(f,"cmyk");let[$,Q,U,J]=f,N=f.length>4?f[4]:1;if(J===1)return[0,0,0,N];return[$>=1?0:255*(1-$)*(1-J),Q>=1?0:255*(1-Q)*(1-J),U>=1?0:255*(1-U)*(1-J),N]},K5=F7;var{max:F5}=Math,V7=(...f)=>{let[$,Q,U]=S(f,"rgb");$=$/255,Q=Q/255,U=U/255;let J=1-F5($,F5(Q,U)),N=J<1?1/(1-J):0,q=(1-$-J)*N,Z=(1-Q-J)*N,D=(1-U-J)*N;return[q,Z,D,J]},V5=V7;G.prototype.cmyk=function(){return V5(this._rgb)};var y7=(...f)=>new G(...f,"cmyk");Object.assign(_,{cmyk:y7});R.format.cmyk=K5;R.autodetect.push({p:2,test:(...f)=>{if(f=S(f,"cmyk"),v(f)==="array"&&f.length===4)return"cmyk"}});var W7=(...f)=>{let $=S(f,"hsla"),Q=U0(f)||"lsa";if($[0]=s($[0]||0)+"deg",$[1]=s($[1]*100)+"%",$[2]=s($[2]*100)+"%",Q==="hsla"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="hsla";else $.length=3;return`${Q.substr(0,3)}(${$.join(" ")})`},y5=W7;var Y7=(...f)=>{let $=S(f,"lab"),Q=U0(f)||"lab";if($[0]=s($[0])+"%",$[1]=s($[1]),$[2]=s($[2]),Q==="laba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lab(${$.join(" ")})`},W5=Y7;var G7=(...f)=>{let $=S(f,"lch"),Q=U0(f)||"lab";if($[0]=s($[0])+"%",$[1]=s($[1]),$[2]=isNaN($[2])?"none":s($[2])+"deg",Q==="lcha"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lch(${$.join(" ")})`},Y5=G7;var I7=(...f)=>{let $=S(f,"lab");if($[0]=s($[0]*100)+"%",$[1]=kf($[1]),$[2]=kf($[2]),$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklab(${$.join(" ")})`},G5=I7;var w7=(...f)=>{let[$,Q,U,...J]=S(f,"rgb"),[N,q,Z]=qf($,Q,U),[D,X,K]=tf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},rf=w7;var B7=(...f)=>{let $=S(f,"lch");if($[0]=s($[0]*100)+"%",$[1]=kf($[1]),$[2]=isNaN($[2])?"none":s($[2])+"deg",$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklch(${$.join(" ")})`},I5=B7;var{round:b1}=Math,u7=(...f)=>{let $=S(f,"rgba"),Q=U0(f)||"rgb";if(Q.substr(0,3)==="hsl")return y5(xf($),Q);if(Q.substr(0,3)==="lab"){let U=A0();Z0("d50");let J=W5($f($),Q);return Z0(U),J}if(Q.substr(0,3)==="lch"){let U=A0();Z0("d50");let J=Y5(Hf($),Q);return Z0(U),J}if(Q.substr(0,5)==="oklab")return G5(qf($));if(Q.substr(0,5)==="oklch")return I5(rf($));if($[0]=b1($[0]),$[1]=b1($[1]),$[2]=b1($[2]),Q==="rgba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="rgba";return`${Q.substr(0,3)}(${$.slice(0,Q==="rgb"?3:4).join(" ")})`},w5=u7;var E7=(...f)=>{f=S(f,"lch");let[$,Q,U,...J]=f,[N,q,Z]=df($,Q,U),[D,X,K]=Nf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},gf=E7;var L0=/((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source,w0=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source,cf=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source,X0=/\s*/.source,Df=/\s+/.source,r1=/\s*,\s*/.source,of=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source,Xf=/\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source,B5=new RegExp("^rgba?\\("+X0+[L0,L0,L0].join(Df)+Xf+"\\)$"),u5=new RegExp("^rgb\\("+X0+[L0,L0,L0].join(r1)+X0+"\\)$"),E5=new RegExp("^rgba\\("+X0+[L0,L0,L0,w0].join(r1)+X0+"\\)$"),k5=new RegExp("^hsla?\\("+X0+[of,cf,cf].join(Df)+Xf+"\\)$"),z5=new RegExp("^hsl?\\("+X0+[of,cf,cf].join(r1)+X0+"\\)$"),H5=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,S5=new RegExp("^lab\\("+X0+[w0,w0,w0].join(Df)+Xf+"\\)$"),O5=new RegExp("^lch\\("+X0+[w0,w0,of].join(Df)+Xf+"\\)$"),p5=new RegExp("^oklab\\("+X0+[w0,w0,w0].join(Df)+Xf+"\\)$"),M5=new RegExp("^oklch\\("+X0+[w0,w0,of].join(Df)+Xf+"\\)$"),{round:T5}=Math,Zf=(f)=>{return f.map(($,Q)=>Q<=2?N0(T5($),0,255):$)},c=(f,$=0,Q=100,U=!1)=>{if(typeof f==="string"&&f.endsWith("%"))if(f=parseFloat(f.substring(0,f.length-1))/100,U)f=$+(f+1)*0.5*(Q-$);else f=$+f*(Q-$);return+f},$0=(f,$)=>{return f==="none"?$:f},P5=(f)=>{if(f=f.toLowerCase().trim(),f==="transparent")return[0,0,0,0];let $;if(R.format.named)try{return R.format.named(f)}catch(Q){}if(($=f.match(B5))||($=f.match(u5))){let Q=$.slice(1,4);for(let J=0;J<3;J++)Q[J]=+c($0(Q[J],0),0,255);Q=Zf(Q);let U=$[4]!==void 0?+c($[4],0,1):1;return Q[3]=U,Q}if($=f.match(E5)){let Q=$.slice(1,5);for(let U=0;U<4;U++)Q[U]=+c(Q[U],0,255);return Q}if(($=f.match(k5))||($=f.match(z5))){let Q=$.slice(1,4);Q[0]=+$0(Q[0].replace("deg",""),0),Q[1]=+c($0(Q[1],0),0,100)*0.01,Q[2]=+c($0(Q[2],0),0,100)*0.01;let U=Zf(Sf(Q)),J=$[4]!==void 0?+c($[4],0,1):1;return U[3]=J,U}if($=f.match(H5)){let Q=$.slice(1,4);Q[1]*=0.01,Q[2]*=0.01;let U=Sf(Q);for(let J=0;J<3;J++)U[J]=T5(U[J]);return U[3]=+$[4],U}if($=f.match(S5)){let Q=$.slice(1,4);Q[0]=c($0(Q[0],0),0,100),Q[1]=c($0(Q[1],0),-125,125,!0),Q[2]=c($0(Q[2],0),-125,125,!0);let U=A0();Z0("d50");let J=Zf(ff(Q));Z0(U);let N=$[4]!==void 0?+c($[4],0,1):1;return J[3]=N,J}if($=f.match(O5)){let Q=$.slice(1,4);Q[0]=c(Q[0],0,100),Q[1]=c($0(Q[1],0),0,150,!1),Q[2]=+$0(Q[2].replace("deg",""),0);let U=A0();Z0("d50");let J=Zf(Qf(Q));Z0(U);let N=$[4]!==void 0?+c($[4],0,1):1;return J[3]=N,J}if($=f.match(p5)){let Q=$.slice(1,4);Q[0]=c($0(Q[0],0),0,1),Q[1]=c($0(Q[1],0),-0.4,0.4,!0),Q[2]=c($0(Q[2],0),-0.4,0.4,!0);let U=Zf(Nf(Q)),J=$[4]!==void 0?+c($[4],0,1):1;return U[3]=J,U}if($=f.match(M5)){let Q=$.slice(1,4);Q[0]=c($0(Q[0],0),0,1),Q[1]=c($0(Q[1],0),0,0.4,!1),Q[2]=+$0(Q[2].replace("deg",""),0);let U=Zf(gf(Q)),J=$[4]!==void 0?+c($[4],0,1):1;return U[3]=J,U}};P5.test=(f)=>{return B5.test(f)||k5.test(f)||S5.test(f)||O5.test(f)||p5.test(f)||M5.test(f)||u5.test(f)||E5.test(f)||z5.test(f)||H5.test(f)||f==="transparent"};var g1=P5;G.prototype.css=function(f){return w5(this._rgb,f)};var k7=(...f)=>new G(...f,"css");_.css=k7;R.format.css=g1;R.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&v(f)==="string"&&g1.test(f))return"css"}});R.format.gl=(...f)=>{let $=S(f,"rgba");return $[0]*=255,$[1]*=255,$[2]*=255,$};var z7=(...f)=>new G(...f,"gl");_.gl=z7;G.prototype.gl=function(){let f=this._rgb;return[f[0]/255,f[1]/255,f[2]/255,f[3]]};G.prototype.hex=function(f){return nf(this._rgb,f)};var H7=(...f)=>new G(...f,"hex");_.hex=H7;R.format.hex=_f;R.autodetect.push({p:4,test:(f,...$)=>{if(!$.length&&v(f)==="string"&&[3,4,5,6,7,8,9].indexOf(f.length)>=0)return"hex"}});var{log:ef}=Math,S7=(f)=>{let $=f/100,Q,U,J;if($<66)Q=255,U=$<6?0:-155.25485562709179-0.44596950469579133*(U=$-2)+104.49216199393888*ef(U),J=$<20?0:-254.76935184120902+0.8274096064007395*(J=$-10)+115.67994401066147*ef(J);else Q=351.97690566805693+0.114206453784165*(Q=$-55)-40.25366309332127*ef(Q),U=325.4494125711974+0.07943456536662342*(U=$-50)-28.0852963507957*ef(U),J=255;return[Q,U,J,1]},lf=S7;var{round:O7}=Math,p7=(...f)=>{let $=S(f,"rgb"),Q=$[0],U=$[2],J=1000,N=40000,q=0.4,Z;while(N-J>q){Z=(N+J)*0.5;let D=lf(Z);if(D[2]/D[0]>=U/Q)N=Z;else J=Z}return O7(Z)},L5=p7;G.prototype.temp=G.prototype.kelvin=G.prototype.temperature=function(){return L5(this._rgb)};var i1=(...f)=>new G(...f,"temp");Object.assign(_,{temp:i1,kelvin:i1,temperature:i1});R.format.temp=R.format.kelvin=R.format.temperature=lf;G.prototype.oklch=function(){return rf(this._rgb)};var M7=(...f)=>new G(...f,"oklch");Object.assign(_,{oklch:M7});R.format.oklch=gf;R.autodetect.push({p:2,test:(...f)=>{if(f=S(f,"oklch"),v(f)==="array"&&f.length===3)return"oklch"}});Object.assign(_,{analyze:n1,average:h2,bezier:b2,blend:g2,brewer:X5,Color:G,colors:R0,contrast:o2,contrastAPCA:f5,cubehelix:C1,deltaE:t1,distance:x1,input:R,interpolate:O0,limits:d1,mix:O0,random:i2,scale:m0,scales:q5,valid:N5});var t=_;var{min:T7,max:P7}=Math,K0=(f,$=0,Q=1)=>{return T7(P7($,f),Q)};var l0=(f)=>{f._clipped=!1,f._unclipped=f.slice(0);for(let $=0;$<=3;$++)if($<3){if(f[$]<0||f[$]>255)f._clipped=!0;f[$]=K0(f[$],0,255)}else if($===3)f[$]=K0(f[$],0,1);return f};var v5={};for(let f of["Boolean","Number","String","Function","Array","Date","RegExp","Undefined","Null"])v5[`[object ${f}]`]=f.toLowerCase();function j(f){return v5[Object.prototype.toString.call(f)]||"object"}var O=(f,$=null)=>{if(f.length>=3)return Array.prototype.slice.call(f);if(j(f[0])=="object"&&$)return $.split("").filter((Q)=>f[0][Q]!==void 0).map((Q)=>f[0][Q]);return f[0].slice(0)};var J0=(f)=>{if(f.length<2)return null;let $=f.length-1;if(j(f[$])=="string")return f[$].toLowerCase();return null};var{PI:af,min:sf,max:f1}=Math,f0=(f)=>Math.round(f*100)/100,Of=(f)=>Math.round(f*100)/100,F0=af*2,$1=af/3,j5=af/180,R5=180/af;function Q1(f){return[...f.slice(0,3).reverse(),...f.slice(3)]}var A={format:{},autodetect:[]};class A5{constructor(...f){let $=this;if(j(f[0])==="object"&&f[0].constructor&&f[0].constructor===this.constructor)return f[0];let Q=J0(f),U=!1;if(!Q){if(U=!0,!A.sorted)A.autodetect=A.autodetect.sort((J,N)=>N.p-J.p),A.sorted=!0;for(let J of A.autodetect)if(Q=J.test(...f),Q)break}if(A.format[Q]){let J=A.format[Q].apply(null,U?f:f.slice(0,-1));$._rgb=l0(J)}else throw Error("unknown format: "+f);if($._rgb.length===3)$._rgb.push(1)}toString(){if(j(this.hex)=="function")return this.hex();return`[${this._rgb.join(",")}]`}}var I=A5;var m5="3.1.2";var _5=(...f)=>{return new I(...f)};_5.version=m5;var C=_5;var L7={aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkgrey:"#a9a9a9",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkslategrey:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dimgrey:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",grey:"#808080",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",laserlemon:"#ffff54",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrod:"#fafad2",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightgrey:"#d3d3d3",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightslategrey:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",maroon2:"#7f0000",maroon3:"#b03060",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",purple2:"#7f007f",purple3:"#a020f0",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",slategrey:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},n0=L7;var v7=/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/,j7=/^#?([A-Fa-f0-9]{8}|[A-Fa-f0-9]{4})$/,R7=(f)=>{if(f.match(v7)){if(f.length===4||f.length===7)f=f.substr(1);if(f.length===3)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2];let $=parseInt(f,16),Q=$>>16,U=$>>8&255,J=$&255;return[Q,U,J,1]}if(f.match(j7)){if(f.length===5||f.length===9)f=f.substr(1);if(f.length===4)f=f.split(""),f=f[0]+f[0]+f[1]+f[1]+f[2]+f[2]+f[3]+f[3];let $=parseInt(f,16),Q=$>>24&255,U=$>>16&255,J=$>>8&255,N=Math.round(($&255)/255*100)/100;return[Q,U,J,N]}throw Error(`unknown hex color: ${f}`)},U1=R7;var{round:J1}=Math,A7=(...f)=>{let[$,Q,U,J]=O(f,"rgba"),N=J0(f)||"auto";if(J===void 0)J=1;if(N==="auto")N=J<1?"rgba":"rgb";$=J1($),Q=J1(Q),U=J1(U);let Z="000000"+($<<16|Q<<8|U).toString(16);Z=Z.substr(Z.length-6);let D="0"+J1(J*255).toString(16);switch(D=D.substr(D.length-2),N.toLowerCase()){case"rgba":return`#${Z}${D}`;case"argb":return`#${D}${Z}`;default:return`#${Z}`}},N1=A7;I.prototype.name=function(){let f=N1(this._rgb,"rgb");for(let $ of Object.keys(n0))if(n0[$]===f)return $.toLowerCase();return f};A.format.named=(f)=>{if(f=f.toLowerCase(),n0[f])return U1(n0[f]);throw Error("unknown color name: "+f)};A.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&j(f)==="string"&&n0[f.toLowerCase()])return"named"}});I.prototype.alpha=function(f,$=!1){if(f!==void 0&&j(f)==="number"){if($)return this._rgb[3]=f,this;return new I([this._rgb[0],this._rgb[1],this._rgb[2],f],"rgb")}return this._rgb[3]};I.prototype.clipped=function(){return this._rgb._clipped||!1};var pf={Kn:18,labWhitePoint:"d65",Xn:0.95047,Yn:1,Zn:1.08883,t0:0.137931034,t1:0.206896552,t2:0.12841855,t3:0.008856452,kE:0.008856451679035631,kKE:8,kK:903.2962962962963,RefWhiteRGB:{X:0.95047,Y:1,Z:1.08883},MtxRGB2XYZ:{m00:0.4124564390896922,m01:0.21267285140562253,m02:0.0193338955823293,m10:0.357576077643909,m11:0.715152155287818,m12:0.11919202588130297,m20:0.18043748326639894,m21:0.07217499330655958,m22:0.9503040785363679},MtxXYZ2RGB:{m00:3.2404541621141045,m01:-0.9692660305051868,m02:0.055643430959114726,m10:-1.5371385127977166,m11:1.8760108454466942,m12:-0.2040259135167538,m20:-0.498531409556016,m21:0.041556017530349834,m22:1.0572251882231791},As:0.9414285350000001,Bs:1.040417467,Cs:1.089532651,MtxAdaptMa:{m00:0.8951,m01:-0.7502,m02:0.0389,m10:0.2664,m11:1.7135,m12:-0.0685,m20:-0.1614,m21:0.0367,m22:1.0296},MtxAdaptMaI:{m00:0.9869929054667123,m01:0.43230526972339456,m02:-0.008528664575177328,m10:-0.14705425642099013,m11:0.5183602715367776,m12:0.04004282165408487,m20:0.15996265166373125,m21:0.0492912282128556,m22:0.9684866957875502}},p0=pf,m7=new Map([["a",[1.0985,0.35585]],["b",[1.0985,0.35585]],["c",[0.98074,1.18232]],["d50",[0.96422,0.82521]],["d55",[0.95682,0.92149]],["d65",[0.95047,1.08883]],["e",[1,1,1]],["f2",[0.99186,0.67393]],["f7",[0.95041,1.08747]],["f11",[1.00962,0.6435]],["icc",[0.96422,0.82521]]]);function V0(f){let $=m7.get(String(f).toLowerCase());if(!$)throw Error("unknown Lab illuminant "+f);pf.labWhitePoint=f,pf.Xn=$[0],pf.Zn=$[1]}function d0(){return pf.labWhitePoint}var _7=(...f)=>{f=O(f,"lab");let[$,Q,U]=f,[J,N,q]=C7($,Q,U),[Z,D,X]=o1(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},C7=(f,$,Q)=>{let{kE:U,kK:J,kKE:N,Xn:q,Yn:Z,Zn:D}=p0,X=(f+16)/116,K=0.002*$+X,F=X-0.005*Q,V=K*K*K,Y=F*F*F,u=V>U?V:(116*K-16)/J,z=f>N?Math.pow((f+16)/116,3):f/J,B=Y>U?Y:(116*F-16)/J,W=u*q,M=z*Z,L=B*D;return[W,M,L]},c1=(f)=>{let $=Math.sign(f);return f=Math.abs(f),(f<=0.0031308?f*12.92:1.055*Math.pow(f,0.4166666666666667)-0.055)*$},o1=(f,$,Q)=>{let{MtxAdaptMa:U,MtxAdaptMaI:J,MtxXYZ2RGB:N,RefWhiteRGB:q,Xn:Z,Yn:D,Zn:X}=p0,K=Z*U.m00+D*U.m10+X*U.m20,F=Z*U.m01+D*U.m11+X*U.m21,V=Z*U.m02+D*U.m12+X*U.m22,Y=q.X*U.m00+q.Y*U.m10+q.Z*U.m20,u=q.X*U.m01+q.Y*U.m11+q.Z*U.m21,z=q.X*U.m02+q.Y*U.m12+q.Z*U.m22,B=(f*U.m00+$*U.m10+Q*U.m20)*(Y/K),W=(f*U.m01+$*U.m11+Q*U.m21)*(u/F),M=(f*U.m02+$*U.m12+Q*U.m22)*(z/V),L=B*J.m00+W*J.m10+M*J.m20,p=B*J.m01+W*J.m11+M*J.m21,n=B*J.m02+W*J.m12+M*J.m22,m=c1(L*N.m00+p*N.m10+n*N.m20),w=c1(L*N.m01+p*N.m11+n*N.m21),y=c1(L*N.m02+p*N.m12+n*N.m22);return[m*255,w*255,y*255]},Kf=_7;var n7=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),[N,q,Z]=l1($,Q,U),[D,X,K]=d7(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function d7(f,$,Q){let{Xn:U,Yn:J,Zn:N,kE:q,kK:Z}=p0,D=f/U,X=$/J,K=Q/N,F=D>q?Math.pow(D,0.3333333333333333):(Z*D+16)/116,V=X>q?Math.pow(X,0.3333333333333333):(Z*X+16)/116,Y=K>q?Math.pow(K,0.3333333333333333):(Z*K+16)/116;return[116*V-16,500*(F-V),200*(V-Y)]}function e1(f){let $=Math.sign(f);return f=Math.abs(f),(f<=0.04045?f/12.92:Math.pow((f+0.055)/1.055,2.4))*$}var l1=(f,$,Q)=>{f=e1(f/255),$=e1($/255),Q=e1(Q/255);let{MtxRGB2XYZ:U,MtxAdaptMa:J,MtxAdaptMaI:N,Xn:q,Yn:Z,Zn:D,As:X,Bs:K,Cs:F}=p0,V=f*U.m00+$*U.m10+Q*U.m20,Y=f*U.m01+$*U.m11+Q*U.m21,u=f*U.m02+$*U.m12+Q*U.m22,z=q*J.m00+Z*J.m10+D*J.m20,B=q*J.m01+Z*J.m11+D*J.m21,W=q*J.m02+Z*J.m12+D*J.m22,M=V*J.m00+Y*J.m10+u*J.m20,L=V*J.m01+Y*J.m11+u*J.m21,p=V*J.m02+Y*J.m12+u*J.m22;return M*=z/X,L*=B/K,p*=W/F,V=M*N.m00+L*N.m10+p*N.m20,Y=M*N.m01+L*N.m11+p*N.m21,u=M*N.m02+L*N.m12+p*N.m22,[V,Y,u]},Ff=n7;I.prototype.lab=function(){return Ff(this._rgb)};var t7=(...f)=>new I(...f,"lab");Object.assign(C,{lab:t7,getLabWhitePoint:d0,setLabWhitePoint:V0});A.format.lab=Kf;A.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"lab"),j(f)==="array"&&f.length===3)return"lab"}});I.prototype.darken=function(f=1){let $=this,Q=$.lab();return Q[0]-=p0.Kn*f,new I(Q,"lab").alpha($.alpha(),!0)};I.prototype.brighten=function(f=1){return this.darken(-f)};I.prototype.darker=I.prototype.darken;I.prototype.brighter=I.prototype.brighten;I.prototype.get=function(f){let[$,Q]=f.split("."),U=this[$]();if(Q){let J=$.indexOf(Q)-($.substr(0,2)==="ok"?2:0);if(J>-1)return U[J];throw Error(`unknown channel ${Q} in mode ${$}`)}else return U};var{pow:x7}=Math,h7=0.0000001,b7=20;I.prototype.luminance=function(f,$="rgb"){if(f!==void 0&&j(f)==="number"){if(f===0)return new I([0,0,0,this._rgb[3]],"rgb");if(f===1)return new I([255,255,255,this._rgb[3]],"rgb");let Q=this.luminance(),U=b7,J=(q,Z)=>{let D=q.interpolate(Z,0.5,$),X=D.luminance();if(Math.abs(f-X)f?J(q,D):J(D,Z)},N=(Q>f?J(new I([0,0,0]),this):J(this,new I([255,255,255]))).rgb();return new I([...N,this._rgb[3]])}return r7(...this._rgb.slice(0,3))};var r7=(f,$,Q)=>{return f=a1(f),$=a1($),Q=a1(Q),0.2126*f+0.7152*$+0.0722*Q},a1=(f)=>{return f/=255,f<=0.03928?f/12.92:x7((f+0.055)/1.055,2.4)};var h={};var M0=(f,$,Q=0.5,...U)=>{let J=U[0]||"lrgb";if(!h[J]&&!U.length)J=Object.keys(h)[0];if(!h[J])throw Error(`interpolation mode ${J} is not defined`);if(j(f)!=="object")f=new I(f);if(j($)!=="object")$=new I($);return h[J](f,$,Q).alpha(f.alpha()+Q*($.alpha()-f.alpha()))};I.prototype.mix=I.prototype.interpolate=function(f,$=0.5,...Q){return M0(this,f,$,...Q)};I.prototype.premultiply=function(f=!1){let $=this._rgb,Q=$[3];if(f)return this._rgb=[$[0]*Q,$[1]*Q,$[2]*Q,Q],this;else return new I([$[0]*Q,$[1]*Q,$[2]*Q,Q],"rgb")};var{sin:g7,cos:i7}=Math,c7=(...f)=>{let[$,Q,U]=O(f,"lch");if(isNaN(U))U=0;return U=U*j5,[$,i7(U)*Q,g7(U)*Q]},q1=c7;var o7=(...f)=>{f=O(f,"lch");let[$,Q,U]=f,[J,N,q]=q1($,Q,U),[Z,D,X]=Kf(J,N,q);return[Z,D,X,f.length>3?f[3]:1]},Vf=o7;var e7=(...f)=>{let $=Q1(O(f,"hcl"));return Vf(...$)},C5=e7;var{sqrt:l7,atan2:a7,round:s7}=Math,f4=(...f)=>{let[$,Q,U]=O(f,"lab"),J=l7(Q*Q+U*U),N=(a7(U,Q)*R5+360)%360;if(s7(J*1e4)===0)N=Number.NaN;return[$,J,N]},Z1=f4;var $4=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),[N,q,Z]=Ff($,Q,U),[D,X,K]=Z1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},Mf=$4;I.prototype.lch=function(){return Mf(this._rgb)};I.prototype.hcl=function(){return Q1(Mf(this._rgb))};var Q4=(...f)=>new I(...f,"lch"),U4=(...f)=>new I(...f,"hcl");Object.assign(C,{lch:Q4,hcl:U4});A.format.lch=Vf;A.format.hcl=C5;["lch","hcl"].forEach((f)=>A.autodetect.push({p:2,test:(...$)=>{if($=O($,f),j($)==="array"&&$.length===3)return f}}));I.prototype.saturate=function(f=1){let $=this,Q=$.lch();if(Q[1]+=p0.Kn*f,Q[1]<0)Q[1]=0;return new I(Q,"lch").alpha($.alpha(),!0)};I.prototype.desaturate=function(f=1){return this.saturate(-f)};I.prototype.set=function(f,$,Q=!1){let[U,J]=f.split("."),N=this[U]();if(J){let q=U.indexOf(J)-(U.substr(0,2)==="ok"?2:0);if(q>-1){if(j($)=="string")switch($.charAt(0)){case"+":N[q]+=+$;break;case"-":N[q]+=+$;break;case"*":N[q]*=+$.substr(1);break;case"/":N[q]/=+$.substr(1);break;default:N[q]=+$}else if(j($)==="number")N[q]=$;else throw Error("unsupported value for Color.set");let Z=new I(N,U);if(Q)return this._rgb=Z._rgb,this;return Z}throw Error(`unknown channel ${J} in mode ${U}`)}else return N};I.prototype.tint=function(f=0.5,...$){return M0(this,"white",f,...$)};I.prototype.shade=function(f=0.5,...$){return M0(this,"black",f,...$)};var J4=(f,$,Q)=>{let U=f._rgb,J=$._rgb;return new I(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"rgb")};h.rgb=J4;var{sqrt:s1,pow:yf}=Math,N4=(f,$,Q)=>{let[U,J,N]=f._rgb,[q,Z,D]=$._rgb;return new I(s1(yf(U,2)*(1-Q)+yf(q,2)*Q),s1(yf(J,2)*(1-Q)+yf(Z,2)*Q),s1(yf(N,2)*(1-Q)+yf(D,2)*Q),"rgb")};h.lrgb=N4;var q4=(f,$,Q)=>{let U=f.lab(),J=$.lab();return new I(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"lab")};h.lab=q4;var y0=(f,$,Q,U)=>{let J,N;if(U==="hsl")J=f.hsl(),N=$.hsl();else if(U==="hsv")J=f.hsv(),N=$.hsv();else if(U==="hcg")J=f.hcg(),N=$.hcg();else if(U==="hsi")J=f.hsi(),N=$.hsi();else if(U==="lch"||U==="hcl")U="hcl",J=f.hcl(),N=$.hcl();else if(U==="oklch")J=f.oklch().reverse(),N=$.oklch().reverse();let q,Z,D,X,K,F;if(U.substr(0,1)==="h"||U==="oklch")[q,D,K]=J,[Z,X,F]=N;let V,Y,u,z;if(!isNaN(q)&&!isNaN(Z)){if(Z>q&&Z-q>180)z=Z-(q+360);else if(Z180)z=Z+360-q;else z=Z-q;Y=q+Q*z}else if(!isNaN(q)){if(Y=q,(F==1||F==0)&&U!="hsv")V=D}else if(!isNaN(Z)){if(Y=Z,(K==1||K==0)&&U!="hsv")V=X}else Y=Number.NaN;if(V===void 0)V=D+Q*(X-D);return u=K+Q*(F-K),U==="oklch"?new I([u,V,Y],U):new I([Y,V,u],U)};var n5=(f,$,Q)=>{return y0(f,$,Q,"lch")};h.lch=n5;h.hcl=n5;var Z4=(f)=>{if(j(f)=="number"&&f>=0&&f<=16777215){let $=f>>16,Q=f>>8&255,U=f&255;return[$,Q,U,1]}throw Error("unknown num color: "+f)},d5=Z4;var D4=(...f)=>{let[$,Q,U]=O(f,"rgb");return($<<16)+(Q<<8)+U},t5=D4;I.prototype.num=function(){return t5(this._rgb)};var X4=(...f)=>new I(...f,"num");Object.assign(C,{num:X4});A.format.num=d5;A.autodetect.push({p:5,test:(...f)=>{if(f.length===1&&j(f[0])==="number"&&f[0]>=0&&f[0]<=16777215)return"num"}});var K4=(f,$,Q)=>{let U=f.num(),J=$.num();return new I(U+Q*(J-U),"num")};h.num=K4;var{floor:F4}=Math,V4=(...f)=>{f=O(f,"hcg");let[$,Q,U]=f,J,N,q;U=U*255;let Z=Q*255;if(Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let D=F4($),X=$-D,K=U*(1-Q),F=K+Z*(1-X),V=K+Z*X,Y=K+Z;switch(D){case 0:[J,N,q]=[Y,V,K];break;case 1:[J,N,q]=[F,Y,K];break;case 2:[J,N,q]=[K,Y,V];break;case 3:[J,N,q]=[K,F,Y];break;case 4:[J,N,q]=[V,K,Y];break;case 5:[J,N,q]=[Y,K,F];break}}return[J,N,q,f.length>3?f[3]:1]},x5=V4;var y4=(...f)=>{let[$,Q,U]=O(f,"rgb"),J=sf($,Q,U),N=f1($,Q,U),q=N-J,Z=q*100/255,D=J/(255-q)*100,X;if(q===0)X=Number.NaN;else{if($===N)X=(Q-U)/q;if(Q===N)X=2+(U-$)/q;if(U===N)X=4+($-Q)/q;if(X*=60,X<0)X+=360}return[X,Z,D]},h5=y4;I.prototype.hcg=function(){return h5(this._rgb)};var W4=(...f)=>new I(...f,"hcg");C.hcg=W4;A.format.hcg=x5;A.autodetect.push({p:1,test:(...f)=>{if(f=O(f,"hcg"),j(f)==="array"&&f.length===3)return"hcg"}});var Y4=(f,$,Q)=>{return y0(f,$,Q,"hcg")};h.hcg=Y4;var{cos:Wf}=Math,G4=(...f)=>{f=O(f,"hsi");let[$,Q,U]=f,J,N,q;if(isNaN($))$=0;if(isNaN(Q))Q=0;if($>360)$-=360;if($<0)$+=360;if($/=360,$<0.3333333333333333)q=(1-Q)/3,J=(1+Q*Wf(F0*$)/Wf($1-F0*$))/3,N=1-(q+J);else if($<0.6666666666666666)$-=0.3333333333333333,J=(1-Q)/3,N=(1+Q*Wf(F0*$)/Wf($1-F0*$))/3,q=1-(J+N);else $-=0.6666666666666666,N=(1-Q)/3,q=(1+Q*Wf(F0*$)/Wf($1-F0*$))/3,J=1-(N+q);return J=K0(U*J*3),N=K0(U*N*3),q=K0(U*q*3),[J*255,N*255,q*255,f.length>3?f[3]:1]},b5=G4;var{min:I4,sqrt:w4,acos:B4}=Math,u4=(...f)=>{let[$,Q,U]=O(f,"rgb");$/=255,Q/=255,U/=255;let J,N=I4($,Q,U),q=($+Q+U)/3,Z=q>0?1-N/q:0;if(Z===0)J=NaN;else{if(J=($-Q+($-U))/2,J/=w4(($-Q)*($-Q)+($-U)*(Q-U)),J=B4(J),U>Q)J=F0-J;J/=F0}return[J*360,Z,q]},r5=u4;I.prototype.hsi=function(){return r5(this._rgb)};var E4=(...f)=>new I(...f,"hsi");C.hsi=E4;A.format.hsi=b5;A.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"hsi"),j(f)==="array"&&f.length===3)return"hsi"}});var k4=(f,$,Q)=>{return y0(f,$,Q,"hsi")};h.hsi=k4;var z4=(...f)=>{f=O(f,"hsl");let[$,Q,U]=f,J,N,q;if(Q===0)J=N=q=U*255;else{let Z=[0,0,0],D=[0,0,0],X=U<0.5?U*(1+Q):U+Q-U*Q,K=2*U-X,F=$/360;Z[0]=F+0.3333333333333333,Z[1]=F,Z[2]=F-0.3333333333333333;for(let V=0;V<3;V++){if(Z[V]<0)Z[V]+=1;if(Z[V]>1)Z[V]-=1;if(6*Z[V]<1)D[V]=K+(X-K)*6*Z[V];else if(2*Z[V]<1)D[V]=X;else if(3*Z[V]<2)D[V]=K+(X-K)*(0.6666666666666666-Z[V])*6;else D[V]=K}[J,N,q]=[D[0]*255,D[1]*255,D[2]*255]}if(f.length>3)return[J,N,q,f[3]];return[J,N,q,1]},Tf=z4;var H4=(...f)=>{f=O(f,"rgba");let[$,Q,U]=f;$/=255,Q/=255,U/=255;let J=sf($,Q,U),N=f1($,Q,U),q=(N+J)/2,Z,D;if(N===J)Z=0,D=Number.NaN;else Z=q<0.5?(N-J)/(N+J):(N-J)/(2-N-J);if($==N)D=(Q-U)/(N-J);else if(Q==N)D=2+(U-$)/(N-J);else if(U==N)D=4+($-Q)/(N-J);if(D*=60,D<0)D+=360;if(f.length>3&&f[3]!==void 0)return[D,Z,q,f[3]];return[D,Z,q]},D1=H4;I.prototype.hsl=function(){return D1(this._rgb)};var S4=(...f)=>new I(...f,"hsl");C.hsl=S4;A.format.hsl=Tf;A.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"hsl"),j(f)==="array"&&f.length===3)return"hsl"}});var O4=(f,$,Q)=>{return y0(f,$,Q,"hsl")};h.hsl=O4;var{floor:p4}=Math,M4=(...f)=>{f=O(f,"hsv");let[$,Q,U]=f,J,N,q;if(U*=255,Q===0)J=N=q=U;else{if($===360)$=0;if($>360)$-=360;if($<0)$+=360;$/=60;let Z=p4($),D=$-Z,X=U*(1-Q),K=U*(1-Q*D),F=U*(1-Q*(1-D));switch(Z){case 0:[J,N,q]=[U,F,X];break;case 1:[J,N,q]=[K,U,X];break;case 2:[J,N,q]=[X,U,F];break;case 3:[J,N,q]=[X,K,U];break;case 4:[J,N,q]=[F,X,U];break;case 5:[J,N,q]=[U,X,K];break}}return[J,N,q,f.length>3?f[3]:1]},g5=M4;var{min:T4,max:P4}=Math,L4=(...f)=>{f=O(f,"rgb");let[$,Q,U]=f,J=T4($,Q,U),N=P4($,Q,U),q=N-J,Z,D,X;if(X=N/255,N===0)Z=Number.NaN,D=0;else{if(D=q/N,$===N)Z=(Q-U)/q;if(Q===N)Z=2+(U-$)/q;if(U===N)Z=4+($-Q)/q;if(Z*=60,Z<0)Z+=360}return[Z,D,X]},i5=L4;I.prototype.hsv=function(){return i5(this._rgb)};var v4=(...f)=>new I(...f,"hsv");C.hsv=v4;A.format.hsv=g5;A.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"hsv"),j(f)==="array"&&f.length===3)return"hsv"}});var j4=(f,$,Q)=>{return y0(f,$,Q,"hsv")};h.hsv=j4;function a0(f,$){let Q=f.length;if(!Array.isArray(f[0]))f=[f];if(!Array.isArray($[0]))$=$.map((q)=>[q]);let U=$[0].length,J=$[0].map((q,Z)=>$.map((D)=>D[Z])),N=f.map((q)=>J.map((Z)=>{if(!Array.isArray(q))return Z.reduce((D,X)=>D+X*q,0);return q.reduce((D,X,K)=>D+X*(Z[K]||0),0)}));if(Q===1)N=N[0];if(U===1)return N.map((q)=>q[0]);return N}var R4=(...f)=>{f=O(f,"lab");let[$,Q,U,...J]=f,[N,q,Z]=A4([$,Q,U]),[D,X,K]=o1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]};function A4(f){var $=[[1.2268798758459243,-0.5578149944602171,0.2813910456659647],[-0.0405757452148008,1.112286803280317,-0.0717110580655164],[-0.0763729366746601,-0.4214933324022432,1.5869240198367816]],Q=[[1,0.3963377773761749,0.2158037573099136],[1,-0.1055613458156586,-0.0638541728258133],[1,-0.0894841775298119,-1.2914855480194092]],U=a0(Q,f);return a0($,U.map((J)=>J**3))}var Yf=R4;var m4=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),N=l1($,Q,U);return[..._4(N),...J.length>0&&J[0]<1?[J[0]]:[]]};function _4(f){let $=[[0.819022437996703,0.3619062600528904,-0.1288737815209879],[0.0329836539323885,0.9292868615863434,0.0361446663506424],[0.0481771893596242,0.2642395317527308,0.6335478284694309]],Q=[[0.210454268309314,0.7936177747023054,-0.0040720430116193],[1.9779985324311684,-2.42859224204858,0.450593709617411],[0.0259040424655478,0.7827717124575296,-0.8086757549230774]],U=a0($,f);return a0(Q,U.map((J)=>Math.cbrt(J)))}var Gf=m4;I.prototype.oklab=function(){return Gf(this._rgb)};var C4=(...f)=>new I(...f,"oklab");Object.assign(C,{oklab:C4});A.format.oklab=Yf;A.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"oklab"),j(f)==="array"&&f.length===3)return"oklab"}});var n4=(f,$,Q)=>{let U=f.oklab(),J=$.oklab();return new I(U[0]+Q*(J[0]-U[0]),U[1]+Q*(J[1]-U[1]),U[2]+Q*(J[2]-U[2]),"oklab")};h.oklab=n4;var d4=(f,$,Q)=>{return y0(f,$,Q,"oklch")};h.oklch=d4;var{pow:f2,sqrt:$2,PI:Q2,cos:c5,sin:o5,atan2:t4}=Math,e5=(f,$="lrgb",Q=null)=>{let U=f.length;if(!Q)Q=Array.from(Array(U)).map(()=>1);let J=U/Q.reduce(function(F,V){return F+V});if(Q.forEach((F,V)=>{Q[V]*=J}),f=f.map((F)=>new I(F)),$==="lrgb")return x4(f,Q);let N=f.shift(),q=N.get($),Z=[],D=0,X=0;for(let F=0;F{let Y=F.get($);K+=F.alpha()*Q[V+1];for(let u=0;u=360)V-=360;q[F]=V}else q[F]=q[F]/Z[F];return K/=U,new I(q,$).alpha(K>0.99999?1:K,!0)},x4=(f,$)=>{let Q=f.length,U=[0,0,0,0];for(let J=0;J0.9999999)U[3]=1;return new I(l0(U))};var{pow:h4}=Math;function t0(f){let $="rgb",Q=C("#ccc"),U=0,J=[0,1],N=[],q=[0,0],Z=!1,D=[],X=!1,K=0,F=1,V=!1,Y={},u=!0,z=1,B=function(w){if(w=w||["#fff","#000"],w&&j(w)==="string"&&C.brewer&&C.brewer[w.toLowerCase()])w=C.brewer[w.toLowerCase()];if(j(w)==="array"){if(w.length===1)w=[w[0],w[0]];w=w.slice(0);for(let y=0;y=Z[E])E++;return E-1}return 0},M=(w)=>w,L=(w)=>w,p=function(w,y){let E,k;if(y==null)y=!1;if(isNaN(w)||w===null)return Q;if(!y)if(Z&&Z.length>2)k=W(w)/(Z.length-2);else if(F!==K)k=(w-K)/(F-K);else k=1;else k=w;if(k=L(k),!y)k=M(k);if(z!==1)k=h4(k,z);k=q[0]+k*(1-q[0]-q[1]),k=K0(k,0,1);let H=Math.floor(k*1e4);if(u&&Y[H])E=Y[H];else{if(j(D)==="array")for(let P=0;P=T&&P===N.length-1){E=D[P];break}if(k>T&&kY={};B(f);let m=function(w){let y=C(p(w));if(X&&y[X])return y[X]();else return y};return m.classes=function(w){if(w!=null){if(j(w)==="array")Z=w,J=[w[0],w[w.length-1]];else{let y=C.analyze(J);if(w===0)Z=[y.min,y.max];else Z=C.limits(y,"e",w)}return m}return Z},m.domain=function(w){if(!arguments.length)return J;K=w[0],F=w[w.length-1],N=[];let y=D.length;if(w.length===y&&K!==F)for(let E of Array.from(w))N.push((E-K)/(F-K));else{for(let E=0;E2){let E=w.map((H,P)=>P/(w.length-1)),k=w.map((H)=>(H-K)/(F-K));if(!k.every((H,P)=>E[P]===H))L=(H)=>{if(H<=0||H>=1)return H;let P=0;while(H>=k[P+1])P++;let T=(H-k[P])/(k[P+1]-k[P]);return E[P]+T*(E[P+1]-E[P])}}}return J=[K,F],m},m.mode=function(w){if(!arguments.length)return $;return $=w,n(),m},m.range=function(w,y){return B(w,y),m},m.out=function(w){return X=w,m},m.spread=function(w){if(!arguments.length)return U;return U=w,m},m.correctLightness=function(w){if(w==null)w=!0;if(V=w,n(),V)M=function(y){let E=p(0,!0).lab()[0],k=p(1,!0).lab()[0],H=E>k,P=p(y,!0).lab()[0],T=E+(k-E)*y,b=P-T,l=0,G0=1,H0=20;while(Math.abs(b)>0.01&&H0-- >0)(function(){if(H)b*=-1;if(b<0)l=y,y+=(G0-y)*0.5;else G0=y,y+=(l-y)*0.5;return P=p(y,!0).lab()[0],b=P-T})();return y};else M=(y)=>y;return m},m.padding=function(w){if(w!=null){if(j(w)==="number")w=[w,w];return q=w,m}else return q},m.colors=function(w,y){if(arguments.length<2)y="hex";let E=[];if(arguments.length===0)E=D.slice(0);else if(w===1)E=[m(0.5)];else if(w>1){let k=J[0],H=J[1]-k;E=b4(0,w,!1).map((P)=>m(k+P/(w-1)*H))}else{f=[];let k=[];if(Z&&Z.length>2)for(let H=1,P=Z.length,T=1<=P;T?HP;T?H++:H--)k.push((Z[H-1]+Z[H])*0.5);else k=J;E=k.map((H)=>m(H))}if(C[y])E=E.map((k)=>k[y]());return E},m.cache=function(w){if(w!=null)return u=w,m;else return u},m.gamma=function(w){if(w!=null)return z=w,m;else return z},m.nodata=function(w){if(w!=null)return Q=C(w),m;else return Q},m}function b4(f,$,Q){let U=[],J=f<$,N=!Q?$:J?$+1:$-1;for(let q=f;J?qN;J?q++:q--)U.push(q);return U}var r4=function(f){let $=[1,1];for(let Q=1;Qnew I(N)),f.length===2)[Q,U]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>Q[Z]+N*(U[Z]-Q[Z]));return new I(q,"lab")};else if(f.length===3)[Q,U,J]=f.map((N)=>N.lab()),$=function(N){let q=[0,1,2].map((Z)=>(1-N)*(1-N)*Q[Z]+2*(1-N)*N*U[Z]+N*N*J[Z]);return new I(q,"lab")};else if(f.length===4){let N;[Q,U,J,N]=f.map((q)=>q.lab()),$=function(q){let Z=[0,1,2].map((D)=>(1-q)*(1-q)*(1-q)*Q[D]+3*(1-q)*(1-q)*q*U[D]+3*(1-q)*q*q*J[D]+q*q*q*N[D]);return new I(Z,"lab")}}else if(f.length>=5){let N,q,Z;N=f.map((D)=>D.lab()),Z=f.length-1,q=r4(Z),$=function(D){let X=1-D,K=[0,1,2].map((F)=>N.reduce((V,Y,u)=>V+q[u]*X**(Z-u)*D**u*Y[F],0));return new I(K,"lab")}}else throw RangeError("No point in running bezier with only one color.");return $},l5=(f)=>{let $=g4(f);return $.scale=()=>t0($),$};var{round:a5}=Math;I.prototype.rgb=function(f=!0){if(f===!1)return this._rgb.slice(0,3);return this._rgb.slice(0,3).map(a5)};I.prototype.rgba=function(f=!0){return this._rgb.slice(0,4).map(($,Q)=>{return Q<3?f===!1?$:a5($):$})};var i4=(...f)=>new I(...f,"rgb");Object.assign(C,{rgb:i4});A.format.rgb=(...f)=>{let $=O(f,"rgba");if($[3]===void 0)$[3]=1;return $};A.autodetect.push({p:3,test:(...f)=>{if(f=O(f,"rgba"),j(f)==="array"&&(f.length===3||f.length===4&&j(f[3])=="number"&&f[3]>=0&&f[3]<=1))return"rgb"}});var B0=(f,$,Q)=>{if(!B0[Q])throw Error("unknown blend mode "+Q);return B0[Q](f,$)},x0=(f)=>($,Q)=>{let U=C(Q).rgb(),J=C($).rgb();return C.rgb(f(U,J))},h0=(f)=>($,Q)=>{let U=[];return U[0]=f($[0],Q[0]),U[1]=f($[1],Q[1]),U[2]=f($[2],Q[2]),U},c4=(f)=>f,o4=(f,$)=>f*$/255,e4=(f,$)=>f>$?$:f,l4=(f,$)=>f>$?f:$,a4=(f,$)=>255*(1-(1-f/255)*(1-$/255)),s4=(f,$)=>$<128?2*f*$/255:255*(1-2*(1-f/255)*(1-$/255)),f$=(f,$)=>255*(1-(1-$/255)/(f/255)),$$=(f,$)=>{if(f===255)return 255;return f=255*($/255)/(1-f/255),f>255?255:f};B0.normal=x0(h0(c4));B0.multiply=x0(h0(o4));B0.screen=x0(h0(a4));B0.overlay=x0(h0(s4));B0.darken=x0(h0(e4));B0.lighten=x0(h0(l4));B0.dodge=x0(h0($$));B0.burn=x0(h0(f$));var s5=B0;var{pow:Q$,sin:U$,cos:J$}=Math;function U2(f=300,$=-1.5,Q=1,U=1,J=[0,1]){let N=0,q;if(j(J)==="array")q=J[1]-J[0];else q=0,J=[J,J];let Z=function(D){let X=F0*((f+120)/360+$*D),K=Q$(J[0]+q*D,U),V=(N!==0?Q[0]+D*N:Q)*K*(1-K)/2,Y=J$(X),u=U$(X),z=K+V*(-0.14861*Y+1.78277*u),B=K+V*(-0.29227*Y-0.90649*u),W=K+V*(1.97294*Y);return C(l0([z*255,B*255,W*255,1]))};return Z.start=function(D){if(D==null)return f;return f=D,Z},Z.rotations=function(D){if(D==null)return $;return $=D,Z},Z.gamma=function(D){if(D==null)return U;return U=D,Z},Z.hue=function(D){if(D==null)return Q;if(Q=D,j(Q)==="array"){if(N=Q[1]-Q[0],N===0)Q=Q[1]}else N=0;return Z},Z.lightness=function(D){if(D==null)return J;if(j(D)==="array")J=D,q=D[1]-D[0];else J=[D,D],q=0;return Z},Z.scale=()=>C.scale(Z),Z.hue(Q),Z}var N$="0123456789abcdef",{floor:q$,random:Z$}=Math,f6=()=>{let f="#";for(let $=0;$<6;$++)f+=N$.charAt(q$(Z$()*16));return new I(f,"hex")};var{log:$6,pow:D$,floor:X$,abs:K$}=Math;function J2(f,$=null){let Q={min:Number.MAX_VALUE,max:Number.MAX_VALUE*-1,sum:0,values:[],count:0};if(j(f)==="object")f=Object.values(f);return f.forEach((U)=>{if($&&j(U)==="object")U=U[$];if(U!==void 0&&U!==null&&!isNaN(U)){if(Q.values.push(U),Q.sum+=U,UQ.max)Q.max=U;Q.count+=1}}),Q.domain=[Q.min,Q.max],Q.limits=(U,J)=>N2(Q,U,J),Q}function N2(f,$="equal",Q=7){if(j(f)=="array")f=J2(f);let{min:U,max:J}=f,N=f.values.sort((Z,D)=>Z-D);if(Q===1)return[U,J];let q=[];if($.substr(0,1)==="c")q.push(U),q.push(J);if($.substr(0,1)==="e"){q.push(U);for(let Z=1;Z 0");let Z=Math.LOG10E*$6(U),D=Math.LOG10E*$6(J);q.push(U);for(let X=1;X200)F=!1}let u={};for(let B=0;BB-W),q.push(z[0]);for(let B=1;B{f=new I(f),$=new I($);let Q=f.luminance(),U=$.luminance();return Q>U?(Q+0.05)/(U+0.05):(U+0.05)/(Q+0.05)};var U6=0.027,F$=0.0005,V$=0.1,J6=1.14,X1=0.022,N6=1.414,Z6=(f,$)=>{if(f=new I(f),$=new I($),f.alpha()<1)f=M0($,f,f.alpha(),"rgb");let Q=q6(...f.rgb()),U=q6(...$.rgb()),J=Q>=X1?Q:Q+Math.pow(X1-Q,N6),N=U>=X1?U:U+Math.pow(X1-U,N6),q=Math.pow(N,0.56)-Math.pow(J,0.57),Z=Math.pow(N,0.65)-Math.pow(J,0.62),D=Math.abs(N-J)0?D-U6:D+U6)*100};function q6(f,$,Q){return 0.2126729*Math.pow(f/255,2.4)+0.7151522*Math.pow($/255,2.4)+0.072175*Math.pow(Q/255,2.4)}var{sqrt:v0,pow:o,min:y$,max:W$,atan2:D6,abs:X6,cos:K1,sin:K6,exp:Y$,PI:F6}=Math;function q2(f,$,Q=1,U=1,J=1){var N=function(c0){return 360*c0/(2*F6)},q=function(c0){return 2*F6*c0/360};f=new I(f),$=new I($);let[Z,D,X]=Array.from(f.lab()),[K,F,V]=Array.from($.lab()),Y=(Z+K)/2,u=v0(o(D,2)+o(X,2)),z=v0(o(F,2)+o(V,2)),B=(u+z)/2,W=0.5*(1-v0(o(B,7)/(o(B,7)+o(25,7)))),M=D*(1+W),L=F*(1+W),p=v0(o(M,2)+o(X,2)),n=v0(o(L,2)+o(V,2)),m=(p+n)/2,w=N(D6(X,M)),y=N(D6(V,L)),E=w>=0?w:w+360,k=y>=0?y:y+360,H=X6(E-k)>180?(E+k+360)/2:(E+k)/2,P=1-0.17*K1(q(H-30))+0.24*K1(q(2*H))+0.32*K1(q(3*H+6))-0.2*K1(q(4*H-63)),T=k-E;T=X6(T)<=180?T:k<=E?T+360:T-360,T=2*v0(p*n)*K6(q(T)/2);let b=K-Z,l=n-p,G0=1+0.015*o(Y-50,2)/v0(20+o(Y-50,2)),H0=1+0.045*m,i0=1+0.015*m*P,O1=30*Y$(-o((H-275)/25,2)),p1=-(2*v0(o(m,7)/(o(m,7)+o(25,7))))*K6(2*q(O1)),M1=v0(o(b/(Q*G0),2)+o(l/(U*H0),2)+o(T/(J*i0),2)+p1*(l/(U*H0))*(T/(J*i0)));return W$(0,y$(100,M1))}function Z2(f,$,Q="lab"){f=new I(f),$=new I($);let U=f.get(Q),J=$.get(Q),N=0;for(let q in U){let Z=(U[q]||0)-(J[q]||0);N+=Z*Z}return Math.sqrt(N)}var V6=(...f)=>{try{return new I(...f),!0}catch($){return!1}};var y6={cool(){return t0([C.hsl(180,1,0.9),C.hsl(250,0.7,0.4)])},hot(){return t0(["#000","#f00","#ff0","#fff"],[0,0.25,0.75,1]).mode("rgb")}};var D2={OrRd:["#fff7ec","#fee8c8","#fdd49e","#fdbb84","#fc8d59","#ef6548","#d7301f","#b30000","#7f0000"],PuBu:["#fff7fb","#ece7f2","#d0d1e6","#a6bddb","#74a9cf","#3690c0","#0570b0","#045a8d","#023858"],BuPu:["#f7fcfd","#e0ecf4","#bfd3e6","#9ebcda","#8c96c6","#8c6bb1","#88419d","#810f7c","#4d004b"],Oranges:["#fff5eb","#fee6ce","#fdd0a2","#fdae6b","#fd8d3c","#f16913","#d94801","#a63603","#7f2704"],BuGn:["#f7fcfd","#e5f5f9","#ccece6","#99d8c9","#66c2a4","#41ae76","#238b45","#006d2c","#00441b"],YlOrBr:["#ffffe5","#fff7bc","#fee391","#fec44f","#fe9929","#ec7014","#cc4c02","#993404","#662506"],YlGn:["#ffffe5","#f7fcb9","#d9f0a3","#addd8e","#78c679","#41ab5d","#238443","#006837","#004529"],Reds:["#fff5f0","#fee0d2","#fcbba1","#fc9272","#fb6a4a","#ef3b2c","#cb181d","#a50f15","#67000d"],RdPu:["#fff7f3","#fde0dd","#fcc5c0","#fa9fb5","#f768a1","#dd3497","#ae017e","#7a0177","#49006a"],Greens:["#f7fcf5","#e5f5e0","#c7e9c0","#a1d99b","#74c476","#41ab5d","#238b45","#006d2c","#00441b"],YlGnBu:["#ffffd9","#edf8b1","#c7e9b4","#7fcdbb","#41b6c4","#1d91c0","#225ea8","#253494","#081d58"],Purples:["#fcfbfd","#efedf5","#dadaeb","#bcbddc","#9e9ac8","#807dba","#6a51a3","#54278f","#3f007d"],GnBu:["#f7fcf0","#e0f3db","#ccebc5","#a8ddb5","#7bccc4","#4eb3d3","#2b8cbe","#0868ac","#084081"],Greys:["#ffffff","#f0f0f0","#d9d9d9","#bdbdbd","#969696","#737373","#525252","#252525","#000000"],YlOrRd:["#ffffcc","#ffeda0","#fed976","#feb24c","#fd8d3c","#fc4e2a","#e31a1c","#bd0026","#800026"],PuRd:["#f7f4f9","#e7e1ef","#d4b9da","#c994c7","#df65b0","#e7298a","#ce1256","#980043","#67001f"],Blues:["#f7fbff","#deebf7","#c6dbef","#9ecae1","#6baed6","#4292c6","#2171b5","#08519c","#08306b"],PuBuGn:["#fff7fb","#ece2f0","#d0d1e6","#a6bddb","#67a9cf","#3690c0","#02818a","#016c59","#014636"],Viridis:["#440154","#482777","#3f4a8a","#31678e","#26838f","#1f9d8a","#6cce5a","#b6de2b","#fee825"],Spectral:["#9e0142","#d53e4f","#f46d43","#fdae61","#fee08b","#ffffbf","#e6f598","#abdda4","#66c2a5","#3288bd","#5e4fa2"],RdYlGn:["#a50026","#d73027","#f46d43","#fdae61","#fee08b","#ffffbf","#d9ef8b","#a6d96a","#66bd63","#1a9850","#006837"],RdBu:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#f7f7f7","#d1e5f0","#92c5de","#4393c3","#2166ac","#053061"],PiYG:["#8e0152","#c51b7d","#de77ae","#f1b6da","#fde0ef","#f7f7f7","#e6f5d0","#b8e186","#7fbc41","#4d9221","#276419"],PRGn:["#40004b","#762a83","#9970ab","#c2a5cf","#e7d4e8","#f7f7f7","#d9f0d3","#a6dba0","#5aae61","#1b7837","#00441b"],RdYlBu:["#a50026","#d73027","#f46d43","#fdae61","#fee090","#ffffbf","#e0f3f8","#abd9e9","#74add1","#4575b4","#313695"],BrBG:["#543005","#8c510a","#bf812d","#dfc27d","#f6e8c3","#f5f5f5","#c7eae5","#80cdc1","#35978f","#01665e","#003c30"],RdGy:["#67001f","#b2182b","#d6604d","#f4a582","#fddbc7","#ffffff","#e0e0e0","#bababa","#878787","#4d4d4d","#1a1a1a"],PuOr:["#7f3b08","#b35806","#e08214","#fdb863","#fee0b6","#f7f7f7","#d8daeb","#b2abd2","#8073ac","#542788","#2d004b"],Set2:["#66c2a5","#fc8d62","#8da0cb","#e78ac3","#a6d854","#ffd92f","#e5c494","#b3b3b3"],Accent:["#7fc97f","#beaed4","#fdc086","#ffff99","#386cb0","#f0027f","#bf5b17","#666666"],Set1:["#e41a1c","#377eb8","#4daf4a","#984ea3","#ff7f00","#ffff33","#a65628","#f781bf","#999999"],Set3:["#8dd3c7","#ffffb3","#bebada","#fb8072","#80b1d3","#fdb462","#b3de69","#fccde5","#d9d9d9","#bc80bd","#ccebc5","#ffed6f"],Dark2:["#1b9e77","#d95f02","#7570b3","#e7298a","#66a61e","#e6ab02","#a6761d","#666666"],Paired:["#a6cee3","#1f78b4","#b2df8a","#33a02c","#fb9a99","#e31a1c","#fdbf6f","#ff7f00","#cab2d6","#6a3d9a","#ffff99","#b15928"],Pastel2:["#b3e2cd","#fdcdac","#cbd5e8","#f4cae4","#e6f5c9","#fff2ae","#f1e2cc","#cccccc"],Pastel1:["#fbb4ae","#b3cde3","#ccebc5","#decbe4","#fed9a6","#ffffcc","#e5d8bd","#fddaec","#f2f2f2"]},Y6=Object.keys(D2),W6=new Map(Y6.map((f)=>[f.toLowerCase(),f])),G$=typeof Proxy==="function"?new Proxy(D2,{get(f,$){let Q=$.toLowerCase();if(W6.has(Q))return f[W6.get(Q)]},getOwnPropertyNames(){return Object.getOwnPropertyNames(Y6)}}):D2,G6=G$;var I$=(...f)=>{f=O(f,"cmyk");let[$,Q,U,J]=f,N=f.length>4?f[4]:1;if(J===1)return[0,0,0,N];return[$>=1?0:255*(1-$)*(1-J),Q>=1?0:255*(1-Q)*(1-J),U>=1?0:255*(1-U)*(1-J),N]},I6=I$;var{max:w6}=Math,w$=(...f)=>{let[$,Q,U]=O(f,"rgb");$=$/255,Q=Q/255,U=U/255;let J=1-w6($,w6(Q,U)),N=J<1?1/(1-J):0,q=(1-$-J)*N,Z=(1-Q-J)*N,D=(1-U-J)*N;return[q,Z,D,J]},B6=w$;I.prototype.cmyk=function(){return B6(this._rgb)};var B$=(...f)=>new I(...f,"cmyk");Object.assign(C,{cmyk:B$});A.format.cmyk=I6;A.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"cmyk"),j(f)==="array"&&f.length===4)return"cmyk"}});var u$=(...f)=>{let $=O(f,"hsla"),Q=J0(f)||"lsa";if($[0]=f0($[0]||0)+"deg",$[1]=f0($[1]*100)+"%",$[2]=f0($[2]*100)+"%",Q==="hsla"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="hsla";else $.length=3;return`${Q.substr(0,3)}(${$.join(" ")})`},u6=u$;var E$=(...f)=>{let $=O(f,"lab"),Q=J0(f)||"lab";if($[0]=f0($[0])+"%",$[1]=f0($[1]),$[2]=f0($[2]),Q==="laba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lab(${$.join(" ")})`},E6=E$;var k$=(...f)=>{let $=O(f,"lch"),Q=J0(f)||"lab";if($[0]=f0($[0])+"%",$[1]=f0($[1]),$[2]=isNaN($[2])?"none":f0($[2])+"deg",Q==="lcha"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`lch(${$.join(" ")})`},k6=k$;var z$=(...f)=>{let $=O(f,"lab");if($[0]=f0($[0]*100)+"%",$[1]=Of($[1]),$[2]=Of($[2]),$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklab(${$.join(" ")})`},z6=z$;var H$=(...f)=>{let[$,Q,U,...J]=O(f,"rgb"),[N,q,Z]=Gf($,Q,U),[D,X,K]=Z1(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},F1=H$;var S$=(...f)=>{let $=O(f,"lch");if($[0]=f0($[0]*100)+"%",$[1]=Of($[1]),$[2]=isNaN($[2])?"none":f0($[2])+"deg",$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1);else $.length=3;return`oklch(${$.join(" ")})`},H6=S$;var{round:X2}=Math,O$=(...f)=>{let $=O(f,"rgba"),Q=J0(f)||"rgb";if(Q.substr(0,3)==="hsl")return u6(D1($),Q);if(Q.substr(0,3)==="lab"){let U=d0();V0("d50");let J=E6(Ff($),Q);return V0(U),J}if(Q.substr(0,3)==="lch"){let U=d0();V0("d50");let J=k6(Mf($),Q);return V0(U),J}if(Q.substr(0,5)==="oklab")return z6(Gf($));if(Q.substr(0,5)==="oklch")return H6(F1($));if($[0]=X2($[0]),$[1]=X2($[1]),$[2]=X2($[2]),Q==="rgba"||$.length>3&&$[3]<1)$[3]="/ "+($.length>3?$[3]:1),Q="rgba";return`${Q.substr(0,3)}(${$.slice(0,Q==="rgb"?3:4).join(" ")})`},S6=O$;var p$=(...f)=>{f=O(f,"lch");let[$,Q,U,...J]=f,[N,q,Z]=q1($,Q,U),[D,X,K]=Yf(N,q,Z);return[D,X,K,...J.length>0&&J[0]<1?[J[0]]:[]]},V1=p$;var j0=/((?:-?\d+)|(?:-?\d+(?:\.\d+)?)%|none)/.source,u0=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%?)|none)/.source,y1=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)%)|none)/.source,W0=/\s*/.source,wf=/\s+/.source,K2=/\s*,\s*/.source,W1=/((?:-?(?:\d+(?:\.\d*)?|\.\d+)(?:deg)?)|none)/.source,Bf=/\s*(?:\/\s*((?:[01]|[01]?\.\d+)|\d+(?:\.\d+)?%))?/.source,O6=new RegExp("^rgba?\\("+W0+[j0,j0,j0].join(wf)+Bf+"\\)$"),p6=new RegExp("^rgb\\("+W0+[j0,j0,j0].join(K2)+W0+"\\)$"),M6=new RegExp("^rgba\\("+W0+[j0,j0,j0,u0].join(K2)+W0+"\\)$"),T6=new RegExp("^hsla?\\("+W0+[W1,y1,y1].join(wf)+Bf+"\\)$"),P6=new RegExp("^hsl?\\("+W0+[W1,y1,y1].join(K2)+W0+"\\)$"),L6=/^hsla\(\s*(-?\d+(?:\.\d+)?),\s*(-?\d+(?:\.\d+)?)%\s*,\s*(-?\d+(?:\.\d+)?)%\s*,\s*([01]|[01]?\.\d+)\)$/,v6=new RegExp("^lab\\("+W0+[u0,u0,u0].join(wf)+Bf+"\\)$"),j6=new RegExp("^lch\\("+W0+[u0,u0,W1].join(wf)+Bf+"\\)$"),R6=new RegExp("^oklab\\("+W0+[u0,u0,u0].join(wf)+Bf+"\\)$"),A6=new RegExp("^oklch\\("+W0+[u0,u0,W1].join(wf)+Bf+"\\)$"),{round:m6}=Math,If=(f)=>{return f.map(($,Q)=>Q<=2?K0(m6($),0,255):$)},e=(f,$=0,Q=100,U=!1)=>{if(typeof f==="string"&&f.endsWith("%"))if(f=parseFloat(f.substring(0,f.length-1))/100,U)f=$+(f+1)*0.5*(Q-$);else f=$+f*(Q-$);return+f},Q0=(f,$)=>{return f==="none"?$:f},_6=(f)=>{if(f=f.toLowerCase().trim(),f==="transparent")return[0,0,0,0];let $;if(A.format.named)try{return A.format.named(f)}catch(Q){}if(($=f.match(O6))||($=f.match(p6))){let Q=$.slice(1,4);for(let J=0;J<3;J++)Q[J]=+e(Q0(Q[J],0),0,255);Q=If(Q);let U=$[4]!==void 0?+e($[4],0,1):1;return Q[3]=U,Q}if($=f.match(M6)){let Q=$.slice(1,5);for(let U=0;U<4;U++)Q[U]=+e(Q[U],0,255);return Q}if(($=f.match(T6))||($=f.match(P6))){let Q=$.slice(1,4);Q[0]=+Q0(Q[0].replace("deg",""),0),Q[1]=+e(Q0(Q[1],0),0,100)*0.01,Q[2]=+e(Q0(Q[2],0),0,100)*0.01;let U=If(Tf(Q)),J=$[4]!==void 0?+e($[4],0,1):1;return U[3]=J,U}if($=f.match(L6)){let Q=$.slice(1,4);Q[1]*=0.01,Q[2]*=0.01;let U=Tf(Q);for(let J=0;J<3;J++)U[J]=m6(U[J]);return U[3]=+$[4],U}if($=f.match(v6)){let Q=$.slice(1,4);Q[0]=e(Q0(Q[0],0),0,100),Q[1]=e(Q0(Q[1],0),-125,125,!0),Q[2]=e(Q0(Q[2],0),-125,125,!0);let U=d0();V0("d50");let J=If(Kf(Q));V0(U);let N=$[4]!==void 0?+e($[4],0,1):1;return J[3]=N,J}if($=f.match(j6)){let Q=$.slice(1,4);Q[0]=e(Q[0],0,100),Q[1]=e(Q0(Q[1],0),0,150,!1),Q[2]=+Q0(Q[2].replace("deg",""),0);let U=d0();V0("d50");let J=If(Vf(Q));V0(U);let N=$[4]!==void 0?+e($[4],0,1):1;return J[3]=N,J}if($=f.match(R6)){let Q=$.slice(1,4);Q[0]=e(Q0(Q[0],0),0,1),Q[1]=e(Q0(Q[1],0),-0.4,0.4,!0),Q[2]=e(Q0(Q[2],0),-0.4,0.4,!0);let U=If(Yf(Q)),J=$[4]!==void 0?+e($[4],0,1):1;return U[3]=J,U}if($=f.match(A6)){let Q=$.slice(1,4);Q[0]=e(Q0(Q[0],0),0,1),Q[1]=e(Q0(Q[1],0),0,0.4,!1),Q[2]=+Q0(Q[2].replace("deg",""),0);let U=If(V1(Q)),J=$[4]!==void 0?+e($[4],0,1):1;return U[3]=J,U}};_6.test=(f)=>{return O6.test(f)||T6.test(f)||v6.test(f)||j6.test(f)||R6.test(f)||A6.test(f)||p6.test(f)||M6.test(f)||P6.test(f)||L6.test(f)||f==="transparent"};var F2=_6;I.prototype.css=function(f){return S6(this._rgb,f)};var M$=(...f)=>new I(...f,"css");C.css=M$;A.format.css=F2;A.autodetect.push({p:5,test:(f,...$)=>{if(!$.length&&j(f)==="string"&&F2.test(f))return"css"}});A.format.gl=(...f)=>{let $=O(f,"rgba");return $[0]*=255,$[1]*=255,$[2]*=255,$};var T$=(...f)=>new I(...f,"gl");C.gl=T$;I.prototype.gl=function(){let f=this._rgb;return[f[0]/255,f[1]/255,f[2]/255,f[3]]};I.prototype.hex=function(f){return N1(this._rgb,f)};var P$=(...f)=>new I(...f,"hex");C.hex=P$;A.format.hex=U1;A.autodetect.push({p:4,test:(f,...$)=>{if(!$.length&&j(f)==="string"&&[3,4,5,6,7,8,9].indexOf(f.length)>=0)return"hex"}});var{log:Y1}=Math,L$=(f)=>{let $=f/100,Q,U,J;if($<66)Q=255,U=$<6?0:-155.25485562709179-0.44596950469579133*(U=$-2)+104.49216199393888*Y1(U),J=$<20?0:-254.76935184120902+0.8274096064007395*(J=$-10)+115.67994401066147*Y1(J);else Q=351.97690566805693+0.114206453784165*(Q=$-55)-40.25366309332127*Y1(Q),U=325.4494125711974+0.07943456536662342*(U=$-50)-28.0852963507957*Y1(U),J=255;return[Q,U,J,1]},G1=L$;var{round:v$}=Math,j$=(...f)=>{let $=O(f,"rgb"),Q=$[0],U=$[2],J=1000,N=40000,q=0.4,Z;while(N-J>q){Z=(N+J)*0.5;let D=G1(Z);if(D[2]/D[0]>=U/Q)N=Z;else J=Z}return v$(Z)},C6=j$;I.prototype.temp=I.prototype.kelvin=I.prototype.temperature=function(){return C6(this._rgb)};var V2=(...f)=>new I(...f,"temp");Object.assign(C,{temp:V2,kelvin:V2,temperature:V2});A.format.temp=A.format.kelvin=A.format.temperature=G1;I.prototype.oklch=function(){return F1(this._rgb)};var R$=(...f)=>new I(...f,"oklch");Object.assign(C,{oklch:R$});A.format.oklch=V1;A.autodetect.push({p:2,test:(...f)=>{if(f=O(f,"oklch"),j(f)==="array"&&f.length===3)return"oklch"}});Object.assign(C,{analyze:J2,average:e5,bezier:l5,blend:s5,brewer:G6,Color:I,colors:n0,contrast:Q6,contrastAPCA:Z6,cubehelix:U2,deltaE:q2,distance:Z2,input:A,interpolate:M0,limits:N2,mix:M0,random:f6,scale:t0,scales:y6,valid:V6});var d=C;var y2=(f)=>{return typeof f==="number"&&!isNaN(f)&&isFinite(f)},T0=(f,$,Q)=>{if(!y2(f))return $;return Math.max($,Math.min(Q,f))},Y0=(f,$,Q)=>{try{if(!y2(f)||!y2($)||$<=0)return 0;let U=f/($-1);switch(Q){case"geometric":return A$(f,$);case"fibonacci":return m$($)[f]||0;case"golden-ratio":return _$($)[f]||0;case"logarithmic":return C$(f,$);case"powers-of-2":return n$(f,$);case"musical-ratio":return d$(f,$);case"cielab-uniform":return t$(f,$);case"ease-in":return x$(f,$);case"ease-out":return h$(f,$);case"ease-in-out":return b$(f,$);default:return U}}catch(U){return console.error("Error calculating scale position:",U),0}},A$=(f,$)=>{try{if($<=1)return 0;let U=1,J=Math.pow(3,$-1),N=(Math.pow(3,f)-U)/(J-U);return T0(N,0,1)}catch(Q){return console.error("Error calculating geometric position:",Q),0}},m$=(f)=>{try{let $=[0,1];for(let J=2;JT0((J-Q)/(U-Q),0,1))}catch($){return console.error("Error calculating Fibonacci positions:",$),Array(f).fill(0)}},_$=(f)=>{try{let Q=[];for(let N=0;NT0((N-U)/(J-U),0,1))}catch($){return console.error("Error calculating golden ratio positions:",$),Array(f).fill(0)}},C$=(f,$)=>{try{let U=$,J=Math.log(1),N=Math.log(U),q=f+1,Z=(Math.log(q)-J)/(N-J);return T0(Z,0,1)}catch(Q){return console.error("Error calculating logarithmic position:",Q),0}},n$=(f,$)=>{try{let U=Math.pow(2,$-1),J=(Math.pow(2,f)-1)/(U-1);return T0(J,0,1)}catch(Q){return console.error("Error calculating powers of 2 position:",Q),0}},d$=(f,$)=>{try{let Q=[1,1.0666666666666667,1.125,1.2,1.25,1.3333333333333333,1.40625,1.5,1.6,1.6666666666666667,1.875,2],U=[];if($<=Q.length)U=Q.slice(0,$);else for(let Z=0;Z<$;Z++)U.push(1*Math.pow(2,Z/($-1)));let J=U[0],N=U[U.length-1],q=(U[f]-J)/(N-J);return T0(q,0,1)}catch(Q){return console.error("Error calculating musical ratio position:",Q),0}},t$=(f,$)=>{try{let Q=f/($-1);return T0(Q,0,1)}catch(Q){return console.error("Error calculating CIELAB uniform position:",Q),0}},x$=(f,$)=>{try{let Q=f/($-1),U=Q*Q;return T0(U,0,1)}catch(Q){return console.error("Error calculating ease-in position:",Q),0}},h$=(f,$)=>{try{let Q=f/($-1),U=1-(1-Q)*(1-Q);return T0(U,0,1)}catch(Q){return console.error("Error calculating ease-out position:",Q),0}},b$=(f,$)=>{try{let Q=f/($-1),U=Q<0.5?2*Q*Q:1-Math.pow(-2*Q+2,2)/2;return T0(U,0,1)}catch(Q){return console.error("Error calculating ease-in-out position:",Q),0}},W2=(f,$)=>{let Q=$.lightnessDistributionType||"linear",U=$.hueDistributionType||"linear",J=$.saturationDistributionType||"linear";return{lightness:Y0(f,$.totalSteps,Q),hue:Y0(f,$.totalSteps,U),saturation:Y0(f,$.totalSteps,J)}};var b0=(f)=>Math.max(0,Math.min(255,f)),Pf=(f,$,Q,U)=>{let J=f.rgb(),N=$.rgb(),q;switch(U){case"darken":q=[Math.min(J[0],N[0]),Math.min(J[1],N[1]),Math.min(J[2],N[2])];break;case"multiply":q=[J[0]*N[0]/255,J[1]*N[1]/255,J[2]*N[2]/255];break;case"plus-darker":q=[b0(J[0]+N[0]-255),b0(J[1]+N[1]-255),b0(J[2]+N[2]-255)];break;case"color-burn":q=J.map((B,W)=>{let M=N[W];if(M===0)return 0;return b0(255-(255-B)*255/M)});break;case"lighten":q=[Math.max(J[0],N[0]),Math.max(J[1],N[1]),Math.max(J[2],N[2])];break;case"screen":q=[255-(255-J[0])*(255-N[0])/255,255-(255-J[1])*(255-N[1])/255,255-(255-J[2])*(255-N[2])/255];break;case"plus-lighter":q=[b0(J[0]+N[0]),b0(J[1]+N[1]),b0(J[2]+N[2])];break;case"color-dodge":q=J.map((B,W)=>{let M=N[W];if(M===255)return 255;return b0(B*255/(255-M))});break;case"overlay":q=J.map((B,W)=>{let M=N[W],L=B/255,p=M/255;if(L<0.5)return 2*L*p*255;else return(1-2*(1-L)*(1-p))*255});break;case"soft-light":q=J.map((B,W)=>{let M=N[W],L=B/255,p=M/255;if(p<0.5)return(2*L*p+L*L*(1-2*p))*255;else return(2*L*(1-p)+Math.sqrt(L)*(2*p-1))*255});break;case"hard-light":q=J.map((B,W)=>{let M=N[W],L=B/255,p=M/255;if(p<0.5)return 2*L*p*255;else return(1-2*(1-L)*(1-p))*255});break;case"difference":q=[Math.abs(J[0]-N[0]),Math.abs(J[1]-N[1]),Math.abs(J[2]-N[2])];break;case"exclusion":q=[J[0]+N[0]-2*J[0]*N[0]/255,J[1]+N[1]-2*J[1]*N[1]/255,J[2]+N[2]-2*J[2]*N[2]/255];break;case"hue":let D=f.hsl(),X=$.hsl();return d.hsl(X[0]||0,D[1]||0,D[2]||0);case"saturation":let K=f.hsl(),F=$.hsl();return d.hsl(K[0]||0,F[1]||0,K[2]||0);case"color":let V=f.hsl(),Y=$.hsl();return d.hsl(Y[0]||0,Y[1]||0,V[2]||0);case"luminosity":let u=f.hsl(),z=$.hsl();return d.hsl(u[0]||0,u[1]||0,z[2]||0);case"normal":default:return d.mix(f,$,Q,"rgb")}let Z=d.rgb(...q);return d.mix(f,Z,Q,"rgb")};function Y2(f){if(f<=0.04045)return f/12.92;return Math.pow((f+0.055)/1.055,2.4)}function G2(f){if(f<=0.0031308)return f*12.92;return 1.055*Math.pow(f,0.4166666666666667)-0.055}function n6(f,$,Q){return[Y2(f/255),Y2($/255),Y2(Q/255)]}function d6(f,$,Q){return[Math.round(Math.max(0,Math.min(1,G2(f)))*255),Math.round(Math.max(0,Math.min(1,G2($)))*255),Math.round(Math.max(0,Math.min(1,G2(Q)))*255)]}function t6(f,$,Q){let U=0.4122214708*f+0.5363325363*$+0.0514459929*Q,J=0.2119034982*f+0.6806995451*$+0.1073969566*Q,N=0.0883024619*f+0.2817188376*$+0.6299787005*Q,q=Math.cbrt(U),Z=Math.cbrt(J),D=Math.cbrt(N),X=0.2104542553*q+0.793617785*Z-0.0040720468*D,K=1.9779984951*q-2.428592205*Z+0.4505937099*D,F=0.0259040371*q+0.7827717662*Z-0.808675766*D;return[X,K,F]}function I2(f,$,Q){let U=f+0.3963377774*$+0.2158037573*Q,J=f-0.1055613458*$-0.0638541728*Q,N=f-0.0894841775*$-1.291485548*Q,q=U*U*U,Z=J*J*J,D=N*N*N,X=4.0767416621*q-3.3077115913*Z+0.2309699292*D,K=-1.2684380046*q+2.6097574011*Z-0.3413193965*D,F=-0.0041960863*q-0.7034186147*Z+1.707614701*D;return[X,K,F]}function x6(f,$,Q){let U=Math.sqrt($*$+Q*Q),J=Math.atan2(Q,$)*180/Math.PI;if(J<0)J+=360;return[f,U,J]}function w2(f,$,Q){let U=Q*Math.PI/180;return[f,$*Math.cos(U),$*Math.sin(U)]}function h6(f){let[$,Q,U]=i6(f),[J,N,q]=n6($,Q,U),[Z,D,X]=t6(J,N,q);return x6(Z,D,X)}function b6(f,$,Q){let[,U,J]=w2(f,$,Q),[N,q,Z]=I2(f,U,J),[D,X,K]=d6(N,q,Z);return g$(D,X,K)}function r6(f,$,Q){let[U,J,N]=n6(f,$,Q),[q,Z,D]=t6(U,J,N);return x6(q,Z,D)}function r$(f,$,Q){let[,U,J]=w2(f,$,Q),[N,q,Z]=I2(f,U,J);return d6(N,q,Z)}function g6(f,$,Q){let[,U,J]=w2(f,$,Q),[N,q,Z]=I2(f,U,J),D=0.000001;return N>=-0.000001&&N<=1.000001&&q>=-0.000001&&q<=1.000001&&Z>=-0.000001&&Z<=1.000001}function i6(f){let $=f.replace(/^#/,"");if($.length===3||$.length===4)$=$.split("").map((U)=>U+U).join("");let Q=parseInt($.substring(0,6),16);return[Q>>16&255,Q>>8&255,Q&255]}function g$(f,$,Q){let U=(J)=>Math.max(0,Math.min(255,J)).toString(16).padStart(2,"0");return`#${U(f)}${U($)}${U(Q)}`}function c6(f){let $=f.trim().toLowerCase();if($.startsWith("#"))return i6($);let Q=$.match(/^rgba?\(\s*(\d+(?:\.\d+)?)\s*[,\s]\s*(\d+(?:\.\d+)?)\s*[,\s]\s*(\d+(?:\.\d+)?)/);if(Q)return[Math.round(parseFloat(Q[1])),Math.round(parseFloat(Q[2])),Math.round(parseFloat(Q[3]))];let U=$.match(/^hsla?\(\s*(\d+(?:\.\d+)?)\s*[,\s]\s*(\d+(?:\.\d+)?)%\s*[,\s]\s*(\d+(?:\.\d+)?)%/);if(U){let N=parseFloat(U[1]),q=parseFloat(U[2])/100,Z=parseFloat(U[3])/100;return i$(N,q,Z)}let J=$.match(/^oklch\(\s*(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)\s+(\d+(?:\.\d+)?)/);if(J){let N=parseFloat(J[1]),q=parseFloat(J[2]),Z=parseFloat(J[3]);return r$(N,q,Z)}return null}function i$(f,$,Q){f=(f%360+360)%360;let U=(1-Math.abs(2*Q-1))*$,J=U*(1-Math.abs(f/60%2-1)),N=Q-U/2,q,Z,D;if(f<60)q=U,Z=J,D=0;else if(f<120)q=J,Z=U,D=0;else if(f<180)q=0,Z=U,D=J;else if(f<240)q=0,Z=J,D=U;else if(f<300)q=J,Z=0,D=U;else q=U,Z=0,D=J;return[Math.round((q+N)*255),Math.round((Z+N)*255),Math.round((D+N)*255)]}function I1(f){let{l:$,c:Q,h:U,alpha:J}=f;return{l:Math.round($*100)/100,c:Math.round(Q*100)/100,h:Math.round(U),alpha:J!==void 0?Math.round(J*100)/100:J}}function c$(f){let{l:$,c:Q,h:U,alpha:J}=f;return{l:Math.round($*1000)/1000,c:Math.round(Q*1000)/1000,h:Math.round(U),alpha:J!==void 0?Math.round(J*1000)/1000:J}}function g(f){try{if(f.startsWith("#")){let[N,q,Z]=h6(f);return{l:N,c:q,h:Z}}let $=c6(f);if(!$)throw Error(`Invalid color: ${f}`);let[Q,U,J]=r6($[0],$[1],$[2]);return{l:Q,c:U,h:J}}catch($){return console.error("Error converting to OKLCH:",$),{l:0.5,c:0,h:0,alpha:1}}}function E0(f){try{return b6(f.l,f.c,f.h)}catch($){return console.error("Error converting from OKLCH:",$),"#808080"}}function r(f){let $=I1(f),{l:Q,c:U,h:J,alpha:N}=$;if(N!==void 0&&N<1)return`oklch(${Q} ${U} ${J} / ${N})`;return`oklch(${Q} ${U} ${J})`}function o6(f){try{return g6(f.l,f.c,f.h)}catch($){return console.error("Error checking sRGB gamut:",$),!1}}function e6(f,$){let Q=0,U=0.5,J=0,N=20;while(J0.001){let q=(Q+U)/2;if(o6({l:f,c:q,h:$}))Q=q;else U=q;J++}return Math.max(0,Q)}function o$(f){let $=e6(f.l,f.h);if(f.c>$)return{...f,c:$};return f}function k0(f,$=!1){let{l:Q,c:U,h:J,alpha:N}=f;if(Q=Math.max(0,Math.min(1,Q)),J=(J%360+360)%360,N!==void 0)N=Math.max(0,Math.min(1,N));if($){let Z=c$({l:Q,c:U,h:J,alpha:N}),D=e6(Z.l,Z.h),X=Math.min(Z.c,D);return{...Z,c:X}}return o$({l:Q,c:U,h:J,alpha:N})}var w1=(f,$)=>{try{if($==="hsl"){let[Q,U,J]=f.hsl(),N=r0(Q,0,360),q=r0(U,0,1),Z=r0(J,0,1);return`hsl(${Math.round(N)}, ${Math.round(q*100)}%, ${Math.round(Z*100)}%)`}if($==="oklch"){let Q=f.hex(),U=g(Q);return r(U)}return f.hex()}catch(Q){return console.error("Error formatting color:",Q),"#000000"}},s0=(f)=>{return typeof f==="number"&&!isNaN(f)&&isFinite(f)},r0=(f,$,Q)=>{if(!s0(f))return $;return Math.max($,Math.min(Q,f))},e$=(f,$,Q,U,J)=>{try{let N=f.lightnessStart/100,q=f.lightnessEnd/100,Z=N+(q-N)*$;return r0(Z,0,1)}catch(N){return console.error("Error calculating lightness:",N),0.5}},l$=(f,$,Q,U,J)=>{try{let N=f.chromaEnd-f.chromaStart,q=(Q+f.chromaStart+N*$)%360;while(q<0)q+=360;return r0(q,0,360)}catch(N){return console.error("Error calculating hue:",N),0}},a$=(f,$,Q,U,J)=>{try{let N=f.saturationStart/100*Q,q=f.saturationEnd/100*Q,Z=N+(q-N)*$;return r0(Z,0,1)}catch(N){return console.error("Error calculating saturation:",N),0.5}},s$=(f,$,Q,U,J)=>{try{let N=f.lightnessStart/100,q=f.lightnessEnd/100,Z=N+(q-N)*$;return r0(Z,0,1)}catch(N){return console.error("Error calculating OKLCH lightness:",N),0.5}},fQ=(f,$,Q,U,J)=>{try{let N=f.chromaEnd-f.chromaStart,q=(Q+f.chromaStart+N*$)%360;while(q<0)q+=360;return r0(q,0,360)}catch(N){return console.error("Error calculating OKLCH hue:",N),0}},$Q=(f,$,Q,U,J)=>{try{let N=f.saturationStart/100*Q,q=f.saturationEnd/100*Q,Z=N+(q-N)*$;return Math.max(0,Z)}catch(N){return console.error("Error calculating OKLCH chroma:",N),0.1}},QQ=(f,$,Q,U)=>{try{let[J,N,q]=Q.hsl(),Z=s0(J)?J:0,D=s0(N)?N:0,X=s0(q)?q:0,K=W2($,f),F=e$(f,K.lightness,X,U,$),V=l$(f,K.hue,Z,U,$),Y=a$(f,K.saturation,D,U,$);if(!s0(V)||!s0(Y)||!s0(F))return console.warn("Invalid color values detected, using fallback:",{newHue:V,newSaturation:Y,newLightness:F}),w1(d.hsl(0,0,0.5),f.colorFormat);let u=d.hsl(V,Y,F);if(f.tintColor&&f.tintOpacity&&f.tintOpacity>0)try{let z=d(f.tintColor),B=f.tintOpacity/100,W=f.tintBlendMode||"normal";u=Pf(u,z,B,W)}catch(z){console.error("Error applying tint:",z)}return w1(u,f.colorFormat)}catch(J){return console.error("Error generating single color:",J),w1(d.hsl(0,0,0.5),f.colorFormat)}},UQ=(f,$,Q,U)=>{try{let J=W2($,f),N=s$(f,J.lightness,Q.l,U,$),q=fQ(f,J.hue,Q.h,U,$),Z=$Q(f,J.saturation,Q.c,U,$),D={l:N,c:Z,h:q,alpha:Q.alpha};if(D=k0(D),f.tintColor&&f.tintOpacity&&f.tintOpacity>0)try{let X=E0(D),K=d(X),F=d(f.tintColor),V=f.tintOpacity/100,Y=f.tintBlendMode||"normal";K=Pf(K,F,V,Y);let u=K.hex();D=g(u)}catch(X){console.error("Error applying tint to OKLCH:",X)}return r(I1(D))}catch(J){return console.error("Error generating single OKLCH color:",J),r(I1({l:0.5,c:0.1,h:0,alpha:1}))}},JQ=(f)=>{let $=[];for(let Q=0;Q{try{let $=d(f.baseColor),Q=[],U=Math.floor(f.totalSteps/2);for(let J=0;J{let N=$?f.length===1?u1($):`${u1($)}-${u1(U.name)}`:u1(U.name);if(J>0)Q.push("");Q.push(` /* ${N} */`),U.colors.forEach((q,Z)=>{Q.push(` --${N}-${Z}: ${q};`)})}),Q.push("}"),Q.join(` +`)}function u2(f,$){let Q={ramps:f.map((U)=>({name:$?f.length===1?$:`${$}-${U.name}`:U.name,baseColor:U.baseColor,colors:U.colors}))};return JSON.stringify(Q,null,2)}function E2(f){return f.map(($)=>$.colors.join(` `)).join(` -`)}function NQ(f){let $=f.trim();if(/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/.test($))return"hex";if(/^rgb\s*\(/.test($))return"rgb";if(/^hsl\s*\(/.test($))return"hsl";if(/^oklch\s*\(/.test($))return"oklch";throw Error(`Unknown color format: ${f}`)}function uf(f){let $=f.map((U)=>NQ(U)),Q=$[0];for(let U=1;U<$.length;U++)if($[U]!==Q)throw Error(`All colors must use the same format. Found '${Q}' and '${$[U]}': ${f[0]} vs ${f[U]}`);return Q}function h0(f,$){let Q=h(f),[U]=Q.oklch(),J=(Z)=>{switch(Z){case"hsl":{let[D,X,K]=Q.hsl();return`hsl(${Math.round(D||0)}, ${Math.round(X*100)}%, ${Math.round(K*100)}%)`}case"rgb":{let[D,X,K]=Q.rgb();return`rgb(${D}, ${X}, ${K})`}case"oklch":{let[D,X,K]=Q.oklch();return`oklch(${(D*100).toFixed(1)}% ${X.toFixed(3)} ${Math.round(K||0)})`}default:return f}},N=J($),q=new String(N);return Object.defineProperties(q,{hex:{value:()=>Q.hex(),enumerable:!1},hsl:{value:()=>J("hsl"),enumerable:!1},rgb:{value:()=>J("rgb"),enumerable:!1},oklch:{value:()=>J("oklch"),enumerable:!1},luminance:{value:U,enumerable:!1}}),q}function E2(f){let $;try{$=h(f)}catch{throw Error(`Invalid color: "${f}"`)}let Q=$.hex(),[U,J,N]=$.rgb(),[q,Z,D]=$.hsl(),[X,K,F]=$.oklch(),V={r:U,g:J,b:N},G={h:Math.round(q||0),s:Math.round(Z*100),l:Math.round(D*100)},B={l:parseFloat((X*100).toFixed(1)),c:parseFloat(K.toFixed(3)),h:Math.round(F||0)},S=(w)=>{switch(w){case"hsl":return`hsl(${G.h}, ${G.s}%, ${G.l}%)`;case"rgb":return`rgb(${U}, ${J}, ${N})`;case"oklch":return`oklch(${(X*100).toFixed(1)}% ${K.toFixed(3)} ${Math.round(F||0)})`;default:return Q}};return{hex:Q,rgb:V,hsl:G,oklch:B,luminance:X,format(w){return S(w)},output(w,m){let L=m||"color";switch(w){case"css":{let p=[":root {"];return p.push(` --${L}-hex: ${Q};`),p.push(` --${L}-rgb: ${S("rgb")};`),p.push(` --${L}-hsl: ${S("hsl")};`),p.push(` --${L}-oklch: ${S("oklch")};`),p.push("}"),p.join(` -`)}case"json":return JSON.stringify({hex:Q,rgb:V,hsl:G,oklch:B},null,2);case"text":default:return Q}},toString(){return Q}}}class Pf{_baseColor;_size=10;_format="hex";_lightnessStart=0;_lightnessEnd=100;_saturationStart=100;_saturationEnd=0;_hueStart=-10;_hueEnd=10;_lightnessDistribution="linear";_saturationDistribution="linear";_hueDistribution="linear";_tintColor;_tintOpacity=0;_tintBlend="normal";_harmonies=[];constructor(f){try{h(f)}catch{throw Error(`Invalid color: "${f}"`)}this._baseColor=h(f).hex()}size(f){if(f<2||f>100)throw Error("Size must be between 2 and 100");return this._size=f,this}format(f){return this._format=f,this}lightness(f,$){return this._lightnessStart=f,this._lightnessEnd=$,this}saturation(f,$){return this._saturationStart=f,this._saturationEnd=$,this}hue(f,$){return this._hueStart=f,this._hueEnd=$,this}lightnessDistribution(f){return this._lightnessDistribution=f,this}saturationDistribution(f){return this._saturationDistribution=f,this}hueDistribution(f){return this._hueDistribution=f,this}tint(f,$,Q="normal"){try{h(f)}catch{throw Error(`Invalid tint color: "${f}"`)}return this._tintColor=h(f).hex(),this._tintOpacity=$,this._tintBlend=Q,this}add(f,$){if(f==="shift"){if($===void 0)throw Error("shift requires a degrees value");this._harmonies.push({type:"shift",degrees:$})}else this._harmonies.push({type:f});return this}buildConfig(f){return{id:"sdk",name:"ramp",baseColor:f,colorFormat:"hex",totalSteps:this._size,lightnessStart:this._lightnessStart,lightnessEnd:this._lightnessEnd,chromaStart:this._hueStart,chromaEnd:this._hueEnd,saturationStart:this._saturationStart,saturationEnd:this._saturationEnd,lightnessDistributionType:this._lightnessDistribution,saturationDistributionType:this._saturationDistribution,hueDistributionType:this._hueDistribution,tintColor:this._tintColor,tintOpacity:this._tintOpacity,tintBlendMode:this._tintBlend,swatches:[]}}formatColor(f){let $=h(f);switch(this._format){case"hsl":{let[Q,U,J]=$.hsl();return`hsl(${Math.round(Q||0)}, ${Math.round(U*100)}%, ${Math.round(J*100)}%)`}case"rgb":{let[Q,U,J]=$.rgb();return`rgb(${Q}, ${U}, ${J})`}case"oklch":{let[Q,U,J]=$.oklch();return`oklch(${(Q*100).toFixed(1)}% ${U.toFixed(3)} ${Math.round(J||0)})`}default:return $.hex()}}getHarmonyColors(f,$){switch(f){case"complementary":return s6($).slice(1);case"triadic":return a6($).slice(1);case"analogous":return l6($).slice(1);case"split-complementary":return f8($).slice(1);case"square":return $8($).slice(1);case"compound":return Q8($).slice(1)}}buildRamps(){let f=[],$=I1(this.buildConfig(this._baseColor));f.push({name:"base",baseColor:this.formatColor(this._baseColor),colors:$.map((Q)=>this.formatColor(Q))});for(let Q of this._harmonies)if(Q.type==="shift"){let U=h(this._baseColor),[J,N,q]=U.hsl(),Z=((J||0)+(Q.degrees||0))%360,D=h.hsl(Z,N,q).hex(),X=I1(this.buildConfig(D));f.push({name:`shift-${Math.round(Q.degrees||0)}`,baseColor:this.formatColor(D),colors:X.map((K)=>this.formatColor(K))})}else{let U=this.getHarmonyColors(Q.type,this._baseColor);U.forEach((J,N)=>{let q=U.length>1?`-${N+1}`:"",Z=I1(this.buildConfig(J));f.push({name:`${Q.type}${q}`,baseColor:this.formatColor(J),colors:Z.map((D)=>this.formatColor(D))})})}return f}getFormat(){return this._format}output(f,$){let Q=this.buildRamps();switch(f){case"css":return w2(Q,$);case"json":return u2(Q,$);case"text":return B2(Q);default:throw Error(`Unknown output format: ${f}`)}}}function u1(f){let $=null;function Q(){if(!$)$=f.buildRamps();return $}function U(){$=null}let J=(N)=>{let Z=Q()[0].colors,D=Math.max(1,Math.min(Z.length,N))-1;return h0(Z[D],f.getFormat())};return J.size=(N)=>{return U(),f.size(N),J},J.format=(N)=>{return U(),f.format(N),J},J.lightness=(N,q)=>{return U(),f.lightness(N,q),J},J.saturation=(N,q)=>{return U(),f.saturation(N,q),J},J.hue=(N,q)=>{return U(),f.hue(N,q),J},J.lightnessDistribution=(N)=>{return U(),f.lightnessDistribution(N),J},J.saturationDistribution=(N)=>{return U(),f.saturationDistribution(N),J},J.hueDistribution=(N)=>{return U(),f.hueDistribution(N),J},J.tint=(N,q,Z)=>{return U(),f.tint(N,q,Z??"normal"),J},J.add=(N,q)=>{if(U(),N==="shift")f.add(N,q);else f.add(N);return J},J.output=(N,q)=>{let Z=Q();switch(N){case"css":return w2(Z,q);case"json":return u2(Z,q);case"text":return B2(Z)}},Object.defineProperty(J,"palette",{get:()=>Q()[0].colors,enumerable:!0}),Object.defineProperty(J,"ramps",{get:()=>Q(),enumerable:!0}),J}function T0(f,$,Q,U="oklch"){if(U==="oklch")return qQ(f,$,Q);return t.mix(f,$,Q,U).hex()}function qQ(f,$,Q){let U=s(f),J=s($),N=U.h,Z=J.h-N;if(Z>180)Z-=360;if(Z<-180)Z+=360;let D=N+Q*Z;if(D<0)D+=360;if(D>=360)D-=360;if(U.c<0.002&&J.c<0.002)D=0;else if(U.c<0.002)D=J.h;else if(J.c<0.002)D=U.h;let X={l:U.l+Q*(J.l-U.l),c:U.c+Q*(J.c-U.c),h:D},K=wf(X);return If(K)}function U8(f,$,Q,U="oklch"){let J=[];for(let N=0;NT0(B,S,u,Q),V=$-1,G=[];for(let B=0;B<$;B++){let S=V===0?0:B/V,u=F(U,J,S),w=F(N,Z,S),m=F(q,D,S),L=F(X,K,S);for(let p=0;p<$;p++){let n=V===0?0:p/V,A=F(u,w,n),I=F(m,L,n);for(let y=0;y<$;y++){let E=V===0?0:y/V;G.push(F(A,I,E))}}}return G}function N8(f,$,Q,U,J="oklch"){let N=(D,X,K)=>T0(D,X,K,J),q=U-1,Z=[];for(let D=0;D180)Z-=360;if(Z<-180)Z+=360;let D=N+Q*Z;if(D<0)D+=360;if(D>=360)D-=360;if(U.c<0.002&&J.c<0.002)D=0;else if(U.c<0.002)D=J.h;else if(J.c<0.002)D=U.h;let X={l:U.l+Q*(J.l-U.l),c:U.c+Q*(J.c-U.c),h:D},K=k0(X);return E0(K)}function U8(f,$,Q,U="oklch"){let J=[];for(let N=0;Nz0(u,z,B,Q),V=$-1,Y=[];for(let u=0;u<$;u++){let z=V===0?0:u/V,B=F(U,J,z),W=F(N,Z,z),M=F(q,D,z),L=F(X,K,z);for(let p=0;p<$;p++){let n=V===0?0:p/V,m=F(B,W,n),w=F(M,L,n);for(let y=0;y<$;y++){let E=V===0?0:y/V;Y.push(F(m,w,E))}}}return Y}function N8(f,$,Q,U,J="oklch"){let N=(D,X,K)=>z0(D,X,K,J),q=U-1,Z=[];for(let D=0;DqQ(U)),Q=$[0];for(let U=1;U<$.length;U++)if($[U]!==Q)throw Error(`All colors must use the same format. Found '${Q}' and '${$[U]}': ${f[0]} vs ${f[U]}`);return Q}function g0(f,$){let Q=t(f),[U]=Q.oklch(),J=(Z)=>{switch(Z){case"hsl":{let[D,X,K]=Q.hsl();return`hsl(${Math.round(D||0)}, ${Math.round(X*100)}%, ${Math.round(K*100)}%)`}case"rgb":{let[D,X,K]=Q.rgb();return`rgb(${D}, ${X}, ${K})`}case"oklch":{let[D,X,K]=Q.oklch();return`oklch(${(D*100).toFixed(1)}% ${X.toFixed(3)} ${Math.round(K||0)})`}default:return f}},N=J($),q=new String(N);return Object.defineProperties(q,{hex:{value:()=>Q.hex(),enumerable:!1},hsl:{value:()=>J("hsl"),enumerable:!1},rgb:{value:()=>J("rgb"),enumerable:!1},oklch:{value:()=>J("oklch"),enumerable:!1},luminance:{value:U,enumerable:!1}}),q}function a(f){let $;try{$=t(f)}catch{throw Error(`Invalid color: "${f}"`)}let Q=$.hex(),[U,J,N]=$.rgb(),[q,Z,D]=$.hsl(),[X,K,F]=$.oklch(),V={r:U,g:J,b:N},Y={h:Math.round(q||0),s:parseFloat(Z.toFixed(2)),l:parseFloat(D.toFixed(2))},u={l:parseFloat(X.toFixed(3)),c:parseFloat(K.toFixed(3)),h:Math.round(F||0)},z=(W)=>{switch(W){case"hsl":return`hsl(${Y.h}, ${Math.round(Y.s*100)}%, ${Math.round(Y.l*100)}%)`;case"rgb":return`rgb(${U}, ${J}, ${N})`;case"oklch":return`oklch(${(X*100).toFixed(1)}% ${K.toFixed(3)} ${Math.round(F||0)})`;default:return Q}};return{hex:Q,rgb:V,hsl:Y,oklch:u,luminance:X,lighten(W){let M=g(Q);return M.l=Math.max(0,Math.min(1,M.l+W)),a(E0(k0(M)))},darken(W){return this.lighten(-W)},saturate(W){let M=g(Q);return M.c=Math.max(0,M.c+W),a(E0(k0(M)))},desaturate(W){return this.saturate(-W)},rotate(W){let M=g(Q);return M.h=((M.h+W)%360+360)%360,a(E0(k0(M)))},set(W){let M=g(Q);if(W.lightness!==void 0)M.l=Math.max(0,Math.min(1,W.lightness));if(W.chroma!==void 0)M.c=Math.max(0,W.chroma);if(W.hue!==void 0)M.h=(W.hue%360+360)%360;return a(E0(k0(M)))},mix(W,M,L="oklch"){let p=z0(Q,t(W).hex(),M,L);return a(p)},blend(W,M,L){let p=Pf(t(Q),t(W),M,L);return a(p.hex())},format(W){return z(W)},output(W,M){let L=M||"color";switch(W){case"css":{let p=[":root {"];return p.push(` --${L}-hex: ${Q};`),p.push(` --${L}-rgb: ${z("rgb")};`),p.push(` --${L}-hsl: ${z("hsl")};`),p.push(` --${L}-oklch: ${z("oklch")};`),p.push("}"),p.join(` +`)}case"json":return JSON.stringify({hex:Q,rgb:V,hsl:Y,oklch:u},null,2);case"text":default:return Q}},toString(){return Q}}}class Lf{_baseColor;_size=10;_format="hex";_lightnessStart=0;_lightnessEnd=100;_saturationStart=100;_saturationEnd=0;_hueStart=-10;_hueEnd=10;_lightnessDistribution="linear";_saturationDistribution="linear";_hueDistribution="linear";_tintColor;_tintOpacity=0;_tintBlend="normal";_harmonies=[];constructor(f){try{t(f)}catch{throw Error(`Invalid color: "${f}"`)}this._baseColor=t(f).hex()}size(f){if(f<2||f>100)throw Error("Size must be between 2 and 100");return this._size=f,this}format(f){return this._format=f,this}lightness(f,$){return this._lightnessStart=f,this._lightnessEnd=$,this}saturation(f,$){return this._saturationStart=f,this._saturationEnd=$,this}hue(f,$){return this._hueStart=f,this._hueEnd=$,this}lightnessDistribution(f){return this._lightnessDistribution=f,this}saturationDistribution(f){return this._saturationDistribution=f,this}hueDistribution(f){return this._hueDistribution=f,this}tint(f,$,Q="normal"){try{t(f)}catch{throw Error(`Invalid tint color: "${f}"`)}return this._tintColor=t(f).hex(),this._tintOpacity=$,this._tintBlend=Q,this}add(f,$){if(f==="shift"){if($===void 0)throw Error("shift requires a degrees value");this._harmonies.push({type:"shift",degrees:$})}else this._harmonies.push({type:f});return this}buildConfig(f){return{id:"sdk",name:"ramp",baseColor:f,colorFormat:"hex",totalSteps:this._size,lightnessStart:this._lightnessStart,lightnessEnd:this._lightnessEnd,chromaStart:this._hueStart,chromaEnd:this._hueEnd,saturationStart:this._saturationStart,saturationEnd:this._saturationEnd,lightnessDistributionType:this._lightnessDistribution,saturationDistributionType:this._saturationDistribution,hueDistributionType:this._hueDistribution,tintColor:this._tintColor,tintOpacity:this._tintOpacity,tintBlendMode:this._tintBlend,swatches:[]}}formatColor(f){let $=t(f);switch(this._format){case"hsl":{let[Q,U,J]=$.hsl();return`hsl(${Math.round(Q||0)}, ${Math.round(U*100)}%, ${Math.round(J*100)}%)`}case"rgb":{let[Q,U,J]=$.rgb();return`rgb(${Q}, ${U}, ${J})`}case"oklch":{let[Q,U,J]=$.oklch();return`oklch(${(Q*100).toFixed(1)}% ${U.toFixed(3)} ${Math.round(J||0)})`}default:return $.hex()}}getHarmonyColors(f,$){switch(f){case"complementary":return s6($).slice(1);case"triadic":return a6($).slice(1);case"analogous":return l6($).slice(1);case"split-complementary":return f8($).slice(1);case"square":return $8($).slice(1);case"compound":return Q8($).slice(1)}}buildRamps(){let f=[],$=B1(this.buildConfig(this._baseColor));f.push({name:"base",baseColor:this.formatColor(this._baseColor),colors:$.map((Q)=>this.formatColor(Q))});for(let Q of this._harmonies)if(Q.type==="shift"){let U=t(this._baseColor),[J,N,q]=U.hsl(),Z=((J||0)+(Q.degrees||0))%360,D=t.hsl(Z,N,q).hex(),X=B1(this.buildConfig(D));f.push({name:`shift-${Math.round(Q.degrees||0)}`,baseColor:this.formatColor(D),colors:X.map((K)=>this.formatColor(K))})}else{let U=this.getHarmonyColors(Q.type,this._baseColor);U.forEach((J,N)=>{let q=U.length>1?`-${N+1}`:"",Z=B1(this.buildConfig(J));f.push({name:`${Q.type}${q}`,baseColor:this.formatColor(J),colors:Z.map((D)=>this.formatColor(D))})})}return f}getFormat(){return this._format}output(f,$){let Q=this.buildRamps();switch(f){case"css":return B2(Q,$);case"json":return u2(Q,$);case"text":return E2(Q);default:throw Error(`Unknown output format: ${f}`)}}}function E1(f){let $=null;function Q(){if(!$)$=f.buildRamps();return $}function U(){$=null}let J=(N)=>{let Z=Q()[0].colors,D=Math.max(1,Math.min(Z.length,N))-1;return g0(Z[D],f.getFormat())};return J.size=(N)=>{return U(),f.size(N),J},J.format=(N)=>{return U(),f.format(N),J},J.lightness=(N,q)=>{return U(),f.lightness(N,q),J},J.saturation=(N,q)=>{return U(),f.saturation(N,q),J},J.hue=(N,q)=>{return U(),f.hue(N,q),J},J.lightnessDistribution=(N)=>{return U(),f.lightnessDistribution(N),J},J.saturationDistribution=(N)=>{return U(),f.saturationDistribution(N),J},J.hueDistribution=(N)=>{return U(),f.hueDistribution(N),J},J.tint=(N,q,Z)=>{return U(),f.tint(N,q,Z??"normal"),J},J.add=(N,q)=>{if(U(),N==="shift")f.add(N,q);else f.add(N);return J},J.output=(N,q)=>{let Z=Q();switch(N){case"css":return B2(Z,q);case"json":return u2(Z,q);case"text":return E2(Z)}},Object.defineProperty(J,"palette",{get:()=>Q()[0].colors,enumerable:!0}),Object.defineProperty(J,"ramps",{get:()=>Q(),enumerable:!0}),J}function q8(f,$="color"){let Q=[":root {"];for(let U=0;Uh(U).hex());else{let U=h(this._colors[0]).hex(),J=h(this._colors[this._colors.length-1]).hex();if(this._distribution){let N=this._distribution;$=[];for(let q=0;q{let J=Math.max(1,Math.min(f.length,U))-1;return h0(f[J],$)};return Q.palette=f,Q.size=f.length,Q.output=(U,J)=>{switch(U){case"css":return q8(f,J);case"json":return Z8(f,J);case"text":return f.join(` -`);default:throw Error(`Unknown output format: ${U}`)}},Q}var DQ=[{x:0,y:0,z:0},{x:1,y:0,z:0},{x:0,y:1,z:0},{x:0,y:0,z:1},{x:1,y:1,z:0},{x:1,y:0,z:1},{x:0,y:1,z:1},{x:1,y:1,z:1}];class E1{_corners;_interpolation;_format="hex";_distribution;constructor(f,$){let Q=Object.keys(f);if(Q.length!==8)throw Error(`CubeColorSpace requires exactly 8 corner colors, got ${Q.length}`);uf(Object.values(f)),this._corners=f,this._interpolation=$?.interpolation??"oklch"}interpolation(f){return this._interpolation=f,this}format(f){return this._format=f,this}distribution(f){return this._distribution=f,this}size(f){let $=Object.keys(this._corners),Q=$.map((F)=>h(this._corners[F]).hex()),U=this._format,J={};for(let F=0;F<8;F++)J[$[F]]=DQ[F];let N;if(this._distribution){let F=this._distribution,[V,G,B,S,u,w,m,L]=Q,p=(n,A,I)=>T0(n,A,I,this._interpolation);N=[];for(let n=0;n{F=Math.max(0,Math.min(q,Math.round(F))),V=Math.max(0,Math.min(q,Math.round(V))),G=Math.max(0,Math.min(q,Math.round(G)));let B=F*f*f+V*f+G;return h0(N[B],U)},D=(F)=>{let V=0,G=0,B=0;for(let[S,u]of Object.entries(F)){let w=J[S];if(!w)continue;V=Math.max(V,w.x*u),G=Math.max(G,w.y*u),B=Math.max(B,w.z*u)}return Z(V,G,B)},K={tint:D,cube:(F,V,G)=>Z(F,V,G),palette:N,size:f,output:(F,V)=>{switch(F){case"css":return K8(N,f,V);case"json":return F8(N,f,V);case"text":return N.join(` -`);default:throw Error(`Unknown output format: ${F}`)}}};for(let F of $)K[F]=(V)=>D({[F]:V});return K}}class k1{_dark;_light;_hue;_interpolation;_format="hex";_distribution;constructor(f,$,Q){uf([f,$,Q]),this._dark=h(f).hex(),this._light=h($).hex(),this._hue=h(Q).hex(),this._interpolation="oklch"}interpolation(f){return this._interpolation=f,this}format(f){return this._format=f,this}distribution(f){return this._distribution=f,this}size(f){let $;if(this._distribution){let N=this._distribution,q=(Z,D,X)=>T0(Z,D,X,this._interpolation);$=[];for(let Z=0;Z{let Z=Math.max(0,Math.min(f-1,N)),D=Math.max(0,Math.min(f-1,q)),X=Z*f+D;return h0($[X],Q)};return Object.defineProperties(J,{palette:{value:$,enumerable:!0},size:{value:f,enumerable:!0},output:{value:(N,q)=>{switch(N){case"css":return D8($,f,q);case"json":return X8($,f,q);case"text":return $.join(` -`);default:throw Error(`Unknown output format: ${N}`)}},enumerable:!1}}),J}}var k2=[{id:"aaa-normal",name:"AAA Normal text",minRatio:7},{id:"aaa-large",name:"AAA Large text",minRatio:4.5},{id:"aa-normal",name:"AA Normal text",minRatio:4.5},{id:"aa-large",name:"AA Large text",minRatio:3}];function V8(f,$,Q){let[U,J,N]=[f,$,Q].map((q)=>{let Z=q/255;return Z<=0.03928?Z/12.92:Math.pow((Z+0.055)/1.055,2.4)});return 0.2126*U+0.7152*J+0.0722*N}function y8(f,$){let[Q,U,J]=t(f).rgb(),[N,q,Z]=t($).rgb(),D=V8(Q,U,J),X=V8(N,q,Z),K=Math.max(D,X),F=Math.min(D,X);return(K+0.05)/(F+0.05)}function W8(f){return k2.filter(($)=>f>=$.minRatio)}function Y8(f,$){return t.deltaE(f,$)}function z2(f){return Math.round(f*100)/100}function G8(f,$,Q){return Math.pow(f/255,2.4)*0.2126729+Math.pow($/255,2.4)*0.7151522+Math.pow(Q/255,2.4)*0.072175}function I8(f){if(f<0)return 0;if(f<0.022)return f+Math.pow(0.022-f,1.414);return f}function XQ(f,$){let Q=I8(f),U=I8($),J;if(U>Q)J=(Math.pow(U,0.56)-Math.pow(Q,0.57))*1.14;else J=(Math.pow(U,0.65)-Math.pow(Q,0.62))*1.14;if(Math.abs(J)<0.1)return 0;if(J>0)return(J-0.027)*100;else return(J+0.027)*100}function w8(f){let $=f.replace(/^#/,"");if($.length===3)$=$[0]+$[0]+$[1]+$[1]+$[2]+$[2];let Q=parseInt($,16);return[Q>>16&255,Q>>8&255,Q&255]}function u8(f,$){let[Q,U,J]=w8(f),[N,q,Z]=w8($);return XQ(G8(Q,U,J),G8(N,q,Z))}var KQ=[{name:"Preferred body text",threshold:90},{name:"Body text",threshold:75},{name:"Large text",threshold:60},{name:"Large/bold text",threshold:45},{name:"Minimum text",threshold:30},{name:"Non-text",threshold:15}];function FQ(f,$){let Q=h(f).hex(),U=h($).hex();return u8(Q,U)}function VQ(f,$,Q,U){let J=[],N=Y8(f,$);if(N<3)J.push(`Colors are nearly identical (deltaE: ${z2(N)})`);if(Q==="apca"&&Math.abs(U)<15)J.push("Contrast is below minimum usable threshold");else if(Q==="wcag"&&U<1.5)J.push("Contrast is below minimum usable threshold");let q=f.toLowerCase(),Z=$.toLowerCase();if(q==="#000000")J.push("Pure #000000 detected — consider #111111 for screens");if(q==="#ffffff")J.push("Pure #ffffff detected — consider #eeeeee for screens");if(Z==="#000000")J.push("Pure #000000 detected — consider #111111 for screens");if(Z==="#ffffff")J.push("Pure #ffffff detected — consider #eeeeee for screens");return Array.from(new Set(J))}function yQ(f,$,Q){let U,J;if(Q==="wcag"){U=y8(f,$);let D=W8(U);J=k2.map((X)=>({name:X.name,threshold:X.minRatio,pass:D.some((K)=>K.id===X.id)}))}else{U=FQ(f,$);let D=Math.abs(U);J=KQ.map((X)=>({name:X.name,threshold:X.threshold,pass:D>=X.threshold}))}let N=J.some((D)=>D.pass),q=VQ(f,$,Q,U),Z=z2(U);return{foreground:f,background:$,mode:Q,score:Z,pass:N,levels:J,warnings:q}}function WQ(f){let $=[];$.push(`Mode: ${f.mode.toUpperCase()}`),$.push(`Score: ${f.score}`),$.push(`Pass: ${f.pass?"yes":"no"}`),$.push(""),$.push("Levels:");for(let Q of f.levels){let U=Q.pass?"✓":"✗";$.push(` ${U} ${Q.name} (${Q.threshold})`)}if(f.warnings.length>0){$.push(""),$.push("Warnings:");for(let Q of f.warnings)$.push(` ⚠ ${Q}`)}return $.join(` +`)}function F8(f,$,Q="color"){let U=[];for(let J=0;J<$;J++){let N=[];for(let q=0;q<$;q++){let Z=[];for(let D=0;D<$;D++)Z.push(f[J*$*$+q*$+D]);N.push(Z)}U.push(N)}return JSON.stringify({name:Q,size:$,colors:U},null,2)}class k1{_colors;_interpolation="oklch";_format="hex";_distribution;constructor(...f){if(f.length<2)throw Error("LinearColorSpace requires at least 2 colors");uf(f),this._colors=f}interpolation(f){return this._interpolation=f,this}format(f){return this._format=f,this}distribution(f){return this._distribution=f,this}size(f){let $,Q=this._format;if(this._interpolation===!1)$=this._colors.map((U)=>t(U).hex());else{let U=t(this._colors[0]).hex(),J=t(this._colors[this._colors.length-1]).hex();if(this._distribution){let N=this._distribution;$=[];for(let q=0;q{let J=Math.max(1,Math.min(f.length,U))-1;return g0(f[J],$)};return Q.palette=f,Q.size=f.length,Q.output=(U,J)=>{switch(U){case"css":return q8(f,J);case"json":return Z8(f,J);case"text":return f.join(` +`);default:throw Error(`Unknown output format: ${U}`)}},Q.at=(U)=>{let J=Math.max(0,Math.min(f.length-1,U));return a(f[J])},Q.colors=()=>f.map((U)=>a(U)),Q}var DQ=[{x:0,y:0,z:0},{x:1,y:0,z:0},{x:0,y:1,z:0},{x:0,y:0,z:1},{x:1,y:1,z:0},{x:1,y:0,z:1},{x:0,y:1,z:1},{x:1,y:1,z:1}];class z1{_corners;_interpolation;_format="hex";_distribution;constructor(f,$){let Q=Object.keys(f);if(Q.length!==8)throw Error(`CubeColorSpace requires exactly 8 corner colors, got ${Q.length}`);uf(Object.values(f)),this._corners=f,this._interpolation=$?.interpolation??"oklch"}interpolation(f){return this._interpolation=f,this}format(f){return this._format=f,this}distribution(f){return this._distribution=f,this}size(f){let $=Object.keys(this._corners),Q=$.map((F)=>t(this._corners[F]).hex()),U=this._format,J={};for(let F=0;F<8;F++)J[$[F]]=DQ[F];let N;if(this._distribution){let F=this._distribution,[V,Y,u,z,B,W,M,L]=Q,p=(n,m,w)=>z0(n,m,w,this._interpolation);N=[];for(let n=0;n{F=Math.max(0,Math.min(q,Math.round(F))),V=Math.max(0,Math.min(q,Math.round(V))),Y=Math.max(0,Math.min(q,Math.round(Y)));let u=F*f*f+V*f+Y;return g0(N[u],U)},D=(F)=>{let V=0,Y=0,u=0;for(let[z,B]of Object.entries(F)){let W=J[z];if(!W)continue;V=Math.max(V,W.x*B),Y=Math.max(Y,W.y*B),u=Math.max(u,W.z*B)}return Z(V,Y,u)},K={tint:D,cube:(F,V,Y)=>Z(F,V,Y),palette:N,size:f,output:(F,V)=>{switch(F){case"css":return K8(N,f,V);case"json":return F8(N,f,V);case"text":return N.join(` +`);default:throw Error(`Unknown output format: ${F}`)}},at:(F,V,Y)=>{let u=Math.max(0,Math.min(q,Math.round(F))),z=Math.max(0,Math.min(q,Math.round(V))),B=Math.max(0,Math.min(q,Math.round(Y))),W=u*f*f+z*f+B;return a(N[W])},colors:()=>N.map((F)=>a(F))};for(let F of $)K[F]=(V)=>D({[F]:V});return K}}class H1{_dark;_light;_hue;_interpolation;_format="hex";_distribution;constructor(f,$,Q){uf([f,$,Q]),this._dark=t(f).hex(),this._light=t($).hex(),this._hue=t(Q).hex(),this._interpolation="oklch"}interpolation(f){return this._interpolation=f,this}format(f){return this._format=f,this}distribution(f){return this._distribution=f,this}size(f){let $;if(this._distribution){let N=this._distribution,q=(Z,D,X)=>z0(Z,D,X,this._interpolation);$=[];for(let Z=0;Z{let Z=Math.max(0,Math.min(f-1,N)),D=Math.max(0,Math.min(f-1,q)),X=Z*f+D;return g0($[X],Q)};return Object.defineProperties(J,{palette:{value:$,enumerable:!0},size:{value:f,enumerable:!0},output:{value:(N,q)=>{switch(N){case"css":return D8($,f,q);case"json":return X8($,f,q);case"text":return $.join(` +`);default:throw Error(`Unknown output format: ${N}`)}},enumerable:!1},at:{value:(N,q)=>{let Z=Math.max(0,Math.min(f-1,N)),D=Math.max(0,Math.min(f-1,q)),X=Z*f+D;return a($[X])},enumerable:!1},colors:{value:()=>$.map((N)=>a(N)),enumerable:!1}}),J}}var k2=[{id:"aaa-normal",name:"AAA Normal text",minRatio:7},{id:"aaa-large",name:"AAA Large text",minRatio:4.5},{id:"aa-normal",name:"AA Normal text",minRatio:4.5},{id:"aa-large",name:"AA Large text",minRatio:3}];function V8(f,$,Q){let[U,J,N]=[f,$,Q].map((q)=>{let Z=q/255;return Z<=0.03928?Z/12.92:Math.pow((Z+0.055)/1.055,2.4)});return 0.2126*U+0.7152*J+0.0722*N}function y8(f,$){let[Q,U,J]=d(f).rgb(),[N,q,Z]=d($).rgb(),D=V8(Q,U,J),X=V8(N,q,Z),K=Math.max(D,X),F=Math.min(D,X);return(K+0.05)/(F+0.05)}function W8(f){return k2.filter(($)=>f>=$.minRatio)}function Y8(f,$){return d.deltaE(f,$)}function z2(f){return Math.round(f*100)/100}function G8(f,$,Q){return Math.pow(f/255,2.4)*0.2126729+Math.pow($/255,2.4)*0.7151522+Math.pow(Q/255,2.4)*0.072175}function I8(f){if(f<0)return 0;if(f<0.022)return f+Math.pow(0.022-f,1.414);return f}function XQ(f,$){let Q=I8(f),U=I8($),J;if(U>Q)J=(Math.pow(U,0.56)-Math.pow(Q,0.57))*1.14;else J=(Math.pow(U,0.65)-Math.pow(Q,0.62))*1.14;if(Math.abs(J)<0.1)return 0;if(J>0)return(J-0.027)*100;else return(J+0.027)*100}function w8(f){let $=f.replace(/^#/,"");if($.length===3)$=$[0]+$[0]+$[1]+$[1]+$[2]+$[2];let Q=parseInt($,16);return[Q>>16&255,Q>>8&255,Q&255]}function B8(f,$){let[Q,U,J]=w8(f),[N,q,Z]=w8($);return XQ(G8(Q,U,J),G8(N,q,Z))}var KQ=[{name:"Preferred body text",threshold:90},{name:"Body text",threshold:75},{name:"Large text",threshold:60},{name:"Large/bold text",threshold:45},{name:"Minimum text",threshold:30},{name:"Non-text",threshold:15}];function FQ(f,$){let Q=t(f).hex(),U=t($).hex();return B8(Q,U)}function VQ(f,$,Q,U){let J=[],N=Y8(f,$);if(N<3)J.push(`Colors are nearly identical (deltaE: ${z2(N)})`);if(Q==="apca"&&Math.abs(U)<15)J.push("Contrast is below minimum usable threshold");else if(Q==="wcag"&&U<1.5)J.push("Contrast is below minimum usable threshold");let q=f.toLowerCase(),Z=$.toLowerCase();if(q==="#000000")J.push("Pure #000000 detected — consider #111111 for screens");if(q==="#ffffff")J.push("Pure #ffffff detected — consider #eeeeee for screens");if(Z==="#000000")J.push("Pure #000000 detected — consider #111111 for screens");if(Z==="#ffffff")J.push("Pure #ffffff detected — consider #eeeeee for screens");return Array.from(new Set(J))}function yQ(f,$,Q){let U,J;if(Q==="wcag"){U=y8(f,$);let D=W8(U);J=k2.map((X)=>({name:X.name,threshold:X.minRatio,pass:D.some((K)=>K.id===X.id)}))}else{U=FQ(f,$);let D=Math.abs(U);J=KQ.map((X)=>({name:X.name,threshold:X.threshold,pass:D>=X.threshold}))}let N=J.some((D)=>D.pass),q=VQ(f,$,Q,U),Z=z2(U);return{foreground:f,background:$,mode:Q,score:Z,pass:N,levels:J,warnings:q}}function WQ(f){let $=[];$.push(`Mode: ${f.mode.toUpperCase()}`),$.push(`Score: ${f.score}`),$.push(`Pass: ${f.pass?"yes":"no"}`),$.push(""),$.push("Levels:");for(let Q of f.levels){let U=Q.pass?"✓":"✗";$.push(` ${U} ${Q.name} (${Q.threshold})`)}if(f.warnings.length>0){$.push(""),$.push("Warnings:");for(let Q of f.warnings)$.push(` ⚠ ${Q}`)}return $.join(` `)}function YQ(f){let $=[":root {"];return $.push(` --lint-foreground: ${f.foreground};`),$.push(` --lint-background: ${f.background};`),$.push(` --lint-score: ${f.score};`),$.push(` --lint-pass: ${f.pass?"1":"0"};`),$.push("}"),$.join(` -`)}class Bf{_fg;_bg;_mode="apca";_result=null;constructor(f,$){try{this._fg=h(f).hex()}catch{throw Error(`Invalid foreground color: "${f}"`)}try{this._bg=h($).hex()}catch{throw Error(`Invalid background color: "${$}"`)}}mode(f){let $=new Bf(this._fg,this._bg);return $._mode=f,$}_evaluate(){if(!this._result)this._result=yQ(this._fg,this._bg,this._mode);return this._result}get foreground(){return this._evaluate().foreground}get background(){return this._evaluate().background}get score(){return this._evaluate().score}get pass(){return this._evaluate().pass}get levels(){return this._evaluate().levels}get warnings(){return this._evaluate().warnings}output(f){let $=this._evaluate();switch(f){case"json":return JSON.stringify($,null,2);case"css":return YQ($);case"text":default:return WQ($)}}toJSON(){return this._evaluate()}}function O2(f,$){return new Bf(f,$)}function B8(f,$,Q){let U=s(f),J=s($),N=U.h,Z=J.h-N;if(Z>180)Z-=360;if(Z<-180)Z+=360;let D=N+Q*Z;if(D<0)D+=360;if(D>=360)D-=360;if(U.c<0.002&&J.c<0.002)D=0;else if(U.c<0.002)D=J.h;else if(J.c<0.002)D=U.h;let X={l:U.l+Q*(J.l-U.l),c:U.c+Q*(J.c-U.c),h:D},K=wf(X);return If(K)}function z1(f){return u1(new Pf(f))}z1.convert=function($,Q){return E2($).format(Q)};z1.mix=function($,Q,U){return B8($,Q,U)};function E8(f){return E2(f)}var GQ={rampa:z1,color:E8,lint:O2,RampaBuilder:Pf,createRampaFn:u1,LintBuilder:Bf,LinearColorSpace:B1,CubeColorSpace:E1,PlaneColorSpace:k1};globalThis.Rampa=GQ;})(); +`)}class Ef{_fg;_bg;_mode="apca";_result=null;constructor(f,$){try{this._fg=t(f).hex()}catch{throw Error(`Invalid foreground color: "${f}"`)}try{this._bg=t($).hex()}catch{throw Error(`Invalid background color: "${$}"`)}}mode(f){let $=new Ef(this._fg,this._bg);return $._mode=f,$}_evaluate(){if(!this._result)this._result=yQ(this._fg,this._bg,this._mode);return this._result}get foreground(){return this._evaluate().foreground}get background(){return this._evaluate().background}get score(){return this._evaluate().score}get pass(){return this._evaluate().pass}get levels(){return this._evaluate().levels}get warnings(){return this._evaluate().warnings}output(f){let $=this._evaluate();switch(f){case"json":return JSON.stringify($,null,2);case"css":return YQ($);case"text":default:return WQ($)}}toJSON(){return this._evaluate()}}function H2(f,$){return new Ef(f,$)}function u8(f,$,Q){let U=g(f),J=g($),N=U.h,Z=J.h-N;if(Z>180)Z-=360;if(Z<-180)Z+=360;let D=N+Q*Z;if(D<0)D+=360;if(D>=360)D-=360;if(U.c<0.002&&J.c<0.002)D=0;else if(U.c<0.002)D=J.h;else if(J.c<0.002)D=U.h;let X={l:U.l+Q*(J.l-U.l),c:U.c+Q*(J.c-U.c),h:D},K=k0(X);return E0(K)}function S1(f){return E1(new Lf(f))}S1.convert=function($,Q){return a($).format(Q)};S1.mix=function($,Q,U){return u8($,Q,U)};function E8(f){return a(f)}var GQ={rampa:S1,color:E8,lint:H2,RampaBuilder:Lf,createRampaFn:E1,LintBuilder:Ef,LinearColorSpace:k1,CubeColorSpace:z1,PlaneColorSpace:H1};globalThis.Rampa=GQ;})(); diff --git a/src/engine/ImageDecoder.ts b/src/engine/ImageDecoder.ts new file mode 100644 index 00000000..6c5a7d67 --- /dev/null +++ b/src/engine/ImageDecoder.ts @@ -0,0 +1,56 @@ +import { decode as decodePng } from 'fast-png'; +import { decode as decodeJpeg } from 'jpeg-js'; +import { readFileSync } from 'fs'; + +export interface DecodedImage { + width: number; + height: number; + /** RGBA pixel data, 4 bytes per pixel */ + data: Uint8Array; +} + +type ImageFormat = 'png' | 'jpeg'; + +function detectFormat(buffer: Uint8Array): ImageFormat { + // PNG: 89 50 4E 47 + if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4E && buffer[3] === 0x47) { + return 'png'; + } + // JPEG: FF D8 FF + if (buffer[0] === 0xFF && buffer[1] === 0xD8 && buffer[2] === 0xFF) { + return 'jpeg'; + } + throw new Error('Unsupported image format. Only PNG and JPEG are supported.'); +} + +function decodePngImage(buffer: Uint8Array): DecodedImage { + const png = decodePng(buffer); + const { width, height, data, channels } = png; + + if (channels === 4) { + return { width, height, data: new Uint8Array(data.buffer, data.byteOffset, data.byteLength) }; + } + + // Convert RGB (3 channels) to RGBA + const rgba = new Uint8Array(width * height * 4); + for (let i = 0; i < width * height; i++) { + rgba[i * 4] = data[i * channels]; + rgba[i * 4 + 1] = data[i * channels + 1]; + rgba[i * 4 + 2] = data[i * channels + 2]; + rgba[i * 4 + 3] = channels >= 4 ? data[i * channels + 3] : 255; + } + return { width, height, data: rgba }; +} + +function decodeJpegImage(buffer: Uint8Array): DecodedImage { + const jpg = decodeJpeg(buffer, { useTArray: true, formatAsRGBA: true }); + return { width: jpg.width, height: jpg.height, data: jpg.data }; +} + +export function decodeImage(filePath: string): DecodedImage { + const buffer = new Uint8Array(readFileSync(filePath)); + const format = detectFormat(buffer); + + if (format === 'png') return decodePngImage(buffer); + return decodeJpegImage(buffer); +} diff --git a/src/engine/PaletteEngine.ts b/src/engine/PaletteEngine.ts new file mode 100644 index 00000000..a4c0685b --- /dev/null +++ b/src/engine/PaletteEngine.ts @@ -0,0 +1,519 @@ +import { rgbToOklch, oklchToHex } from './OklchMathEngine'; + +export interface RgbPixel { r: number; g: number; b: number } +export interface OklchPixel { l: number; c: number; h: number } + +export interface FrequencyEntry { + rgb: RgbPixel; + oklch: OklchPixel; + hex: string; + count: number; +} + +export interface PaletteEngineEntry { + hex: string; + oklch: OklchPixel; + frequency: number; // 0-1 +} + +export type AnsiColorName = 'black' | 'red' | 'green' | 'yellow' | 'blue' | 'magenta' | 'cyan' | 'white'; + +// ── Pixel Sampling ──────────────────────────────────────────── + +/** + * Grid-based spatial stratification sampler. + * Divides the image into a grid and samples one pixel per cell. + * Skips fully transparent pixels. + */ +export function samplePixels( + data: Uint8Array, + width: number, + height: number, + sampleSize: number = 50000 +): RgbPixel[] { + const totalPixels = width * height; + + if (totalPixels <= sampleSize) { + // Small image — use all pixels + const pixels: RgbPixel[] = []; + for (let i = 0; i < totalPixels; i++) { + const offset = i * 4; + if (data[offset + 3] < 128) continue; // skip transparent + pixels.push({ r: data[offset], g: data[offset + 1], b: data[offset + 2] }); + } + return pixels; + } + + // Calculate grid dimensions + const ratio = width / height; + const cols = Math.round(Math.sqrt(sampleSize * ratio)); + const rows = Math.round(sampleSize / cols); + const cellW = width / cols; + const cellH = height / rows; + + const pixels: RgbPixel[] = []; + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + const x = Math.floor(col * cellW + cellW / 2); + const y = Math.floor(row * cellH + cellH / 2); + const idx = (y * width + x) * 4; + if (data[idx + 3] < 128) continue; + pixels.push({ r: data[idx], g: data[idx + 1], b: data[idx + 2] }); + } + } + return pixels; +} + +// ── Frequency Map ───────────────────────────────────────────── + +function rgbKey(r: number, g: number, b: number): number { + return (r << 16) | (g << 8) | b; +} + +function rgbToHex(r: number, g: number, b: number): string { + return '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1); +} + +export function buildFrequencyMap(pixels: RgbPixel[]): FrequencyEntry[] { + const map = new Map(); + + for (const { r, g, b } of pixels) { + const key = rgbKey(r, g, b); + const entry = map.get(key); + if (entry) { + entry.count++; + } else { + map.set(key, { r, g, b, count: 1 }); + } + } + + const entries: FrequencyEntry[] = []; + for (const { r, g, b, count } of map.values()) { + const [l, c, h] = rgbToOklch(r, g, b); + entries.push({ + rgb: { r, g, b }, + oklch: { l, c, h: isNaN(h) ? 0 : h }, + hex: rgbToHex(r, g, b), + count, + }); + } + + entries.sort((a, b) => b.count - a.count); + return entries; +} + +// ── Raw Palette (deltaE dedup) ──────────────────────────────── + +function oklchDeltaE(a: OklchPixel, b: OklchPixel): number { + // Approximate perceptual distance in OKLCH space + // Weighted: L difference matters most, then chroma, then hue + const dL = (a.l - b.l) * 100; // scale to 0-100 for deltaE-like range + const dC = (a.c - b.c) * 100; + const avgC = (a.c + b.c) / 2; + // Hue difference in radians, weighted by chroma + const dH_deg = Math.abs(a.h - b.h) > 180 + ? 360 - Math.abs(a.h - b.h) + : Math.abs(a.h - b.h); + const dH = (dH_deg / 360) * avgC * 200; // hue matters more at high chroma + return Math.sqrt(dL * dL + dC * dC + dH * dH); +} + +export function buildRawPalette( + freqMap: FrequencyEntry[], + tolerance: number = 2, + maxColors: number = 1000 +): PaletteEngineEntry[] { + const totalCount = freqMap.reduce((sum, e) => sum + e.count, 0); + const merged: { oklch: OklchPixel; hex: string; count: number }[] = []; + + for (const entry of freqMap) { + let found = false; + for (const m of merged) { + if (oklchDeltaE(entry.oklch, m.oklch) < tolerance) { + m.count += entry.count; + // Keep the hex of whichever had more original pixels + found = true; + break; + } + } + if (!found) { + merged.push({ oklch: { ...entry.oklch }, hex: entry.hex, count: entry.count }); + } + if (merged.length >= maxColors * 3) break; // early exit for very large maps + } + + merged.sort((a, b) => b.count - a.count); + const result = merged.slice(0, maxColors); + + return result.map(m => ({ + hex: m.hex, + oklch: m.oklch, + frequency: m.count / totalCount, + })); +} + +// ── K-Means Clustering (OKLCH space) ───────────────────────── + +interface Centroid { + l: number; + c: number; + hSin: number; // sin(hue) for circular mean + hCos: number; // cos(hue) for circular mean + totalWeight: number; +} + +// k-means++ seeding: pick initial centroids maximizing distance between them +function kMeansPlusPlusInit(entries: PaletteEngineEntry[], k: number): OklchPixel[] { + const centroids: OklchPixel[] = []; + + // First centroid: most frequent color + centroids.push({ ...entries[0].oklch }); + + // Remaining centroids: weighted by distance² to nearest existing centroid + const distances = new Float64Array(entries.length).fill(Infinity); + + for (let ci = 1; ci < k; ci++) { + // Update distances to nearest centroid + for (let i = 0; i < entries.length; i++) { + const d = oklchDeltaE(entries[i].oklch, centroids[ci - 1]); + if (d < distances[i]) distances[i] = d; + } + + // Weight by distance² × frequency for better spread + let totalWeight = 0; + for (let i = 0; i < entries.length; i++) { + totalWeight += distances[i] * distances[i] * entries[i].frequency; + } + + // Pick next centroid proportional to weighted distance² + let threshold = Math.random() * totalWeight; + let chosen = 0; + for (let i = 0; i < entries.length; i++) { + threshold -= distances[i] * distances[i] * entries[i].frequency; + if (threshold <= 0) { chosen = i; break; } + } + + centroids.push({ ...entries[chosen].oklch }); + } + + return centroids; +} + +export function kMeansClustering( + entries: PaletteEngineEntry[], + count: number = 10, + tolerance: number = 4, + maxIterations: number = 20 +): PaletteEngineEntry[] { + if (entries.length <= count) return entries; + + const k = Math.min(count, entries.length); + let centroids = kMeansPlusPlusInit(entries, k); + + const assignments = new Int32Array(entries.length); + const totalFreq = entries.reduce((s, e) => s + e.frequency, 0); + + for (let iter = 0; iter < maxIterations; iter++) { + let changed = false; + + // Assign each entry to nearest centroid + for (let i = 0; i < entries.length; i++) { + let minDist = Infinity; + let minIdx = 0; + for (let j = 0; j < centroids.length; j++) { + const d = oklchDeltaE(entries[i].oklch, centroids[j]); + if (d < minDist) { + minDist = d; + minIdx = j; + } + } + if (assignments[i] !== minIdx) { + assignments[i] = minIdx; + changed = true; + } + } + + if (!changed) break; + + // Recompute centroids as weighted mean + const newCentroids: Centroid[] = Array.from({ length: k }, () => ({ + l: 0, c: 0, hSin: 0, hCos: 0, totalWeight: 0, + })); + + for (let i = 0; i < entries.length; i++) { + const ci = assignments[i]; + const w = entries[i].frequency; + const e = entries[i].oklch; + const hRad = (e.h * Math.PI) / 180; + newCentroids[ci].l += e.l * w; + newCentroids[ci].c += e.c * w; + newCentroids[ci].hSin += Math.sin(hRad) * w; + newCentroids[ci].hCos += Math.cos(hRad) * w; + newCentroids[ci].totalWeight += w; + } + + centroids = newCentroids.map(nc => { + if (nc.totalWeight === 0) return { l: 0, c: 0, h: 0 }; + const h = ((Math.atan2(nc.hSin / nc.totalWeight, nc.hCos / nc.totalWeight) * 180) / Math.PI + 360) % 360; + return { + l: nc.l / nc.totalWeight, + c: nc.c / nc.totalWeight, + h, + }; + }); + } + + // Build result: one entry per cluster + const clusterFreqs = new Float64Array(k); + for (let i = 0; i < entries.length; i++) { + clusterFreqs[assignments[i]] += entries[i].frequency; + } + + const result: PaletteEngineEntry[] = []; + for (let j = 0; j < k; j++) { + if (clusterFreqs[j] === 0) continue; + const clamped = { + l: Math.max(0, Math.min(1, centroids[j].l)), + c: Math.max(0, centroids[j].c), + h: centroids[j].h, + }; + result.push({ + hex: oklchToHex(clamped.l, clamped.c, clamped.h), + oklch: clamped, + frequency: clusterFreqs[j] / totalFreq, + }); + } + + result.sort((a, b) => b.frequency - a.frequency); + + // Post-merge: collapse clusters closer than tolerance deltaE + const merged: PaletteEngineEntry[] = []; + for (const entry of result) { + let wasMerged = false; + for (const m of merged) { + if (oklchDeltaE(entry.oklch, m.oklch) < tolerance) { + m.frequency += entry.frequency; + wasMerged = true; + break; + } + } + if (!wasMerged) merged.push({ ...entry }); + } + + return merged; +} + +// ── ANSI Classification ────────────────────────────────────── + +export function classifyAnsi(oklch: OklchPixel): AnsiColorName { + const { l, c, h } = oklch; + + // Achromatic: low chroma + if (c < 0.03) { + if (l < 0.25) return 'black'; + if (l > 0.75) return 'white'; + return l < 0.5 ? 'black' : 'white'; + } + + // Dark colors with some chroma + if (l < 0.15) return 'black'; + if (l > 0.85 && c < 0.05) return 'white'; + + // Chromatic: classify by hue + if (h >= 330 || h < 30) return 'red'; + if (h >= 30 && h < 60) return 'yellow'; // orange-ish → yellow + if (h >= 60 && h < 90) return 'yellow'; + if (h >= 90 && h < 170) return 'green'; + if (h >= 170 && h < 210) return 'cyan'; + if (h >= 210 && h < 270) return 'blue'; + if (h >= 270 && h < 330) return 'magenta'; + + return 'white'; // fallback +} + +export function buildAnsiPalette( + entries: PaletteEngineEntry[], + countPerCategory: number = 5, + tolerance: number = 4 +): Record { + const buckets: Record = { + black: [], red: [], green: [], yellow: [], + blue: [], magenta: [], cyan: [], white: [], + }; + + for (const entry of entries) { + const name = classifyAnsi(entry.oklch); + const bucket = buckets[name]; + if (bucket.length >= countPerCategory) continue; + + // Skip if too close to an existing entry in this bucket + const tooClose = bucket.some(b => oklchDeltaE(entry.oklch, b.oklch) < tolerance); + if (tooClose) continue; + + bucket.push(entry); + } + + // Sort each bucket by frequency descending + for (const key of Object.keys(buckets) as AnsiColorName[]) { + buckets[key].sort((a, b) => b.frequency - a.frequency); + } + + return buckets; +} + +// ── Group by OKLCH property ────────────────────────────────── + +export interface GroupBucket { + name: string; + min: number; + max: number; +} + +const DEFAULT_L_BUCKETS: GroupBucket[] = [ + { name: 'darkest', min: 0, max: 0.2 }, + { name: 'dark', min: 0.2, max: 0.4 }, + { name: 'mid', min: 0.4, max: 0.6 }, + { name: 'light', min: 0.6, max: 0.8 }, + { name: 'lightest', min: 0.8, max: 1.0 }, +]; + +const DEFAULT_C_BUCKETS: GroupBucket[] = [ + { name: 'gray', min: 0, max: 0.02 }, + { name: 'muted', min: 0.02, max: 0.06 }, + { name: 'saturated', min: 0.06, max: 0.12 }, + { name: 'vivid', min: 0.12, max: Infinity }, +]; + +const DEFAULT_H_BUCKETS: GroupBucket[] = [ + { name: 'red', min: 0, max: 45 }, + { name: 'orange', min: 45, max: 75 }, + { name: 'yellow', min: 75, max: 105 }, + { name: 'green', min: 105, max: 165 }, + { name: 'cyan', min: 165, max: 195 }, + { name: 'blue', min: 195, max: 270 }, + { name: 'purple', min: 270, max: 330 }, + { name: 'pink', min: 330, max: 360 }, +]; + +export type GroupByProperty = 'L' | 'C' | 'H'; + +export function getDefaultBuckets(property: GroupByProperty): GroupBucket[] { + switch (property) { + case 'L': return DEFAULT_L_BUCKETS; + case 'C': return DEFAULT_C_BUCKETS; + case 'H': return DEFAULT_H_BUCKETS; + } +} + +function getPropertyValue(oklch: OklchPixel, property: GroupByProperty): number { + switch (property) { + case 'L': return oklch.l; + case 'C': return oklch.c; + case 'H': return oklch.h; + } +} + +export function buildGroupPalette( + entries: PaletteEngineEntry[], + property: GroupByProperty, + buckets: GroupBucket[], + countPerBucket: number = 5, + tolerance: number = 4 +): Record { + const result: Record = {}; + for (const b of buckets) { + result[b.name] = []; + } + + for (const entry of entries) { + const val = getPropertyValue(entry.oklch, property); + for (const b of buckets) { + if (val >= b.min && val < b.max) { + const bucket = result[b.name]; + if (bucket.length >= countPerBucket) break; + + const tooClose = bucket.some(e => oklchDeltaE(entry.oklch, e.oklch) < tolerance); + if (tooClose) break; + + bucket.push(entry); + break; + } + } + } + + for (const key of Object.keys(result)) { + result[key].sort((a, b) => b.frequency - a.frequency); + } + + return result; +} + +// ── Average Color ──────────────────────────────────────────── + +export function computeAverage(entries: PaletteEngineEntry[]): OklchPixel { + let totalW = 0; + let sumL = 0; + let sumC = 0; + let sumSin = 0; + let sumCos = 0; + + for (const e of entries) { + const w = e.frequency; + sumL += e.oklch.l * w; + sumC += e.oklch.c * w; + const hRad = (e.oklch.h * Math.PI) / 180; + sumSin += Math.sin(hRad) * w; + sumCos += Math.cos(hRad) * w; + totalW += w; + } + + if (totalW === 0) return { l: 0, c: 0, h: 0 }; + + const h = ((Math.atan2(sumSin / totalW, sumCos / totalW) * 180) / Math.PI + 360) % 360; + return { + l: sumL / totalW, + c: sumC / totalW, + h, + }; +} + +// ── Temperature ────────────────────────────────────────────── + +export function classifyTemperature(entries: PaletteEngineEntry[]): 'warm' | 'cool' | 'neutral' { + let warmWeight = 0; + let coolWeight = 0; + let neutralWeight = 0; + + for (const e of entries) { + const { h, c } = e.oklch; + const w = e.frequency; + + if (c < 0.03) { + neutralWeight += w; + continue; + } + + // Warm hues: red, orange, yellow (roughly 0-90, 330-360) + if ((h >= 330 || h < 90)) { + warmWeight += w; + } + // Cool hues: green, cyan, blue (roughly 90-270) + else if (h >= 90 && h < 270) { + coolWeight += w; + } + // Magenta is mixed — slightly warm + else { + warmWeight += w * 0.6; + coolWeight += w * 0.4; + } + } + + const total = warmWeight + coolWeight + neutralWeight; + if (total === 0) return 'neutral'; + + const warmRatio = warmWeight / total; + const coolRatio = coolWeight / total; + + if (Math.abs(warmRatio - coolRatio) < 0.1) return 'neutral'; + return warmRatio > coolRatio ? 'warm' : 'cool'; +} diff --git a/tests/fixtures/test-palette.png b/tests/fixtures/test-palette.png new file mode 100644 index 00000000..a91635d7 Binary files /dev/null and b/tests/fixtures/test-palette.png differ