diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index 2d4347e8..00000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,25 +0,0 @@
-{
-	"env": {
-		"browser": true,
-		"es2021": true,
-		"node": true
-	},
-	"extends": ["eslint:recommended", "plugin:import/recommended"],
-	"parserOptions": {
-		"ecmaVersion": 12,
-		"sourceType": "module"
-	},
-	"plugins": ["import"],
-	"rules": {
-		"constructor-super": 1,
-		"import/no-anonymous-default-export": 1,
-		"import/no-unused-modules": 1,
-		"no-const-assign": 1,
-		"no-loss-of-precision": 0,
-		"no-mixed-spaces-and-tabs": 0,
-		"no-this-before-super": 1,
-		"no-undef": 2,
-		"no-unused-vars": [1, { "args": "none" }],
-		"valid-typeof": 1
-	}
-}
diff --git a/.git-hooks/pre-commit b/.git-hooks/pre-commit
deleted file mode 100755
index e29abb23..00000000
--- a/.git-hooks/pre-commit
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-npx pretty-quick --staged
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 316ccb69..00000000
--- a/.gitignore
+++ /dev/null
@@ -1,12 +0,0 @@
-*.sublime-workspace
-.DS_Store
-build/
-bundled/
-node_modules
-*.log
-.nyc_output/
-coverage/
-yarn-error.log
-
-# Website
-www/
\ No newline at end of file
diff --git a/docs/static/.nojekyll b/.nojekyll
similarity index 100%
rename from docs/static/.nojekyll
rename to .nojekyll
diff --git a/.prettierignore b/.prettierignore
deleted file mode 100644
index 2e1fa2d5..00000000
--- a/.prettierignore
+++ /dev/null
@@ -1 +0,0 @@
-*.md
\ No newline at end of file
diff --git a/docs/static/CNAME b/CNAME
similarity index 100%
rename from docs/static/CNAME
rename to CNAME
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index cffe52ec..00000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# Contributing
-
-## Development
-
-Tests are defined using the `node:test` and `node:assert` modules. Running the tests require Node 21 or newer:
-
-```bash
-npm run test
-```
-
-We use ESLint to lint JavaScript code. 
-
-
-```bash
-npm run lint
-```
-
-While Culori can be used from source in environments supporting ES Modules, we also use esbuild to build bundles in CommonJS, ESM, and UMD formats.
-
-```bash
-npm run build
-```
-
-## Documentation
-
-The documentation website [culorijs.org] is built with Eleventy out of the `www/` folder, and deployed on GitHub pages via the `gh-pages` branch.
-
-The following scripts are available:
-
-```bash
-npm run docs:start
-npm run docs:build
-npm run docs:deploy
-```
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index fa64274b..00000000
--- a/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2018 Dan Burzo
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/README.md b/README.md
deleted file mode 100644
index b55a14c3..00000000
--- a/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-![culori](./docs/img/culori.svg)
-
-<a href="https://www.npmjs.org/package/culori"><img src="https://img.shields.io/npm/v/culori.svg?style=flat-square&labelColor=d84f4c&color=black" alt="npm version"></a> <a href="https://bundlephobia.com/result?p=culori"><img src="https://img.shields.io/bundlephobia/minzip/culori?style=flat-square&labelColor=d84f4c&color=black" alt="bundle size"></a>
-
-Culori is a comprehensive color library for JavaScript that works across many color spaces to offer conversion, interpolation, color difference formulas, blending functions, and more. It provides up-to-date support for the color spaces defined in [CSS Color Module Level 4](https://drafts.csswg.org/css-color/) specification.
-
-```bash
-npm install culori
-```
-
-The full documentation is published on [culorijs.org](https://culorijs.org). Some quick entry points:
-
--   [Getting started](https://culorijs.org/getting-started)
--   [API References](https://culorijs.org/api/)
--   [Supported color spaces](https://culorijs.org/color-spaces/)
-
-## Contributing
-
-Contributions of all kinds (feedback, ideas, bug fixes, documentation) are welcome. 
-
-Please open a GitHub issue/discussion before putting in any work that’s not straightforward.
-
-More in [CONTRIBUTING.md](./CONTRIBUTING.md).
diff --git a/api/index.html b/api/index.html
new file mode 100644
index 00000000..c782d6dd
--- /dev/null
+++ b/api/index.html
@@ -0,0 +1,1653 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 API Reference &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li >
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li class="active">
+							<a href="/api/">API reference</a>
+						</li>
+						<li >
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>API Reference</h1>
+				<details>
+<summary>API table of contents</summary>
+<ul class='api-toc'>
+<li><a href='#color-spaces'>a98</a></li>
+<li><a href='#average'>average</a></li>
+<li><a href='#averageAngle'>averageAngle</a></li>
+<li><a href='#averageNumber'>averageNumber</a></li>
+<li><a href='#blend'>blend</a></li>
+<li><a href='#blerp'>blerp</a></li>
+<li><a href='#clampChroma'>clampChroma</a></li>
+<li><a href='#clampRgb'>clampRgb</a></li>
+<li><a href='#colorsNamed'>colorsNamed</a></li>
+<li><a href='#converter'>converter</a></li>
+<li><a href='#color-spaces'>cubehelix</a></li>
+<li><a href='#differenceCie76'>differenceCie76</a></li>
+<li><a href='#differenceCie94'>differenceCie94</a></li>
+<li><a href='#differenceCiede2000'>differenceCiede2000</a></li>
+<li><a href='#differenceCmc'>differenceCmc</a></li>
+<li><a href='#differenceEuclidean'>differenceEuclidean</a></li>
+<li><a href='#differenceHueChroma'>differenceHueChroma</a></li>
+<li><a href='#differenceHueNaive'>differenceHueNaive</a></li>
+<li><a href='#differenceHueSaturation'>differenceHueSaturation</a></li>
+<li><a href='#differenceHyab'>differenceHyab</a></li>
+<li><a href='#differenceKotsarenkoRamos'>differenceKotsarenkoRamos</a></li>
+<li><a href='#differenceItp'>differenceItp</a></li>
+<li><a href='#displayable'>displayable</a></li>
+<li><a href='#color-spaces'>dlab</a></li>
+<li><a href='#color-spaces'>dlch</a></li>
+<li><a href='#easingGamma'>easingGamma</a></li>
+<li><a href='#easingInOutSine'>easingInOutSine</a></li>
+<li><a href='#easingMidpoint'>easingMidpoint</a></li>
+<li><a href='#easingSmootherstep'>easingSmootherstep</a></li>
+<li><a href='#easingSmoothstep'>easingSmoothstep</a></li>
+<li><a href='#easingSmoothstepInverse'>easingSmoothstepInverse</a></li>
+<li><a href='#filterBrightness'>filterBrightness</a></li>
+<li><a href='#filterContrast'>filterContrast</a></li>
+<li><a href='#filterDeficiencyDeuter'>filterDeficiencyDeuter</a></li>
+<li><a href='#filterDeficiencyProt'>filterDeficiencyProt</a></li>
+<li><a href='#filterDeficiencyTrit'>filterDeficiencyTrit</a></li>
+<li><a href='#filterGrayscale'>filterGrayscale</a></li>
+<li><a href='#filterHueRotate'>filterHueRotate</a></li>
+<li><a href='#filterInvert'>filterInvert</a></li>
+<li><a href='#filterSaturate'>filterSaturate</a></li>
+<li><a href='#filterSepia'>filterSepia</a></li>
+<li><a href='#fixupAlpha'>fixupAlpha</a></li>
+<li><a href='#fixupHueDecreasing'>fixupHueDecreasing</a></li>
+<li><a href='#fixupHueIncreasing'>fixupHueIncreasing</a></li>
+<li><a href='#fixupHueLonger'>fixupHueLonger</a></li>
+<li><a href='#fixupHueShorter'>fixupHueShorter</a></li>
+<li><a href='#formatCss'>formatCss</a></li>
+<li><a href='#formatHex'>formatHex</a></li>
+<li><a href='#formatHex8'>formatHex8</a></li>
+<li><a href='#formatHsl'>formatHsl</a></li>
+<li><a href='#formatRgb'>formatRgb</a></li>
+<li><a href='#getMode'>getMode</a></li>
+<li><a href='#color-spaces'>hsi</a></li>
+<li><a href='#color-spaces'>hsl</a></li>
+<li><a href='#color-spaces'>hsv</a></li>
+<li><a href='#color-spaces'>hwb</a></li>
+<li><a href='#inGamut'>inGamut</a></li>
+<li><a href='#interpolate'>interpolate</a></li>
+<li><a href='#interpolateWith'>interpolateWith</a></li>
+<li><a href='#interpolateWithPremultipliedAlpha'>interpolateWithPremultipliedAlpha</a></li>
+<li><a href='#interpolatorLinear'>interpolatorLinear</a></li>
+<li><a href='#interpolatorPiecewise'>interpolatorPiecewise</a></li>
+<li><a href='#interpolatorSplineBasis'>interpolatorSplineBasis</a></li>
+<li><a href='#interpolatorSplineBasisClosed'>interpolatorSplineBasisClosed</a></li>
+<li><a href='#interpolatorSplineMonotone'>interpolatorSplineMonotone</a></li>
+<li><a href='#interpolatorSplineMonotone2'>interpolatorSplineMonotone2</a></li>
+<li><a href='#interpolatorSplineMonotoneClosed'>interpolatorSplineMonotoneClosed</a></li>
+<li><a href='#interpolatorSplineNatural'>interpolatorSplineNatural</a></li>
+<li><a href='#interpolatorSplineNaturalClosed'>interpolatorSplineNaturalClosed</a></li>
+<li><a href='#color-spaces'>itp</a></li>
+<li><a href='#color-spaces'>jab</a></li>
+<li><a href='#color-spaces'>jch</a></li>
+<li><a href='#color-spaces'>lab65</a></li>
+<li><a href='#color-spaces'>lab</a></li>
+<li><a href='#color-spaces'>lch65</a></li>
+<li><a href='#color-spaces'>lch</a></li>
+<li><a href='#color-spaces'>lchuv</a></li>
+<li><a href='#lerp'>lerp</a></li>
+<li><a href='#color-spaces'>lrgb</a></li>
+<li><a href='#color-spaces'>luv</a></li>
+<li><a href='#mapAlphaDivide'>mapAlphaDivide</a></li>
+<li><a href='#mapAlphaMultiply'>mapAlphaMultiply</a></li>
+<li><a href='#mapTransferGamma'>mapTransferGamma</a></li>
+<li><a href='#mapTransferLinear'>mapTransferLinear</a></li>
+<li><a href='#mapper'>mapper</a></li>
+<li><a href='#nearest'>nearest</a></li>
+<li><a href='#color-spaces'>oklab</a></li>
+<li><a href='#color-spaces'>oklch</a></li>
+<li><a href='#parse'>parse</a></li>
+<li><a href='#color-spaces'>p3</a></li>
+<li><a href='#color-spaces'>prophoto</a></li>
+<li><a href='#random'>random</a></li>
+<li><a href='#color-spaces'>rec2020</a></li>
+<li><a href='#color-spaces'>rgb</a></li>
+<li><a href='#round'>round</a></li>
+<li><a href='#samples'>samples</a></li>
+<li><a href='#toGamut'>toGamut</a></li>
+<li><a href='#trilerp'>trilerp</a></li>
+<li><a href='#unlerp'>unlerp</a></li>
+<li><a href='#useMode'>useMode</a></li>
+<li><a href='#wcagContrast'>wcagContrast</a></li>
+<li><a href='#wcagLuminance'>wcagLuminance</a></li>
+<li><a href='#color-spaces'>xyb</a></li>
+<li><a href='#color-spaces'>xyz50</a></li>
+<li><a href='#color-spaces'>xyz65</a></li>
+<li><a href='#color-spaces'>yiq</a></li>
+</ul>
+</details>
+<h2>Colors are plain objects</h2>
+<p>Culori does not have a <em>Color</em> class. Instead, it uses plain objects to represent colors:</p>
+<pre class="language-js"><code class="language-js"><span class="token comment">/* A RGB color */</span>
+<span class="token punctuation">{</span>
+  <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'rgb'</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">0.1</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">g</span><span class="token operator">:</span> <span class="token number">0.2</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token number">1</span>
+<span class="token punctuation">}</span></code></pre>
+<p>The object needs to have a <code>mode</code> property that identifies the color space, and values for each channel in that particular color space (see the <a href="/color-spaces">Color Spaces</a> page for the channels and ranges expected for each color space). Optionally, the <code>alpha</code> property is used for the color's alpha channel.</p>
+<h2>Parsing and conversion</h2>
+<p><a id="parse" href="#parse">#</a> <strong>parse</strong>(<em>string</em>) → <em>color</em> or <em>undefined</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/parse.js">src/parse.js</a></p>
+<p>Parses a string and returns the corresponding <em>color</em>. The color will be in the matching color space, e.g. RGB for hex strings, HSL for <code>hsl(…, …, …)</code> strings, et cetera. If no built-in parsers can match the string, the function will return <code>undefined</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> parse <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">/* A named color */</span>
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'red'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { r: 1, g: 0, b: 0, mode: 'rgb' }</span>
+
+<span class="token comment">/* A hex color */</span>
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'#ff0000'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { r: 1, g: 0, b: 0, mode: 'rgb' }</span>
+
+<span class="token comment">/* A HSL color */</span>
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'hsl(60 50% 10% / 100%)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { h: 60, s: 0.5, b: 0.1, alpha: 1, mode: 'hsl' }</span>
+
+<span class="token comment">/* A Lab color */</span>
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'lab(100% -50 50)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { l: 100, a: -50, b: 50, mode: 'lab' }</span></code></pre>
+<p>In most cases, instead of using <code>parse()</code> directly (which only operates on strings), you'll want to use a <a href="#converter"><code>converter()</code></a>, which accepts strings and color objects and returns objects in a predictable color space.</p>
+<p><a id="converter" href="#converter">#</a> <strong>converter</strong>(<em>mode = &quot;rgb&quot;</em>) → <em>function (color or String)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/converter.js">src/converter.js</a></p>
+<p>Returns a <em>converter</em>: a function that can convert any color to the <em>mode</em> color space.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> converter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> rgb <span class="token operator">=</span> <span class="token function">converter</span><span class="token punctuation">(</span><span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">let</span> lab <span class="token operator">=</span> <span class="token function">converter</span><span class="token punctuation">(</span><span class="token string">'lab'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">rgb</span><span class="token punctuation">(</span><span class="token string">'#f0f0f0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: "rgb", r: 0.49…, g: 0.49…, b: 0.49… }</span>
+
+<span class="token function">lab</span><span class="token punctuation">(</span><span class="token string">'#f0f0f0'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: "lab", l: 94.79…, a: 0, b: 0 }</span></code></pre>
+<p>Converters accept either strings (which will be parsed with <code>parse()</code> under the hood) or color objects. If the <code>mode</code> key is absent from the color object passed to a converter, it's assumed to be in the converter's color space.</p>
+<h2>Formatting</h2>
+<p>These methods serialize colors to strings, in various formats.</p>
+<p><a id="formatHex" href="#formatHex">#</a> <strong>formatHex</strong>(<em>color</em> or <em>string</em>) → <em>string</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Returns the hex string for the given color. The color's <code>alpha</code> channel is omitted, and the red, green, and blue channels are clamped to the the interval <code>[0, 255]</code>, i.e. colors that are not displayable are serialized as if they'd been passed through the <code>clampRgb</code> method.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatHex <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">formatHex</span><span class="token punctuation">(</span><span class="token string">'red'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ "#ff0000"</span></code></pre>
+<p><a id="formatHex8" href="#formatHex8">#</a> <strong>formatHex8</strong>(<em>color</em> or <em>string</em>) → <em>string</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Returns the 8-character hex string for the given color. The red, green, blue, and alpha channels are clamped to the the interval <code>[0, 255]</code>, i.e. colors that are not displayable are serialized as if they'd been passed through the <code>clampRgb</code> method.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatHex8 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">formatHex8</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'rgb'</span><span class="token punctuation">,</span> <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">g</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token number">0.5</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ "#ff000080"</span></code></pre>
+<p><a id="formatRgb" href="#formatRgb">#</a> <strong>formatRgb</strong>(<em>color</em> or <em>string</em>) → <em>string</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Returns the <code>rgb(…)</code> / <code>rgba(…)</code> string for the given color. Fully opaque colors will be serialized as <code>rgb()</code>, and semi-transparent colors as <code>rgba()</code>, in accordance with the <a href="https://drafts.csswg.org/cssom/#serialize-a-css-component-value">CSSOM standard serialization</a>. Like in the case of <code>formatHex</code>, the red, green, and blue channels are clamped to the interval <code>[0, 255]</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatRgb <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">formatRgb</span><span class="token punctuation">(</span><span class="token string">'lab(50 0 0 / 25%)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ "rgba(119, 119, 119, 0.25)"</span></code></pre>
+<p><a id="formatHsl" href="#formatHsl">#</a> <strong>formatHsl</strong>(<em>color</em> or <em>string</em>) → <em>string</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Returns the <code>hsl(…)</code> / <code>hsla(…)</code> string for the given color. Fully opaque colors will be serialized as <code>hsl()</code>, and semi-transparent colors as <code>hsla()</code>. All values are rounded to a precision of two digits. The Saturation and Lightness are clamped to the interval <code>[0%, 100%]</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatHsl <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">formatHsl</span><span class="token punctuation">(</span><span class="token string">'lab(50 0 0 / 25%)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 'hsla(194.33, 0%, 46.63%, 0.25)'</span></code></pre>
+<p><a id="formatCss" href="#formatCss">#</a> <strong>formatCss</strong>(<em>color</em> or <em>string</em>) → <em>string</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Returns a CSS string for the given color, based on the CSS Color Level 4 specification. A few color spaces, such as <code>hsl</code> or <code>lab</code>, have their own functional representation in CSS. We use that whenever possible; the <code>hsl</code> color space is represented as <code>hsl(h% s l / alpha)</code>. Predefined color spaces are represented using the <code>color()</code> notation with the appropriate identifier for the color space, e.g. <code>color(display-p3 r g b / alpha)</code>. All other colors paces use the <code>color()</code> notation with a dashed identifier. For example, <code>jab</code> is represented as <code>color(--jzazbz j a b / alpha)</code>.</p>
+<p>You can find the exact string produced for each color space under the <em>Serialized as</em> entry on the <a href="/color-spaces">Color Spaces</a> page.</p>
+<p>Channel values are serialized as-is, with no change in the precision. To avoid compatibility issues, sRGB colors are represented as <code>color(srgb r g b / alpha)</code> rather than <code>rgb(r, g, b, alpha)</code>. For the latter, use the <a href="#formatRgb"><code>formatRgb()</code></a> method instead.</p>
+<p>An alpha of exactly <code>1</code> is omitted from the representation.</p>
+<p><strong>Note:</strong> The strings returned by these methods are not widely supported in current browsers and should not be used in CSS as-is.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatCss <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">/* 
+	A mode with its own function notation.
+*/</span>
+<span class="token function">formatCss</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'hsl'</span><span class="token punctuation">,</span> <span class="token literal-property property">h</span><span class="token operator">:</span> <span class="token number">30</span><span class="token punctuation">,</span> <span class="token literal-property property">s</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">l</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token number">0.5</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 'hsl(30 100% 50% / 0.5)'</span>
+
+<span class="token comment">/*
+	A predefined color space.
+ */</span>
+<span class="token function">formatCss</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'p3'</span><span class="token punctuation">,</span> <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token literal-property property">s</span><span class="token operator">:</span> <span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 'color(display-p3 0.5 0.25 1)'</span>
+
+<span class="token comment">/*
+	sRGB colors.
+ */</span>
+<span class="token function">formatCss</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'rgb'</span><span class="token punctuation">,</span> <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token literal-property property">s</span><span class="token operator">:</span> <span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token number">0.25</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 'color(srgb 0.5 0.25 1 / 0.25)'</span>
+
+<span class="token comment">/*
+	A custom color space.
+ */</span>
+<span class="token function">formatCss</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'lrgb'</span><span class="token punctuation">,</span> <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token literal-property property">s</span><span class="token operator">:</span> <span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token number">0.25</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 'color(--srgb-linear 0.5 0.25 1 / 0.25)'</span></code></pre>
+<h2>Gamut mapping</h2>
+<p>Some color spaces (Lab and LCh in particular) allow you to express colors that can't be displayed on-screen. The methods below allow you to identify when that's the case and to produce displayable versions of the colors.</p>
+<p><a id="inGamut" href="#inGamut">#</a> <strong>inGamut</strong>(<em>mode = &quot;rgb&quot;</em>) → <em>function (color | string)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/clamp.js">src/clamp.js</a></p>
+<p>Given a color space, returns a function with which to check whether a particular color is within the gamut of that color space.</p>
+<p>This is meant to be used with RGB-based color spaces and their derivates (<code>hsl</code>, <code>hsv</code>, etc.). If the color space has no gamut limits, the function will always return <code>true</code>, regardless of the color passed to it. To find out which color spaces have gamut limits, see the <a href="/color-spaces/">Color Spaces</a> page.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> inGamut <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> inRgb <span class="token operator">=</span> <span class="token function">inGamut</span><span class="token punctuation">(</span><span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">inRgb</span><span class="token punctuation">(</span><span class="token string">'red'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ true</span>
+
+<span class="token function">inRgb</span><span class="token punctuation">(</span><span class="token string">'color(srgb 1.1 0 0)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ false</span></code></pre>
+<p><a id="displayable" href="#displayable">#</a> <strong>displayable</strong>(<em>color</em> or <em>string</em>) → <em>boolean</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/clamp.js">src/clamp.js</a></p>
+<p>Checks whether a particular color fits inside the sRGB gamut. Equivalent to <code>inGamut('rgb')</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> displayable <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">displayable</span><span class="token punctuation">(</span><span class="token string">'red'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ true</span>
+
+<span class="token function">displayable</span><span class="token punctuation">(</span><span class="token string">'color(srgb 1.1 0 0)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ false</span></code></pre>
+<p><a id="clampRgb" href="#clampRgb">#</a> <strong>clampRgb</strong>(<em>color</em> or <em>string</em>) → <em>color</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/clamp.js">src/clamp.js</a></p>
+<p>Obtains a displayable version of the color by clamping the <code>r</code>, <code>g</code>, <code>b</code> channel values of the color's RGB representation to the interval <code>[0, 1]</code>. The returned color is in the same color space as the original color.</p>
+<p>This is the faster, simpler, way to make a color displayable. It's what browsers do when you use a CSS color whose channels exceed the gamut. For example, <code>rgb(300 100 200)</code> is interpreted as <code>rgb(255 100 200)</code>.</p>
+<p>Because clamping individual red, green, and blue values independently can alter their proportions in the final color, it often changes the color's hue.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> clampRgb <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">// RGB clamping:</span>
+<span class="token function">clampRgb</span><span class="token punctuation">(</span><span class="token string">'lab(50% 100 100)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: "lab", l: 54.29…, a: 80.81…, b: 69.88… }</span></code></pre>
+<p><a id="clampGamut" href="#clampGamut">#</a> <strong>clampGamut</strong>(<em>mode = 'rgb'</em>) → <em>function(color | string)</em></p>
+<p>This function extends the functionality of <code>clampRgb</code> to other color spaces. Given a color space, it returns a function with which to obtain colors within the gamut of that color space.</p>
+<p>If the color space has no gamut limits, colors are returned unchanged. To find out which color spaces have gamut limits, see the <a href="/color-spaces/">Color Spaces</a> page.</p>
+<p>The in-gamut color is always returned in the color space of the original color.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatCss<span class="token punctuation">,</span> clampGamut <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> crimson <span class="token operator">=</span> <span class="token string">'color(display-p3 0.8 0.1 0.3)'</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> toRgb <span class="token operator">=</span> <span class="token function">clampGamut</span><span class="token punctuation">(</span><span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">formatCss</span><span class="token punctuation">(</span><span class="token function">toRgb</span><span class="token punctuation">(</span>crimson<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 'color(display-p3 0.801… 0.169… 0.302…)'</span></code></pre>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/clamp.js">src/clamp.js</a></p>
+<p><a id="clampChroma" href="#clampChroma">#</a> <strong>clampChroma</strong>(<em>color</em> or <em>string</em>, <em>mode = 'lch'</em>, <em>rgbGamut = 'rgb'</em>) → <em>color</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/clamp.js">src/clamp.js</a></p>
+<p>Obtains a displayable version of the color by converting it to a temporary color space containing a Chroma channel, then looking for the closest Chroma value that's displayable for the given Lightness and Hue. Compared to <code>clampRgb</code>, the function has the advantage of preserving the hue of the original color. The displayable color returned by this function will be converted back to the original color space.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> clampChroma <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">clampChroma</span><span class="token punctuation">(</span><span class="token string">'lab(50% 100 100)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'lab', l:50.00…, a: 63.11…, b: 63.11… }</span></code></pre>
+<p>By default, the color is converted to <code>lch</code> to perform the clamping, but any color space that contains a Chroma dimension can be used by sending an explicit <code>mode</code> argument.</p>
+<p>Likewise, the destination RGB gamut can be overriden with the corresponding parameter.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> clampChroma <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">clampChroma</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'oklch'</span><span class="token punctuation">,</span> <span class="token literal-property property">l</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token literal-property property">c</span><span class="token operator">:</span> <span class="token number">0.16</span><span class="token punctuation">,</span> <span class="token literal-property property">h</span><span class="token operator">:</span> <span class="token number">180</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'oklch'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'oklch', l: 0.5, c: 0.09, h: 180 }</span></code></pre>
+<p>In general, chroma clamping is more accurate and computationally simpler when performed in the color's original space, where possible. Here's some sample code that uses the color's own <code>mode</code> for color spaces containing a Chroma dimension, and <code>lch</code> otherwise:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> clampChroma <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">clampChroma</span><span class="token punctuation">(</span>color<span class="token punctuation">,</span> color<span class="token punctuation">.</span>c <span class="token operator">!==</span> <span class="token keyword">undefined</span> <span class="token operator">?</span> color<span class="token punctuation">.</span>mode <span class="token operator">:</span> <span class="token string">'lch'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>If the chroma-finding algorithm fails to find a displayable color (which can happen when not even the achromatic version, with <code>Chroma = 0</code>, is displayable), the method falls back to the <code>clampRgb</code> method, as a last resort.</p>
+<p>The function uses <a href="https://en.wikipedia.org/wiki/Bisection_method">the bisection method</a> to speed up the search for the largest Chroma value. However, due to discontinuities in the CIELCh color space, the function is not guaranteed to return the optimal result. <a href="https://github.com/d3/d3-color/issues/33">See this discussion</a> for details.</p>
+<p><a id="toGamut" href="#toGamut">#</a> <strong>toGamut</strong>(<em>dest = 'rgb'</em>, <em>mode = 'oklch'</em>, <em>delta = differenceEuclidean('oklch')</em>, <em>jnd = 0.02</em>) → <em>function (color | string)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/clamp.js">src/clamp.js</a></p>
+<p>Obtain a color that's in the <code>dest</code> gamut, by first converting it to the <code>mode</code> color space and then finding the largest chroma that's in gamut, similar to <code>clampChroma()</code>.</p>
+<p>The color returned is in the <code>dest</code> color space.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> p3<span class="token punctuation">,</span> toGamut <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> color <span class="token operator">=</span> <span class="token string">'lch(80% 150 60)'</span><span class="token punctuation">;</span>
+
+<span class="token function">p3</span><span class="token punctuation">(</span>color<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: "p3", r: 1.229…, g: 0.547…, b: -0.073… }</span>
+
+<span class="token keyword">const</span> toP3 <span class="token operator">=</span> <span class="token function">toGamut</span><span class="token punctuation">(</span><span class="token string">'p3'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">toP3</span><span class="token punctuation">(</span>color<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: "p3", r: 0.999…, g: 0.696…, b: 0.508… }</span></code></pre>
+<p>To address the shortcomings of <code>clampChroma</code>, which can sometimes produce colors more desaturated than necessary, the test used in the binary search is replaced with “is color is roughly in gamut”, by comparing the candidate to the clipped version (obtained with <code>clampGamut</code>). The test passes if the colors are not to dissimilar, judged by the <code>delta</code> color difference function and an associated <code>jnd</code> just-noticeable difference value.</p>
+<p>The default arguments for this function correspond to <a href="https://drafts.csswg.org/css-color/#css-gamut-mapping">the gamut mapping algorithm</a> defined in the CSS Color Module Level 4 spec, but the algorithm itself is slightly different.</p>
+<p>The “roughly in gamut” aspect of the algorithm can be disabled by passing <code>null</code> for the <code>delta</code> color difference function:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> toGamut <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> clampToP3 <span class="token operator">=</span> <span class="token function">toGamut</span><span class="token punctuation">(</span><span class="token string">'p3'</span><span class="token punctuation">,</span> <span class="token string">'oklch'</span><span class="token punctuation">,</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>The algorithm expects an LCH-like color space, containing lightness and chroma components, for the <code>mode</code> argument.</p>
+<h2>Interpolation</h2>
+<p>In any color space, colors occupy positions given by their values for each channel. Interpolating colors means tracing a line through the coordinates of these colors, and figuring out what colors reside on the line at various positions.</p>
+<img src='/img/red-blue.png' height='20' alt='red and blue, linearly interpolated'/>
+<p>Above is the path between red and blue in the RGB color space. Going from left to right, we start at red and steadily blend in more and more blue as we progress, until the color is fully blue at destination. This is a <em>linear interpolation</em> between two colors.</p>
+<p><a id="interpolate" href="#interpolate">#</a> <strong>interpolate</strong>(<em>colors</em>, <em>mode = &quot;rgb&quot;</em>, <em>overrides</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/interpolate.js">src/interpolate/interpolate.js</a></p>
+<p>Returns an <em>interpolator</em> in the <em>mode</em> color space for an array of <em>colors</em>. The interpolator is a function that accepts a value <em>t</em> in the interval <code>[0, 1]</code> and returns the interpolated color in the <em>mode</em> color space.</p>
+<p>The colors in the array can be in any color space, or they can even be strings.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> grays <span class="token operator">=</span> <span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'#fff'</span><span class="token punctuation">,</span> <span class="token string">'#000'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">grays</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'rgb', r: 0.5, g: 0.5, b: 0.5 }</span></code></pre>
+<p>By default, colors in all spaces are interpolated linearly across all channels. You can override the way specific channels are interpolated with the <em>overrides</em> object, the third argument of <code>interpolate()</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> interpolatorSplineBasis <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> my_interpolator <span class="token operator">=</span> <span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'blue'</span><span class="token punctuation">,</span> <span class="token string">'red'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'lch'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
+	<span class="token comment">// spline instead of linear interpolation:</span>
+	<span class="token literal-property property">h</span><span class="token operator">:</span> interpolatorSplineBasis
+<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>There are a few interpolation methods available, listed below. Depending on the channel, the numeric values can be interpreted/interpolated in various <em>modes</em>. The hue channel, for example, is interpolated by taking into account the <em>shortest path around the hue circle</em> (<code>fixupHue</code>). And the <code>fixupAlpha</code> mode assumes an <em>undefined</em> alpha is <code>1</code>.</p>
+<h3>Color stop positions</h3>
+<p>You can specify positions of color stops to interpolate in the way they're defined in the <a href="https://drafts.csswg.org/css-images-4/#color-stop-syntax">CSS Images Module Level 4</a> specification:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token number">0.25</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>In the image below, you can see the effect of interpolating with evenly-spaced colors (1) vs. positioned colors stops (2):</p>
+<p><img src="/img/evenly-spaced-vs-positions.png" alt="Evenly spaced vs. positions"></p>
+<p>To specify a positioned color stop, use an array that contains the color followed by its position. The color stops should be specified in ascending order.</p>
+<p>For omitted (implicit) positions, we apply the rules <a href="https://drafts.csswg.org/css-images-4/#color-stop-syntax">from the spec</a>:</p>
+<ol>
+<li>if the first color doesn't have a position, it's assumed to be <code>0</code>; if the last color doesn't have a position, it's assumed to be <code>1</code>;</li>
+<li>any other color stops that don't have a position will be evenly distributed along the gradient line between the positioned color stops.</li>
+</ol>
+<h3>Easing functions</h3>
+<p>You can add easing functions between any two colors in the array:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> <span class="token function-variable function">easeIn</span> <span class="token operator">=</span> <span class="token parameter">t</span> <span class="token operator">=></span> t <span class="token operator">*</span> t<span class="token punctuation">;</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> easeIn<span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>Any function in the <em>colors</em> array will be interpreted as an easing function, which is (for our purposes), a function that takes an argument <code>t ∈ [0, 1]</code> and returns a value <code>v ∈ [0, 1]</code>.</p>
+<p>To apply the same easing function between all color pairs, instead of individual ones, add the easing as the first element in the array:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> <span class="token function-variable function">easeIn</span> <span class="token operator">=</span> <span class="token parameter">t</span> <span class="token operator">=></span> t <span class="token operator">*</span> t<span class="token punctuation">;</span>
+
+<span class="token comment">// this form:</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span>easeIn<span class="token punctuation">,</span> <span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// is equivalent to:</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> easeIn<span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> easeIn<span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>The easing function can alternatively be applied the hard way:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> interpolatorPiecewise<span class="token punctuation">,</span> lerp <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> <span class="token function-variable function">easeIn</span> <span class="token operator">=</span> <span class="token parameter">t</span> <span class="token operator">=></span> t <span class="token operator">*</span> t<span class="token punctuation">;</span>
+
+<span class="token function">interpolate</span><span class="token punctuation">(</span>
+	<span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
+	<span class="token string">'rgb'</span><span class="token punctuation">,</span>
+	<span class="token function">interpolatorPiecewise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b<span class="token punctuation">,</span> t</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">lerp</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token function">easeIn</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
+<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>This formula can be helpful if you wanted to apply a different easing function per channel:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> interpolatorPiecewise<span class="token punctuation">,</span> lerp <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token keyword">function</span> <span class="token function">piecewiseEasing</span><span class="token punctuation">(</span><span class="token parameter">easingFn</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
+	<span class="token keyword">return</span> <span class="token function">interpolatorPiecewise</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b<span class="token punctuation">,</span> t</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">lerp</span><span class="token punctuation">(</span>a<span class="token punctuation">,</span> b<span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token function">easingFn</span><span class="token punctuation">(</span>t<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token punctuation">}</span>
+
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'rgb'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
+	<span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token function">piecewiseEasing</span><span class="token punctuation">(</span>easeIn<span class="token punctuation">)</span><span class="token punctuation">,</span>
+	<span class="token literal-property property">g</span><span class="token operator">:</span> <span class="token function">piecewiseEasing</span><span class="token punctuation">(</span>easeOut<span class="token punctuation">)</span><span class="token punctuation">,</span>
+	<span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token function">piecewiseEasing</span><span class="token punctuation">(</span>easeInOut<span class="token punctuation">)</span>
+<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>Culori comes with <a href="#built-in-easing-functions">just a few</a> easing functions, but you can find several online:</p>
+<ul>
+<li><a href="https://gist.github.com/gre/1650294">some classic easing functions</a>;</li>
+<li><a href="https://github.com/mattdesl/eases">eases</a> by Matt DesLauriers;</li>
+<li><a href="https://github.com/gre/bezier-easing">bezier-easing</a> by Gaëtan Renaudeau builds <code>cubic-bezier</code> easings as defined in the <a href="http://drafts.csswg.org/css-easing-1">CSS Easing Functions Level 1</a> spec;</li>
+<li><a href="https://github.com/d3/d3-scale">d3-scale</a> lets you set the scale's domain and range to <code>[0, 1]</code>.</li>
+</ul>
+<h3>Interpolation hints</h3>
+<p>Any number in the <em>colors</em> array will be interpreted as an <a href="https://drafts.csswg.org/css-images-4/#color-stop-syntax">interpolation hint</a>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">// interpolation hint:</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>As opposed to how current browsers implement the CSS spec (<a href="https://github.com/w3c/csswg-drafts/issues/3931">see discussion</a>), interpolation hints <em>do not</em> affect color stop positions in Culori.</p>
+<h3 id='built-in-easing-functions'>Built-in easing functions</h3>
+<p><a id="easingMidpoint" href="#easingMidpoint">#</a> <strong>easingMidpoint</strong>(<em>H = 0.5</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/easing/midpoint.js">src/easing/midpoint.js</a></p>
+<p><a href="https://github.com/w3c/csswg-drafts/issues/3935">Proposed here</a>, the <code>midpoint</code> easing function lets you shift the midpoint of a gradient like in tools such as Adobe Photoshop. You can use it with <a href="#interpolate"><code>interpolate()</code></a> as an alternative to interpolation hints:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> easingMidpoint <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token comment">// Explicit midpoint easing:</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token function">easingMidpoint</span><span class="token punctuation">(</span><span class="token number">0.25</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// ...is equivalent to:</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p><a id="easingSmoothstep" href="#easingSmoothstep">#</a> <strong>easingSmoothstep</strong></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/easing/smoothstep.js">src/easing/smoothstep.js</a></p>
+<p>The <a href="https://en.wikipedia.org/wiki/Smoothstep">Smoothstep</a> easing function.</p>
+<p><a id="easingSmoothstepInverse" href="#easingSmoothstepInverse">#</a> <strong>easingSmoothstep</strong></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/easing/smoothstep.js">src/easing/smoothstep.js</a></p>
+<p>The inverse of the <a href="https://en.wikipedia.org/wiki/Smoothstep">Smoothstep</a> easing function.</p>
+<p><a id="easingSmootherstep" href="#easingSmootherstep">#</a> <strong>easingSmootherstep</strong></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/easing/smootherstep.js">src/easing/smootherstep.js</a></p>
+<p>Smootherstep is a variant of the <a href="https://en.wikipedia.org/wiki/Smoothstep">Smoothstep</a> easing function.</p>
+<p><a id="easingInOutSine" href="#easingInOutSine">#</a> <strong>easingInOutSine</strong></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/easing/inOutSine.js">src/easing/inOutSine.js</a></p>
+<p>Sinusoidal in-out easing. Can be used to create, for example, a cosine interpolation <a href="http://paulbourke.net/miscellaneous/interpolation/">as described by Paul Bourke</a>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> easingInOutSine <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span>easingInOutSine<span class="token punctuation">,</span> <span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p><a id="easingGamma" href="#easingGamma">#</a> <strong>easingGamma</strong>(<em>γ = 1</em>) → <em>function(t)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/easing/gamma.js">src/easing/gamma.js</a></p>
+<p>The <a href="https://en.wikipedia.org/wiki/Gamma_correction">gamma</a> easing.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> samples<span class="token punctuation">,</span> easingGamma <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token function">easingGamma</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ [0, 0.0625, 0.25, 0.5625, 1]</span></code></pre>
+<h3>Interpolation methods</h3>
+<div class='api-figure-grid'>
+<figure>
+  <img src='/img/interpolator-linear.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorLinear'>
+      <code><strong>interpolatorLinear</strong></code>
+    </a>
+  </figcaption>
+</figure>
+<figure>
+  <img src='/img/interpolator-basis.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorSplineBasis'>
+      <code><strong>interpolatorSplineBasis</strong></code>
+    </a>
+  </figcaption>
+</figure>
+<figure>
+  <img src='/img/interpolator-basis-closed.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorSplineBasisClosed'>
+      <code><strong>interpolatorSplineBasisClosed</strong></code>
+    </a>
+  </figcaption>
+</figure>
+<figure>
+  <img src='/img/interpolator-natural.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorSplineNatural'>
+      <code><strong>interpolatorSplineNatural</strong></code>
+    </a>
+  </figcaption>
+</figure>
+<figure>
+  <img src='/img/interpolator-natural-closed.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorSplineNaturalClosed'>
+      <code><strong>interpolatorSplineNaturalClosed</strong></code>
+    </a>
+  </figcaption>
+</figure>
+<figure>
+  <img src='/img/interpolator-monotone.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorSplineMonotone'>
+      <code><strong>interpolatorSplineMonotone</strong></code>
+    </a>
+  </figcaption>
+</figure>
+<figure>
+  <img src='/img/interpolator-monotone-2.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorSplineMonotone2'>
+      <code><strong>interpolatorSplineMonotone2</strong></code>
+    </a>
+  </figcaption>
+</figure>
+<figure>
+  <img src='/img/interpolator-monotone-closed.svg' width='400' height='80'/>
+  <figcaption>
+    <a href='#interpolatorSplineMonotoneClosed'>
+      <code><strong>interpolatorSplineMonotoneClosed</strong></code>
+    </a>
+  </figcaption>
+</figure>
+</div>
+<p>You'll use these methods when you want to override how colors get interpolated in a specific color space, or when defining the default interpolation for custom color spaces.</p>
+<p><a id="interpolatorLinear" href="#interpolatorLinear">#</a> <strong>interpolatorLinear</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/linear.js">src/interpolate/linear.js</a></p>
+<img src='/img/interpolator-linear.svg' width='400' height='80'/>
+<p>A linear interpolator for values in a channel.</p>
+<h4>Basis splines</h4>
+<p><a href="https://en.wikipedia.org/wiki/B-spline">Basis splines</a> (also called <em>B-splines</em>) are available in the following variants:</p>
+<p><a id="interpolatorSplineBasis" href="#interpolatorSplineBasis">#</a> <strong>interpolatorSplineBasis</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/splineBasis.js">src/interpolate/splineBasis.js</a></p>
+<img src='/img/interpolator-basis.svg' width='400' height='80'/>
+<p>A basis spline which uses one-sided finite differences for the slopes at the boundaries.</p>
+<p><a id="interpolatorSplineBasisClosed" href="#interpolatorSplineBasisClosed">#</a> <strong>interpolatorSplineBasisClosed</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/splineBasis.js">src/interpolate/splineBasis.js</a></p>
+<img src='/img/interpolator-basis-closed.svg' width='400' height='80'/>
+<p>A basis spline which considers the <em>values</em> array to be periodic.</p>
+<h4>Natural splines</h4>
+<p><a href="https://en.wikipedia.org/wiki/Spline_interpolation">Natural interpolating splines</a> are related to basis splines, as explained in <a href="https://www.math.ucla.edu/~baker/149.1.02w/handouts/dd_splines.pdf">this handout</a> by Kirby A. Baker (sections 4 and 5).</p>
+<p><a id="interpolatorSplineNatural" href="#interpolatorSplineNatural">#</a> <strong>interpolatorSplineNatural</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/splineNatural.js">src/interpolate/splineNatural.js</a></p>
+<img src='/img/interpolator-natural.svg' width='400' height='80'/>
+<p>A natural spline which uses one-sided finite differences for the slopes at the boundaries.</p>
+<p><a id="interpolatorSplineNaturalClosed" href="#interpolatorSplineNaturalClosed">#</a> <strong>interpolatorSplineNaturalClosed</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/splineNatural.js">src/interpolate/splineNatural.js</a></p>
+<img src='/img/interpolator-natural-closed.svg' width='400' height='80'/>
+<p>A natural spline which considers the <em>values</em> array to be periodic.</p>
+<h4>Monotone splines</h4>
+<p>The monotone splines are based on the following paper (via <a href="https://github.com/d3/d3-shape">d3-shape</a>):</p>
+<blockquote>
+<p>Steffen, M. <a href="https://ui.adsabs.harvard.edu/abs/1990A&amp;A...239..443S"><em>&quot;A simple method for monotonic interpolation in one dimension.&quot;</em></a> in Astronomy and Astrophysics, Vol. 239, p. 443-450 (Nov. 1990), Provided by the SAO/NASA Astrophysics Data System.</p>
+</blockquote>
+<p>The following variants are available:</p>
+<p><a id="interpolatorSplineMonotone" href="#interpolatorSplineMonotone">#</a> <strong>interpolatorSplineMonotone</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/splineMonotone.js">src/interpolate/splineMonotone.js</a></p>
+<img src='/img/interpolator-monotone.svg' width='400' height='80'/>
+<p>A monotone spline that uses one-sided finite differences to find the slopes at the boundaries.</p>
+<p><a id="interpolatorSplineMonotone2" href="#interpolatorSplineMonotone2">#</a> <strong>interpolatorSplineMonotone2</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/splineMonotone.js">src/interpolate/splineMonotone.js</a></p>
+<img src='/img/interpolator-monotone-2.svg' width='400' height='80'/>
+<p>A monotone spline for which we derive the slopes at the boundaries by tracing a parabola through the first/last three values.</p>
+<p><a id="interpolatorSplineMonotoneClosed" href="#interpolatorSplineMonotoneClosed">#</a> <strong>interpolatorSplineMonotoneClosed</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/splineMonotone.js">src/interpolate/splineMonotone.js</a></p>
+<img src='/img/interpolator-monotone-closed.svg' width='400' height='80'/>
+<p>A monotone spline which considers the <em>values</em> array to be periodic.</p>
+<h4>Custom piecewise interpolation</h4>
+<p><a id='interpolatorPiecewise' href='#interpolatorPiecewise'>#</a> <strong>interpolatorPiecewise</strong>(<em>interpolator</em>) <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/piecewise.js">src/interpolate/piecewise.js</a></p>
+<p>Use a custom piecewise interpolator function in the form <code>function (a, b, t) =&gt; value</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> interpolatorPiecewise <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> <span class="token function-variable function">linear</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">a<span class="token punctuation">,</span> b<span class="token punctuation">,</span> t</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">(</span><span class="token number">1</span> <span class="token operator">-</span> t<span class="token punctuation">)</span> <span class="token operator">*</span> a <span class="token operator">+</span> t <span class="token operator">*</span> b<span class="token punctuation">;</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token function">interpolatorPiecewise</span><span class="token punctuation">(</span>linear<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>When one of the two values to be interpolated is undefined, it will mirror the defined value: <code>[undefined, b]</code> becomes <code>[b, b]</code>. If both values are undefined, they are left as-is.</p>
+<p>The <a href="#interpolatorLinear"><code>interpolatorLinear()</code></a> function uses <code>interpolatorPiecewise()</code> under the hood.</p>
+<h3>Interpolation Fixup</h3>
+<p>By default, channel values that need to be interpolated are treated as normal numbers. However, for some channels, the values hold special singificance and can be fixed up before interpolation for better results.</p>
+<h4>Hue fixup</h4>
+<p>Hue is a circular value, so there are two directions in which to interpolate between two hues (clockwise and anti-clockwise). The functions below take an array of hues and adjusts them to impose a certain interpolation direction while maintaining the absolute difference between consecutive hues.</p>
+<p>Adjusted hues will not necessarily be in the <code>[0, 360)</code> interval. All fixup methods leave undefined values, and the values immediately following them, unaltered. The names of the methods come from <a href="https://github.com/w3c/csswg-drafts/issues/4735">this discussion</a>.</p>
+<p><a id="fixupHueShorter" href="#fixupHueShorter">#</a> <strong>fixupHueShorter</strong>(<em>values</em>) → <em>Array</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/fixup/hue.js">src/fixup/hue.js</a></p>
+<p>Adjusts the hues so that values are interpolated along the <em>shortest path around the hue circle</em>.</p>
+<p>This is the default in all built-in color spaces using a hue channel. Below is an extract from the definition of the HSL color space:</p>
+<pre class="language-js"><code class="language-js"><span class="token comment">/* --- hsl/definition.js --- */</span>
+<span class="token keyword">export</span> <span class="token keyword">default</span> <span class="token punctuation">{</span>
+	<span class="token comment">// ...</span>
+	<span class="token literal-property property">interpolate</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+		<span class="token literal-property property">h</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+			<span class="token literal-property property">use</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+			<span class="token literal-property property">fixup</span><span class="token operator">:</span> fixupHueShorter
+		<span class="token punctuation">}</span><span class="token punctuation">,</span>
+		<span class="token literal-property property">s</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+		<span class="token literal-property property">l</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+		<span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+			<span class="token literal-property property">use</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+			<span class="token literal-property property">fixup</span><span class="token operator">:</span> fixupAlpha
+		<span class="token punctuation">}</span>
+	<span class="token punctuation">}</span>
+	<span class="token comment">// ...</span>
+<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
+<p>To omit the fixup and treat hues as normal numbers, use a custom interpolation on the <code>h</code> channel, and overwrite the <code>fixup</code> function with an identity function:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> hsl_long <span class="token operator">=</span> <span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'blue'</span><span class="token punctuation">,</span> <span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'hsl'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
+	<span class="token literal-property property">h</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+		<span class="token function-variable function">fixup</span><span class="token operator">:</span> <span class="token parameter">arr</span> <span class="token operator">=></span> arr
+	<span class="token punctuation">}</span>
+<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>Treating the hues array as-is (with an <em>identity function</em>) corresponds to the <code>specified</code> fixup method <a href="https://github.com/w3c/csswg-drafts/issues/4735">in the CSSWG issue</a> mentioned earlier.</p>
+<p><a id="fixupHueLonger" href="#fixupHueLonger">#</a> <strong>fixupHueLonger</strong>(<em>values</em>) → <em>Array</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/fixup/hue.js">src/fixup/hue.js</a></p>
+<p>Adjusts the hues so that they are interpolated along the <em>longest path around the hue circle</em>.</p>
+<p><a id="fixupHueIncreasing" href="#fixupHueIncreasing">#</a> <strong>fixupHueIncreasing</strong>(<em>values</em>) → <em>Array</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/fixup/hue.js">src/fixup/hue.js</a></p>
+<p>Adjusts the hues so that every hue is larger than the previous.</p>
+<p><a id="fixupHueDecreasing" href="#fixupHueDecreasing">#</a> <strong>fixupHueDecreasing</strong>(<em>values</em>) → <em>Array</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/fixup/hue.js">src/fixup/hue.js</a></p>
+<p>Adjusts the hues so that every hue is smaller than the previous.</p>
+<h4>Alpha fixup</h4>
+<p><a id="fixupAlpha" href="#fixupAlpha">#</a> <strong>fixupAlpha</strong>(<em>values</em>) → <em>Array</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/fixup/alpha.js">src/fixup/alpha.js</a></p>
+<p>Turns all <code>undefined</code> values in the array to <code>1</code> (full opacity), unless <em>all</em> values in the array are <code>undefined</code>, in which case it leaves the values unaltered.</p>
+<p>This is the default method for the alpha channel in all built-in color spaces.</p>
+<h3>Evenly-spaced samples</h3>
+<p><a id="samples" href="#samples">#</a> <strong>samples</strong>(<em>n = 2</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/samples.js">src/samples.js</a></p>
+<p>Returns an array of <em>n</em> equally-spaced samples in the <code>[0, 1]</code> range, with <code>0</code> and <code>1</code> at the ends.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> samples <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ [0, 0.5, 1]</span>
+
+<span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ [0, 0.25, 0.5, 0.75, 1]</span></code></pre>
+<p>The samples are useful for <a href="#interpolate"><code>interpolate()</code></a> to generate color scales:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> samples<span class="token punctuation">,</span> interpolate<span class="token punctuation">,</span> formatHex <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> grays <span class="token operator">=</span> <span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'#fff'</span><span class="token punctuation">,</span> <span class="token string">'#000'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>grays<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>formatHex<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ ["#ffffff", "#bfbfbf", "#808080", "#404040", "#000000"]</span></code></pre>
+<p>As with the <a href="#interpolate"><code>interpolate()</code></a> method, you can map the samples through an easing function or scale to obtain a different distribution of the samples.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> samples <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token keyword">import</span> easing <span class="token keyword">from</span> <span class="token string">'bezier-easing'</span><span class="token punctuation">;</span>
+
+<span class="token comment">// Bezier easing:</span>
+<span class="token keyword">let</span> bezier <span class="token operator">=</span> <span class="token function">easing</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>bezier<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// easeInQuad:</span>
+<span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token parameter">t</span> <span class="token operator">=></span> t <span class="token operator">*</span> t<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<h3>Lerp</h3>
+<p><a id="lerp" href="#lerp">#</a> <strong>lerp</strong>(<em>a</em>, <em>b</em>, <em>t</em>) → <em>value</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/lerp.js">src/interpolate/lerp.js</a></p>
+<p>Interpolates between the values <code>a</code> and <code>b</code> at the point <code>t ∈ [0, 1]</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> lerp <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token function">lerp</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 7.5</span></code></pre>
+<p><a id="unlerp" href="#unlerp">#</a> <strong>unlerp</strong>(<em>a</em>, <em>b</em>, <em>v</em>) → <em>value</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/lerp.js">src/interpolate/lerp.js</a></p>
+<p>Returns the point <code>t</code> at which the value <code>v</code> is located between the values <code>a</code> and <code>b</code>. The inverse of <code>lerp</code>.</p>
+<p><a id="blerp" href="#blerp">#</a> <strong>blerp</strong>(<em>a00</em>, <em>a01</em>, <em>a10</em>, <em>a11</em>, <em>tx</em>, <em>ty</em>) → <em>value</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/lerp.js">src/interpolate/lerp.js</a></p>
+<p>Perform the <a href="https://en.wikipedia.org/wiki/Bilinear_interpolation">bilinear interpolation</a> of the four values <code>a00</code>, <code>a01</code>, <code>a10</code>, and <code>a11</code> at the point <code>(tx, ty)</code>, with <code>tx, ty ∈ [0, 1]</code>. This is the extension of <code>lerp</code> to two dimensions.</p>
+<p><a id="trilerp" href="#trilerp">#</a> <strong>trilerp</strong>(<em>a000</em>, <em>a010</em>, <em>a100</em>, <em>a110</em>, <em>a001</em>, <em>a011</em>, <em>a101</em>, <em>a111</em>, <em>tx</em>, <em>ty</em>, <em>tz</em>) → <em>value</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate/lerp.js">src/interpolate/lerp.js</a></p>
+<p>Perform the <a href="https://en.wikipedia.org/wiki/Trilinear_interpolation">trilinear interpolation</a> of the eight values <code>a000</code>, <code>a010</code>, <code>a100</code>, <code>a110</code>, <code>a001</code>, <code>a011</code>, <code>a101</code>, and <code>a111</code> at the point <code>(tx, ty, tz)</code>, with <code>tx, ty, tz ∈ [0, 1]</code>. This is the extension of <code>lerp</code> to three dimensions.</p>
+<h3>Mappings</h3>
+<p><a id="mapper" href="#mapper">#</a> <strong>mapper</strong>(<em>fn</em>, <em>mode = &quot;rgb&quot;</em>) → <em>function (color | string)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/map.js">src/map.js</a></p>
+<p>Creates a mapping that applies <em>fn</em> on each channel of the color in the <em>mode</em> color space.</p>
+<p>The resulting function accepts a single argument (a color object or a string), which it converts to the <em>mode</em> color space if necessary.</p>
+<p>The <em>mode</em> parameter can be set to <code>null</code>, in which case the mapper will iterate through the channels in the color's original color space.</p>
+<p>The <em>fn</em> callback has the following signature:</p>
+<p><strong>fn</strong>(<em>value</em>, <em>channel</em>, <em>color</em>, <em>mode</em>)</p>
+<p>where:</p>
+<ul>
+<li><code>value</code> is the current value;</li>
+<li><code>channel</code> is the current channel;</li>
+<li><code>color</code> is a reference to the entire color object;</li>
+<li><code>mode</code> is forwarded from the call to <code>mapper</code>.</li>
+</ul>
+<p>Here's the implementation of alpha premultiplication:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mapper <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> multiplyAlpha <span class="token operator">=</span> <span class="token function">mapper</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">val<span class="token punctuation">,</span> ch<span class="token punctuation">,</span> color</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
+	<span class="token keyword">if</span> <span class="token punctuation">(</span>ch <span class="token operator">!==</span> <span class="token string">'alpha'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
+		<span class="token keyword">return</span> <span class="token punctuation">(</span>val <span class="token operator">||</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token punctuation">(</span>color<span class="token punctuation">.</span>alpha <span class="token operator">!==</span> <span class="token keyword">undefined</span> <span class="token operator">?</span> color<span class="token punctuation">.</span>alpha <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+	<span class="token punctuation">}</span>
+	<span class="token keyword">return</span> val<span class="token punctuation">;</span>
+<span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">multiplyAlpha</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">g</span><span class="token operator">:</span> <span class="token number">0.6</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">0.4</span><span class="token punctuation">,</span> <span class="token literal-property property">a</span><span class="token operator">:</span> <span class="token number">0.5</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'rgb', r: 0.5, g: 0.3, b: 0.2, a: 0.5 }</span></code></pre>
+<p>All channels, including <code>alpha</code>, are included in the mapping. You may want to handle the <code>alpha</code> channel differently in the callback function, like in the example above.</p>
+<p>Returning <code>undefined</code> or <code>NaN</code> from the callback function will omit that channel from the resulting color object.</p>
+<h4>Built-in mappings</h4>
+<p><a id="mapAlphaMultiply" href="#mapAlphaMultiply">#</a> <strong>mapAlphaMultiply</strong></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/map.js">src/map.js</a></p>
+<p>Multiplies the color's alpha value into all its other channels:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mapper<span class="token punctuation">,</span> mapAlphaMultiply <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> multiplyAlpha <span class="token operator">=</span> <span class="token function">mapper</span><span class="token punctuation">(</span>mapAlphaMultiply<span class="token punctuation">,</span> <span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">multiplyAlpha</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">g</span><span class="token operator">:</span> <span class="token number">0.6</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">0.4</span><span class="token punctuation">,</span> <span class="token literal-property property">a</span><span class="token operator">:</span> <span class="token number">0.5</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'rgb', r: 0.5, g: 0.3, b: 0.2, a: 0.5 }</span></code></pre>
+<p>Any <code>undefined</code> channel value will be considered to be <code>0</code> (zero), to enable alpha-premultiplied interpolation with achromatic colors in hue-based color spaces (HSL, LCh, etc.).</p>
+<p><a id="mapAlphaDivide" href="#mapAlphaDivide">#</a> <strong>mapAlphaDivide</strong></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/map.js">src/map.js</a></p>
+<p>Divides a color's other channels by its alpha value. It's the opposite of <code>mapAlphaMultiply</code>, and is used in interpolation with alpha premultiplication:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> mapper<span class="token punctuation">,</span> mapAlphaMultiply<span class="token punctuation">,</span> mapAlphaDivide <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> multiplyAlpha <span class="token operator">=</span> <span class="token function">mapper</span><span class="token punctuation">(</span>mapAlphaMultiply<span class="token punctuation">,</span> <span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">let</span> divideAlpha <span class="token operator">=</span> <span class="token function">mapper</span><span class="token punctuation">(</span>mapAlphaDivide<span class="token punctuation">,</span> <span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">divideAlpha</span><span class="token punctuation">(</span><span class="token function">multiplyAlpha</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">r</span><span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token literal-property property">g</span><span class="token operator">:</span> <span class="token number">0.6</span><span class="token punctuation">,</span> <span class="token literal-property property">b</span><span class="token operator">:</span> <span class="token number">0.4</span><span class="token punctuation">,</span> <span class="token literal-property property">a</span><span class="token operator">:</span> <span class="token number">0.5</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'rgb', r: 1, g: 0.6, b: 0.4, a: 0.5 }</span></code></pre>
+<p>Any <code>undefined</code> channel value will be considered to be <code>0</code> (zero), to enable alpha-premultiplied interpolation with achromatic colors in hue-based color spaces (HSL, LCh, etc.).</p>
+<p><a id="mapTransferLinear" href="#mapTransferLinear">#</a> <strong>mapTransferLinear</strong>(<em>slope = 1</em>, <em>intercept = 0</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/map.js">src/map.js</a></p>
+<p><a id="mapTransferGamma" href="#mapTransferGamma">#</a> <strong>mapTransferGamma</strong>(<em>amplitude = 1</em>, <em>exponent = 1</em>, <em>offset = 0</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/map.js">src/map.js</a></p>
+<h4>Interpolating with mappings</h4>
+<p><a id="interpolateWith" href="#interpolateWith">#</a> <strong>interpolateWith</strong>(<em>premap</em>, <em>postmap</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate.js">src/interpolate.js</a></p>
+<p>Adds a <em>pre-mapping</em> and a <em>post-mapping</em> to an interpolation, to enable things like alpha premultiplication:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolateWith<span class="token punctuation">,</span> mapAlphaMultiply<span class="token punctuation">,</span> mapAlphaDivide <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> interpolateWithAlphaPremult <span class="token operator">=</span> <span class="token function">interpolateWith</span><span class="token punctuation">(</span>
+	mapAlphaMultiply<span class="token punctuation">,</span>
+	mapAlphaDivide
+<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">interpolateWithAlphaPremult</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'transparent'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">0.25</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>To chain more than one mapping:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolateWith<span class="token punctuation">,</span> mapAlphaMultiply<span class="token punctuation">,</span> mapAlphaDivide <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> <span class="token function-variable function">mapChromaMultiply</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">v<span class="token punctuation">,</span> ch<span class="token punctuation">,</span> c<span class="token punctuation">,</span> mode</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
+	<span class="token comment">// ...</span>
+<span class="token punctuation">}</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> <span class="token function-variable function">mapChromaDivide</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token parameter">v<span class="token punctuation">,</span> ch<span class="token punctuation">,</span> c<span class="token punctuation">,</span> mode</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
+	<span class="token comment">// ...</span>
+<span class="token punctuation">}</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> interpolateWithAlphaChromaPremult <span class="token operator">=</span> <span class="token function">interpolateWith</span><span class="token punctuation">(</span>
+	<span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">mapChromaMultiply</span><span class="token punctuation">(</span><span class="token function">mapAlphaMultiply</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
+	<span class="token punctuation">(</span><span class="token parameter"><span class="token operator">...</span>args</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token function">mapAlphaDivide</span><span class="token punctuation">(</span><span class="token function">mapChromaDivide</span><span class="token punctuation">(</span><span class="token operator">...</span>args<span class="token punctuation">)</span><span class="token punctuation">)</span>
+<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">interpolateWithAlphaPremult</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'transparent'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">(</span><span class="token number">0.25</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p><a id="interpolateWithPremultipliedAlpha" href="#interpolateWithPremultipliedAlpha">#</a> <strong>interpolateWithPremultipliedAlpha</strong>(<em>colors</em>, <em>mode = &quot;rgb&quot;</em>, <em>overrides</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/interpolate.js">src/interpolate.js</a></p>
+<p>Takes the same arguments as <a href="#interpolate"><code>interpolate()</code></a>, but applies <a href="https://drafts.csswg.org/css-images-4/#premultiplied">alpha premultiplication</a>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> interpolateWithPremultipliedAlpha <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token keyword">let</span> colors <span class="token operator">=</span> <span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'transparent'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
+
+<span class="token comment">// alpha ignored for the R/G/B channels:</span>
+<span class="token function">interpolate</span><span class="token punctuation">(</span>colors<span class="token punctuation">,</span> <span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// alpha premultiplied into the R/G/B channels:</span>
+<span class="token function">interpolateWithPremultipliedAlpha</span><span class="token punctuation">(</span>colors<span class="token punctuation">,</span> <span class="token string">'rgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<h2>Color Difference</h2>
+<p>These methods are concerned to finding the <a href="https://en.wikipedia.org/wiki/Color_difference">distance between two colors</a> based on various formulas. Each of these formulas will return a <em>function (colorA, colorB)</em> that lets you measure the distance between two colors.</p>
+<h3>Euclidean distance</h3>
+<p><a id="differenceEuclidean" href="#differenceEuclidean">#</a> <strong>differenceEuclidean</strong>(<em>mode = 'rgb'</em>, <em>weights = [1, 1, 1, 0]</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Returns a <a href="https://en.wikipedia.org/wiki/Color_difference#Euclidean">Euclidean distance</a> function in a certain color space.</p>
+<p>You can optionally assign different weights to the channels in the color space. See, for example, the <a href="#differenceKotsarenkoRamos">Kotsarenko/Ramos distance</a> or <a href="#differenceItp">ΔE<sub>ITP</sub></a>.</p>
+<p>The default weights <code>[1, 1, 1, 0]</code> mean that the <em>alpha</em>, which is the fourth channel in all the color spaces Culori defines, is not taken into account. Send <code>[1, 1, 1, 1]</code> as the weights to include it in the computation.</p>
+<p>In cylindrical spaces, the hue is factored into the Euclidean distance in a variety of ways. The functions below are used internally:</p>
+<p><a id="differenceHueChroma" href="#differenceHueChroma">#</a> <strong>differenceHueChroma</strong>(<em>colorA</em>, <em>colorB</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the hue contribution as the geometric mean of chord lengths belonging to the chromas of the two colors. This is the handling of hue in cylindrical forms of CIE-related color spaces: <code>lch</code>, <code>lchuv</code>, <code>dlch</code>, <code>oklch</code>, <code>jch</code>.</p>
+<p><a id="differenceHueSaturation" href="#differenceHueSaturation">#</a> <strong>differenceHueSaturation</strong>(<em>colorA</em>, <em>colorB</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the hue contribution as the geometric mean of chord lengths belonging to the saturations of the two colors. This is the handling of hue in the HSL / HSV / HSI family of color spaces.</p>
+<p><a id="differenceHueNaive" href="#differenceHueNaive">#</a> <strong>differenceHueNaive</strong>(<em>colorA</em>, <em>colorB</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>For remaining color spaces (HWB), we consider hues numbers, but apply a <em>shortest path around the hue circle</em> (analogous to <a href="#fixupHueShorter"><code>fixupHueShorter</code></a>). If you insist on using Euclidean distances on these spaces, you can use the <code>weights</code> to control the contribution of the hue difference towards the total difference.</p>
+<h3>CIE color difference formulas</h3>
+<p>All these color difference functions operate on the <code>lab65</code> color space.</p>
+<p><a id="differenceCie76" href="#differenceCie76">#</a> <strong>differenceCie76</strong>()</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the <a href="https://en.wikipedia.org/wiki/Color_difference#CIE76">CIE76</a> ΔE*<sub>ab</sub> color difference between the colors <em>a</em> and <em>b</em>. The function is identical to <a href="#differenceEuclidean"><code>differenceEuclidean('lab65')</code></a>.</p>
+<p><a id="differenceCie94" href="#differenceCie94">#</a> <strong>differenceCie94</strong>(<em>kL = 1</em>, <em>K1 = 0.045</em>, <em>K2 = 0.015</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the <a href="https://en.wikipedia.org/wiki/Color_difference#CIE94">CIE94</a> ΔE*<sub>94</sub> color difference between the colors <em>a</em> and <em>b</em>.</p>
+<p><a id="differenceCiede2000" href="#differenceCiede2000">#</a> <strong>differenceCiede2000</strong>(<em>Kl = 1</em>, <em>Kc = 1</em>, <em>Kh = 1</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the <a href="https://en.wikipedia.org/wiki/Color_difference#CIEDE2000">CIEDE2000</a> ΔE*<sub>00</sub> color difference between the colors <em>a</em> and <em>b</em> as implemented by <a href="http://www2.ece.rochester.edu/~gsharma/ciede2000/">G. Sharma</a>.</p>
+<p><a id="differenceCmc" href="#differenceCmc">#</a> <strong>differenceCmc</strong>()</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the <a href="https://en.wikipedia.org/wiki/Color_difference#CMC_l:c_(1984)">CMC l:c (1984)</a> ΔE*<sub>CMC</sub> color difference between the colors <em>a</em> and <em>b</em>.</p>
+<p>ΔE*<sub>CMC</sub> is not considered a metric since it's not symmetrical, that is the distance from <em>a</em> to <em>b</em> is not always equal to the distance from <em>b</em> to <em>a</em>. Therefore it cannot be reliably used with <a href="#nearest"><code>nearest()</code></a>.</p>
+<p><a id="differenceHyab" href="#differenceHyab">#</a> <strong>differenceHyab</strong>()</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the HyAB color difference between the colors <em>a</em> and <em>b</em>, as proposed in:</p>
+<blockquote>
+<p>Abasi S, Amani Tehran M, Fairchild MD. <em>Distance metrics for very large color differences.</em> Color Res Appl. 2019; 1–16. https://doi.org/10.1002/col.22451 (<a href="http://markfairchild.org/PDFs/PAP40.pdf">PDF</a>)</p>
+</blockquote>
+<p>The HyAB formula combines the Euclidean and <a href="https://en.wikipedia.org/wiki/Taxicab_geometry">city block</a> distance and has been experimentally shown to work better for large color differences than CIEDE2000, while still holding up well for smaller color differences, making it a <em>&quot;good candidate formula for image processing and computer vision applications&quot;</em>.</p>
+<h3>Other difference formulas</h3>
+<p><a id="differenceKotsarenkoRamos" href="#differenceKotsarenkoRamos">#</a> <strong>differenceKotsarenkoRamos</strong>()</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the <a href="http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf">Kotsarenko/Ramos</a> color difference between the colors <em>a</em> and <em>b</em>. This is a weighted Euclidean distance in the <code>yiq</code> color space.</p>
+<p><a id="differenceItp" href="#differenceItp">#</a> <strong>differenceItp</strong>()</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/difference.js">src/difference.js</a></p>
+<p>Computes the <a href="https://www.itu.int/rec/R-REC-BT.2124/en">ΔE<sub>ITP</sub></a> color difference metric between the colors <em>a</em> and <em>b</em>. This is a weighted Euclidean distance in the <code>itp</code> color space, scaled by a factor of 720 so that a the just-noticeable difference (<abbr>JND</abbr>) corresponds to a value of 1.</p>
+<h3>Nearest color(s)</h3>
+<p><a id="nearest" href="#nearest">#</a> <strong>nearest</strong>(<em>colors</em>, <em>metric = differenceEuclidean()</em>, <em>accessor = identity</em>) → <em>function(color, n = 1, τ = Infinity)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/nearest.js">src/nearest.js</a></p>
+<p>Takes a <em>colors</em> array and a <em>metric</em> color difference formula, and returns a function with which you can find <em>n</em> colors nearest to <em>color</em>, with a maximum distance of <em>τ</em>. Use <em>n = Infinity</em> to get all colors in the array with a maximum distance of <em>τ</em>.</p>
+<pre class="language-js"><code class="language-js"><span class="token comment">/*
+	Example: get three CSS named colors closest to any color
+ */</span>
+<span class="token keyword">import</span> <span class="token punctuation">{</span> colorsNamed<span class="token punctuation">,</span> nearest<span class="token punctuation">,</span> differenceCiede2000 <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> colors <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>colorsNamed<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">let</span> nearestNamedColors <span class="token operator">=</span> <span class="token function">nearest</span><span class="token punctuation">(</span>colors<span class="token punctuation">,</span> <span class="token function">differenceCiede2000</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">nearestNamedColors</span><span class="token punctuation">(</span><span class="token string">'lch(50% 70 60)'</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// => ["chocolate", "sienna", "peru"]</span></code></pre>
+<p>By default, <em>colors</em> needs to be an array of color values. If your array contains something other than a simple color value, you can provide the <code>accessor</code> argument to point to the color value associated with each item in the array.</p>
+<p>The example below shows a common data structure for a color palette: an object whose keys are the names and whose values are their associated color representations.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> nearest<span class="token punctuation">,</span> differenceEuclidean <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">/*
+	Example: get the closest color from a palette
+ */</span>
+<span class="token keyword">let</span> palette <span class="token operator">=</span> <span class="token punctuation">{</span>
+	<span class="token literal-property property">Burgundy</span><span class="token operator">:</span> <span class="token string">'#914e72'</span><span class="token punctuation">,</span>
+	<span class="token literal-property property">Blue</span><span class="token operator">:</span> <span class="token string">'#0078bf'</span><span class="token punctuation">,</span>
+	<span class="token literal-property property">Green</span><span class="token operator">:</span> <span class="token string">'#00a95c'</span><span class="token punctuation">,</span>
+	<span class="token string-property property">'Medium Blue'</span><span class="token operator">:</span> <span class="token string">'#3255a4'</span><span class="token punctuation">,</span>
+	<span class="token string-property property">'Bright Red'</span><span class="token operator">:</span> <span class="token string">'#f15060'</span>
+<span class="token punctuation">}</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> names <span class="token operator">=</span> Object<span class="token punctuation">.</span><span class="token function">keys</span><span class="token punctuation">(</span>palette<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> nearestColors <span class="token operator">=</span> <span class="token function">nearest</span><span class="token punctuation">(</span>
+	names<span class="token punctuation">,</span>
+	<span class="token function">differenceEuclidean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
+	<span class="token parameter">name</span> <span class="token operator">=></span> palette<span class="token punctuation">[</span>name<span class="token punctuation">]</span>
+<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">nearestColors</span><span class="token punctuation">(</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// => ["Bright Red"]</span></code></pre>
+<h2>Blending</h2>
+<p>Culori makes available the separable blend modes defined in the W3C <a href="https://drafts.fxtf.org/compositing-2/">Compositing and Blending Level 2</a> specification.</p>
+<p><a id="blend" href="#blend">#</a> <strong>blend</strong>(<em>colors</em>, <em>type = 'normal'</em>, <em>mode = 'rgb'</em>) → <em>color</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/blend.js">src/blend.js</a></p>
+<p>A separable blend mode is a simple formula that gets applied to each channel in the color space independently. The available blend modes are <code>color-burn</code>, <code>color-dodge</code>, <code>darken</code>, <code>difference</code>, <code>exclusion</code>, <code>hard-light</code>, <code>lighten</code>, <code>multiply</code>, <code>normal</code>, <code>overlay</code>, <code>screen</code>
+, and <code>soft-light</code>. They are designed to work on RGB colors, so <em>mode</em> is expected to be <code>rgb</code> or <code>lrgb</code>.</p>
+<p>An example of blending three colors:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> blend <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">blend</span><span class="token punctuation">(</span>
+	<span class="token punctuation">[</span><span class="token string">'rgba(255, 0, 0, 0.5)'</span><span class="token punctuation">,</span> <span class="token string">'rgba(0, 255, 0, 0.5)'</span><span class="token punctuation">,</span> <span class="token string">'rgba(0, 0, 255, 0.5)'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
+	<span class="token string">'screen'</span>
+<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'rgb', alpha: 0.875, r: 0.57…, g: 0.57…, b:0.57… }</span></code></pre>
+<p>In addition to strings, the <em>type</em> parameter supports a <em>function (b, s) → v</em> that takes the values of the <em>backdrop</em> and <em>source</em> color to return the blended value. This allows you to write your own (separable) blending functions. For example, an <em>average</em> blending mode:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> blend <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">blend</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token keyword">function</span> <span class="token function">average</span><span class="token punctuation">(</span><span class="token parameter">b<span class="token punctuation">,</span> s</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
+	<span class="token keyword">return</span> <span class="token punctuation">(</span>b <span class="token operator">+</span> s<span class="token punctuation">)</span> <span class="token operator">/</span> <span class="token number">2</span><span class="token punctuation">;</span>
+<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>The non-separable blend modes — <code>color</code>, <code>hue</code>, <code>saturation</code>, and <code>lightness</code> — are not available. The effect which they mean to produce is better obtained with simple formulas on a cylindrical color space (e.g. HSL).</p>
+<h2>Average color</h2>
+<p><a id="average" href="#average">#</a> <strong>average</strong>(<em>colors</em>, <em>mode = 'rgb'</em>, <em>overrides</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/average.js">src/average.js</a></p>
+<p>Returns the average color of the <em>colors</em> array, in the color space specified by the <em>mode</em> argument. The color is obtained by the arithmetic average of values on each individual channel.</p>
+<p>Colors with undefined values on a channel don't participate in the average for that channel.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> average <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">average</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'salmon'</span><span class="token punctuation">,</span> <span class="token string">'tomato'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'lab'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { 'mode': 'lab', l: 65.41…, a: 53.00…, b: 39.01… }</span></code></pre>
+<p><a id="averageNumber" href="#averageNumber">#</a> <strong>averageNumber</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/average.js">src/average.js</a></p>
+<p>The arithmetic mean of values in the <em>values</em> array.</p>
+<p><a id="averageAngle" href="#averageAngle">#</a> <strong>averageAngle</strong>(<em>values</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/average.js">src/average.js</a></p>
+<p>The function used by default to average hue values in all built-in color spaces, using the formula for <a href="https://en.wikipedia.org/wiki/Mean_of_circular_quantities">the mean of circular quantities</a>.</p>
+<h2>Random colors</h2>
+<p><a id="random" href="#random">#</a> <strong>random</strong>(<em>mode = 'rgb'</em>, <em>constraints = {}</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/random.js">src/random.js</a></p>
+<p>Obtain a random color from a particular color space, with optional constraints. The resulting color will be in the color space from where it has been picked.</p>
+<p>Basic usage:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> random <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">random</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'rgb', r: 0.75, g: 0.12, b: 0.99 }</span></code></pre>
+<h3>Specifying constraints</h3>
+<p>Random colors are, by definition, all over the color space and not all of them will look particularly nice. Some color spaces, such as HSL or HSV, are also biased towards colors close to black and/or white, because of the way these color spaces stretch the RGB cube into cylinders.</p>
+<p>For more control on how the colors are generated, you can specify constraints for each individual channel in the color space. Constraints can be either a <em>constant number</em> or an <em>interval</em> from where to pick the channel value:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> random <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">random</span><span class="token punctuation">(</span><span class="token string">'hsv'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span>
+	<span class="token literal-property property">h</span><span class="token operator">:</span> <span class="token number">120</span><span class="token punctuation">,</span> <span class="token comment">// number</span>
+	<span class="token literal-property property">s</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token number">0.75</span><span class="token punctuation">]</span> <span class="token comment">// interval</span>
+<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'hsv', h: 120, s: 0.51…, v: 0.89… }</span></code></pre>
+<p>The <em>alpha</em> channel is excluded by default. To obtain colors with random alpha values, include a constraint for <code>alpha</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> random <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">random</span><span class="token punctuation">(</span><span class="token string">'lrgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'lrgb', r: 0.74…, g: 0.15…, b: 0.34… }</span>
+
+<span class="token function">random</span><span class="token punctuation">(</span><span class="token string">'lrgb'</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'lrgb', r: 0.33…, g: 0.72…, b: 0.04…, alpha: 0.12… }</span></code></pre>
+<h3>Displayable random colors</h3>
+<p>The value for any channel in the color space for which there are no constraints will be picked from the entire range of that channel. However, some color spaces, such as CIELAB or CIELCH, don't have explicit ranges for certain channels; for these, some approximate ranges <a href="https://github.com/evercoder/culori/blob/main/tools/ranges.js">have been pre-computed</a> as the limits of the displayable sRGB gamut.</p>
+<p>Even with these ranges in place, a combination of channel values may not be displayable. Check if that's the case with <a href="#displayable"><code>displayable()</code></a>, and pass the color through a <a href="#clampRgb"><code>clamp*</code></a> function to obtain a displayable version.</p>
+<h2>WCAG utilities</h2>
+<p>A couple of utility functions based on the <a href="https://www.w3.org/TR/WCAG20/">Web Content Acccessibility Guidelines 2.0 specification</a>.</p>
+<p><a id="wcagLuminance" href="#wcagLuminance">#</a> <strong>wcagLuminance</strong>(<em>color</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/wcag.js">src/wcag.js</a></p>
+<p>Computes the <a href="https://www.w3.org/TR/WCAG20/#relativeluminancedef">relative luminance</a> of a color.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> wcagLuminance <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">wcagLuminance</span><span class="token punctuation">(</span><span class="token string">'red'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 0.2126</span></code></pre>
+<p><a id="wcagContrast" href="#wcagContrast">#</a> <strong>wcagContrast</strong>(<em>colorA</em>, <em>colorB</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/wcag.js">src/wcag.js</a></p>
+<p>Computes the <a href="https://www.w3.org/TR/WCAG20/#contrast-ratiodef">contrast ratio</a> between two colors.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> wcagContrast <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">wcagContrast</span><span class="token punctuation">(</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'black'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 5.252</span></code></pre>
+<h2>Filters</h2>
+<p>Filters apply certain graphical effects to a color. Culori currently implements two sets of filter functions:</p>
+<h3>CSS Filter Effects</h3>
+<p>These correspond to the filter effects defined in the W3C <a href="https://drafts.fxtf.org/filter-effects-1/">Filter Effects Module Level 1</a> specification.</p>
+<p>The <em>amount</em> parameter is usually in the <code>[0, 1]</code> interval, but may go above <code>1</code> for some filters. The filters were designed for RGB colors, so the <em>mode</em> parameter is expected to be <code>rgb</code> or <code>lrgb</code>.</p>
+<p>The resulting color is returned in the color space of the original color.</p>
+<p><a id="filterBrightness" href="#filterBrightness">#</a> <strong>filterBrightness</strong>(<em>amount = 1</em>, <em>mode = 'rgb'</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/filter.js">src/filter.js</a></p>
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/brightness"><code>brightness()</code></a> CSS filter. An <em>amount</em> of <code>1</code> leaves the color unchanged. Smaller values darken the color (with <code>0</code> being fully black), while larger values brighten it.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> filterBrightness <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> brighten <span class="token operator">=</span> <span class="token function">filterBrightness</span><span class="token punctuation">(</span><span class="token number">2</span><span class="token punctuation">,</span> <span class="token string">'lrgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">brighten</span><span class="token punctuation">(</span><span class="token string">'salmon'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'rgb', r: 1.32…, g: 0.68…, b: 0.61… }</span></code></pre>
+<p><a id="filterContrast" href="#filterContrast">#</a> <strong>filterContrast</strong>(<em>amount = 1</em>, <em>mode = 'rgb'</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/filter.js">src/filter.js</a></p>
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/contrast"><code>contrast()</code></a> filter. An <em>amount</em> of <code>1</code> leaves the color unchanged. Smaller values decrease the contrast (with <code>0</code> being fully gray), while larger values increase it.</p>
+<p><a id="filterSepia" href="#filterSepia">#</a> <strong>filterSepia</strong>(<em>amount = 1</em>, <em>mode = 'rgb'</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/filter.js">src/filter.js</a></p>
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/sepia"><code>sepia()</code></a> filter. An <em>amount</em> of <code>0</code> leaves the color unchanged, and <code>1</code> applies the sepia effect fully.</p>
+<p><a id="filterGrayscale" href="#filterGrayscale">#</a> <strong>filterGrayscale</strong>(<em>amount = 1</em>, <em>mode = 'rgb'</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/filter.js">src/filter.js</a></p>
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/grayscale"><code>grayscale()</code></a> filter. An <em>amount</em> of <code>0</code> leaves the color unchanged, and <code>1</code> makes the color fully achromatic.</p>
+<p><a id="filterSaturate" href="#filterSaturate">#</a> <strong>filterSaturate</strong>(<em>amount = 1</em>, <em>mode = 'rgb'</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/filter.js">src/filter.js</a></p>
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/saturate"><code>saturate()</code></a> filter. An <em>amount</em> of <code>1</code> leaves the color unchanged. Smaller values desaturate the color (with <code>0</code> being fully achromatic), while larger values saturate it.</p>
+<p><a id="filterInvert" href="#filterInvert">#</a> <strong>filterInvert</strong>(<em>amount = 1</em>, <em>mode = 'rgb'</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/filter.js">src/filter.js</a></p>
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/invert"><code>invert()</code></a> filter. An <em>amount</em> of <code>0</code> leaves the color unchanged, and <code>1</code> makes the color fully inverted.</p>
+<p><a id="filterHueRotate" href="#filterHueRotate">#</a> <strong>filterHueRotate</strong>(<em>degrees = 0</em>, <em>mode = 'rgb'</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/filter.js">src/filter.js</a></p>
+<p>The <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/hue-rotate"><code>hue-rotate()</code></a> filter.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> samples<span class="token punctuation">,</span> interpolate<span class="token punctuation">,</span> filterSepia<span class="token punctuation">,</span> formatHex <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
+	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
+	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token function">filterSepia</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
+	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>formatHex<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// ⇒ ["#751800", "#664200", "#576c00", "#1a3e82", "#0010ff"];</span></code></pre>
+<p>Some of the effects may be obtained more straightforwardly with simple calculations in other color spaces. For example, <a href="#filterHueRotate">hue rotation</a> can just as well be implemented as <code>color.h += angle</code> in a cylindrical color space such as HSL.</p>
+<h3>Color vision deficiency (CVD) simulation</h3>
+<p>Simulate how a color may be perceived by people with color vision deficiencies (CVD).</p>
+<p><a id="filterDeficiencyProt" href="#filterDeficiencyProt">#</a> <strong>filterDeficiencyProt</strong>(<em>severity = 1</em>) → <em>function (color)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/deficiency.js">src/deficiency.js</a></p>
+<p>Simulate protanomaly and protanopia. The <code>severity</code> parameter is in the interval <code>[0, 1]</code>, where <code>0</code> corresponds to normal vision and <code>1</code> (the default value) corresponds to protanopia.</p>
+<p><a id="filterDeficiencyDeuter" href="#filterDeficiencyDeuter">#</a> <strong>filterDeficiencyDeuter</strong>(<em>severity = 1</em>) → <em>function (color)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/deficiency.js">src/deficiency.js</a></p>
+<p>Simulate deuteranomaly and deuteranopia. The <code>severity</code> parameter is in the interval <code>[0, 1]</code>, where <code>0</code> corresponds to normal vision and <code>1</code> (the default value) corresponds to deuteranopia.</p>
+<p><a id="filterDeficiencyTrit" href="#filterDeficiencyTrit">#</a> <strong>filterDeficiencyTrit</strong>(<em>severity = 1</em>) → <em>function (color)</em></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/deficiency.js">src/deficiency.js</a></p>
+<p>Simuate tritanomaly and tritanopia. The <code>severity</code> parameter is in the interval <code>[0, 1]</code>, where <code>0</code> corresponds to normal vision and <code>1</code> (the default value) corresponds to tritanopia.</p>
+<p>Examples:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate<span class="token punctuation">,</span> filterDeficiencyProt<span class="token punctuation">,</span> formatHex <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+culori
+	<span class="token punctuation">.</span><span class="token function">samples</span><span class="token punctuation">(</span><span class="token number">5</span><span class="token punctuation">)</span>
+	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">,</span> <span class="token string">'blue'</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
+	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span><span class="token function">filterDeficiencyProt</span><span class="token punctuation">(</span><span class="token number">0.5</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
+	<span class="token punctuation">.</span><span class="token function">map</span><span class="token punctuation">(</span>formatHex<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// ⇒ ["#751800", "#664200", "#576c00", "#1a3e82", "#0010ff"];</span></code></pre>
+<p>Based on the work of Machado, Oliveira and Fernandes (2009), using <a href="https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html">precomputed matrices</a> provided by the authors. References thanks to the <a href="http://colorspace.r-forge.r-project.org/reference/simulate_cvd.html"><code>colorspace</code> package for R</a>.</p>
+<blockquote>
+<p>G. M. Machado, M. M. Oliveira and L. A. F. Fernandes, <em>&quot;A Physiologically-based Model for Simulation of Color Vision Deficiency,&quot;</em> in IEEE Transactions on Visualization and Computer Graphics, vol. 15, no. 6, pp. 1291-1298, Nov.-Dec. 2009, <a href="https://doi.ieeecomputersociety.org/10.1109/TVCG.2009.113">doi: 10.1109/TVCG.2009.113</a>.</p>
+</blockquote>
+<h2>Miscellaneous</h2>
+<p><a id="colorsNamed" href="#colorsNamed">#</a> <strong>colorsNamed</strong></p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/colors/named.js">src/colors/named.js</a></p>
+<p>An object whose keys are all the CSS named colors.</p>
+<p><a id="round" href="#round">#</a> <strong>round</strong>(<em>n = 8</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/round.js">src/round.js</a></p>
+<p>Returns a <em>rounder</em>: a function with which to round numbers to at most <em>n</em> digits of precision.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> round <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> approx <span class="token operator">=</span> <span class="token function">round</span><span class="token punctuation">(</span><span class="token number">4</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">approx</span><span class="token punctuation">(</span><span class="token number">0.38393993</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ 0.3839</span></code></pre>
+<h2 id='color-spaces'>
+  <a href='#color-spaces'>#</a>
+  Available color spaces
+</h2>
+<p>The default import (<code>culori</code>) comes with all the color spaces pre-registered into the library. For convenience, you can also import directly <code>mode</code> as a shortcut to <a href="#converter"><code>converter(mode)</code></a>. For example, instead of <a href="#converter"><code>converter('hsl')</code></a>, you can import <code>hsl</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token comment">// Instead of this:</span>
+<span class="token keyword">import</span> <span class="token punctuation">{</span> converter <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> hsl <span class="token operator">=</span> <span class="token function">converter</span><span class="token punctuation">(</span><span class="token string">'hsl'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// You can do this:</span>
+<span class="token keyword">import</span> <span class="token punctuation">{</span> hsl <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span></code></pre>
+<p>On the other hand, when importing the <a href="/guides/tree-shaking">tree-shaken version</a> (<code>culori/fn</code>), color spaces need to be registered manually with <a href="#useMode"><code>useMode()</code></a> based on their <strong>definition object</strong>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useMode<span class="token punctuation">,</span> modeHsl <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> hsl <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeHsl<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>The table below summarizes two pieces of information:</p>
+<ul>
+<li>What the <code>mode</code> is for a specific color space built into Culori, which is also the name of the shortcut to the converter for that color space.</li>
+<li>What the definition object for a color space is called.</li>
+</ul>
+<p>The available color spaces are discussed into more detail on the <a href="/color-spaces">Color Spaces</a> page.</p>
+<table>
+<thead>
+<tr>
+<th>Mode</th>
+<th>Color space</th>
+<th>Definition object</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>a98</code></td>
+<td>A98 RGB color space, compatible with Adobe RGB (1998)</td>
+<td><code>modeA98</code></td>
+</tr>
+<tr>
+<td><code>cubehelix</code></td>
+<td>Cubehelix color space</td>
+<td><code>modeCubehelix</code></td>
+</tr>
+<tr>
+<td><code>dlab</code></td>
+<td>DIN99o Lab color space</td>
+<td><code>modeDlab</code></td>
+</tr>
+<tr>
+<td><code>dlch</code></td>
+<td>DIN99o LCh color space</td>
+<td><code>modeDlch</code></td>
+</tr>
+<tr>
+<td><code>hsi</code></td>
+<td>HSI color space</td>
+<td><code>modeHsi</code></td>
+</tr>
+<tr>
+<td><code>hsl</code></td>
+<td>HSL color space</td>
+<td><code>modeHsl</code></td>
+</tr>
+<tr>
+<td><code>hsv</code></td>
+<td>HSV color space</td>
+<td><code>modeHsv</code></td>
+</tr>
+<tr>
+<td><code>hwb</code></td>
+<td>HWB color space</td>
+<td><code>modeHwb</code></td>
+</tr>
+<tr>
+<td><code>itp</code></td>
+<td>IC<sub>t</sub>C<sub>p</sub> color space</td>
+<td><code>modeItp</code></td>
+</tr>
+<tr>
+<td><code>jab</code></td>
+<td>J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space</td>
+<td><code>modeJab</code></td>
+</tr>
+<tr>
+<td><code>jch</code></td>
+<td>J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> in cylindrical form</td>
+<td><code>modeJch</code></td>
+</tr>
+<tr>
+<td><code>lab</code></td>
+<td>CIELAB color space (D50 Illuminant)</td>
+<td><code>modeLab</code></td>
+</tr>
+<tr>
+<td><code>lab65</code></td>
+<td>CIELAB color space (D65 Illuminant)</td>
+<td><code>modeLab65</code></td>
+</tr>
+<tr>
+<td><code>lch</code></td>
+<td>CIELCh color space (D50 Illuminant)</td>
+<td><code>modeLch</code></td>
+</tr>
+<tr>
+<td><code>lch65</code></td>
+<td>CIELCh color space (D65 Illuminant)</td>
+<td><code>modeLch65</code></td>
+</tr>
+<tr>
+<td><code>lchuv</code></td>
+<td>CIELCHuv color space (D50 Illuminant)</td>
+<td><code>modeLchuv</code></td>
+</tr>
+<tr>
+<td><code>lrgb</code></td>
+<td>Linear-light sRGB color space</td>
+<td><code>modeLrgb</code></td>
+</tr>
+<tr>
+<td><code>luv</code></td>
+<td>CIELUV color space (D50 Illuminant)</td>
+<td><code>modeLuv</code></td>
+</tr>
+<tr>
+<td><code>oklab</code></td>
+<td>Oklab color space</td>
+<td><code>modeOklab</code></td>
+</tr>
+<tr>
+<td><code>oklch</code></td>
+<td>Oklab color space, cylindrical form</td>
+<td><code>modeOklch</code></td>
+</tr>
+<tr>
+<td><code>p3</code></td>
+<td>Display P3 color space</td>
+<td><code>modeP3</code></td>
+</tr>
+<tr>
+<td><code>prophoto</code></td>
+<td>ProPhoto RGB color space</td>
+<td><code>modeProphoto</code></td>
+</tr>
+<tr>
+<td><code>rec2020</code></td>
+<td>Rec. 2020 RGB color space</td>
+<td><code>modeRec2020</code></td>
+</tr>
+<tr>
+<td><code>rgb</code></td>
+<td>sRGB color space</td>
+<td><code>modeRgb</code></td>
+</tr>
+<tr>
+<td><code>xyb</code></td>
+<td>XYB color space</td>
+<td><code>modeXyb</code></td>
+</tr>
+<tr>
+<td><code>xyz50</code></td>
+<td>XYZ with D50 white-point</td>
+<td><code>modeXyz50</code></td>
+</tr>
+<tr>
+<td><code>xyz65</code></td>
+<td>XYZ with D65 white-point</td>
+<td><code>modeXyz65</code></td>
+</tr>
+<tr>
+<td><code>yiq</code></td>
+<td>YIQ color space</td>
+<td><code>modeYiq</code></td>
+</tr>
+</tbody>
+</table>
+<h2>Extending culori</h2>
+<p><a id="useMode" href="#useMode">#</a> <strong>useMode</strong>(<em>definition</em>) → <em>function</em>.</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/modes.js">src/modes.js</a></p>
+<p>Defines a new color space based on its <em>definition</em>. See <a href="#color-mode-def">Color mode definition</a> for the expected object shape.</p>
+<p>Returns a converter function for the newly defined mode.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useMode <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> hsl <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span><span class="token punctuation">{</span>
+	<span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'hsl'</span>
+	<span class="token comment">// ...</span>
+<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token function">hsl</span><span class="token punctuation">(</span><span class="token string">'hsl(50 100% 100% / 100)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p><a id="getMode" href="#getMode">#</a> <strong>getMode</strong>(<em>mode</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/modes.js">src/modes.js</a></p>
+<p>Returns the definition object for the <em>mode</em> color space.</p>
+<h3 id='color-mode-def'>
+  <a href='#color-mode-def'>#</a>
+  Color mode definition
+</h3>
+<p>The properties a definition needs are the following:</p>
+<h4><code>mode</code> (<em>string</em>)</h4>
+<p>The string identifier for the color space.</p>
+<h4><code>channels</code> (<em>array</em>)</h4>
+<p>A list of channels for the color space.</p>
+<h4><code>toMode</code> (<em>object</em>)</h4>
+<p>A set of functions to convert from the color space we're defining to other color spaces. At least <code>rgb</code> needs to be included; in case a specific conversion pair between two color spaces is missing, RGB is used as the &quot;buffer&quot; for the conversion.</p>
+<h4><code>fromMode</code> (<em>object</em>)</h4>
+<p>The opposite of <code>toMode</code>. A set of function to convert from various color spaces to the color space we're defining. At least <code>rgb</code> needs to be included.</p>
+<h4><code>ranges</code> (<em>object</em>, optional)</h4>
+<p>The reference ranges for values in specific channels; if left unspecified, defaults to <code>[0, 1]</code>.</p>
+<h4><code>parse</code> (<em>array</em>, optional)</h4>
+<p>Any parsers for the color space that can transform strings into colors. These can be either functions, or strings — the latter is used as the color space's identifier to parse the <code>color(&lt;ident&gt;)</code> CSS syntax.</p>
+<h4><code>serialize</code> (<em>function</em> or <em>string</em>, optional)</h4>
+<p>Defines how to serialize the color space to a CSS string with <a href="#formatCss"><code>formatCss()</code></a>.</p>
+<p>If you pass in a function, it receives a color object as its only argument, and should return a string that can be used in CSS. If you pass in a string, it's used as a color profile identifier, and the color is serialized using the <code>color()</code> CSS syntax. When omitted altogether, the default color profile identifier is <code>--${mode}</code>.</p>
+<h4><code>interpolate</code></h4>
+<p>The default interpolations for the color space, one for each channel. Each interpolation is defined by its interpolator (the <code>use</code> key) and its fixup function (the <code>fixup</code> key). When defined as a function, a channel interpolation is meant to define its interpolator, with the fixup being a no-op.</p>
+<h4><code>difference</code></h4>
+<p>The default Euclidean distance method for each channel in the color space; mostly used for the <code>h</code> channel in cylindrical color spaces.</p>
+<h4><code>average</code></h4>
+<p>The default average function for each channel in the color space; when left unspecified, defaults to <a href="#averageNumber"><code>averageNumber</code></a>.</p>
+<p>All built-in color spaces follow these conventions in regards to the <code>channels</code> array follows:</p>
+<ul>
+<li>there are four channels in the color space;</li>
+<li>the fourth channel is always <code>alpha</code>.</li>
+</ul>
+<p>This makes sure <a href="#differenceEuclidean"><code>differenceEuclidean()</code></a> works as expected, but there may be more hidden assumptions in the codebase.</p>
+<p>Here's a sample definition for the HSL color space:</p>
+<pre class="language-js"><code class="language-js"><span class="token punctuation">{</span>
+  <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'hsl'</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">fromMode</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+    <span class="token literal-property property">rgb</span><span class="token operator">:</span> convertRgbToHsl
+  <span class="token punctuation">}</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">toMode</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+    <span class="token literal-property property">rgb</span><span class="token operator">:</span> convertHslToRgb
+  <span class="token punctuation">}</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">channels</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">'h'</span><span class="token punctuation">,</span> <span class="token string">'s'</span><span class="token punctuation">,</span> <span class="token string">'l'</span><span class="token punctuation">,</span> <span class="token string">'alpha'</span><span class="token punctuation">]</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">ranges</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+    <span class="token literal-property property">h</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">360</span><span class="token punctuation">]</span>
+  <span class="token punctuation">}</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">parse</span><span class="token operator">:</span> <span class="token punctuation">[</span>parseHsl<span class="token punctuation">]</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">serialize</span><span class="token operator">:</span> serializeHsl<span class="token punctuation">,</span>
+  <span class="token literal-property property">interpolate</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+    <span class="token literal-property property">h</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+      <span class="token literal-property property">use</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+      <span class="token literal-property property">fixup</span><span class="token operator">:</span> fixupHueShorter
+    <span class="token punctuation">}</span><span class="token punctuation">,</span>
+    <span class="token literal-property property">s</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+    <span class="token literal-property property">l</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+    <span class="token literal-property property">alpha</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+      <span class="token literal-property property">use</span><span class="token operator">:</span> interpolatorLinear<span class="token punctuation">,</span>
+      <span class="token literal-property property">fixup</span><span class="token operator">:</span> fixupAlpha
+    <span class="token punctuation">}</span>
+  <span class="token punctuation">}</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">difference</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+    <span class="token literal-property property">h</span><span class="token operator">:</span> differenceHueSaturation
+  <span class="token punctuation">}</span><span class="token punctuation">,</span>
+  <span class="token literal-property property">average</span><span class="token operator">:</span> <span class="token punctuation">{</span>
+    <span class="token literal-property property">h</span><span class="token operator">:</span> averageAngle
+  <span class="token punctuation">}</span>
+<span class="token punctuation">}</span><span class="token punctuation">;</span></code></pre>
+<p><a id="useParser" href="#useParser">#</a> <strong>useParser</strong>(<em>parser</em>, <em>mode</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/modes.js">src/modes.js</a></p>
+<p>Register a new parser. The parser can be:</p>
+<ul>
+<li>a function, in which case the <em>mode</em> argument is not necessary.</li>
+<li>a string representing the identifier to match in the <code>color()</code> syntax, in which case the <em>mode</em> argument is required.</li>
+</ul>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useParser <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">// Register custom parser</span>
+<span class="token function">useParser</span><span class="token punctuation">(</span><span class="token keyword">function</span><span class="token punctuation">(</span><span class="token parameter">str</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
+  <span class="token keyword">let</span> color <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
+  <span class="token comment">// parse the string</span>
+  <span class="token keyword">return</span> color<span class="token punctuation">;</span>
+<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token comment">// Register `color(--oklab)` syntax</span>
+<span class="token function">useParser</span><span class="token punctuation">(</span><span class="token string">'--oklab'</span><span class="token punctuation">,</span> <span class="token string">'oklab'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p><a id="removeParser" href="#removeParser">#</a> <strong>removeParser</strong>(<em>parser</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/modes.js">src/modes.js</a></p>
+<p>Remove a previously registered parser function or string, including parsers registered by default.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> parse<span class="token punctuation">,</span> parseNamed<span class="token punctuation">,</span> removeParser <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'tomato'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ Object { mode: "rgb", r: 1, g: 0.38823529411764707, b: 0.2784313725490196 }</span>
+
+<span class="token function">removeParser</span><span class="token punctuation">(</span>parseNamed<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'tomato'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ undefined</span></code></pre>
+<h2 id='low-level-api'>
+  <a href='#low-level-api'>#</a>
+  Low-level API
+</h2>
+<h3 id='parsing-functions'>
+  <a id="parsing-functions" href="#parsing-functions">#</a>
+  Parsing functions
+</h3>
+<p><a id="parseHex" href="#parseHex">#</a> <strong>parseHex</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses hex strings of 3, 4, 6, or 8 characters, with or without the <code>#</code> prefix, and returns <code>rgb</code> color objects.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> parseHex <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">parseHex</span><span class="token punctuation">(</span><span class="token string">'#abc'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">parseHex</span><span class="token punctuation">(</span><span class="token string">'#abcd'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">parseHex</span><span class="token punctuation">(</span><span class="token string">'#abcdef'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">parseHex</span><span class="token punctuation">(</span><span class="token string">'#abcdef12'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p><a id="parseHsl" href="#parseHsl">#</a> <strong>parseHsl</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses <code>hsl(…)</code> strings in the modern format and returns <code>hsl</code> color objects.</p>
+<p><a id="parseHslLegacy" href="#parseHslLegacy">#</a> <strong>parseHslLegacy</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses <code>hsl(…)</code> / <code>hsla(…)</code> strings in the legacy (comma-separated) format and returns <code>hsl</code> color objects.</p>
+<p><a id="parseHwb" href="#parseHwb">#</a> <strong>parseHwb</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses <code>hwb(…)</code> strings and returns <code>hwb</code> color objects.</p>
+<p><a id="parseLab" href="#parseLab">#</a> <strong>parseLab</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses <code>lab(…)</code> strings and returns <code>lab</code> color objects.</p>
+<p><a id="parseLch" href="#parseLch">#</a> <strong>parseLch</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses <code>lch(…)</code> strings and returns <code>lch</code> color objects.</p>
+<p><a id="parseNamed" href="#parseNamed">#</a> <strong>parseNamed</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses named CSS colors (eg. <code>tomato</code>) and returns <code>rgb</code> color objects.</p>
+<p><a id="parseOklab" href="#parseOklab">#</a> <strong>parseOklab</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses <code>oklab(…)</code> strings and returns <code>oklab</code> color objects.</p>
+<p><a id="parseOklch" href="#parseOklch">#</a> <strong>parseOklch</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses <code>oklch(…)</code> strings and returns <code>oklch</code> color objects.</p>
+<p><a id="parseRgb" href="#parseRgb">#</a> <strong>parseRgb</strong>(<em>color</em>) → <em>color</em></p>
+<p>Parses <code>rgb(…)</code> strings in the modern syntax and returns <code>rgb</code> color objects.</p>
+<p><a id="parseRgbLegacy" href="#parseRgbLegacy">#</a> <strong>parseRgbLegacy</strong>(<em>color</em>) → <em>color</em></p>
+<p>Parses <code>rgb(…)</code> / <code>rgba(…)</code> strings in the legacy (comma-separated) syntax and returns <code>rgb</code> color objects.</p>
+<p><a id="parseTransparent" href="#parseTransparent">#</a><strong>parseTransparent</strong>(<em>string</em>) → <em>color</em></p>
+<p>Parses the <code>transparent</code> string and returns a transparent black <code>rgb</code> color object.</p>
+<h3>Serialization functions</h3>
+<p><a id="serializeHex" href="#serializeHex">#</a><strong>serializeHex</strong>(<em>color</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Serialize a <code>rgb</code> <em>color</em> to a 6-character hex code. See <a href="#formatHex"><code>formatHex()</code></a> for details.</p>
+<p><a id="serializeHex8" href="#serializeHex8">#</a><strong>serializeHex8</strong>(<em>color</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Serialize a <code>rgb</code> <em>color</em> to a 8-character hex code. See <a href="#formatHex8"><code>formatHex8()</code></a> for details.</p>
+<p><a id="serializeHsl" href="#serializeHsl">#</a><strong>serializeHsl</strong>(<em>color</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Serialize a <code>hsl</code> <em>color</em> to a <code>hsl(…)</code> string. See <a href="#formatHsl"><code>formatHsl()</code></a> for details.</p>
+<p><a id="serializeRgb" href="#serializeRgb">#</a><strong>serializeRgb</strong>(<em>color</em>)</p>
+<p><span aria-label='Source:'>☞</span> <a href="https://github.com/evercoder/culori/blob/main/src/formatter.js">src/formatter.js</a></p>
+<p>Serialize a <code>rgb</code> <em>color</em> to a <code>rgb(…)</code> string. See <a href="#formatRgb"><code>formatRgb()</code></a> for details.</p>
+<h3>Conversion functions</h3>
+<table>
+<thead>
+<tr>
+<th>Function</th>
+<th>Conversion</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><strong>convertA98ToXyz65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>a98</code> → <code>xyz65</code></td>
+</tr>
+<tr>
+<td><strong>convertCubehelixToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>cubehelix</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertDlchToLab65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>dlch</code> → <code>lab65</code></td>
+</tr>
+<tr>
+<td><strong>convertHsiToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>hsi</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertHslToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>hsl</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertHsvToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>hsv</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertHwbToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>hwb</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertJabToJch</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>jab</code> → <code>jch</code></td>
+</tr>
+<tr>
+<td><strong>convertJabToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>jab</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertJabToXyz65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>jab</code> → <code>xyz65</code></td>
+</tr>
+<tr>
+<td><strong>convertJchToJab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>jch</code> → <code>jab</code></td>
+</tr>
+<tr>
+<td><strong>convertLab65ToDlch</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lab65</code> → <code>dlch</code></td>
+</tr>
+<tr>
+<td><strong>convertLab65ToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lab65</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertLab65ToXyz65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lab65</code> → <code>xyz65</code></td>
+</tr>
+<tr>
+<td><strong>convertLabToLch</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lab</code> → <code>lch</code></td>
+</tr>
+<tr>
+<td><strong>convertLabToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lab</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertLabToXyz50</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lab</code> → <code>xyz50</code></td>
+</tr>
+<tr>
+<td><strong>convertLchToLab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lch</code> → <code>lab</code></td>
+</tr>
+<tr>
+<td><strong>convertLchuvToLuv</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lchuv</code> → <code>luv</code></td>
+</tr>
+<tr>
+<td><strong>convertLrgbToOklab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lrgb</code> → <code>oklab</code></td>
+</tr>
+<tr>
+<td><strong>convertLrgbToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>lrgb</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertLuvToLchuv</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>luv</code> → <code>lchuv</code></td>
+</tr>
+<tr>
+<td><strong>convertLuvToXyz50</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>luv</code> → <code>xyz50</code></td>
+</tr>
+<tr>
+<td><strong>convertOkhslToOklab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>okhsl</code> → <code>oklab</code></td>
+</tr>
+<tr>
+<td><strong>convertOkhsvToOklab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>okhsv</code> → <code>oklab</code></td>
+</tr>
+<tr>
+<td><strong>convertOklabToLrgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>oklab</code> → <code>lrgb</code></td>
+</tr>
+<tr>
+<td><strong>convertOklabToOkhsl</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>oklab</code> → <code>okhsl</code></td>
+</tr>
+<tr>
+<td><strong>convertOklabToOkhsv</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>oklab</code> → <code>okhsv</code></td>
+</tr>
+<tr>
+<td><strong>convertOklabToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>oklab</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertP3ToXyz65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>p3</code> → <code>xyz65</code></td>
+</tr>
+<tr>
+<td><strong>convertProphotoToXyz50</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>prophoto</code> → <code>xyz50</code></td>
+</tr>
+<tr>
+<td><strong>convertRec2020ToXyz65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rec2020</code> → <code>xyz65</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToCubehelix</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>cubehelix</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToHsi</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>hsi</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToHsl</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>hsl</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToHsv</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>hsv</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToHwb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>hwb</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToJab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>jab</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToLab65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>lab65</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToLab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>lab</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToLrgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>lrgb</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToOklab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>oklab</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToXyb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>xyb</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToXyz50</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>xyz50</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToXyz65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>xyz65</code></td>
+</tr>
+<tr>
+<td><strong>convertRgbToYiq</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>rgb</code> → <code>yiq</code></td>
+</tr>
+<tr>
+<td><strong>convertXybToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyb</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz50ToLab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz50</code> → <code>lab</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz50ToLuv</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz50</code> → <code>luv</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz50ToProphoto</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz50</code> → <code>prophoto</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz50ToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz50</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz50ToXyz65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz50</code> → <code>xyz65</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz65ToA98</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz65</code> → <code>a98</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz65ToJab</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz65</code> → <code>jab</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz65ToLab65</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz65</code> → <code>lab65</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz65ToP3</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz65</code> → <code>p3</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz65ToRec2020</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz65</code> → <code>rec2020</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz65ToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz65</code> → <code>rgb</code></td>
+</tr>
+<tr>
+<td><strong>convertXyz65ToXyz50</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>xyz65</code> → <code>xyz50</code></td>
+</tr>
+<tr>
+<td><strong>convertYiqToRgb</strong>(<em>color</em>) → <em>color</em></td>
+<td><code>yiq</code> → <code>rgb</code></td>
+</tr>
+</tbody>
+</table>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/api.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/benchmark/README.md b/benchmark/README.md
deleted file mode 100644
index e8ffc724..00000000
--- a/benchmark/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# Culori Benchmarks
-
-In the `culori/benchmark` folder, run `npm install` to fetch all the dependencies. With `node index.js` you can then execute all the benchmarks.
diff --git a/benchmark/index.html b/benchmark/index.html
deleted file mode 100644
index c207e26f..00000000
--- a/benchmark/index.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="utf-8" />
-		<title>culori browser playground</title>
-		<script type="text/javascript" src="../build/culori.umd.js"></script>
-	</head>
-	<body></body>
-</html>
diff --git a/benchmark/index.js b/benchmark/index.js
deleted file mode 100644
index 8f312bbc..00000000
--- a/benchmark/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import './tests/rgb-parse-speed.js';
-import './tests/namedcolors-parse-speed.js';
-import './tests/interpolate-speed.js';
diff --git a/benchmark/package-lock.json b/benchmark/package-lock.json
deleted file mode 100644
index 6e7e4c06..00000000
--- a/benchmark/package-lock.json
+++ /dev/null
@@ -1,97 +0,0 @@
-{
-	"name": "culori-benchmarks",
-	"version": "1.0.0",
-	"lockfileVersion": 2,
-	"requires": true,
-	"packages": {
-		"": {
-			"name": "culori-benchmarks",
-			"version": "1.0.0",
-			"license": "MIT",
-			"devDependencies": {
-				"chroma-js": "^3.1.2",
-				"colorjs.io": "^0.5.2",
-				"d3-color": "^3.1.0",
-				"d3-interpolate": "^3.0.1",
-				"tinycolor2": "^1.6.0"
-			}
-		},
-		"node_modules/chroma-js": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-3.1.2.tgz",
-			"integrity": "sha512-IJnETTalXbsLx1eKEgx19d5L6SRM7cH4vINw/99p/M11HCuXGRWL+6YmCm7FWFGIo6dtWuQoQi1dc5yQ7ESIHg==",
-			"dev": true,
-			"license": "(BSD-3-Clause AND Apache-2.0)"
-		},
-		"node_modules/colorjs.io": {
-			"version": "0.5.2",
-			"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
-			"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/d3-color": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
-			"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
-			"dev": true,
-			"engines": {
-				"node": ">=12"
-			}
-		},
-		"node_modules/d3-interpolate": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
-			"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
-			"dev": true,
-			"dependencies": {
-				"d3-color": "1 - 3"
-			},
-			"engines": {
-				"node": ">=12"
-			}
-		},
-		"node_modules/tinycolor2": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
-			"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
-			"dev": true,
-			"license": "MIT"
-		}
-	},
-	"dependencies": {
-		"chroma-js": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-3.1.2.tgz",
-			"integrity": "sha512-IJnETTalXbsLx1eKEgx19d5L6SRM7cH4vINw/99p/M11HCuXGRWL+6YmCm7FWFGIo6dtWuQoQi1dc5yQ7ESIHg==",
-			"dev": true
-		},
-		"colorjs.io": {
-			"version": "0.5.2",
-			"resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.5.2.tgz",
-			"integrity": "sha512-twmVoizEW7ylZSN32OgKdXRmo1qg+wT5/6C3xu5b9QsWzSFAhHLn2xd8ro0diCsKfCj1RdaTP/nrcW+vAoQPIw==",
-			"dev": true
-		},
-		"d3-color": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz",
-			"integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==",
-			"dev": true
-		},
-		"d3-interpolate": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz",
-			"integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==",
-			"dev": true,
-			"requires": {
-				"d3-color": "1 - 3"
-			}
-		},
-		"tinycolor2": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz",
-			"integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==",
-			"dev": true
-		}
-	}
-}
diff --git a/benchmark/package.json b/benchmark/package.json
deleted file mode 100644
index 9d631427..00000000
--- a/benchmark/package.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
-	"name": "culori-benchmarks",
-	"type": "module",
-	"version": "1.0.0",
-	"main": "index.js",
-	"license": "MIT",
-	"devDependencies": {
-		"chroma-js": "^3.1.2",
-		"d3-color": "^3.1.0",
-		"d3-interpolate": "^3.0.1",
-		"tinycolor2": "^1.6.0",
-		"colorjs.io": "^0.5.2"
-	}
-}
diff --git a/benchmark/tests/ciede2000-vs-din99o.js b/benchmark/tests/ciede2000-vs-din99o.js
deleted file mode 100644
index 94518ae9..00000000
--- a/benchmark/tests/ciede2000-vs-din99o.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import {
-	nearest,
-	differenceCiede2000,
-	differenceDin99o
-} from '../../src/index.js';
-import benchmark from '../util/benchmark.js';
-
-let colors = Object.keys(culori.colorsNamed);
-
-let ciede2000 = nearest(colors, differenceCiede2000());
-let din99o = nearest(colors, differenceDin99o());
-
-benchmark('ciede2000', () => {
-	for (var k = 0; k < 100; k++) {
-		for (var i = 0; i < colors.length; i++) {
-			ciede2000(colors[i]);
-		}
-	}
-});
-
-benchmark('din99o', () => {
-	for (var k = 0; k < 100; k++) {
-		for (var i = 0; i < colors.length; i++) {
-			din99o(colors[i]);
-		}
-	}
-});
diff --git a/benchmark/tests/interpolate-speed.js b/benchmark/tests/interpolate-speed.js
deleted file mode 100644
index 71a4e654..00000000
--- a/benchmark/tests/interpolate-speed.js
+++ /dev/null
@@ -1,85 +0,0 @@
-import chroma from 'chroma-js';
-import { color } from 'd3-color';
-import { quantize, interpolateRgb } from 'd3-interpolate';
-import tinycolor from 'tinycolor2';
-import { samples, interpolate, formatHex } from '../../src/index.js';
-import benchmark from '../util/benchmark.js';
-
-console.log(`
-Benchmark: interpolate speed
-============================
-`);
-
-let count = 1000;
-let iterations = 1000;
-
-benchmark('culori: #fff -> #000 in RGB', () => {
-	for (var i = 0; i < iterations; i++) {
-		samples(count)
-			.map(interpolate(['#fff', '#000']))
-			.map(formatHex);
-	}
-});
-
-let interpolator = interpolate(['#fff', '#000']);
-let hex = formatHex;
-
-benchmark('culori: #fff -> #000 in RGB (cached)', () => {
-	for (var i = 0; i < iterations; i++) {
-		samples(count).map(interpolator).map(hex);
-	}
-});
-
-benchmark('culori: #fff -> #000 in RGB (cached, single map)', () => {
-	for (var i = 0; i < iterations; i++) {
-		samples(count).map(c => hex(interpolator(c)));
-	}
-});
-
-benchmark('chroma: #fff -> #000 in RGB', () => {
-	for (var i = 0; i < iterations; i++) {
-		chroma.scale(['#fff', '#000']).colors(count);
-	}
-});
-
-let scale = chroma.scale(['#fff', '#000']);
-benchmark('chroma: #fff -> #000 in RGB (cached)', () => {
-	for (var i = 0; i < iterations; i++) {
-		scale.colors(count);
-	}
-});
-
-benchmark('d3-color: #fff -> #000 in RGB', () => {
-	for (var i = 0; i < iterations; i++) {
-		quantize(interpolateRgb('#fff', '#000'), count);
-	}
-});
-
-let interp = interpolateRgb('#fff', '#000');
-benchmark('d3-color: #fff -> #000 in RGB (cached)', () => {
-	for (var i = 0; i < iterations; i++) {
-		quantize(interp, count);
-	}
-});
-
-let colors = ['red', 'white', 'green', 'blue', 'black', 'fuchsia', 'cyan'];
-
-benchmark('culori: multiple colors in RGB', () => {
-	for (var i = 0; i < iterations; i++) {
-		samples(count).map(interpolate(colors)).map(hex);
-	}
-});
-
-benchmark('culori: multiple colors in RGB (cached)', () => {
-	let it = interpolate(colors);
-	for (var i = 0; i < iterations; i++) {
-		samples(count).map(it).map(hex);
-	}
-});
-
-let scale2 = chroma.scale(colors);
-benchmark('chroma: multiple colors in RGB (cached)', () => {
-	for (var i = 0; i < iterations; i++) {
-		scale2.colors(count);
-	}
-});
diff --git a/benchmark/tests/namedcolors-parse-speed.js b/benchmark/tests/namedcolors-parse-speed.js
deleted file mode 100644
index ce79929b..00000000
--- a/benchmark/tests/namedcolors-parse-speed.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import chroma from 'chroma-js';
-import { color } from 'd3-color';
-import tinycolor from 'tinycolor2';
-import { rgb, colorsNamed } from '../../src/index.js';
-import benchmark from '../util/benchmark.js';
-
-console.log(`
-Benchmark: named colors parse speed
-===================================
-`);
-
-let colors = Object.keys(colorsNamed);
-let iterations = 10000;
-
-benchmark('chroma: chroma("colorname")', () => {
-	for (var it = 0; it < iterations; it++) {
-		for (var i = 0; i < colors.length; i++) {
-			chroma(colors[i]);
-		}
-	}
-});
-
-benchmark('d3-color: color("colorname")', () => {
-	for (var it = 0; it < iterations; it++) {
-		for (var i = 0; i < colors.length; i++) {
-			color(colors[i]);
-		}
-	}
-});
-
-benchmark('tinycolor: tinycolor("colorname")', () => {
-	for (var it = 0; it < iterations; it++) {
-		for (var i = 0; i < colors.length; i++) {
-			tinycolor(colors[i]);
-		}
-	}
-});
-
-benchmark('culori: culori("colorname")', () => {
-	for (var it = 0; it < iterations; it++) {
-		for (var i = 0; i < colors.length; i++) {
-			rgb(colors[i]);
-		}
-	}
-});
diff --git a/benchmark/tests/rgb-parse-speed.js b/benchmark/tests/rgb-parse-speed.js
deleted file mode 100644
index d129be9b..00000000
--- a/benchmark/tests/rgb-parse-speed.js
+++ /dev/null
@@ -1,74 +0,0 @@
-import chroma from 'chroma-js';
-import { color } from 'd3-color';
-import tinycolor from 'tinycolor2';
-import { ColorSpace, sRGB, parse } from 'colorjs.io/fn';
-import { rgb } from '../../src/index.js';
-import benchmark from '../util/benchmark.js';
-
-console.log(`
-Benchmark: RGB parse speed
-==========================
-`);
-
-let increment = 2;
-
-benchmark('chroma: chroma("rgb(r,g,b)")', () => {
-	for (var r = 0; r <= 255; r += increment) {
-		for (var g = 0; g <= 255; g += increment) {
-			for (var b = 0; b <= 255; b += increment) {
-				chroma(`rgb(${r},${g},${b})`);
-			}
-		}
-	}
-});
-
-benchmark('d3-color: color("rgb(r,g,b)")', () => {
-	for (var r = 0; r <= 255; r += increment) {
-		for (var g = 0; g <= 255; g += increment) {
-			for (var b = 0; b <= 255; b += increment) {
-				color(`rgb(${r},${g},${b})`);
-			}
-		}
-	}
-});
-
-benchmark('tinycolor: tinycolor("rgb(r,g,b)")', () => {
-	for (var r = 0; r <= 255; r += increment) {
-		for (var g = 0; g <= 255; g += increment) {
-			for (var b = 0; b <= 255; b += increment) {
-				tinycolor(`rgb(${r},${g},${b})`);
-			}
-		}
-	}
-});
-
-benchmark('culori: culori("rgb(r,g,b)")', () => {
-	for (var r = 0; r <= 255; r += increment) {
-		for (var g = 0; g <= 255; g += increment) {
-			for (var b = 0; b <= 255; b += increment) {
-				rgb(`rgb(${r},${g},${b})`);
-			}
-		}
-	}
-});
-
-benchmark('culori: culori("rgb(r g b)")', () => {
-	for (var r = 0; r <= 255; r += increment) {
-		for (var g = 0; g <= 255; g += increment) {
-			for (var b = 0; b <= 255; b += increment) {
-				rgb(`rgb(${r} ${g} ${b})`);
-			}
-		}
-	}
-});
-
-ColorSpace.register(sRGB);
-benchmark('colorjs.io: parse("rgb(r g b)")', () => {
-	for (var r = 0; r <= 255; r += increment) {
-		for (var g = 0; g <= 255; g += increment) {
-			for (var b = 0; b <= 255; b += increment) {
-				parse(`rgb(${r} ${g} ${b})`);
-			}
-		}
-	}
-});
diff --git a/benchmark/util/benchmark.js b/benchmark/util/benchmark.js
deleted file mode 100644
index 8dc09f2a..00000000
--- a/benchmark/util/benchmark.js
+++ /dev/null
@@ -1,15 +0,0 @@
-var start, end;
-function startBench() {
-	start = process.hrtime();
-}
-
-function endBench() {
-	end = process.hrtime(start);
-	return end[0] + 's ' + end[1] / 1000000 + 'ms';
-}
-
-export default function (name, fn) {
-	startBench();
-	fn();
-	console.log(name, endBench());
-}
diff --git a/build.js b/build.js
deleted file mode 100644
index 473dd45c..00000000
--- a/build.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import { build } from 'esbuild';
-import { writeFile } from 'node:fs/promises';
-
-const builds = [];
-
-// Bundled CJS
-builds.push(
-	build({
-		entryPoints: ['./src/index.js'],
-		logLevel: 'info',
-		bundle: true,
-		format: 'cjs',
-		outfile: 'bundled/culori.cjs'
-	})
-);
-
-// Bundled CJS, minified
-builds.push(
-	build({
-		entryPoints: ['./src/index.js'],
-		logLevel: 'info',
-		bundle: true,
-		minify: true,
-		format: 'cjs',
-		outfile: 'bundled/culori.min.cjs'
-	})
-);
-
-// Bundled ESM
-builds.push(
-	build({
-		entryPoints: ['./src/index.js'],
-		logLevel: 'info',
-		bundle: true,
-		format: 'esm',
-		metafile: true,
-		outfile: 'bundled/culori.mjs'
-	}).then(result => {
-		writeFile(
-			'bundled/meta.json',
-			JSON.stringify(result.metafile, null, 2)
-		);
-	})
-);
-
-// Bundled ESM, minified
-builds.push(
-	build({
-		entryPoints: ['./src/index.js'],
-		logLevel: 'info',
-		bundle: true,
-		minify: true,
-		format: 'esm',
-		outfile: 'bundled/culori.min.mjs'
-	})
-);
-
-// Bundled IIFE
-builds.push(
-	build({
-		entryPoints: ['./src/index.js'],
-		logLevel: 'info',
-		bundle: true,
-		format: 'iife',
-		globalName: 'culori',
-		outfile: 'bundled/culori.js'
-	})
-);
-
-// Bundled IIFE, minified
-builds.push(
-	build({
-		entryPoints: ['./src/index.js'],
-		logLevel: 'info',
-		bundle: true,
-		minify: true,
-		format: 'iife',
-		globalName: 'culori',
-		outfile: 'bundled/culori.min.js'
-	})
-);
-
-// Bundled UMD
-// Adapted from: https://github.com/umdjs/umd/blob/master/templates/returnExports.js
-builds.push(
-	build({
-		entryPoints: ['./src/index.js'],
-		logLevel: 'info',
-		bundle: true,
-		format: 'iife',
-		globalName: 'culori',
-		banner: {
-			js: `(function(root, factory) {
-				if (typeof define === 'function' && define.amd) {
-					define([], factory);
-				} else if (typeof module === 'object' && module.exports) {
-					module.exports = factory();
-				} else {
-					root.culori = factory();
-				}
-			}
-			(typeof self !== 'undefined' ? self : this, function() {`
-		},
-		footer: { js: `return culori; }));` },
-		outfile: 'bundled/culori.umd.js'
-	})
-);
-
-await Promise.all(builds);
diff --git a/colophon/index.html b/colophon/index.html
new file mode 100644
index 00000000..7d6479d1
--- /dev/null
+++ b/colophon/index.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 Colophon &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li >
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li >
+							<a href="/api/">API reference</a>
+						</li>
+						<li >
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>Colophon</h1>
+				<p>Culori is developed by <a href="http://danburzo.ro">Dan Burzo</a> with the help of many collaborators, and released under the MIT license.</p>
+<p>The library has been inspired by Mike Bostock's <a href="https://github.com/d3">D3.js</a> and Gregor Aisch's <a href="https://github.com/gka/chroma.js">chroma.js</a>: they have popularized color science in the browser and provided a blueprint for a color manipulation API. I have learned a tremendous amount by reading through the documentation the source code while developing Culori. D3, in particular, has been a treasure trove of ideas and pointers to academic references.</p>
+<p>I pronounce the name of the library as <a href="http://ipa-reader.xyz/?text=ku%CB%90lori">[kuːlori]</a>. Culori is the Romanian word for ‘colors’. The logo is typeset in <a href="https://pstypelab.com/hatchfont">Hatch</a> by Mark Caneso.</p>
+<p>The code is formatted with <a href="https://prettier.io">Prettier</a>, upkept with <a href="https://eslint.org/">ESLint</a>, tested with <a href="https://github.com/ljharb/tape">tape</a>, and bundled with <a href="https://esbuild.github.io/">esbuild</a>. This website is statically generated using <a href="https://11ty.dev">Eleventy</a> and published to GitHub Pages.</p>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/colophon.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/color-spaces/index.html b/color-spaces/index.html
new file mode 100644
index 00000000..bbfc1d0e
--- /dev/null
+++ b/color-spaces/index.html
@@ -0,0 +1,924 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 Color Spaces &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li >
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li >
+							<a href="/api/">API reference</a>
+						</li>
+						<li class="active">
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>Color Spaces</h1>
+				<p>This is an overview of the color spaces built into Culori, listing their channels and expected ranges.</p>
+<details>
+<summary>A note on terminology</summary>
+<p>A <a href="https://en.wikipedia.org/wiki/Color_model">color model</a> is a way to describe colors along certain dimensions. RGB, for example, is a color model: color is expressed as a combination of red, green and blue.</p>
+<p>A color model, along with a precise description of how colors in the model are to be interpreted, makes a color <em>space</em>. sRGB, Display P3 and ProPhoto RGB are all color spaces that employ the RGB model: they describe colors as combination of red, green, and blue primaries; however, they have different notions of how these red, green, and blue primary colors look.</p>
+<p>In some color spaces, such as CIELAB or CIELCh, some channels don't have fixed ranges. For these channels, approximate ranges are obtained by converting all sRGB colors defined by <code>r, g, b ∈ ℕ ⋂ [0, 255]</code> to that specific color space. Whenever that's the case, the range is marked with the approximation symbol <code>≈</code>.</p>
+<p>In addition to the channels listed below, all color spaces also take an optional <code>alpha</code> channel with the range <code>[0, 1]</code>.</p>
+</details>
+<h2>Built-in color spaces</h2>
+<h3>The RGB model</h3>
+<p>The <a href="https://en.wikipedia.org/wiki/RGB_color_model">RGB color model</a> describes colors as mixtures of red, green, and blue primaries. Culori implements several RGB color spaces, all sharing these channels:</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>r</code></td>
+<td><code>[0, 1]</code></td>
+<td>Red channel</td>
+</tr>
+<tr>
+<td><code>g</code></td>
+<td><code>[0, 1]</code></td>
+<td>Green channel</td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[0, 1]</code></td>
+<td>Blue channel</td>
+</tr>
+</tbody>
+</table>
+<h4><code>rgb</code></h4>
+<p>The <a href="https://en.wikipedia.org/wiki/SRGB">sRGB color space</a>, which most people refer to when talking about RGB colors.</p>
+<p>Serialized as <code>color(srgb r g b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h4><code>lrgb</code></h4>
+<p>The linear-light form of the sRGB color space.</p>
+<p>Serialized as <code>color(srgb-linear r g b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h4><code>a98</code></h4>
+<p>The A98 RGB color space, compatible with the <a href="https://en.wikipedia.org/wiki/Adobe_RGB_color_space">Adobe RGB (1998) color space</a>.</p>
+<p>Serialized as <code>color(a98-rgb r g b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h4><code>p3</code></h4>
+<p>The <a href="https://en.wikipedia.org/wiki/DCI-P3#Display_P3">Display P3 color space</a>.</p>
+<p>Serialized as <code>color(display-p3 r g b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h4><code>prophoto</code></h4>
+<p>The <a href="https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space">ProPhoto RGB color space</a>.</p>
+<p>Serialized as <code>color(prophoto-rgb r g b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h4><code>rec2020</code></h4>
+<p>The <a href="https://en.wikipedia.org/wiki/Rec._2020">Rec. 2020 color space</a>.</p>
+<p>Serialized as <code>color(rec2020 r g b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h3>The HSL/HSV/HSI family</h3>
+<p><a href="https://en.wikipedia.org/wiki/HSL_and_HSV">HSL, HSV, and HSI</a> are alternative representations of the RGB color model, created in an attempt to provide a more intuitive way to specify colors.</p>
+<p>The <em>hue</em> is identical across all color models in this family; however, the <em>saturaton</em> is computed differently in each. The saturation in HSL is <strong>not interchangeable</strong> with the saturation from HSV, nor HSI. Achromatic colors (shades of gray) will have an <code>undefined</code> hue.</p>
+<p>As color spaces, they relate to the <a href="#rgb"><code>sRGB</code> color space</a>.</p>
+<h4><code>hsl</code></h4>
+<p>The HSL color space.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+<tr>
+<td><code>s</code></td>
+<td><code>[0, 1]</code></td>
+<td>Saturation in HSL</td>
+</tr>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 1]</code></td>
+<td>Lightness</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>hsl(h s% l%)</code>. A missing hue is serialized as <code>0</code>, with the <code>none</code> keyword for any other missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h4><code>hsv</code></h4>
+<p>The HSV color space.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+<tr>
+<td><code>s</code></td>
+<td><code>[0, 1]</code></td>
+<td>Saturation in HSV</td>
+</tr>
+<tr>
+<td><code>v</code></td>
+<td><code>[0, 1]</code></td>
+<td>Value</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--hsv h s v)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h4><code>hsi</code></h4>
+<p>The HSI color space.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+<tr>
+<td><code>s</code></td>
+<td><code>[0, 1]</code></td>
+<td>Saturation in HSI</td>
+</tr>
+<tr>
+<td><code>i</code></td>
+<td><code>[0, 1]</code></td>
+<td>Intensity</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--hsi h s i)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<h3>HWB</h3>
+<p><a href="https://en.wikipedia.org/wiki/HWB_color_model">The HWB color model</a> was developed by Alvy Ray Smith, who also created the HSV color model. It's meant to be more intuitive for humans to use and faster to compute.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+<tr>
+<td><code>w</code></td>
+<td><code>[0, 1]</code></td>
+<td>Whiteness</td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[0, 1]</code></td>
+<td>Blackness</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>hwb(h w% b%)</code>.</p>
+<p>Serialized as <code>hwb(h w% b%)</code>. A missing hue is serialized as <code>0</code>, with the <code>none</code> keyword for any other missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Has gamut limits.</p>
+<blockquote>
+<p>Smith, Alvy Ray (1996) — <a href="http://alvyray.com/Papers/CG/HWB_JGTv208.pdf">&quot;HWB — A More Intuitive Hue-Based Color Model&quot;</a>, Journal of Graphics, GPU and Game tools.</p>
+</blockquote>
+<h3>CIELAB</h3>
+<p>The <a href="https://en.wikipedia.org/wiki/CIELAB_color_space">CIELAB color space</a>, also known as CIE 1976 L*a*b*, in Cartesian (Lab) and cylindrical (LCh) forms.</p>
+<h4><code>lab</code></h4>
+<p>The CIELAB color space using the <a href="https://en.wikipedia.org/wiki/Standard_illuminant">D50 standard illuminant</a> as the reference white, following the <a href="https://drafts.csswg.org/css-color/#lab-colors">CSS Color Module Level 4 specification</a>.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>CSS Reference Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>a</code></td>
+<td><code>[-125, 125]</code></td>
+<td>Green–red component</td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[-125, 125]</code></td>
+<td>Blue–yellow component</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>lab(l a b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>lch</code></h4>
+<p>The CIELCh color space using the D50 standard illuminant.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>CSS Reference Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>c</code></td>
+<td><code>[0, 150]</code></td>
+<td>Chroma</td>
+</tr>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>lch(l c h)</code>. A missing hue is serialized as <code>0</code>, with the <code>none</code> keyword for any other missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>lab65</code></h4>
+<p>CIELAB relative to the D65 standard illuminant.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>a</code></td>
+<td><code>[-125, 125]</code></td>
+<td>Green–red component</td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[-125, 125]</code></td>
+<td>Blue–yellow component</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--lab-d65 l a b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>lch65</code></h4>
+<p>CIELCh relative to the D65 standard illuminant.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>c</code></td>
+<td><code>[0, 150]</code></td>
+<td>Chroma</td>
+</tr>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--lch-d65 l c h)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h3>CIELUV</h3>
+<p>The <a href="https://en.wikipedia.org/wiki/CIELUV">CIELUV color space</a> in Cartesian (Luv) and cylindrical (LCh) forms, using the D50 standard illuminant.</p>
+<p>CIELuv has an effective Euclidean color difference function:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">let</span> deltaE_uv <span class="token operator">=</span> culori<span class="token punctuation">.</span><span class="token function">colorDifferenceEuclidean</span><span class="token punctuation">(</span><span class="token string">'luv'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<h4><code>luv</code></h4>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>u</code></td>
+<td><code>[-84.936, 175.042]</code>≈</td>
+<td>Green–red component</td>
+</tr>
+<tr>
+<td><code>v</code></td>
+<td><code>[-125.882, 87.243]</code>≈</td>
+<td>Blue–yellow component</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--luv l u v)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>lchuv</code></h4>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>c</code></td>
+<td><code>[0, 176.956]</code>≈</td>
+<td>Chroma</td>
+</tr>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--lchuv l c h)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h3>DIN99 Lab / LCh</h3>
+<p>The <a href="https://de.wikipedia.org/wiki/DIN99-Farbraum">DIN99</a> color space &quot;squishes&quot; the CIELAB D65 color space to obtain an <a href="#culoriDifferenceDin99o">effective color difference</a> metric that can be expressed as a simple Euclidean distance. The latest iteration of the the standard, DIN99o, is available in Cartesian (<code>dlab</code>) and polar (<code>dlch</code>) form.</p>
+<blockquote>
+<p><a href="https://search.worldcat.org/title/Industrial-color-physics/oclc/663097553"><em>Industrial Color Physics</em></a>, Georg A. Klein, Springer (2010)
+<a href="https://www.beuth.de/en/standard/din-6176/292836682">DIN 6176</a>, <em>Colorimetric determination of colour differences of object colours according to the DIN99o formula</em></p>
+</blockquote>
+<h4><code>dlab</code></h4>
+<p>The DIN99o color space in Cartesian form.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>a</code></td>
+<td><code>[-40.09, 45.501]</code>≈</td>
+<td></td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[-40.469, 44.344]</code>≈</td>
+<td></td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--din99o-lab l a b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>dlch</code></h4>
+<p>The DIN99o color space in cylindrical form.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 100]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>c</code></td>
+<td><code>[0, 51.484]</code>≈</td>
+<td>Chroma</td>
+</tr>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--din99o-lch l c h)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h3>Oklab, Oklch, Okhsl, Okhsv</h3>
+<p>The <a href="https://bottosson.github.io/posts/oklab/">Oklab color space</a>, in Cartesian (Lab) and cylindrical (LCh) forms. It uses the D65 standard illuminant.</p>
+<p>See also: <a href="https://bottosson.github.io/posts/colorpicker/">Okhsl and Okhsv, two new color spaces for color picking</a>.</p>
+<h4><code>oklab</code></h4>
+<p>The Oklab color space in Cartesian form.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>CSS Reference Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 1]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>a</code></td>
+<td><code>[-0.4, 0.4]</code></td>
+<td>Green–red component</td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[-0.4, 0.4]</code></td>
+<td>Blue–yellow component</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>oklab(l a b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>oklch</code></h4>
+<p>The Oklab color space in cylindrical form.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 1]</code></td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>c</code></td>
+<td><code>[0, 0.4]</code></td>
+<td>Chroma</td>
+</tr>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>oklch(l c h)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h3><code>okhsl</code></h3>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+<tr>
+<td><code>s</code></td>
+<td><code>[0, 1]</code></td>
+<td>Saturation (Okhsl)</td>
+</tr>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 1]</code></td>
+<td>Lightness</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--okhsl h s l)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h3><code>okhsv</code></h3>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+<tr>
+<td><code>s</code></td>
+<td><code>[0, 1]</code></td>
+<td>Saturation (Okhsv)</td>
+</tr>
+<tr>
+<td><code>v</code></td>
+<td><code>[0, 1]</code></td>
+<td>Value</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--okhsv h s v)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4>Further reading</h4>
+<ul>
+<li><a href="https://raphlinus.github.io/color/2021/01/18/oklab-critique.html">An interactive review of Oklab</a> by Raph Levien</li>
+<li><a href="https://github.com/svgeesus/svgeesus.github.io/blob/master/Color/OKLab-notes.md">Notes on Oklab</a> and <a href="https://www.w3.org/Graphics/Color/Workshop/slides/talk/lilley">Better than Lab? Gamut reduction CIE Lab &amp; OKLab</a> by Chris Lilley</li>
+<li><a href="https://github.com/w3c/csswg-drafts/issues/6642">[css-color] Add OKLab, OKLCH (#6642)</a></li>
+</ul>
+<h3>J<sub>z</sub>a<sub>z</sub>b<sub>z</sub></h3>
+<p>The J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space, as defined by:</p>
+<blockquote>
+<p>Muhammad Safdar, Guihua Cui, Youn Jin Kim, and Ming Ronnier Luo, <a href="https://doi.org/10.1364/OE.25.015131"><em>&quot;Perceptually uniform color space for image signals including high dynamic range and wide gamut&quot;</em></a>, Opt. Express 25, 15131-15151 (2017)</p>
+</blockquote>
+<h4><code>jab</code></h4>
+<p>The J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space in Cartesian form.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>j</code></td>
+<td><code>[0, 0.222]</code>≈</td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>a</code></td>
+<td><code>[-0.109, 0.129]</code>≈</td>
+<td>Green–red component</td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[-0.185, 0.134]</code>≈</td>
+<td>Blue–yellow component</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--jzazbz j a b)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>jch</code></h4>
+<p>The J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space in cylindrical form.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>j</code></td>
+<td><code>[0, 0.222]</code>≈</td>
+<td>Lightness</td>
+</tr>
+<tr>
+<td><code>c</code></td>
+<td><code>[0, 0.190]</code>≈</td>
+<td>Chroma</td>
+</tr>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--jzczhz j c h)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h3>YIQ (<code>yiq</code>)</h3>
+<p><a href="https://en.wikipedia.org/wiki/YIQ">YIQ</a> is the color space used by the NTSC color TV system. It contains the following channels:</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>y</code></td>
+<td><code>[0, 1]</code></td>
+<td>Luma</td>
+</tr>
+<tr>
+<td><code>i</code></td>
+<td><code>[-0.595, 0.595]</code>≈</td>
+<td>In-phase (orange-blue axis)</td>
+</tr>
+<tr>
+<td><code>q</code></td>
+<td><code>[-0.522, 0.522]</code>≈</td>
+<td>Quadrature (green-purple axis)</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--yiq y i q)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<p>The conversion matrices between the sRGB and YIQ color spaces are taken from:</p>
+<blockquote>
+<p>Yuriy Kotsarenko, Fernando Ramos, <a href="http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf"><em>Measuring perceived color difference using YIQ NTSC transmission color space in mobile applications</em></a>, Programación Matemática y Software (2010), Vol. 2, No 2.</p>
+</blockquote>
+<h3>CIE XYZ</h3>
+<p>The <a href="https://en.wikipedia.org/wiki/CIE_1931_color_space">CIE XYZ color space</a>, also known as the CIE 1931 color space.</p>
+<h4><code>xyz50</code></h4>
+<p>The CIE XYZ color space in respect to the D50 standard illuminant.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>x</code></td>
+<td><code>[0, 0.964]</code>≈</td>
+<td>?</td>
+</tr>
+<tr>
+<td><code>y</code></td>
+<td><code>[0, 0.999]</code>≈</td>
+<td>?</td>
+</tr>
+<tr>
+<td><code>z</code></td>
+<td><code>[0, 0.825]</code>≈</td>
+<td>?</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(xyz-d50 x y z)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h4><code>xyz65</code></h4>
+<p>The CIE XYZ color space in respect to the D65 standard illuminant.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>x</code></td>
+<td><code>[0, 0.950]</code>≈</td>
+<td>?</td>
+</tr>
+<tr>
+<td><code>y</code></td>
+<td><code>[0, 1]</code>≈</td>
+<td>?</td>
+</tr>
+<tr>
+<td><code>z</code></td>
+<td><code>[0, 1.088]</code>≈</td>
+<td>?</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(xyz-d65 x y z)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<h3>XYB</h3>
+<p>The XYB color model is part of <a href="https://ds.jpeg.org/whitepapers/jpeg-xl-whitepaper.pdf">the JPEG XL Image Coding System</a>, as an <q>LMS-based colour model inspired by the human visual system, facilitating perceptually uniform quantization. It uses a gamma of 3 for computationally efficient decoding</q>.</p>
+<h4><code>xyb</code></h4>
+<p>The default XYB color space, defined in relationship to sRGB.</p>
+<p>It has the default <em>Chroma from Luma</em> adjustment applied (effectively Y is subtracted from B) so that colors with <code>{ x: 0, b: 0 }</code> coordinates are achromatic.</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>x</code></td>
+<td><code>[-0.0154, 0.0281]</code>≈</td>
+<td>Cyan-red component</td>
+</tr>
+<tr>
+<td><code>y</code></td>
+<td><code>[0, 0.8453]</code>≈</td>
+<td>Luma</td>
+</tr>
+<tr>
+<td><code>b</code></td>
+<td><code>[ -0.2778, 0.3880 ]</code>≈</td>
+<td>Blue-yellow component</td>
+</tr>
+</tbody>
+</table>
+<p>Does not have gamut limits.</p>
+<h3><abbr>IC<sub>t</sub>C<sub>p</sub></abbr></h3>
+<p><abbr>IC<sub>t</sub>C<sub>p</sub></abbr> (or <abbr>ITP</abbr>) color space developed by <a href="https://professional.dolby.com/siteassets/pdfs/ictcp_dolbywhitepaper_v071.pdf">Dolby Laboratories</a>, as defined in <a href="https://www.itu.int/rec/R-REC-BT.2100"><abbr>ITU-R</abbr> Recommendation BT.2100</a>. It is included in the <abbr>CSS</abbr> <a href="https://drafts.csswg.org/css-color-hdr/#ICtCp"><abbr>HDR</abbr> Color Module Level 1</a> specification.</p>
+<h4><code>itp</code></h4>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>i</code></td>
+<td><code>[0, 0.581]</code>≈</td>
+<td>Intensity</td>
+</tr>
+<tr>
+<td><code>t</code></td>
+<td><code>[-0.282, 0.278]</code>≈</td>
+<td>Blue-yellow component (“tritanopia”)</td>
+</tr>
+<tr>
+<td><code>p</code></td>
+<td><code>[-0.162, 0.279]</code>≈</td>
+<td>Green–red component (“protanopia”)</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--ictcp i t p)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+<p>The <code>itp</code> color space is the basis of the <a href="/api/#differenceItp">ΔE<sub>ITP</sub> color difference</a> metric defined in <em>Objective metric for the assessment of the potential visibility of colour differences in television</em> (<a href="https://www.itu.int/rec/R-REC-BT.2124/en">Rec. ITU-R BT.2124</a>).</p>
+<h3>Cubehelix</h3>
+<p><a href="https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/">The Cubehelix color scheme</a> was described by Dave Green in this paper:</p>
+<blockquote>
+<p>Green, D. A., 2011, <a href="http://astron-soc.in/bulletin/11June/289392011.pdf"><em>&quot;A colour scheme for the display of astronomical intensity images&quot;</em></a>, Bulletin of the Astronomical Society of India, 39, 289. (<a href="https://ui.adsabs.harvard.edu/#abs/2011BASI...39..289G">2011BASI...39..289G</a> at <a href="https://ui.adsabs.harvard.edu/">ADS</a>)</p>
+</blockquote>
+<p>It was expanded into a cylindrical color space by <a href="https://en.wikipedia.org/wiki/Mike_Bostock">Mike Bostock</a> and <a href="https://www.jasondavies.com/">Jason Davies</a> in <a href="https://github.com/d3/d3-color">D3</a>.</p>
+<h4><code>cubehelix</code></h4>
+<p>The channels in the <code>cubehelix</code> color space maintain the conventions from D3, namely:</p>
+<table>
+<thead>
+<tr>
+<th>Channel</th>
+<th>Range</th>
+<th>Description</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><code>h</code></td>
+<td><code>[0, 360)</code></td>
+<td>Hue (Based on <em>start color</em> and <em>rotations</em> as defined in Green's paper)</td>
+</tr>
+<tr>
+<td><code>s</code></td>
+<td><code>[0, 4.614]</code></td>
+<td>Saturation (Called <em>hue</em> in op. cit.)</td>
+</tr>
+<tr>
+<td><code>l</code></td>
+<td><code>[0, 1]</code></td>
+<td>Lightness</td>
+</tr>
+</tbody>
+</table>
+<p>Serialized as <code>color(--cubehelix h s l)</code>, with the <code>none</code> keyword for any missing color channel. An explicit <code>alpha &lt; 1</code> is included as <code> / alpha</code>.</p>
+<p>Does not have gamut limits.</p>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/color-spaces.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/docs/css/main.css b/css/main.css
similarity index 100%
rename from docs/css/main.css
rename to css/main.css
diff --git a/culori.min.mjs b/culori.min.mjs
new file mode 100644
index 00000000..0b24f260
--- /dev/null
+++ b/culori.min.mjs
@@ -0,0 +1,4 @@
+var kn=(e,t)=>{if(typeof e=="number"){if(t===3)return{mode:"rgb",r:(e>>8&15|e>>4&240)/255,g:(e>>4&15|e&240)/255,b:(e&15|e<<4&240)/255};if(t===4)return{mode:"rgb",r:(e>>12&15|e>>8&240)/255,g:(e>>8&15|e>>4&240)/255,b:(e>>4&15|e&240)/255,alpha:(e&15|e<<4&240)/255};if(t===6)return{mode:"rgb",r:(e>>16&255)/255,g:(e>>8&255)/255,b:(e&255)/255};if(t===8)return{mode:"rgb",r:(e>>24&255)/255,g:(e>>16&255)/255,b:(e>>8&255)/255,alpha:(e&255)/255}}},st=kn;var Ln={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074},rr=Ln;var Rn=e=>st(rr[e.toLowerCase()],6),or=Rn;var wn=/^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i,_n=e=>{let t;return(t=e.match(wn))?st(parseInt(t[1],16),t[1].length):void 0},nr=_n;var I="([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)",gi=`(?:${I}|none)`,he=`${I}%`,Mi=`(?:${I}%|none)`,Ye=`(?:${I}%|${I})`,Hn=`(?:${I}%|${I}|none)`,Mo=`(?:${I}(deg|grad|rad|turn)|${I})`,vi=`(?:${I}(deg|grad|rad|turn)|${I}|none)`,le="\\s*,\\s*";var yi=new RegExp("^"+Hn+"$");var Xn=new RegExp(`^rgba?\\(\\s*${I}${le}${I}${le}${I}\\s*(?:,\\s*${Ye}\\s*)?\\)$`),Sn=new RegExp(`^rgba?\\(\\s*${he}${le}${he}${le}${he}\\s*(?:,\\s*${Ye}\\s*)?\\)$`),Pn=e=>{let t={mode:"rgb"},r;if(r=e.match(Xn))r[1]!==void 0&&(t.r=r[1]/255),r[2]!==void 0&&(t.g=r[2]/255),r[3]!==void 0&&(t.b=r[3]/255);else if(r=e.match(Sn))r[1]!==void 0&&(t.r=r[1]/100),r[2]!==void 0&&(t.g=r[2]/100),r[3]!==void 0&&(t.b=r[3]/100);else return;return r[4]!==void 0?t.alpha=Math.max(0,Math.min(1,r[4]/100)):r[5]!==void 0&&(t.alpha=Math.max(0,Math.min(1,+r[5]))),t},ar=Pn;var Cn=(e,t)=>e===void 0?void 0:typeof e!="object"?fr(e):e.mode!==void 0?e:t?{...e,mode:t}:void 0,P=Cn;var $n=(e="rgb")=>t=>(t=P(t,e))!==void 0?t.mode===e?t:F[t.mode][e]?F[t.mode][e](t):e==="rgb"?F[t.mode].rgb(t):F.rgb[e](F[t.mode].rgb(t)):void 0,v=$n;var F={},vo={},be=[],ct={},Nn=e=>e,T=e=>(F[e.mode]={...F[e.mode],...e.toMode},Object.keys(e.fromMode||{}).forEach(t=>{F[t]||(F[t]={}),F[t][e.mode]=e.fromMode[t]}),e.ranges||(e.ranges={}),e.difference||(e.difference={}),e.channels.forEach(t=>{if(e.ranges[t]===void 0&&(e.ranges[t]=[0,1]),!e.interpolate[t])throw new Error(`Missing interpolator for: ${t}`);typeof e.interpolate[t]=="function"&&(e.interpolate[t]={use:e.interpolate[t]}),e.interpolate[t].fixup||(e.interpolate[t].fixup=Nn)}),vo[e.mode]=e,(e.parse||[]).forEach(t=>{yo(t,e.mode)}),v(e.mode)),R=e=>vo[e],yo=(e,t)=>{if(typeof e=="string"){if(!t)throw new Error("'mode' required when 'parser' is a string");ct[e]=t}else typeof e=="function"&&be.indexOf(e)<0&&be.push(e)},In=e=>{if(typeof e=="string")delete ct[e];else if(typeof e=="function"){let t=be.indexOf(e);t>0&&be.splice(t,1)}};var ir=/[^\x00-\x7F]|[a-zA-Z_]/,On=/[^\x00-\x7F]|[-\w]/,d={Function:"function",Ident:"ident",Number:"number",Percentage:"percentage",ParenClose:")",None:"none",Hue:"hue",Alpha:"alpha"},x=0;function ht(e){let t=e[x],r=e[x+1];return t==="-"||t==="+"?/\d/.test(r)||r==="."&&/\d/.test(e[x+2]):t==="."?/\d/.test(r):/\d/.test(t)}function lr(e){if(x>=e.length)return!1;let t=e[x];if(ir.test(t))return!0;if(t==="-"){if(e.length-x<2)return!1;let r=e[x+1];return!!(r==="-"||ir.test(r))}return!1}var An={deg:1,rad:180/Math.PI,grad:9/10,turn:360};function Ge(e){let t="";if((e[x]==="-"||e[x]==="+")&&(t+=e[x++]),t+=bt(e),e[x]==="."&&/\d/.test(e[x+1])&&(t+=e[x++]+bt(e)),(e[x]==="e"||e[x]==="E")&&((e[x+1]==="-"||e[x+1]==="+")&&/\d/.test(e[x+2])?t+=e[x++]+e[x++]+bt(e):/\d/.test(e[x+1])&&(t+=e[x++]+bt(e))),lr(e)){let r=xt(e);return r==="deg"||r==="rad"||r==="turn"||r==="grad"?{type:d.Hue,value:t*An[r]}:void 0}return e[x]==="%"?(x++,{type:d.Percentage,value:+t}):{type:d.Number,value:+t}}function bt(e){let t="";for(;/\d/.test(e[x]);)t+=e[x++];return t}function xt(e){let t="";for(;x<e.length&&On.test(e[x]);)t+=e[x++];return t}function qn(e){let t=xt(e);return e[x]==="("?(x++,{type:d.Function,value:t}):t==="none"?{type:d.None,value:void 0}:{type:d.Ident,value:t}}function Dn(e=""){let t=e.trim(),r=[],o;for(x=0;x<t.length;){if(o=t[x++],o===`
+`||o==="	"||o===" "){for(;x<t.length&&(t[x]===`
+`||t[x]==="	"||t[x]===" ");)x++;continue}if(o===",")return;if(o===")"){r.push({type:d.ParenClose});continue}if(o==="+"){if(x--,ht(t)){r.push(Ge(t));continue}return}if(o==="-"){if(x--,ht(t)){r.push(Ge(t));continue}if(lr(t)){r.push({type:d.Ident,value:xt(t)});continue}return}if(o==="."){if(x--,ht(t)){r.push(Ge(t));continue}return}if(o==="/"){for(;x<t.length&&(t[x]===`
+`||t[x]==="	"||t[x]===" ");)x++;let n;if(ht(t)&&(n=Ge(t),n.type!==d.Hue)){r.push({type:d.Alpha,value:n});continue}if(lr(t)&&xt(t)==="none"){r.push({type:d.Alpha,value:{type:d.None,value:void 0}});continue}return}if(/\d/.test(o)){x--,r.push(Ge(t));continue}if(ir.test(o)){x--,r.push(qn(t));continue}return}return r}function En(e){e._i=0;let t=e[e._i++];if(!t||t.type!==d.Function||t.value!=="color"||(t=e[e._i++],t.type!==d.Ident))return;let r=ct[t.value];if(!r)return;let o={mode:r},n=To(e,!1);if(!n)return;let a=R(r).channels;for(let f=0,i,l;f<a.length;f++)i=n[f],l=a[f],i.type!==d.None&&(o[l]=i.type===d.Number?i.value:i.value/100,l==="alpha"&&(o[l]=Math.max(0,Math.min(1,o[l]))));return o}function To(e,t){let r=[],o;for(;e._i<e.length;){if(o=e[e._i++],o.type===d.None||o.type===d.Number||o.type===d.Alpha||o.type===d.Percentage||t&&o.type===d.Hue){r.push(o);continue}if(o.type===d.ParenClose){if(e._i<e.length)return;continue}return}if(!(r.length<3||r.length>4)){if(r.length===4){if(r[3].type!==d.Alpha)return;r[3]=r[3].value}return r.length===3&&r.push({type:d.None,value:void 0}),r.every(n=>n.type!==d.Alpha)?r:void 0}}function Jn(e,t){e._i=0;let r=e[e._i++];if(!r||r.type!==d.Function)return;let o=To(e,t);if(o)return o.unshift(r.value),o}var jn=e=>{if(typeof e!="string")return;let t=Dn(e),r=t?Jn(t,!0):void 0,o,n=0,a=be.length;for(;n<a;)if((o=be[n++](e,r))!==void 0)return o;return t?En(t):void 0},fr=jn;function Yn(e,t){if(!t||t[0]!=="rgb"&&t[0]!=="rgba")return;let r={mode:"rgb"},[,o,n,a,f]=t;if(!(o.type===d.Hue||n.type===d.Hue||a.type===d.Hue))return o.type!==d.None&&(r.r=o.type===d.Number?o.value/255:o.value/100),n.type!==d.None&&(r.g=n.type===d.Number?n.value/255:n.value/100),a.type!==d.None&&(r.b=a.type===d.Number?a.value/255:a.value/100),f.type!==d.None&&(r.alpha=Math.min(1,Math.max(0,f.type===d.Number?f.value:f.value/100))),r}var pr=Yn;var Gn=e=>e==="transparent"?{mode:"rgb",r:0,g:0,b:0,alpha:0}:void 0,dr=Gn;var V=(e,t,r)=>e+r*(t-e),Bn=(e,t,r)=>(r-e)/(t-e),ur=(e,t,r,o,n,a)=>V(V(e,t,n),V(r,o,n),a),Zn=(e,t,r,o,n,a,f,i,l,m,u)=>V(ur(e,t,r,o,l,m),ur(n,a,f,i,l,m),u);var Fn=e=>{let t=[];for(let r=0;r<e.length-1;r++){let o=e[r],n=e[r+1];o===void 0&&n===void 0?t.push(void 0):o!==void 0&&n!==void 0?t.push([o,n]):t.push(o!==void 0?[o,o]:[n,n])}return t},mr=e=>t=>{let r=Fn(t);return o=>{let n=o*r.length,a=o>=1?r.length-1:Math.max(Math.floor(n),0),f=r[a];return f===void 0?void 0:e(f[0],f[1],n-a)}};var p=mr(V);var y=e=>{let t=!1,r=e.map(o=>o!==void 0?(t=!0,o):1);return t?r:e};var Wn={mode:"rgb",channels:["r","g","b","alpha"],parse:[pr,nr,ar,or,dr,"srgb"],serialize:"srgb",interpolate:{r:p,g:p,b:p,alpha:{use:p,fixup:y}},gamut:!0,white:{r:1,g:1,b:1},black:{r:0,g:0,b:0}},Z=Wn;var sr=(e=0)=>Math.pow(Math.abs(e),2.19921875)*Math.sign(e),Un=e=>{let t=sr(e.r),r=sr(e.g),o=sr(e.b),n={mode:"xyz65",x:.5766690429101305*t+.1855582379065463*r+.1882286462349947*o,y:.297344975250536*t+.6273635662554661*r+.0752914584939979*o,z:.0270313613864123*t+.0706888525358272*r+.9913375368376386*o};return e.alpha!==void 0&&(n.alpha=e.alpha),n},gt=Un;var cr=e=>Math.pow(Math.abs(e),.4547069271758437)*Math.sign(e),Kn=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n={mode:"a98",r:cr(e*2.0415879038107465-t*.5650069742788597-.3447313507783297*r),g:cr(e*-.9692436362808798+t*1.8759675015077206+.0415550574071756*r),b:cr(e*.0134442806320312-t*.1183623922310184+1.0151749943912058*r)};return o!==void 0&&(n.alpha=o),n},Mt=Kn;var hr=(e=0)=>{let t=Math.abs(e);return t<=.04045?e/12.92:(Math.sign(e)||1)*Math.pow((t+.055)/1.055,2.4)},Qn=({r:e,g:t,b:r,alpha:o})=>{let n={mode:"lrgb",r:hr(e),g:hr(t),b:hr(r)};return o!==void 0&&(n.alpha=o),n},j=Qn;var Vn=e=>{let{r:t,g:r,b:o,alpha:n}=j(e),a={mode:"xyz65",x:.4123907992659593*t+.357584339383878*r+.1804807884018343*o,y:.2126390058715102*t+.715168678767756*r+.0721923153607337*o,z:.0193308187155918*t+.119194779794626*r+.9505321522496607*o};return n!==void 0&&(a.alpha=n),a},O=Vn;var br=(e=0)=>{let t=Math.abs(e);return t>.0031308?(Math.sign(e)||1)*(1.055*Math.pow(t,.4166666666666667)-.055):e*12.92},e0=({r:e,g:t,b:r,alpha:o},n="rgb")=>{let a={mode:n,r:br(e),g:br(t),b:br(r)};return o!==void 0&&(a.alpha=o),a},Y=e0;var t0=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Y({r:e*3.2409699419045226-t*1.537383177570094-.4986107602930034*r,g:e*-.9692436362808796+t*1.8759675015077204+.0415550574071756*r,b:e*.0556300796969936-t*.2039769588889765+1.0569715142428784*r});return o!==void 0&&(n.alpha=o),n},A=t0;var r0={...Z,mode:"a98",parse:["a98-rgb"],serialize:"a98-rgb",fromMode:{rgb:e=>Mt(O(e)),xyz65:Mt},toMode:{rgb:e=>A(gt(e)),xyz65:gt}},zo=r0;var o0=e=>(e=e%360)<0?e+360:e,k=o0;var vt=(e,t)=>e.map((r,o,n)=>{if(r===void 0)return r;let a=k(r);return o===0||e[o-1]===void 0?a:t(a-k(n[o-1]))}).reduce((r,o)=>!r.length||o===void 0||r[r.length-1]===void 0?(r.push(o),r):(r.push(o+r[r.length-1]),r),[]),X=e=>vt(e,t=>Math.abs(t)<=180?t:t-360*Math.sign(t)),n0=e=>vt(e,t=>Math.abs(t)>=180||t===0?t:t-360*Math.sign(t)),a0=e=>vt(e,t=>t>=0?t:t+360),f0=e=>vt(e,t=>t<=0?t:t-360);var _=[-.14861,1.78277,-.29227,-.90649,1.97294,0],ko=Math.PI/180,Lo=180/Math.PI;var Ro=_[3]*_[4],wo=_[1]*_[4],_o=_[1]*_[2]-_[0]*_[3],i0=({r:e,g:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=(_o*r+e*Ro-t*wo)/(_o+Ro-wo),a=r-n,f=(_[4]*(t-n)-_[2]*a)/_[3],i={mode:"cubehelix",l:n,s:n===0||n===1?void 0:Math.sqrt(a*a+f*f)/(_[4]*n*(1-n))};return i.s&&(i.h=Math.atan2(f,a)*Lo-120),o!==void 0&&(i.alpha=o),i},xr=i0;var l0=({h:e,s:t,l:r,alpha:o})=>{let n={mode:"rgb"};e=(e===void 0?0:e+120)*ko,r===void 0&&(r=0);let a=t===void 0?0:t*r*(1-r),f=Math.cos(e),i=Math.sin(e);return n.r=r+a*(_[0]*f+_[1]*i),n.g=r+a*(_[2]*f+_[3]*i),n.b=r+a*(_[4]*f+_[5]*i),o!==void 0&&(n.alpha=o),n},gr=l0;var ee=(e,t)=>{if(e.h===void 0||t.h===void 0||!e.s||!t.s)return 0;let r=k(e.h),o=k(t.h),n=Math.sin((o-r+360)/2*Math.PI/180);return 2*Math.sqrt(e.s*t.s)*n},Mr=(e,t)=>{if(e.h===void 0||t.h===void 0)return 0;let r=k(e.h),o=k(t.h);return Math.abs(o-r)>180?r-(o-360*Math.sign(o-r)):o-r},te=(e,t)=>{if(e.h===void 0||t.h===void 0||!e.c||!t.c)return 0;let r=k(e.h),o=k(t.h),n=Math.sin((o-r+360)/2*Math.PI/180);return 2*Math.sqrt(e.c*t.c)*n},pe=(e="rgb",t=[1,1,1,0])=>{let r=R(e),o=r.channels,n=r.difference,a=v(e);return(f,i)=>{let l=a(f),m=a(i);return Math.sqrt(o.reduce((u,s,h)=>{let c=n[s]?n[s](l,m):l[s]-m[s];return u+(t[h]||0)*Math.pow(isNaN(c)?0:c,2)},0))}},p0=()=>pe("lab65"),d0=(e=1,t=.045,r=.015)=>{let o=v("lab65");return(n,a)=>{let f=o(n),i=o(a),l=f.l,m=f.a,u=f.b,s=Math.sqrt(m*m+u*u),h=i.l,c=i.a,b=i.b,M=Math.sqrt(c*c+b*b),g=Math.pow(l-h,2),z=Math.pow(s-M,2),L=Math.pow(m-c,2)+Math.pow(u-b,2)-z;return Math.sqrt(g/Math.pow(e,2)+z/Math.pow(1+t*s,2)+L/Math.pow(1+r*s,2))}},u0=(e=1,t=1,r=1)=>{let o=v("lab65");return(n,a)=>{let f=o(n),i=o(a),l=f.l,m=f.a,u=f.b,s=Math.sqrt(m*m+u*u),h=i.l,c=i.a,b=i.b,M=Math.sqrt(c*c+b*b),g=(s+M)/2,z=.5*(1-Math.sqrt(Math.pow(g,7)/(Math.pow(g,7)+Math.pow(25,7)))),L=m*(1+z),H=c*(1+z),C=Math.sqrt(L*L+u*u),$=Math.sqrt(H*H+b*b),N=Math.abs(L)+Math.abs(u)===0?0:Math.atan2(u,L);N+=(N<0)*2*Math.PI;let q=Math.abs(H)+Math.abs(b)===0?0:Math.atan2(b,H);q+=(q<0)*2*Math.PI;let me=h-l,ie=$-C,B=C*$===0?0:q-N;B-=(B>Math.PI)*2*Math.PI,B+=(B<-Math.PI)*2*Math.PI;let Q=2*Math.sqrt(C*$)*Math.sin(B/2),se=(l+h)/2,ce=(C+$)/2,D;C*$===0?D=N+q:(D=(N+q)/2,D-=(Math.abs(N-q)>Math.PI)*Math.PI,D+=(D<0)*2*Math.PI);let dt=Math.pow(se-50,2),ut=1-.17*Math.cos(D-Math.PI/6)+.24*Math.cos(2*D)+.32*Math.cos(3*D+Math.PI/30)-.2*Math.cos(4*D-63*Math.PI/180),Ee=1+.015*dt/Math.sqrt(20+dt),Je=1+.045*ce,ke=1+.015*ce*ut,Vt=30*Math.PI/180*Math.exp(-1*Math.pow((180/Math.PI*D-275)/25,2)),mt=2*Math.sqrt(Math.pow(ce,7)/(Math.pow(ce,7)+Math.pow(25,7))),je=-1*Math.sin(2*Vt)*mt;return Math.sqrt(Math.pow(me/(e*Ee),2)+Math.pow(ie/(t*Je),2)+Math.pow(Q/(r*ke),2)+je*ie/(t*Je)*Q/(r*ke))}},m0=(e=1,t=1)=>{let r=v("lab65");return(o,n)=>{let a=r(o),f=a.l,i=a.a,l=a.b,m=Math.sqrt(i*i+l*l),u=Math.atan2(l,i);u=u+2*Math.PI*(u<0);let s=r(n),h=s.l,c=s.a,b=s.b,M=Math.sqrt(c*c+b*b),g=Math.pow(f-h,2),z=Math.pow(m-M,2),L=Math.pow(i-c,2)+Math.pow(l-b,2)-z,H=Math.sqrt(Math.pow(m,4)/(Math.pow(m,4)+1900)),C=u>=164/180*Math.PI&&u<=345/180*Math.PI?.56+Math.abs(.2*Math.cos(u+168/180*Math.PI)):.36+Math.abs(.4*Math.cos(u+35/180*Math.PI)),$=f<16?.511:.040975*f/(1+.01765*f),N=.0638*m/(1+.0131*m)+.638,q=N*(H*C+1-H);return Math.sqrt(g/Math.pow(e*$,2)+z/Math.pow(t*N,2)+L/Math.pow(q,2))}},s0=()=>{let e=v("lab65");return(t,r)=>{let o=e(t),n=e(r),a=o.l-n.l,f=o.a-n.a,i=o.b-n.b;return Math.abs(a)+Math.sqrt(f*f+i*i)}},c0=()=>pe("yiq",[.5053,.299,.1957]),h0=()=>pe("itp",[518400,129600,518400]);var S=e=>{let t=e.reduce((o,n)=>{if(n!==void 0){let a=n*Math.PI/180;o.sin+=Math.sin(a),o.cos+=Math.cos(a)}return o},{sin:0,cos:0}),r=Math.atan2(t.sin,t.cos)*180/Math.PI;return r<0?360+r:r},Ho=e=>{let t=e.filter(r=>r!==void 0);return t.length?t.reduce((r,o)=>r+o,0)/t.length:void 0},vr=e=>typeof e=="function";function b0(e,t="rgb",r){let o=R(t),n=e.map(v(t));return o.channels.reduce((a,f)=>{let i=n.map(l=>l[f]).filter(l=>l!==void 0);if(i.length){let l;vr(r)?l=r:r&&vr(r[f])?l=r[f]:o.average&&vr(o.average[f])?l=o.average[f]:l=Ho,a[f]=l(i,f)}return a},{mode:t})}var x0={mode:"cubehelix",channels:["h","s","l","alpha"],parse:["--cubehelix"],serialize:"--cubehelix",ranges:{h:[0,360],s:[0,4.614],l:[0,1]},fromMode:{rgb:xr},toMode:{rgb:gr},interpolate:{h:{use:p,fixup:X},s:p,l:p,alpha:{use:p,fixup:y}},difference:{h:ee},average:{h:S}},Xo=x0;var g0=({l:e,a:t,b:r,alpha:o},n="lch")=>{t===void 0&&(t=0),r===void 0&&(r=0);let a=Math.sqrt(t*t+r*r),f={mode:n,l:e,c:a};return a&&(f.h=k(Math.atan2(r,t)*180/Math.PI)),o!==void 0&&(f.alpha=o),f},E=g0;var M0=({l:e,c:t,h:r,alpha:o},n="lab")=>{r===void 0&&(r=0);let a={mode:n,l:e,a:t?t*Math.cos(r/180*Math.PI):0,b:t?t*Math.sin(r/180*Math.PI):0};return o!==void 0&&(a.alpha=o),a},J=M0;var yt=Math.pow(29,3)/Math.pow(3,3),Tt=Math.pow(6,3)/Math.pow(29,3);var w={X:.9642956764295677,Y:1,Z:.8251046025104602},de={X:.3127/.329,Y:1,Z:(1-.3127-.329)/.329},Al=Math.pow(29,3)/Math.pow(3,3),ql=Math.pow(6,3)/Math.pow(29,3);var yr=e=>Math.pow(e,3)>Tt?Math.pow(e,3):(116*e-16)/yt,v0=({l:e,a:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=(e+16)/116,a=t/500+n,f=n-r/200,i={mode:"xyz65",x:yr(a)*de.X,y:yr(n)*de.Y,z:yr(f)*de.Z};return o!==void 0&&(i.alpha=o),i},Be=v0;var y0=e=>A(Be(e)),re=y0;var Tr=e=>e>Tt?Math.cbrt(e):(yt*e+16)/116,T0=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Tr(e/de.X),a=Tr(t/de.Y),f=Tr(r/de.Z),i={mode:"lab65",l:116*a-16,a:500*(n-a),b:200*(a-f)};return o!==void 0&&(i.alpha=o),i},Ze=T0;var z0=e=>{let t=Ze(O(e));return e.r===e.b&&e.b===e.g&&(t.a=t.b=0),t},oe=z0;var xe=.14444444444444443*Math.PI,Le=Math.cos(xe),Re=Math.sin(xe),zt=100/Math.log(139/100);var k0=({l:e,c:t,h:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n={mode:"lab65",l:(Math.exp(e*1/zt)-1)/.0039},a=(Math.exp(.0435*t*1*1)-1)/.075,f=a*Math.cos(r/180*Math.PI-xe),i=a*Math.sin(r/180*Math.PI-xe);return n.a=f*Le-i/.83*Re,n.b=f*Re+i/.83*Le,o!==void 0&&(n.alpha=o),n},we=k0;var L0=({l:e,a:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=t*Le+r*Re,a=.83*(r*Le-t*Re),f=Math.sqrt(n*n+a*a),i={mode:"dlch",l:zt/1*Math.log(1+.0039*e),c:Math.log(1+.075*f)/(.0435*1*1)};return i.c&&(i.h=k((Math.atan2(a,n)+xe)/Math.PI*180)),o!==void 0&&(i.alpha=o),i},_e=L0;var So=e=>we(E(e,"dlch")),Po=e=>J(_e(e),"dlab"),R0={mode:"dlab",parse:["--din99o-lab"],serialize:"--din99o-lab",toMode:{lab65:So,rgb:e=>re(So(e))},fromMode:{lab65:Po,rgb:e=>Po(oe(e))},channels:["l","a","b","alpha"],ranges:{l:[0,100],a:[-40.09,45.501],b:[-40.469,44.344]},interpolate:{l:p,a:p,b:p,alpha:{use:p,fixup:y}}},Co=R0;var w0={mode:"dlch",parse:["--din99o-lch"],serialize:"--din99o-lch",toMode:{lab65:we,dlab:e=>J(e,"dlab"),rgb:e=>re(we(e))},fromMode:{lab65:_e,dlab:e=>E(e,"dlch"),rgb:e=>_e(oe(e))},channels:["l","c","h","alpha"],ranges:{l:[0,100],c:[0,51.484],h:[0,360]},interpolate:{l:p,c:p,h:{use:p,fixup:X},alpha:{use:p,fixup:y}},difference:{h:te},average:{h:S}},$o=w0;function kt({h:e,s:t,i:r,alpha:o}){e=k(e!==void 0?e:0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.abs(e/60%2-1),a;switch(Math.floor(e/60)){case 0:a={r:r*(1+t*(3/(2-n)-1)),g:r*(1+t*(3*(1-n)/(2-n)-1)),b:r*(1-t)};break;case 1:a={r:r*(1+t*(3*(1-n)/(2-n)-1)),g:r*(1+t*(3/(2-n)-1)),b:r*(1-t)};break;case 2:a={r:r*(1-t),g:r*(1+t*(3/(2-n)-1)),b:r*(1+t*(3*(1-n)/(2-n)-1))};break;case 3:a={r:r*(1-t),g:r*(1+t*(3*(1-n)/(2-n)-1)),b:r*(1+t*(3/(2-n)-1))};break;case 4:a={r:r*(1+t*(3*(1-n)/(2-n)-1)),g:r*(1-t),b:r*(1+t*(3/(2-n)-1))};break;case 5:a={r:r*(1+t*(3/(2-n)-1)),g:r*(1-t),b:r*(1+t*(3*(1-n)/(2-n)-1))};break;default:a={r:r*(1-t),g:r*(1-t),b:r*(1-t)}}return a.mode="rgb",o!==void 0&&(a.alpha=o),a}function Lt({r:e,g:t,b:r,alpha:o}){e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.max(e,t,r),a=Math.min(e,t,r),f={mode:"hsi",s:e+t+r===0?0:1-3*a/(e+t+r),i:(e+t+r)/3};return n-a!==0&&(f.h=(n===e?(t-r)/(n-a)+(t<r)*6:n===t?(r-e)/(n-a)+2:(e-t)/(n-a)+4)*60),o!==void 0&&(f.alpha=o),f}var _0={mode:"hsi",toMode:{rgb:kt},parse:["--hsi"],serialize:"--hsi",fromMode:{rgb:Lt},channels:["h","s","i","alpha"],ranges:{h:[0,360]},gamut:"rgb",interpolate:{h:{use:p,fixup:X},s:p,i:p,alpha:{use:p,fixup:y}},difference:{h:ee},average:{h:S}},No=_0;function Rt({h:e,s:t,l:r,alpha:o}){e=k(e!==void 0?e:0),t===void 0&&(t=0),r===void 0&&(r=0);let n=r+t*(r<.5?r:1-r),a=n-(n-r)*2*Math.abs(e/60%2-1),f;switch(Math.floor(e/60)){case 0:f={r:n,g:a,b:2*r-n};break;case 1:f={r:a,g:n,b:2*r-n};break;case 2:f={r:2*r-n,g:n,b:a};break;case 3:f={r:2*r-n,g:a,b:n};break;case 4:f={r:a,g:2*r-n,b:n};break;case 5:f={r:n,g:2*r-n,b:a};break;default:f={r:2*r-n,g:2*r-n,b:2*r-n}}return f.mode="rgb",o!==void 0&&(f.alpha=o),f}function wt({r:e,g:t,b:r,alpha:o}){e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.max(e,t,r),a=Math.min(e,t,r),f={mode:"hsl",s:n===a?0:(n-a)/(1-Math.abs(n+a-1)),l:.5*(n+a)};return n-a!==0&&(f.h=(n===e?(t-r)/(n-a)+(t<r)*6:n===t?(r-e)/(n-a)+2:(e-t)/(n-a)+4)*60),o!==void 0&&(f.alpha=o),f}var H0=(e,t)=>{switch(t){case"deg":return+e;case"rad":return e/Math.PI*180;case"grad":return e/10*9;case"turn":return e*360}},Io=H0;var X0=new RegExp(`^hsla?\\(\\s*${Mo}${le}${he}${le}${he}\\s*(?:,\\s*${Ye}\\s*)?\\)$`),S0=e=>{let t=e.match(X0);if(!t)return;let r={mode:"hsl"};return t[3]!==void 0?r.h=+t[3]:t[1]!==void 0&&t[2]!==void 0&&(r.h=Io(t[1],t[2])),t[4]!==void 0&&(r.s=Math.min(Math.max(0,t[4]/100),1)),t[5]!==void 0&&(r.l=Math.min(Math.max(0,t[5]/100),1)),t[6]!==void 0?r.alpha=Math.max(0,Math.min(1,t[6]/100)):t[7]!==void 0&&(r.alpha=Math.max(0,Math.min(1,+t[7]))),r},kr=S0;function P0(e,t){if(!t||t[0]!=="hsl"&&t[0]!=="hsla")return;let r={mode:"hsl"},[,o,n,a,f]=t;if(o.type!==d.None){if(o.type===d.Percentage)return;r.h=o.value}if(n.type!==d.None){if(n.type===d.Hue)return;r.s=n.value/100}if(a.type!==d.None){if(a.type===d.Hue)return;r.l=a.value/100}return f.type!==d.None&&(r.alpha=Math.min(1,Math.max(0,f.type===d.Number?f.value:f.value/100))),r}var Lr=P0;var C0={mode:"hsl",toMode:{rgb:Rt},fromMode:{rgb:wt},channels:["h","s","l","alpha"],ranges:{h:[0,360]},gamut:"rgb",parse:[Lr,kr],serialize:e=>`hsl(${e.h!==void 0?e.h:"none"} ${e.s!==void 0?e.s*100+"%":"none"} ${e.l!==void 0?e.l*100+"%":"none"}${e.alpha<1?` / ${e.alpha}`:""})`,interpolate:{h:{use:p,fixup:X},s:p,l:p,alpha:{use:p,fixup:y}},difference:{h:ee},average:{h:S}},_t=C0;function He({h:e,s:t,v:r,alpha:o}){e=k(e!==void 0?e:0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.abs(e/60%2-1),a;switch(Math.floor(e/60)){case 0:a={r,g:r*(1-t*n),b:r*(1-t)};break;case 1:a={r:r*(1-t*n),g:r,b:r*(1-t)};break;case 2:a={r:r*(1-t),g:r,b:r*(1-t*n)};break;case 3:a={r:r*(1-t),g:r*(1-t*n),b:r};break;case 4:a={r:r*(1-t*n),g:r*(1-t),b:r};break;case 5:a={r,g:r*(1-t),b:r*(1-t*n)};break;default:a={r:r*(1-t),g:r*(1-t),b:r*(1-t)}}return a.mode="rgb",o!==void 0&&(a.alpha=o),a}function Xe({r:e,g:t,b:r,alpha:o}){e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.max(e,t,r),a=Math.min(e,t,r),f={mode:"hsv",s:n===0?0:1-a/n,v:n};return n-a!==0&&(f.h=(n===e?(t-r)/(n-a)+(t<r)*6:n===t?(r-e)/(n-a)+2:(e-t)/(n-a)+4)*60),o!==void 0&&(f.alpha=o),f}var $0={mode:"hsv",toMode:{rgb:He},parse:["--hsv"],serialize:"--hsv",fromMode:{rgb:Xe},channels:["h","s","v","alpha"],ranges:{h:[0,360]},gamut:"rgb",interpolate:{h:{use:p,fixup:X},s:p,v:p,alpha:{use:p,fixup:y}},difference:{h:ee},average:{h:S}},Ht=$0;function Xt({h:e,w:t,b:r,alpha:o}){if(t===void 0&&(t=0),r===void 0&&(r=0),t+r>1){let n=t+r;t/=n,r/=n}return He({h:e,s:r===1?1:1-t/(1-r),v:1-r,alpha:o})}function St(e){let t=Xe(e);if(t===void 0)return;let r=t.s!==void 0?t.s:0,o=t.v!==void 0?t.v:0,n={mode:"hwb",w:(1-r)*o,b:1-o};return t.h!==void 0&&(n.h=t.h),t.alpha!==void 0&&(n.alpha=t.alpha),n}function N0(e,t){if(!t||t[0]!=="hwb")return;let r={mode:"hwb"},[,o,n,a,f]=t;if(o.type!==d.None){if(o.type===d.Percentage)return;r.h=o.value}if(n.type!==d.None){if(n.type===d.Hue)return;r.w=n.value/100}if(a.type!==d.None){if(a.type===d.Hue)return;r.b=a.value/100}return f.type!==d.None&&(r.alpha=Math.min(1,Math.max(0,f.type===d.Number?f.value:f.value/100))),r}var Rr=N0;var I0={mode:"hwb",toMode:{rgb:Xt},fromMode:{rgb:St},channels:["h","w","b","alpha"],ranges:{h:[0,360]},gamut:"rgb",parse:[Rr],serialize:e=>`hwb(${e.h!==void 0?e.h:"none"} ${e.w!==void 0?e.w*100+"%":"none"} ${e.b!==void 0?e.b*100+"%":"none"}${e.alpha<1?` / ${e.alpha}`:""})`,interpolate:{h:{use:p,fixup:X},w:p,b:p,alpha:{use:p,fixup:y}},difference:{h:Mr},average:{h:S}},Oo=I0;var Se=.1593017578125,Ao=78.84375,Pe=.8359375,Ce=18.8515625,$e=18.6875;function Pt(e){if(e<0)return 0;let t=Math.pow(e,1/Ao);return 1e4*Math.pow(Math.max(0,t-Pe)/(Ce-$e*t),1/Se)}function Ct(e){if(e<0)return 0;let t=Math.pow(e/1e4,Se);return Math.pow((Pe+Ce*t)/(1+$e*t),Ao)}var wr=e=>Math.max(e/203,0),A0=({i:e,t,p:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Pt(e+.008609037037932761*t+.11102962500302593*r),a=Pt(e-.00860903703793275*t-.11102962500302599*r),f=Pt(e+.5600313357106791*t-.32062717498731885*r),i={mode:"xyz65",x:wr(2.070152218389422*n-1.3263473389671556*a+.2066510476294051*f),y:wr(.3647385209748074*n+.680566024947227*a-.0453045459220346*f),z:wr(-.049747207535812*n-.0492609666966138*a+1.1880659249923042*f)};return o!==void 0&&(i.alpha=o),i},$t=A0;var _r=(e=0)=>Math.max(e*203,0),q0=({x:e,y:t,z:r,alpha:o})=>{let n=_r(e),a=_r(t),f=_r(r),i=Ct(.3592832590121217*n+.6976051147779502*a-.0358915932320289*f),l=Ct(-.1920808463704995*n+1.1004767970374323*a+.0753748658519118*f),m=Ct(.0070797844607477*n+.0748396662186366*a+.8433265453898765*f),u=.5*i+.5*l,s=1.61376953125*i-3.323486328125*l+1.709716796875*m,h=4.378173828125*i-4.24560546875*l-.132568359375*m,c={mode:"itp",i:u,t:s,p:h};return o!==void 0&&(c.alpha=o),c},Nt=q0;var D0={mode:"itp",channels:["i","t","p","alpha"],parse:["--ictcp"],serialize:"--ictcp",toMode:{xyz65:$t,rgb:e=>A($t(e))},fromMode:{xyz65:Nt,rgb:e=>Nt(O(e))},ranges:{i:[0,.581],t:[-.369,.272],p:[-.164,.331]},interpolate:{i:p,t:p,p,alpha:{use:p,fixup:y}}},qo=D0;var E0=134.03437499999998,J0=16295499532821565e-27,Hr=e=>{if(e<0)return 0;let t=Math.pow(e/1e4,Se);return Math.pow((Pe+Ce*t)/(1+$e*t),E0)},Xr=(e=0)=>Math.max(e*203,0),j0=({x:e,y:t,z:r,alpha:o})=>{e=Xr(e),t=Xr(t),r=Xr(r);let n=1.15*e-.15*r,a=.66*t+.34*e,f=Hr(.41478972*n+.579999*a+.014648*r),i=Hr(-.20151*n+1.120649*a+.0531008*r),l=Hr(-.0166008*n+.2648*a+.6684799*r),m=(f+i)/2,u={mode:"jab",j:.44*m/(1-.56*m)-J0,a:3.524*f-4.066708*i+.542708*l,b:.199076*f+1.096799*i-1.295875*l};return o!==void 0&&(u.alpha=o),u},We=j0;var Y0=134.03437499999998,Do=16295499532821565e-27,Sr=e=>{if(e<0)return 0;let t=Math.pow(e,1/Y0);return 1e4*Math.pow((Pe-t)/($e*t-Ce),1/Se)},Pr=e=>e/203,G0=({j:e,a:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=(e+Do)/(.44+.56*(e+Do)),a=Sr(n+.13860504*t+.058047316*r),f=Sr(n-.13860504*t-.058047316*r),i=Sr(n-.096019242*t-.8118919*r),l={mode:"xyz65",x:Pr(1.661373024652174*a-.914523081304348*f+.23136208173913045*i),y:Pr(-.3250758611844533*a+1.571847026732543*f-.21825383453227928*i),z:Pr(-.090982811*a-.31272829*f+1.5227666*i)};return o!==void 0&&(l.alpha=o),l},Ue=G0;var B0=e=>{let t=We(O(e));return e.r===e.b&&e.b===e.g&&(t.a=t.b=0),t},Ke=B0;var Z0=e=>A(Ue(e)),Qe=Z0;var F0={mode:"jab",channels:["j","a","b","alpha"],parse:["--jzazbz"],serialize:"--jzazbz",fromMode:{rgb:Ke,xyz65:We},toMode:{rgb:Qe,xyz65:Ue},ranges:{j:[0,.222],a:[-.109,.129],b:[-.185,.134]},interpolate:{j:p,a:p,b:p,alpha:{use:p,fixup:y}}},Eo=F0;var W0=({j:e,a:t,b:r,alpha:o})=>{t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.sqrt(t*t+r*r),a={mode:"jch",j:e,c:n};return n&&(a.h=k(Math.atan2(r,t)*180/Math.PI)),o!==void 0&&(a.alpha=o),a},It=W0;var U0=({j:e,c:t,h:r,alpha:o})=>{r===void 0&&(r=0);let n={mode:"jab",j:e,a:t?t*Math.cos(r/180*Math.PI):0,b:t?t*Math.sin(r/180*Math.PI):0};return o!==void 0&&(n.alpha=o),n},Ot=U0;var K0={mode:"jch",parse:["--jzczhz"],serialize:"--jzczhz",toMode:{jab:Ot,rgb:e=>Qe(Ot(e))},fromMode:{rgb:e=>It(Ke(e)),jab:It},channels:["j","c","h","alpha"],ranges:{j:[0,.221],c:[0,.19],h:[0,360]},interpolate:{h:{use:p,fixup:X},c:p,j:p,alpha:{use:p,fixup:y}},difference:{h:te},average:{h:S}},Jo=K0;var ue=Math.pow(29,3)/Math.pow(3,3),Ne=Math.pow(6,3)/Math.pow(29,3);var Cr=e=>Math.pow(e,3)>Ne?Math.pow(e,3):(116*e-16)/ue,Q0=({l:e,a:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=(e+16)/116,a=t/500+n,f=n-r/200,i={mode:"xyz50",x:Cr(a)*w.X,y:Cr(n)*w.Y,z:Cr(f)*w.Z};return o!==void 0&&(i.alpha=o),i},ge=Q0;var V0=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Y({r:e*3.1341359569958707-t*1.6173863321612538-.4906619460083532*r,g:e*-.978795502912089+t*1.916254567259524+.03344273116131949*r,b:e*.07195537988411677-t*.2289768264158322+1.405386058324125*r});return o!==void 0&&(n.alpha=o),n},W=V0;var ea=e=>W(ge(e)),Ve=ea;var ta=e=>{let{r:t,g:r,b:o,alpha:n}=j(e),a={mode:"xyz50",x:.436065742824811*t+.3851514688337912*r+.14307845442264197*o,y:.22249319175623702*t+.7168870538238823*r+.06061979053616537*o,z:.013923904500943465*t+.09708128566574634*r+.7140993584005155*o};return n!==void 0&&(a.alpha=n),a},U=ta;var $r=e=>e>Ne?Math.cbrt(e):(ue*e+16)/116,ra=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=$r(e/w.X),a=$r(t/w.Y),f=$r(r/w.Z),i={mode:"lab",l:116*a-16,a:500*(n-a),b:200*(a-f)};return o!==void 0&&(i.alpha=o),i},Me=ra;var oa=e=>{let t=Me(U(e));return e.r===e.b&&e.b===e.g&&(t.a=t.b=0),t},et=oa;function na(e,t){if(!t||t[0]!=="lab")return;let r={mode:"lab"},[,o,n,a,f]=t;if(!(o.type===d.Hue||n.type===d.Hue||a.type===d.Hue))return o.type!==d.None&&(r.l=Math.min(Math.max(0,o.value),100)),n.type!==d.None&&(r.a=n.type===d.Number?n.value:n.value*125/100),a.type!==d.None&&(r.b=a.type===d.Number?a.value:a.value*125/100),f.type!==d.None&&(r.alpha=Math.min(1,Math.max(0,f.type===d.Number?f.value:f.value/100))),r}var Nr=na;var aa={mode:"lab",toMode:{xyz50:ge,rgb:Ve},fromMode:{xyz50:Me,rgb:et},channels:["l","a","b","alpha"],ranges:{l:[0,100],a:[-125,125],b:[-125,125]},parse:[Nr],serialize:e=>`lab(${e.l!==void 0?e.l:"none"} ${e.a!==void 0?e.a:"none"} ${e.b!==void 0?e.b:"none"}${e.alpha<1?` / ${e.alpha}`:""})`,interpolate:{l:p,a:p,b:p,alpha:{use:p,fixup:y}}},Ie=aa;var fa={...Ie,mode:"lab65",parse:["--lab-d65"],serialize:"--lab-d65",toMode:{xyz65:Be,rgb:re},fromMode:{xyz65:Ze,rgb:oe},ranges:{l:[0,100],a:[-125,125],b:[-125,125]}},jo=fa;function ia(e,t){if(!t||t[0]!=="lch")return;let r={mode:"lch"},[,o,n,a,f]=t;if(o.type!==d.None){if(o.type===d.Hue)return;r.l=Math.min(Math.max(0,o.value),100)}if(n.type!==d.None&&(r.c=Math.max(0,n.type===d.Number?n.value:n.value*150/100)),a.type!==d.None){if(a.type===d.Percentage)return;r.h=a.value}return f.type!==d.None&&(r.alpha=Math.min(1,Math.max(0,f.type===d.Number?f.value:f.value/100))),r}var Ir=ia;var la={mode:"lch",toMode:{lab:J,rgb:e=>Ve(J(e))},fromMode:{rgb:e=>E(et(e)),lab:E},channels:["l","c","h","alpha"],ranges:{l:[0,100],c:[0,150],h:[0,360]},parse:[Ir],serialize:e=>`lch(${e.l!==void 0?e.l:"none"} ${e.c!==void 0?e.c:"none"} ${e.h!==void 0?e.h:"none"}${e.alpha<1?` / ${e.alpha}`:""})`,interpolate:{h:{use:p,fixup:X},c:p,l:p,alpha:{use:p,fixup:y}},difference:{h:te},average:{h:S}},Oe=la;var pa={...Oe,mode:"lch65",parse:["--lch-d65"],serialize:"--lch-d65",toMode:{lab65:e=>J(e,"lab65"),rgb:e=>re(J(e,"lab65"))},fromMode:{rgb:e=>E(oe(e),"lch65"),lab65:e=>E(e,"lch65")},ranges:{l:[0,100],c:[0,150],h:[0,360]}},Yo=pa;var da=({l:e,u:t,v:r,alpha:o})=>{t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.sqrt(t*t+r*r),a={mode:"lchuv",l:e,c:n};return n&&(a.h=k(Math.atan2(r,t)*180/Math.PI)),o!==void 0&&(a.alpha=o),a},At=da;var ua=({l:e,c:t,h:r,alpha:o})=>{r===void 0&&(r=0);let n={mode:"luv",l:e,u:t?t*Math.cos(r/180*Math.PI):0,v:t?t*Math.sin(r/180*Math.PI):0};return o!==void 0&&(n.alpha=o),n},qt=ua;var Go=(e,t,r)=>4*e/(e+15*t+3*r),Bo=(e,t,r)=>9*t/(e+15*t+3*r),ma=Go(w.X,w.Y,w.Z),sa=Bo(w.X,w.Y,w.Z),ca=e=>e<=Ne?ue*e:116*Math.cbrt(e)-16,ha=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=ca(t/w.Y),a=Go(e,t,r),f=Bo(e,t,r);!isFinite(a)||!isFinite(f)?n=a=f=0:(a=13*n*(a-ma),f=13*n*(f-sa));let i={mode:"luv",l:n,u:a,v:f};return o!==void 0&&(i.alpha=o),i},Ae=ha;var ba=(e,t,r)=>4*e/(e+15*t+3*r),xa=(e,t,r)=>9*t/(e+15*t+3*r),ga=ba(w.X,w.Y,w.Z),Ma=xa(w.X,w.Y,w.Z),va=({l:e,u:t,v:r,alpha:o})=>{if(e===void 0&&(e=0),e===0)return{mode:"xyz50",x:0,y:0,z:0};t===void 0&&(t=0),r===void 0&&(r=0);let n=t/(13*e)+ga,a=r/(13*e)+Ma,f=w.Y*(e<=8?e/ue:Math.pow((e+16)/116,3)),i=f*(9*n)/(4*a),l=f*(12-3*n-20*a)/(4*a),m={mode:"xyz50",x:i,y:f,z:l};return o!==void 0&&(m.alpha=o),m},qe=va;var ya=e=>At(Ae(U(e))),Ta=e=>W(qe(qt(e))),za={mode:"lchuv",toMode:{luv:qt,rgb:Ta},fromMode:{rgb:ya,luv:At},channels:["l","c","h","alpha"],parse:["--lchuv"],serialize:"--lchuv",ranges:{l:[0,100],c:[0,176.956],h:[0,360]},interpolate:{h:{use:p,fixup:X},c:p,l:p,alpha:{use:p,fixup:y}},difference:{h:te},average:{h:S}},Zo=za;var ka={...Z,mode:"lrgb",toMode:{rgb:Y},fromMode:{rgb:j},parse:["srgb-linear"],serialize:"srgb-linear"},Fo=ka;var La={mode:"luv",toMode:{xyz50:qe,rgb:e=>W(qe(e))},fromMode:{xyz50:Ae,rgb:e=>Ae(U(e))},channels:["l","u","v","alpha"],parse:["--luv"],serialize:"--luv",ranges:{l:[0,100],u:[-84.936,175.042],v:[-125.882,87.243]},interpolate:{l:p,u:p,v:p,alpha:{use:p,fixup:y}}},Wo=La;var Ra=({r:e,g:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.cbrt(.412221469470763*e+.5363325372617348*t+.0514459932675022*r),a=Math.cbrt(.2119034958178252*e+.6806995506452344*t+.1073969535369406*r),f=Math.cbrt(.0883024591900564*e+.2817188391361215*t+.6299787016738222*r),i={mode:"oklab",l:.210454268309314*n+.7936177747023054*a-.0040720430116193*f,a:1.9779985324311684*n-2.42859224204858*a+.450593709617411*f,b:.0259040424655478*n+.7827717124575296*a-.8086757549230774*f};return o!==void 0&&(i.alpha=o),i},tt=Ra;var wa=e=>{let t=tt(j(e));return e.r===e.b&&e.b===e.g&&(t.a=t.b=0),t},ne=wa;var _a=({l:e,a:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Math.pow(e+.3963377773761749*t+.2158037573099136*r,3),a=Math.pow(e-.1055613458156586*t-.0638541728258133*r,3),f=Math.pow(e-.0894841775298119*t-1.2914855480194092*r,3),i={mode:"lrgb",r:4.076741636075957*n-3.3077115392580616*a+.2309699031821044*f,g:-1.2684379732850317*n+2.6097573492876887*a-.3413193760026573*f,b:-.0041960761386756*n-.7034186179359362*a+1.7076146940746117*f};return o!==void 0&&(i.alpha=o),i},K=_a;var Ha=e=>Y(K(e)),ae=Ha;function rt(e){let o=1.170873786407767;return .5*(o*e-.206+Math.sqrt((o*e-.206)*(o*e-.206)+4*.03*o*e))}function ve(e){return(e*e+.206*e)/(1.170873786407767*(e+.03))}function Xa(e,t){let r,o,n,a,f,i,l,m;-1.88170328*e-.80936493*t>1?(r=1.19086277,o=1.76576728,n=.59662641,a=.75515197,f=.56771245,i=4.0767416621,l=-3.3077115913,m=.2309699292):1.81444104*e-1.19445276*t>1?(r=.73956515,o=-.45954404,n=.08285427,a=.1254107,f=.14503204,i=-1.2684380046,l=2.6097574011,m=-.3413193965):(r=1.35733652,o=-.00915799,n=-1.1513021,a=-.50559606,f=.00692167,i=-.0041960863,l=-.7034186147,m=1.707614701);let u=r+o*e+n*t+a*e*e+f*e*t,s=.3963377774*e+.2158037573*t,h=-.1055613458*e-.0638541728*t,c=-.0894841775*e-1.291485548*t;{let b=1+u*s,M=1+u*h,g=1+u*c,z=b*b*b,L=M*M*M,H=g*g*g,C=3*s*b*b,$=3*h*M*M,N=3*c*g*g,q=6*s*s*b,me=6*h*h*M,ie=6*c*c*g,B=i*z+l*L+m*H,Q=i*C+l*$+m*N,se=i*q+l*me+m*ie;u=u-B*Q/(Q*Q-.5*B*se)}return u}function Or(e,t){let r=Xa(e,t),o=K({l:1,a:r*e,b:r*t}),n=Math.cbrt(1/Math.max(o.r,o.g,o.b)),a=n*r;return[n,a]}function Sa(e,t,r,o,n,a=null){a||(a=Or(e,t));let f;if((r-n)*a[1]-(a[0]-n)*o<=0)f=a[1]*n/(o*a[0]+a[1]*(n-r));else{f=a[1]*(n-1)/(o*(a[0]-1)+a[1]*(n-r));{let i=r-n,l=o,m=.3963377774*e+.2158037573*t,u=-.1055613458*e-.0638541728*t,s=-.0894841775*e-1.291485548*t,h=i+l*m,c=i+l*u,b=i+l*s;{let M=n*(1-f)+f*r,g=f*o,z=M+g*m,L=M+g*u,H=M+g*s,C=z*z*z,$=L*L*L,N=H*H*H,q=3*h*z*z,me=3*c*L*L,ie=3*b*H*H,B=6*h*h*z,Q=6*c*c*L,se=6*b*b*H,ce=4.0767416621*C-3.3077115913*$+.2309699292*N-1,D=4.0767416621*q-3.3077115913*me+.2309699292*ie,dt=4.0767416621*B-3.3077115913*Q+.2309699292*se,ut=D/(D*D-.5*ce*dt),Ee=-ce*ut,Je=-1.2684380046*C+2.6097574011*$-.3413193965*N-1,ke=-1.2684380046*q+2.6097574011*me-.3413193965*ie,Vt=-1.2684380046*B+2.6097574011*Q-.3413193965*se,mt=ke/(ke*ke-.5*Je*Vt),je=-Je*mt,xo=-.0041960863*C-.7034186147*$+1.707614701*N-1,er=-.0041960863*q-.7034186147*me+1.707614701*ie,zn=-.0041960863*B-.7034186147*Q+1.707614701*se,go=er/(er*er-.5*xo*zn),tr=-xo*go;Ee=ut>=0?Ee:1e6,je=mt>=0?je:1e6,tr=go>=0?tr:1e6,f+=Math.min(Ee,Math.min(je,tr))}}}return f}function ot(e,t,r=null){r||(r=Or(e,t));let o=r[0],n=r[1];return[n/o,n/(1-o)]}function Dt(e,t,r){let o=Or(t,r),n=Sa(t,r,e,1,e,o),a=ot(t,r,o),f=.11516993+1/(7.4477897+4.1590124*r+t*(-2.19557347+1.75198401*r+t*(-2.13704948-10.02301043*r+t*(-4.24894561+5.38770819*r+4.69891013*t)))),i=.11239642+1/(1.6132032-.68124379*r+t*(.40370612+.90148123*r+t*(-.27087943+.6122399*r+t*(.00299215-.45399568*r-.14661872*t)))),l=n/Math.min(e*a[0],(1-e)*a[1]),m=e*f,u=(1-e)*i,s=.9*l*Math.sqrt(Math.sqrt(1/(1/(m*m*m*m)+1/(u*u*u*u))));return m=e*.4,u=(1-e)*.8,[Math.sqrt(1/(1/(m*m)+1/(u*u))),s,n]}function nt(e){let t=e.l!==void 0?e.l:0,r=e.a!==void 0?e.a:0,o=e.b!==void 0?e.b:0,n={mode:"okhsl",l:rt(t)};e.alpha!==void 0&&(n.alpha=e.alpha);let a=Math.sqrt(r*r+o*o);if(!a)return n.s=0,n;let[f,i,l]=Dt(t,r/a,o/a),m;if(a<i){let u=0,s=.8*f,h=1-s/i;m=(a-u)/(s+h*(a-u))*.8}else{let u=i,s=.2*i*i*1.25*1.25/f,h=1-s/(l-i);m=.8+.2*((a-u)/(s+h*(a-u)))}return m&&(n.s=m,n.h=k(Math.atan2(o,r)*180/Math.PI)),n}function at(e){let t=e.h!==void 0?e.h:0,r=e.s!==void 0?e.s:0,o=e.l!==void 0?e.l:0,n={mode:"oklab",l:ve(o)};if(e.alpha!==void 0&&(n.alpha=e.alpha),!r||o===1)return n.a=n.b=0,n;let a=Math.cos(t/180*Math.PI),f=Math.sin(t/180*Math.PI),[i,l,m]=Dt(n.l,a,f),u,s,h,c;r<.8?(u=1.25*r,s=0,h=.8*i,c=1-h/l):(u=5*(r-.8),s=l,h=.2*l*l*1.25*1.25/i,c=1-h/(m-l));let b=s+u*h/(1-c*u);return n.a=b*a,n.b=b*f,n}var Pa={..._t,mode:"okhsl",channels:["h","s","l","alpha"],parse:["--okhsl"],serialize:"--okhsl",fromMode:{oklab:nt,rgb:e=>nt(ne(e))},toMode:{oklab:at,rgb:e=>ae(at(e))}},Uo=Pa;function ft(e){let t=e.l!==void 0?e.l:0,r=e.a!==void 0?e.a:0,o=e.b!==void 0?e.b:0,n=Math.sqrt(r*r+o*o),a=n?r/n:1,f=n?o/n:1,[i,l]=ot(a,f),m=.5,u=1-m/i,s=l/(n+t*l),h=s*t,c=s*n,b=ve(h),M=c*b/h,g=K({l:b,a:a*M,b:f*M}),z=Math.cbrt(1/Math.max(g.r,g.g,g.b,0));t=t/z,n=n/z*rt(t)/t,t=rt(t);let L={mode:"okhsv",s:n?(m+l)*c/(l*m+l*u*c):0,v:t?t/h:0};return L.s&&(L.h=k(Math.atan2(o,r)*180/Math.PI)),e.alpha!==void 0&&(L.alpha=e.alpha),L}function it(e){let t={mode:"oklab"};e.alpha!==void 0&&(t.alpha=e.alpha);let r=e.h!==void 0?e.h:0,o=e.s!==void 0?e.s:0,n=e.v!==void 0?e.v:0,a=Math.cos(r/180*Math.PI),f=Math.sin(r/180*Math.PI),[i,l]=ot(a,f),m=.5,u=1-m/i,s=1-o*m/(m+l-l*u*o),h=o*l*m/(m+l-l*u*o),c=ve(s),b=h*c/s,M=K({l:c,a:a*b,b:f*b}),g=Math.cbrt(1/Math.max(M.r,M.g,M.b,0)),z=ve(n*s),L=h*z/s;return t.l=z*g,t.a=L*a*g,t.b=L*f*g,t}var Ca={...Ht,mode:"okhsv",channels:["h","s","v","alpha"],parse:["--okhsv"],serialize:"--okhsv",fromMode:{oklab:ft,rgb:e=>ft(ne(e))},toMode:{oklab:it,rgb:e=>ae(it(e))}},Ko=Ca;function $a(e,t){if(!t||t[0]!=="oklab")return;let r={mode:"oklab"},[,o,n,a,f]=t;if(!(o.type===d.Hue||n.type===d.Hue||a.type===d.Hue))return o.type!==d.None&&(r.l=Math.min(Math.max(0,o.type===d.Number?o.value:o.value/100),1)),n.type!==d.None&&(r.a=n.type===d.Number?n.value:n.value*.4/100),a.type!==d.None&&(r.b=a.type===d.Number?a.value:a.value*.4/100),f.type!==d.None&&(r.alpha=Math.min(1,Math.max(0,f.type===d.Number?f.value:f.value/100))),r}var Ar=$a;var Na={...Ie,mode:"oklab",toMode:{lrgb:K,rgb:ae},fromMode:{lrgb:tt,rgb:ne},ranges:{l:[0,1],a:[-.4,.4],b:[-.4,.4]},parse:[Ar],serialize:e=>`oklab(${e.l!==void 0?e.l:"none"} ${e.a!==void 0?e.a:"none"} ${e.b!==void 0?e.b:"none"}${e.alpha<1?` / ${e.alpha}`:""})`},Qo=Na;function Ia(e,t){if(!t||t[0]!=="oklch")return;let r={mode:"oklch"},[,o,n,a,f]=t;if(o.type!==d.None){if(o.type===d.Hue)return;r.l=Math.min(Math.max(0,o.type===d.Number?o.value:o.value/100),1)}if(n.type!==d.None&&(r.c=Math.max(0,n.type===d.Number?n.value:n.value*.4/100)),a.type!==d.None){if(a.type===d.Percentage)return;r.h=a.value}return f.type!==d.None&&(r.alpha=Math.min(1,Math.max(0,f.type===d.Number?f.value:f.value/100))),r}var qr=Ia;var Oa={...Oe,mode:"oklch",toMode:{oklab:e=>J(e,"oklab"),rgb:e=>ae(J(e,"oklab"))},fromMode:{rgb:e=>E(ne(e),"oklch"),oklab:e=>E(e,"oklch")},parse:[qr],serialize:e=>`oklch(${e.l!==void 0?e.l:"none"} ${e.c!==void 0?e.c:"none"} ${e.h!==void 0?e.h:"none"}${e.alpha<1?` / ${e.alpha}`:""})`,ranges:{l:[0,1],c:[0,.4],h:[0,360]}},Vo=Oa;var Aa=e=>{let{r:t,g:r,b:o,alpha:n}=j(e),a={mode:"xyz65",x:.486570948648216*t+.265667693169093*r+.1982172852343625*o,y:.2289745640697487*t+.6917385218365062*r+.079286914093745*o,z:0*t+.0451133818589026*r+1.043944368900976*o};return n!==void 0&&(a.alpha=n),a},Et=Aa;var qa=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Y({r:e*2.4934969119414263-t*.9313836179191242-.402710784450717*r,g:e*-.8294889695615749+t*1.7626640603183465+.0236246858419436*r,b:e*.0358458302437845-t*.0761723892680418+.9568845240076871*r},"p3");return o!==void 0&&(n.alpha=o),n},Jt=qa;var Da={...Z,mode:"p3",parse:["display-p3"],serialize:"display-p3",fromMode:{rgb:e=>Jt(O(e)),xyz65:Jt},toMode:{rgb:e=>A(Et(e)),xyz65:Et}},en=Da;var Dr=e=>{let t=Math.abs(e);return t>=.001953125?Math.sign(e)*Math.pow(t,.5555555555555556):16*e},Ea=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n={mode:"prophoto",r:Dr(e*1.3457868816471585-t*.2555720873797946-.0511018649755453*r),g:Dr(e*-.5446307051249019+t*1.5082477428451466+.0205274474364214*r),b:Dr(e*0+t*0+1.2119675456389452*r)};return o!==void 0&&(n.alpha=o),n},jt=Ea;var Er=(e=0)=>{let t=Math.abs(e);return t>=.03125?Math.sign(e)*Math.pow(t,1.8):e/16},Ja=e=>{let t=Er(e.r),r=Er(e.g),o=Er(e.b),n={mode:"xyz50",x:.7977666449006423*t+.1351812974005331*r+.0313477341283922*o,y:.2880748288194013*t+.7118352342418731*r+899369387256e-16*o,z:0*t+0*r+.8251046025104602*o};return e.alpha!==void 0&&(n.alpha=e.alpha),n},Yt=Ja;var ja={...Z,mode:"prophoto",parse:["prophoto-rgb"],serialize:"prophoto-rgb",fromMode:{xyz50:jt,rgb:e=>jt(U(e))},toMode:{xyz50:Yt,rgb:e=>W(Yt(e))}},tn=ja;var rn=1.09929682680944,Ya=.018053968510807,Jr=e=>{let t=Math.abs(e);return t>Ya?(Math.sign(e)||1)*(rn*Math.pow(t,.45)-(rn-1)):4.5*e},Ga=({x:e,y:t,z:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n={mode:"rec2020",r:Jr(e*1.7166511879712683-t*.3556707837763925-.2533662813736599*r),g:Jr(e*-.6666843518324893+t*1.6164812366349395+.0157685458139111*r),b:Jr(e*.0176398574453108-t*.0427706132578085+.9421031212354739*r)};return o!==void 0&&(n.alpha=o),n},Gt=Ga;var on=1.09929682680944,Ba=.018053968510807,jr=(e=0)=>{let t=Math.abs(e);return t<Ba*4.5?e/4.5:(Math.sign(e)||1)*Math.pow((t+on-1)/on,1/.45)},Za=e=>{let t=jr(e.r),r=jr(e.g),o=jr(e.b),n={mode:"xyz65",x:.6369580483012911*t+.1446169035862083*r+.1688809751641721*o,y:.262700212011267*t+.6779980715188708*r+.059301716469862*o,z:0*t+.0280726930490874*r+1.0609850577107909*o};return e.alpha!==void 0&&(n.alpha=e.alpha),n},Bt=Za;var Fa={...Z,mode:"rec2020",fromMode:{xyz65:Gt,rgb:e=>Gt(O(e))},toMode:{xyz65:Bt,rgb:e=>A(Bt(e))},parse:["rec2020"],serialize:"rec2020"},nn=Fa;var fe=.0037930732552754493,Zt=Math.cbrt(fe);var Yr=e=>Math.cbrt(e)-Zt,Wa=e=>{let{r:t,g:r,b:o,alpha:n}=j(e),a=Yr(.3*t+.622*r+.078*o+fe),f=Yr(.23*t+.692*r+.078*o+fe),i=Yr(.2434226892454782*t+.2047674442449682*r+.5518098665095535*o+fe),l={mode:"xyb",x:(a-f)/2,y:(a+f)/2,b:i-(a+f)/2};return n!==void 0&&(l.alpha=n),l},Gr=Wa;var Br=e=>Math.pow(e+Zt,3),Ua=({x:e,y:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n=Br(e+t)-fe,a=Br(t-e)-fe,f=Br(r+t)-fe,i=Y({r:11.031566904639861*n-9.866943908131562*a-.16462299650829934*f,g:-3.2541473810744237*n+4.418770377582723*a-.16462299650829934*f,b:-3.6588512867136815*n+2.7129230459360922*a+1.9459282407775895*f});return o!==void 0&&(i.alpha=o),i},Zr=Ua;var Ka={mode:"xyb",channels:["x","y","b","alpha"],parse:["--xyb"],serialize:"--xyb",toMode:{rgb:Zr},fromMode:{rgb:Gr},ranges:{x:[-.0154,.0281],y:[0,.8453],b:[-.2778,.388]},interpolate:{x:p,y:p,b:p,alpha:{use:p,fixup:y}}},an=Ka;var Qa={mode:"xyz50",parse:["xyz-d50"],serialize:"xyz-d50",toMode:{rgb:W,lab:Me},fromMode:{rgb:U,lab:ge},channels:["x","y","z","alpha"],ranges:{x:[0,.964],y:[0,.999],z:[0,.825]},interpolate:{x:p,y:p,z:p,alpha:{use:p,fixup:y}}},fn=Qa;var Va=e=>{let{x:t,y:r,z:o,alpha:n}=e;t===void 0&&(t=0),r===void 0&&(r=0),o===void 0&&(o=0);let a={mode:"xyz50",x:1.0479298208405488*t+.0229467933410191*r-.0501922295431356*o,y:.0296278156881593*t+.990434484573249*r-.0170738250293851*o,z:-.0092430581525912*t+.0150551448965779*r+.7518742899580008*o};return n!==void 0&&(a.alpha=n),a},Fr=Va;var ef=e=>{let{x:t,y:r,z:o,alpha:n}=e;t===void 0&&(t=0),r===void 0&&(r=0),o===void 0&&(o=0);let a={mode:"xyz65",x:.9554734527042182*t-.0230985368742614*r+.0632593086610217*o,y:-.0283697069632081*t+1.0099954580058226*r+.021041398966943*o,z:.0123140016883199*t-.0205076964334779*r+1.3303659366080753*o};return n!==void 0&&(a.alpha=n),a},Wr=ef;var tf={mode:"xyz65",toMode:{rgb:A,xyz50:Fr},fromMode:{rgb:O,xyz50:Wr},ranges:{x:[0,.95],y:[0,1],z:[0,1.088]},channels:["x","y","z","alpha"],parse:["xyz","xyz-d65"],serialize:"xyz-d65",interpolate:{x:p,y:p,z:p,alpha:{use:p,fixup:y}}},ln=tf;var rf=({r:e,g:t,b:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n={mode:"yiq",y:.29889531*e+.58662247*t+.11448223*r,i:.59597799*e-.2741761*t-.32180189*r,q:.21147017*e-.52261711*t+.31114694*r};return o!==void 0&&(n.alpha=o),n},Ur=rf;var of=({y:e,i:t,q:r,alpha:o})=>{e===void 0&&(e=0),t===void 0&&(t=0),r===void 0&&(r=0);let n={mode:"rgb",r:e+.95608445*t+.6208885*r,g:e-.27137664*t-.6486059*r,b:e-1.10561724*t+1.70250126*r};return o!==void 0&&(n.alpha=o),n},Kr=of;var nf={mode:"yiq",toMode:{rgb:Kr},fromMode:{rgb:Ur},channels:["y","i","q","alpha"],parse:["--yiq"],serialize:"--yiq",ranges:{i:[-.595,.595],q:[-.522,.522]},interpolate:{y:p,i:p,q:p,alpha:{use:p,fixup:y}}},pn=nf;var af=(e,t)=>Math.round(e*(t=Math.pow(10,t)))/t,ff=(e=4)=>t=>typeof t=="number"?af(t,e):t,Qr=ff;var lt=Qr(2),pt=e=>Math.max(0,Math.min(1,e||0)),ye=e=>Math.round(pt(e)*255),Vr=v("rgb"),lf=v("hsl"),eo=e=>{if(e===void 0)return;let t=ye(e.r),r=ye(e.g),o=ye(e.b);return"#"+(1<<24|t<<16|r<<8|o).toString(16).slice(1)},dn=e=>{if(e===void 0)return;let t=ye(e.alpha!==void 0?e.alpha:1);return eo(e)+(256|t).toString(16).slice(1)},un=e=>{if(e===void 0)return;let t=ye(e.r),r=ye(e.g),o=ye(e.b);return e.alpha===void 0||e.alpha===1?`rgb(${t}, ${r}, ${o})`:`rgba(${t}, ${r}, ${o}, ${lt(pt(e.alpha))})`},mn=e=>{if(e===void 0)return;let t=lt(e.h||0),r=lt(pt(e.s)*100)+"%",o=lt(pt(e.l)*100)+"%";return e.alpha===void 0||e.alpha===1?`hsl(${t}, ${r}, ${o})`:`hsla(${t}, ${r}, ${o}, ${lt(pt(e.alpha))})`},pf=e=>{let t=P(e);if(!t)return;let r=R(t.mode);if(!r.serialize||typeof r.serialize=="string"){let o=`color(${r.serialize||`--${t.mode}`} `;return r.channels.forEach((n,a)=>{n!=="alpha"&&(o+=(a?" ":"")+(t[n]!==void 0?t[n]:"none"))}),t.alpha!==void 0&&t.alpha<1&&(o+=` / ${t.alpha}`),o+")"}if(typeof r.serialize=="function")return r.serialize(t)},df=e=>eo(Vr(e)),uf=e=>dn(Vr(e)),mf=e=>un(Vr(e)),sf=e=>mn(lf(e));var cf={normal:(e,t)=>t,multiply:(e,t)=>e*t,screen:(e,t)=>e+t-e*t,"hard-light":(e,t)=>t<.5?e*2*t:2*t*(1-e)-1,overlay:(e,t)=>e<.5?t*2*e:2*e*(1-t)-1,darken:(e,t)=>Math.min(e,t),lighten:(e,t)=>Math.max(e,t),"color-dodge":(e,t)=>e===0?0:t===1?1:Math.min(1,e/(1-t)),"color-burn":(e,t)=>e===1?1:t===0?0:1-Math.min(1,(1-e)/t),"soft-light":(e,t)=>t<.5?e-(1-2*t)*e*(1-e):e+(2*t-1)*((e<.25?((16*e-12)*e+4)*e:Math.sqrt(e))-e),difference:(e,t)=>Math.abs(e-t),exclusion:(e,t)=>e+t-2*e*t},hf=(e,t="normal",r="rgb")=>{let o=typeof t=="function"?t:cf[t],n=v(r),a=R(r).channels;return e.map(i=>{let l=n(i);return l.alpha===void 0&&(l.alpha=1),l}).reduce((i,l)=>{if(i===void 0)return l;let m=l.alpha+i.alpha*(1-l.alpha);return a.reduce((u,s)=>(s!=="alpha"&&(m===0?u[s]=0:(u[s]=l.alpha*(1-i.alpha)*l[s]+l.alpha*i.alpha*o(i[s],l[s])+(1-l.alpha)*i.alpha*i[s],u[s]=Math.max(0,Math.min(1,u[s]/m)))),u),{mode:r,alpha:m})})},bf=hf;var xf=([e,t])=>e+Math.random()*(t-e),gf=e=>Object.keys(e).reduce((t,r)=>{let o=e[r];return t[r]=Array.isArray(o)?o:[o,o],t},{}),Mf=(e="rgb",t={})=>{let r=R(e),o=gf(t);return r.channels.reduce((n,a)=>((o.alpha||a!=="alpha")&&(n[a]=xf(o[a]||r.ranges[a])),n),{mode:e})},vf=Mf;var Te=(e,t="rgb",r=!1)=>{let o=t?R(t).channels:null,n=t?v(t):P;return a=>{let f=n(a);if(!f)return;let i=(o||R(f.mode).channels).reduce((m,u)=>{let s=e(f[u],u,f,t);return s!==void 0&&!isNaN(s)&&(m[u]=s),m},{mode:f.mode});if(!r)return i;let l=P(a);return l&&l.mode!==i.mode?v(l.mode)(i):i}},to=(e,t,r)=>t!=="alpha"?(e||0)*(r.alpha!==void 0?r.alpha:1):e,ro=(e,t,r)=>t!=="alpha"&&r.alpha!==0?(e||0)/(r.alpha!==void 0?r.alpha:1):e,Ft=(e=1,t=0)=>(r,o)=>o!=="alpha"?r*e+t:r,yf=(e=1,t=1,r=0)=>(o,n)=>n!=="alpha"?e*Math.pow(o,t)+r:o;var Tf=e=>{e[0]===void 0&&(e[0]=0),e[e.length-1]===void 0&&(e[e.length-1]=1);let t=1,r,o,n,a;for(;t<e.length;){if(e[t]===void 0){for(o=t,n=e[t-1],r=t;e[r]===void 0;)r++;for(a=(e[r]-n)/(r-t+1);t<r;)e[t]=n+(t+1-o)*a,t++}else e[t]<e[t-1]&&(e[t]=e[t-1]);t++}return e},sn=Tf;var zf=(e=.5)=>t=>e<=0?1:e>=1?0:Math.pow(t,Math.log(.5)/Math.log(e)),oo=zf;var Wt=e=>typeof e=="function",ze=e=>e&&typeof e=="object",cn=e=>typeof e=="number",hn=(e,t="rgb",r,o)=>{let n=R(t),a=v(t),f=[],i=[],l={};e.forEach(h=>{Array.isArray(h)?(f.push(a(h[0])),i.push(h[1])):cn(h)||Wt(h)?l[i.length]=h:(f.push(a(h)),i.push(void 0))}),sn(i);let m=n.channels.reduce((h,c)=>{let b;return ze(r)&&ze(r[c])&&r[c].fixup?b=r[c].fixup:ze(n.interpolate[c])&&n.interpolate[c].fixup?b=n.interpolate[c].fixup:b=M=>M,h[c]=b(f.map(M=>M[c])),h},{});if(o){let h=f.map((c,b)=>n.channels.reduce((M,g)=>(M[g]=m[g][b],M),{mode:t}));m=n.channels.reduce((c,b)=>(c[b]=h.map(M=>{let g=o(M[b],b,M,t);return isNaN(g)?void 0:g}),c),{})}let u=n.channels.reduce((h,c)=>{let b;return Wt(r)?b=r:ze(r)&&Wt(r[c])?b=r[c]:ze(r)&&ze(r[c])&&r[c].use?b=r[c].use:Wt(n.interpolate[c])?b=n.interpolate[c]:ze(n.interpolate[c])&&(b=n.interpolate[c].use),h[c]=b(m[c]),h},{}),s=f.length-1;return h=>{if(h=Math.min(Math.max(0,h),1),h<=i[0])return f[0];if(h>i[s])return f[s];let c=0;for(;i[c]<h;)c++;let b=i[c-1],M=i[c]-b,g=(h-b)/M,z=l[c]||l[0];z!==void 0&&(cn(z)&&(z=oo((z-b)/M)),g=z(g));let L=(c-1+g)/s;return n.channels.reduce((H,C)=>{let $=u[C](L);return $!==void 0&&(H[C]=$),H},{mode:t})}},kf=(e,t="rgb",r)=>hn(e,t,r),bn=(e,t)=>(r,o="rgb",n)=>{let a=t?Te(t,o):void 0,f=hn(r,o,n,e);return a?i=>a(f(i)):f},Lf=bn(to,ro);var Ut=(e,t)=>(e+t)%t,xn=(e,t,r,o,n)=>{let a=n*n,f=a*n;return((1-3*n+3*a-f)*e+(4-6*a+3*f)*t+(1+3*n+3*a-3*f)*r+f*o)/6},no=e=>t=>{let r=e.length-1,o=t>=1?r-1:Math.max(0,Math.floor(t*r));return xn(o>0?e[o-1]:2*e[o]-e[o+1],e[o],e[o+1],o<r-1?e[o+2]:2*e[o+1]-e[o],(t-o/r)*r)},ao=e=>t=>{let r=e.length-1,o=Math.floor(t*r);return xn(e[Ut(o-1,e.length)],e[Ut(o,e.length)],e[Ut(o+1,e.length)],e[Ut(o+2,e.length)],(t-o/r)*r)};var gn=e=>{let t,r=e.length-1,o=new Array(r),n=new Array(r),a=new Array(r);for(o[1]=1/4,n[1]=(6*e[1]-e[0])/4,t=2;t<r;++t)o[t]=1/(4-o[t-1]),n[t]=(6*e[t]-(t==r-1?e[r]:0)-n[t-1])*o[t];for(a[0]=e[0],a[r]=e[r],r-1>0&&(a[r-1]=n[r-1]),t=r-2;t>0;--t)a[t]=n[t]-o[t]*a[t+1];return a},Rf=e=>no(gn(e)),wf=e=>ao(gn(e));var De=Math.sign,fo=Math.min,G=Math.abs,io=e=>{let t=e.length-1,r=[],o=[],n=[];for(let a=0;a<t;a++)r.push((e[a+1]-e[a])*t),o.push(a>0?.5*(e[a+1]-e[a-1])*t:void 0),n.push(a>0?(De(r[a-1])+De(r[a]))*fo(G(r[a-1]),G(r[a]),.5*G(o[a])):void 0);return[r,o,n]},lo=(e,t,r)=>{let o=e.length-1,n=o*o;return a=>{let f;a>=1?f=o-1:f=Math.max(0,Math.floor(a*o));let i=a-f/o,l=i*i,m=l*i;return(t[f]+t[f+1]-2*r[f])*n*m+(3*r[f]-2*t[f]-t[f+1])*o*l+t[f]*i+e[f]}},_f=e=>{if(e.length<3)return p(e);let t=e.length-1,[r,,o]=io(e);return o[0]=r[0],o[t]=r[t-1],lo(e,o,r)},Hf=e=>{if(e.length<3)return p(e);let t=e.length-1,[r,o,n]=io(e);return o[0]=(e[1]*2-e[0]*1.5-e[2]*.5)*t,o[t]=(e[t]*1.5-e[t-1]*2+e[t-2]*.5)*t,n[0]=o[0]*r[0]<=0?0:G(o[0])>2*G(r[0])?2*r[0]:o[0],n[t]=o[t]*r[t-1]<=0?0:G(o[t])>2*G(r[t-1])?2*r[t-1]:o[t],lo(e,n,r)},Xf=e=>{let t=e.length-1,[r,o,n]=io(e);o[0]=.5*(e[1]-e[t])*t,o[t]=.5*(e[0]-e[t-1])*t;let a=(e[0]-e[t])*t,f=a;return n[0]=(De(a)+De(r[0]))*fo(G(a),G(r[0]),.5*G(o[0])),n[t]=(De(r[t-1])+De(f))*fo(G(r[t-1]),G(f),.5*G(o[t])),lo(e,n,r)};var Sf=(e=1)=>e===1?t=>t:t=>Math.pow(t,e),po=Sf;var Pf=(e=2,t=1)=>{let r=po(t);if(e<2)return e<1?[]:[r(.5)];let o=[];for(let n=0;n<e;n++)o.push(r(n/(e-1)));return o},Cf=Pf;var Mn=v("rgb"),vn=e=>{let t={mode:e.mode,r:Math.max(0,Math.min(e.r!==void 0?e.r:0,1)),g:Math.max(0,Math.min(e.g!==void 0?e.g:0,1)),b:Math.max(0,Math.min(e.b!==void 0?e.b:0,1))};return e.alpha!==void 0&&(t.alpha=e.alpha),t},yn=e=>vn(Mn(e)),Tn=e=>e!==void 0&&(e.r===void 0||e.r>=0&&e.r<=1)&&(e.g===void 0||e.g>=0&&e.g<=1)&&(e.b===void 0||e.b>=0&&e.b<=1);function uo(e){return Tn(Mn(e))}function Kt(e="rgb"){let{gamut:t}=R(e);if(!t)return o=>!0;let r=v(typeof t=="string"?t:e);return o=>Tn(r(o))}function $f(e){return e=P(e),e===void 0||uo(e)?e:v(e.mode)(yn(e))}function mo(e="rgb"){let{gamut:t}=R(e);if(!t)return a=>P(a);let r=typeof t=="string"?t:e,o=v(r),n=Kt(r);return a=>{let f=P(a);if(!f)return;let i=o(f);if(n(i))return f;let l=vn(i);return f.mode===l.mode?l:v(f.mode)(l)}}function Nf(e,t="lch",r="rgb"){e=P(e);let o=r==="rgb"?uo:Kt(r),n=r==="rgb"?yn:mo(r);if(e===void 0||o(e))return e;let a=v(e.mode);e=v(t)(e);let f={...e,c:0};if(!o(f))return a(n(f));let i=0,l=e.c!==void 0?e.c:0,m=R(t).ranges.c,u=(m[1]-m[0])/Math.pow(2,13),s=f.c;for(;l-i>u;)f.c=i+(l-i)*.5,o(f)?(s=f.c,i=f.c):l=f.c;return a(o(f)?f:{...f,c:s})}function If(e="rgb",t="oklch",r=pe("oklch"),o=.02){let n=v(e),a=R(e);if(!a.gamut)return u=>n(u);let f=Kt(e),i=mo(e),l=v(t),{ranges:m}=R(t);if(!m.l||!m.c)throw new Error("LCH-like space expected");return u=>{if(u=P(u),u===void 0)return;let s={...l(u)};if(s.l===void 0&&(s.l=0),s.c===void 0&&(s.c=0),s.l>=m.l[1]){let g={...a.white,mode:e};return u.alpha!==void 0&&(g.alpha=u.alpha),g}if(s.l<=m.l[0]){let g={...a.black,mode:e};return u.alpha!==void 0&&(g.alpha=u.alpha),g}if(f(s))return n(s);let h=0,c=s.c,b=(m.c[1]-m.c[0])/4e3,M=i(s);for(;c-h>b;)s.c=(h+c)*.5,M=i(s),f(s)||r&&o>0&&r(s,M)<=o?h=s.c:c=s.c;return n(f(s)?s:M)}}var Of=(e,t=pe(),r=o=>o)=>{let o=e.map((n,a)=>({color:r(n),i:a}));return(n,a=1,f=1/0)=>(isFinite(a)&&(a=Math.max(1,Math.min(a,o.length-1))),o.forEach(i=>{i.d=t(n,i.color)}),o.sort((i,l)=>i.d-l.d).slice(0,a).filter(i=>i.d<f).map(i=>e[i.i]))},Af=Of;var so=e=>Math.max(e,0),co=e=>Math.max(Math.min(e,1),0),qf=(e,t,r)=>e===void 0||t===void 0?void 0:e+r*(t-e),Df=e=>{let t=1-co(e);return[.393+.607*t,.769-.769*t,.189-.189*t,0,.349-.349*t,.686+.314*t,.168-.168*t,0,.272-.272*t,.534-.534*t,.131+.869*t,0,0,0,0,1]},Ef=e=>{let t=so(e);return[.213+.787*t,.715-.715*t,.072-.072*t,0,.213-.213*t,.715+.285*t,.072-.072*t,0,.213-.213*t,.715-.715*t,.072+.928*t,0,0,0,0,1]},Jf=e=>{let t=1-co(e);return[.2126+.7874*t,.7152-.7152*t,.0722-.0722*t,0,.2126-.2126*t,.7152+.2848*t,.0722-.0722*t,0,.2126-.2126*t,.7152-.7152*t,.0722+.9278*t,0,0,0,0,1]},jf=e=>{let t=Math.PI*e/180,r=Math.cos(t),o=Math.sin(t);return[.213+r*.787-o*.213,.715-r*.715-o*.715,.072-r*.072+o*.928,0,.213-r*.213+o*.143,.715+r*.285+o*.14,.072-r*.072-o*.283,0,.213-r*.213-o*.787,.715-r*.715+o*.715,.072+r*.928+o*.072,0,0,0,0,1]},Qt=(e,t,r=!1)=>{let o=v(t),n=R(t).channels;return a=>{let f=o(a);if(!f)return;let i={mode:t},l,m=n.length;for(let s=0;s<e.length;s++)l=n[Math.floor(s/m)],f[l]!==void 0&&(i[l]=(i[l]||0)+e[s]*(f[n[s%m]]||0));if(!r)return i;let u=P(a);return u&&i.mode!==u.mode?v(u.mode)(i):i}},Yf=(e=1,t="rgb")=>{let r=so(e);return Te(Ft(r),t,!0)},Gf=(e=1,t="rgb")=>{let r=so(e);return Te(Ft(r,(1-r)/2),t,!0)},Bf=(e=1,t="rgb")=>Qt(Df(e),t,!0),Zf=(e=1,t="rgb")=>Qt(Ef(e),t,!0),Ff=(e=1,t="rgb")=>Qt(Jf(e),t,!0),Wf=(e=1,t="rgb")=>{let r=co(e);return Te((o,n)=>n==="alpha"?o:qf(r,1-r,o),t,!0)},Uf=(e=0,t="rgb")=>Qt(jf(e),t,!0);var Kf=v("rgb"),Qf=[[1,0,-0,0,1,0,-0,-0,1],[.856167,.182038,-.038205,.029342,.955115,.015544,-.00288,-.001563,1.004443],[.734766,.334872,-.069637,.05184,.919198,.028963,-.004928,-.004209,1.009137],[.630323,.465641,-.095964,.069181,.890046,.040773,-.006308,-.007724,1.014032],[.539009,.579343,-.118352,.082546,.866121,.051332,-.007136,-.011959,1.019095],[.458064,.679578,-.137642,.092785,.846313,.060902,-.007494,-.016807,1.024301],[.38545,.769005,-.154455,.100526,.829802,.069673,-.007442,-.02219,1.029632],[.319627,.849633,-.169261,.106241,.815969,.07779,-.007025,-.028051,1.035076],[.259411,.923008,-.18242,.110296,.80434,.085364,-.006276,-.034346,1.040622],[.203876,.990338,-.194214,.112975,.794542,.092483,-.005222,-.041043,1.046265],[.152286,1.052583,-.204868,.114503,.786281,.099216,-.003882,-.048116,1.051998]],Vf=[[1,0,-0,0,1,0,-0,-0,1],[.866435,.177704,-.044139,.049567,.939063,.01137,-.003453,.007233,.99622],[.760729,.319078,-.079807,.090568,.889315,.020117,-.006027,.013325,.992702],[.675425,.43385,-.109275,.125303,.847755,.026942,-.00795,.018572,.989378],[.605511,.52856,-.134071,.155318,.812366,.032316,-.009376,.023176,.9862],[.547494,.607765,-.155259,.181692,.781742,.036566,-.01041,.027275,.983136],[.498864,.674741,-.173604,.205199,.754872,.039929,-.011131,.030969,.980162],[.457771,.731899,-.18967,.226409,.731012,.042579,-.011595,.034333,.977261],[.422823,.781057,-.203881,.245752,.709602,.044646,-.011843,.037423,.974421],[.392952,.82361,-.216562,.263559,.69021,.046232,-.01191,.040281,.97163],[.367322,.860646,-.227968,.280085,.672501,.047413,-.01182,.04294,.968881]],ei=[[1,0,-0,0,1,0,-0,-0,1],[.92667,.092514,-.019184,.021191,.964503,.014306,.008437,.054813,.93675],[.89572,.13333,-.02905,.029997,.9454,.024603,.013027,.104707,.882266],[.905871,.127791,-.033662,.026856,.941251,.031893,.01341,.148296,.838294],[.948035,.08949,-.037526,.014364,.946792,.038844,.010853,.193991,.795156],[1.017277,.027029,-.044306,-.006113,.958479,.047634,.006379,.248708,.744913],[1.104996,-.046633,-.058363,-.032137,.971635,.060503,.001336,.317922,.680742],[1.193214,-.109812,-.083402,-.058496,.97941,.079086,-.002346,.403492,.598854],[1.257728,-.139648,-.118081,-.078003,.975409,.102594,-.003316,.501214,.502102],[1.278864,-.125333,-.153531,-.084748,.957674,.127074,-989e-6,.601151,.399838],[1.255528,-.076749,-.178779,-.078411,.930809,.147602,.004733,.691367,.3039]],ho=(e,t)=>{let r=Math.max(0,Math.min(1,t)),o=Math.round(r/.1),n=Math.round(r%.1),a=e[o];if(n>0&&o<e.length-1){let f=e[o+1];a=a.map((i,l)=>V(a[l],f[l],n))}return f=>{let i=P(f);if(i===void 0)return;let{r:l,g:m,b:u}=Kf(i),s={mode:"rgb",r:a[0]*l+a[1]*m+a[2]*u,g:a[3]*l+a[4]*m+a[5]*u,b:a[6]*l+a[7]*m+a[8]*u};return i.alpha!==void 0&&(s.alpha=i.alpha),v(i.mode)(s)}},ti=(e=1)=>ho(Qf,e),ri=(e=1)=>ho(Vf,e),oi=(e=1)=>ho(ei,e);var ni=e=>e*e*(3-2*e),ai=e=>.5-Math.sin(Math.asin(1-2*e)/3);var fi=e=>e*e*e*(e*(e*6-15)+10),ii=fi;var li=e=>(1-Math.cos(e*Math.PI))/2,pi=li;function bo(e){let t=v("lrgb")(e);return .2126*t.r+.7152*t.g+.0722*t.b}function di(e,t){let r=bo(e),o=bo(t);return(Math.max(r,o)+.05)/(Math.min(r,o)+.05)}var R5=T(zo),w5=T(Xo),_5=T(Co),H5=T($o),X5=T(No),S5=T(_t),P5=T(Ht),C5=T(Oo),$5=T(qo),N5=T(Eo),I5=T(Jo),O5=T(Ie),A5=T(jo),q5=T(Oe),D5=T(Yo),E5=T(Zo),J5=T(Fo),j5=T(Wo),Y5=T(Uo),G5=T(Ko),B5=T(Qo),Z5=T(Vo),F5=T(en),W5=T(tn),U5=T(nn),K5=T(Z),Q5=T(an),V5=T(fn),e2=T(ln),t2=T(pn);export{R5 as a98,b0 as average,S as averageAngle,Ho as averageNumber,bf as blend,ur as blerp,Nf as clampChroma,mo as clampGamut,$f as clampRgb,rr as colorsNamed,gt as convertA98ToXyz65,gr as convertCubehelixToRgb,we as convertDlchToLab65,kt as convertHsiToRgb,Rt as convertHslToRgb,He as convertHsvToRgb,Xt as convertHwbToRgb,$t as convertItpToXyz65,It as convertJabToJch,Qe as convertJabToRgb,Ue as convertJabToXyz65,Ot as convertJchToJab,_e as convertLab65ToDlch,re as convertLab65ToRgb,Be as convertLab65ToXyz65,E as convertLabToLch,Ve as convertLabToRgb,ge as convertLabToXyz50,J as convertLchToLab,qt as convertLchuvToLuv,tt as convertLrgbToOklab,Y as convertLrgbToRgb,At as convertLuvToLchuv,qe as convertLuvToXyz50,at as convertOkhslToOklab,it as convertOkhsvToOklab,K as convertOklabToLrgb,nt as convertOklabToOkhsl,ft as convertOklabToOkhsv,ae as convertOklabToRgb,Et as convertP3ToXyz65,Yt as convertProphotoToXyz50,Bt as convertRec2020ToXyz65,xr as convertRgbToCubehelix,Lt as convertRgbToHsi,wt as convertRgbToHsl,Xe as convertRgbToHsv,St as convertRgbToHwb,Ke as convertRgbToJab,et as convertRgbToLab,oe as convertRgbToLab65,j as convertRgbToLrgb,ne as convertRgbToOklab,Gr as convertRgbToXyb,U as convertRgbToXyz50,O as convertRgbToXyz65,Ur as convertRgbToYiq,Zr as convertXybToRgb,Me as convertXyz50ToLab,Ae as convertXyz50ToLuv,jt as convertXyz50ToProphoto,W as convertXyz50ToRgb,Wr as convertXyz50ToXyz65,Mt as convertXyz65ToA98,Nt as convertXyz65ToItp,We as convertXyz65ToJab,Ze as convertXyz65ToLab65,Jt as convertXyz65ToP3,Gt as convertXyz65ToRec2020,A as convertXyz65ToRgb,Fr as convertXyz65ToXyz50,Kr as convertYiqToRgb,v as converter,w5 as cubehelix,p0 as differenceCie76,d0 as differenceCie94,u0 as differenceCiede2000,m0 as differenceCmc,pe as differenceEuclidean,te as differenceHueChroma,Mr as differenceHueNaive,ee as differenceHueSaturation,s0 as differenceHyab,h0 as differenceItp,c0 as differenceKotsarenkoRamos,uo as displayable,_5 as dlab,H5 as dlch,po as easingGamma,pi as easingInOutSine,oo as easingMidpoint,ii as easingSmootherstep,ni as easingSmoothstep,ai as easingSmoothstepInverse,Yf as filterBrightness,Gf as filterContrast,ri as filterDeficiencyDeuter,ti as filterDeficiencyProt,oi as filterDeficiencyTrit,Ff as filterGrayscale,Uf as filterHueRotate,Wf as filterInvert,Zf as filterSaturate,Bf as filterSepia,y as fixupAlpha,f0 as fixupHueDecreasing,a0 as fixupHueIncreasing,n0 as fixupHueLonger,X as fixupHueShorter,pf as formatCss,df as formatHex,uf as formatHex8,sf as formatHsl,mf as formatRgb,R as getMode,X5 as hsi,S5 as hsl,P5 as hsv,C5 as hwb,Kt as inGamut,kf as interpolate,bn as interpolateWith,Lf as interpolateWithPremultipliedAlpha,p as interpolatorLinear,mr as interpolatorPiecewise,no as interpolatorSplineBasis,ao as interpolatorSplineBasisClosed,_f as interpolatorSplineMonotone,Hf as interpolatorSplineMonotone2,Xf as interpolatorSplineMonotoneClosed,Rf as interpolatorSplineNatural,wf as interpolatorSplineNaturalClosed,$5 as itp,N5 as jab,I5 as jch,O5 as lab,A5 as lab65,q5 as lch,D5 as lch65,E5 as lchuv,V as lerp,J5 as lrgb,j5 as luv,ro as mapAlphaDivide,to as mapAlphaMultiply,yf as mapTransferGamma,Ft as mapTransferLinear,Te as mapper,zo as modeA98,Xo as modeCubehelix,Co as modeDlab,$o as modeDlch,No as modeHsi,_t as modeHsl,Ht as modeHsv,Oo as modeHwb,qo as modeItp,Eo as modeJab,Jo as modeJch,Ie as modeLab,jo as modeLab65,Oe as modeLch,Yo as modeLch65,Zo as modeLchuv,Fo as modeLrgb,Wo as modeLuv,Uo as modeOkhsl,Ko as modeOkhsv,Qo as modeOklab,Vo as modeOklch,en as modeP3,tn as modeProphoto,nn as modeRec2020,Z as modeRgb,an as modeXyb,fn as modeXyz50,ln as modeXyz65,pn as modeYiq,Af as nearest,Y5 as okhsl,G5 as okhsv,B5 as oklab,Z5 as oklch,F5 as p3,fr as parse,nr as parseHex,Lr as parseHsl,kr as parseHslLegacy,Rr as parseHwb,Nr as parseLab,Ir as parseLch,or as parseNamed,Ar as parseOklab,qr as parseOklch,pr as parseRgb,ar as parseRgbLegacy,dr as parseTransparent,W5 as prophoto,vf as random,U5 as rec2020,In as removeParser,K5 as rgb,Qr as round,Cf as samples,eo as serializeHex,dn as serializeHex8,mn as serializeHsl,un as serializeRgb,If as toGamut,Zn as trilerp,Bn as unlerp,T as useMode,yo as useParser,di as wcagContrast,bo as wcagLuminance,Q5 as xyb,V5 as xyz50,e2 as xyz65,t2 as yiq};
diff --git a/docs/api.md b/docs/api.md
deleted file mode 100644
index 3408d811..00000000
--- a/docs/api.md
+++ /dev/null
@@ -1,1904 +0,0 @@
----
-layout: default.njk
-title: API Reference
-codebase: 'https://github.com/evercoder/culori/blob/main'
----
-
-<details>
-<summary>API table of contents</summary>
-<ul class='api-toc'>
-<li><a href='#color-spaces'>a98</a></li>
-<li><a href='#average'>average</a></li>
-<li><a href='#averageAngle'>averageAngle</a></li>
-<li><a href='#averageNumber'>averageNumber</a></li>
-<li><a href='#blend'>blend</a></li>
-<li><a href='#blerp'>blerp</a></li>
-<li><a href='#clampChroma'>clampChroma</a></li>
-<li><a href='#clampRgb'>clampRgb</a></li>
-<li><a href='#colorsNamed'>colorsNamed</a></li>
-<li><a href='#converter'>converter</a></li>
-<li><a href='#color-spaces'>cubehelix</a></li>
-<li><a href='#differenceCie76'>differenceCie76</a></li>
-<li><a href='#differenceCie94'>differenceCie94</a></li>
-<li><a href='#differenceCiede2000'>differenceCiede2000</a></li>
-<li><a href='#differenceCmc'>differenceCmc</a></li>
-<li><a href='#differenceEuclidean'>differenceEuclidean</a></li>
-<li><a href='#differenceHueChroma'>differenceHueChroma</a></li>
-<li><a href='#differenceHueNaive'>differenceHueNaive</a></li>
-<li><a href='#differenceHueSaturation'>differenceHueSaturation</a></li>
-<li><a href='#differenceHyab'>differenceHyab</a></li>
-<li><a href='#differenceKotsarenkoRamos'>differenceKotsarenkoRamos</a></li>
-<li><a href='#differenceItp'>differenceItp</a></li>
-<li><a href='#displayable'>displayable</a></li>
-<li><a href='#color-spaces'>dlab</a></li>
-<li><a href='#color-spaces'>dlch</a></li>
-<li><a href='#easingGamma'>easingGamma</a></li>
-<li><a href='#easingInOutSine'>easingInOutSine</a></li>
-<li><a href='#easingMidpoint'>easingMidpoint</a></li>
-<li><a href='#easingSmootherstep'>easingSmootherstep</a></li>
-<li><a href='#easingSmoothstep'>easingSmoothstep</a></li>
-<li><a href='#easingSmoothstepInverse'>easingSmoothstepInverse</a></li>
-<li><a href='#filterBrightness'>filterBrightness</a></li>
-<li><a href='#filterContrast'>filterContrast</a></li>
-<li><a href='#filterDeficiencyDeuter'>filterDeficiencyDeuter</a></li>
-<li><a href='#filterDeficiencyProt'>filterDeficiencyProt</a></li>
-<li><a href='#filterDeficiencyTrit'>filterDeficiencyTrit</a></li>
-<li><a href='#filterGrayscale'>filterGrayscale</a></li>
-<li><a href='#filterHueRotate'>filterHueRotate</a></li>
-<li><a href='#filterInvert'>filterInvert</a></li>
-<li><a href='#filterSaturate'>filterSaturate</a></li>
-<li><a href='#filterSepia'>filterSepia</a></li>
-<li><a href='#fixupAlpha'>fixupAlpha</a></li>
-<li><a href='#fixupHueDecreasing'>fixupHueDecreasing</a></li>
-<li><a href='#fixupHueIncreasing'>fixupHueIncreasing</a></li>
-<li><a href='#fixupHueLonger'>fixupHueLonger</a></li>
-<li><a href='#fixupHueShorter'>fixupHueShorter</a></li>
-<li><a href='#formatCss'>formatCss</a></li>
-<li><a href='#formatHex'>formatHex</a></li>
-<li><a href='#formatHex8'>formatHex8</a></li>
-<li><a href='#formatHsl'>formatHsl</a></li>
-<li><a href='#formatRgb'>formatRgb</a></li>
-<li><a href='#getMode'>getMode</a></li>
-<li><a href='#color-spaces'>hsi</a></li>
-<li><a href='#color-spaces'>hsl</a></li>
-<li><a href='#color-spaces'>hsv</a></li>
-<li><a href='#color-spaces'>hwb</a></li>
-<li><a href='#inGamut'>inGamut</a></li>
-<li><a href='#interpolate'>interpolate</a></li>
-<li><a href='#interpolateWith'>interpolateWith</a></li>
-<li><a href='#interpolateWithPremultipliedAlpha'>interpolateWithPremultipliedAlpha</a></li>
-<li><a href='#interpolatorLinear'>interpolatorLinear</a></li>
-<li><a href='#interpolatorPiecewise'>interpolatorPiecewise</a></li>
-<li><a href='#interpolatorSplineBasis'>interpolatorSplineBasis</a></li>
-<li><a href='#interpolatorSplineBasisClosed'>interpolatorSplineBasisClosed</a></li>
-<li><a href='#interpolatorSplineMonotone'>interpolatorSplineMonotone</a></li>
-<li><a href='#interpolatorSplineMonotone2'>interpolatorSplineMonotone2</a></li>
-<li><a href='#interpolatorSplineMonotoneClosed'>interpolatorSplineMonotoneClosed</a></li>
-<li><a href='#interpolatorSplineNatural'>interpolatorSplineNatural</a></li>
-<li><a href='#interpolatorSplineNaturalClosed'>interpolatorSplineNaturalClosed</a></li>
-<li><a href='#color-spaces'>itp</a></li>
-<li><a href='#color-spaces'>jab</a></li>
-<li><a href='#color-spaces'>jch</a></li>
-<li><a href='#color-spaces'>lab65</a></li>
-<li><a href='#color-spaces'>lab</a></li>
-<li><a href='#color-spaces'>lch65</a></li>
-<li><a href='#color-spaces'>lch</a></li>
-<li><a href='#color-spaces'>lchuv</a></li>
-<li><a href='#lerp'>lerp</a></li>
-<li><a href='#color-spaces'>lrgb</a></li>
-<li><a href='#color-spaces'>luv</a></li>
-<li><a href='#mapAlphaDivide'>mapAlphaDivide</a></li>
-<li><a href='#mapAlphaMultiply'>mapAlphaMultiply</a></li>
-<li><a href='#mapTransferGamma'>mapTransferGamma</a></li>
-<li><a href='#mapTransferLinear'>mapTransferLinear</a></li>
-<li><a href='#mapper'>mapper</a></li>
-<li><a href='#nearest'>nearest</a></li>
-<li><a href='#color-spaces'>oklab</a></li>
-<li><a href='#color-spaces'>oklch</a></li>
-<li><a href='#parse'>parse</a></li>
-<li><a href='#color-spaces'>p3</a></li>
-<li><a href='#color-spaces'>prophoto</a></li>
-<li><a href='#random'>random</a></li>
-<li><a href='#color-spaces'>rec2020</a></li>
-<li><a href='#color-spaces'>rgb</a></li>
-<li><a href='#round'>round</a></li>
-<li><a href='#samples'>samples</a></li>
-<li><a href='#toGamut'>toGamut</a></li>
-<li><a href='#trilerp'>trilerp</a></li>
-<li><a href='#unlerp'>unlerp</a></li>
-<li><a href='#useMode'>useMode</a></li>
-<li><a href='#wcagContrast'>wcagContrast</a></li>
-<li><a href='#wcagLuminance'>wcagLuminance</a></li>
-<li><a href='#color-spaces'>xyb</a></li>
-<li><a href='#color-spaces'>xyz50</a></li>
-<li><a href='#color-spaces'>xyz65</a></li>
-<li><a href='#color-spaces'>yiq</a></li>
-</ul>
-</details>
-
-## Colors are plain objects
-
-Culori does not have a _Color_ class. Instead, it uses plain objects to represent colors:
-
-```js
-/* A RGB color */
-{
-  mode: 'rgb',
-  r: 0.1,
-  g: 0.2,
-  b: 1,
-  alpha: 1
-}
-```
-
-The object needs to have a `mode` property that identifies the color space, and values for each channel in that particular color space (see the [Color Spaces](/color-spaces) page for the channels and ranges expected for each color space). Optionally, the `alpha` property is used for the color's alpha channel.
-
-## Parsing and conversion
-
-<a id="parse" href="#parse">#</a> **parse**(_string_) → _color_ or _undefined_
-
-<span aria-label='Source:'>☞</span> [src/parse.js]({{codebase}}/src/parse.js)
-
-Parses a string and returns the corresponding _color_. The color will be in the matching color space, e.g. RGB for hex strings, HSL for `hsl(…, …, …)` strings, et cetera. If no built-in parsers can match the string, the function will return `undefined`.
-
-```js
-import { parse } from 'culori';
-
-/* A named color */
-parse('red');
-// ⇒ { r: 1, g: 0, b: 0, mode: 'rgb' }
-
-/* A hex color */
-parse('#ff0000');
-// ⇒ { r: 1, g: 0, b: 0, mode: 'rgb' }
-
-/* A HSL color */
-parse('hsl(60 50% 10% / 100%)');
-// ⇒ { h: 60, s: 0.5, b: 0.1, alpha: 1, mode: 'hsl' }
-
-/* A Lab color */
-parse('lab(100% -50 50)');
-// ⇒ { l: 100, a: -50, b: 50, mode: 'lab' }
-```
-
-In most cases, instead of using `parse()` directly (which only operates on strings), you'll want to use a [`converter()`](#converter), which accepts strings and color objects and returns objects in a predictable color space.
-
-<a id="converter" href="#converter">#</a> **converter**(_mode = "rgb"_) → _function (color or String)_
-
-<span aria-label='Source:'>☞</span> [src/converter.js]({{codebase}}/src/converter.js)
-
-Returns a _converter_: a function that can convert any color to the _mode_ color space.
-
-```js
-import { converter } from 'culori';
-
-let rgb = converter('rgb');
-let lab = converter('lab');
-
-rgb('#f0f0f0');
-// ⇒ { mode: "rgb", r: 0.49…, g: 0.49…, b: 0.49… }
-
-lab('#f0f0f0');
-// ⇒ { mode: "lab", l: 94.79…, a: 0, b: 0 }
-```
-
-Converters accept either strings (which will be parsed with `parse()` under the hood) or color objects. If the `mode` key is absent from the color object passed to a converter, it's assumed to be in the converter's color space.
-
-## Formatting
-
-These methods serialize colors to strings, in various formats.
-
-<a id="formatHex" href="#formatHex">#</a> **formatHex**(_color_ or _string_) → _string_
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Returns the hex string for the given color. The color's `alpha` channel is omitted, and the red, green, and blue channels are clamped to the the interval `[0, 255]`, i.e. colors that are not displayable are serialized as if they'd been passed through the `clampRgb` method.
-
-```js
-import { formatHex } from 'culori';
-
-formatHex('red');
-// ⇒ "#ff0000"
-```
-
-<a id="formatHex8" href="#formatHex8">#</a> **formatHex8**(_color_ or _string_) → _string_
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Returns the 8-character hex string for the given color. The red, green, blue, and alpha channels are clamped to the the interval `[0, 255]`, i.e. colors that are not displayable are serialized as if they'd been passed through the `clampRgb` method.
-
-```js
-import { formatHex8 } from 'culori';
-
-formatHex8({ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0.5 });
-// ⇒ "#ff000080"
-```
-
-<a id="formatRgb" href="#formatRgb">#</a> **formatRgb**(_color_ or _string_) → _string_
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Returns the `rgb(…)` / `rgba(…)` string for the given color. Fully opaque colors will be serialized as `rgb()`, and semi-transparent colors as `rgba()`, in accordance with the [CSSOM standard serialization](https://drafts.csswg.org/cssom/#serialize-a-css-component-value). Like in the case of `formatHex`, the red, green, and blue channels are clamped to the interval `[0, 255]`.
-
-```js
-import { formatRgb } from 'culori';
-
-formatRgb('lab(50 0 0 / 25%)');
-// ⇒ "rgba(119, 119, 119, 0.25)"
-```
-
-<a id="formatHsl" href="#formatHsl">#</a> **formatHsl**(_color_ or _string_) → _string_
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Returns the `hsl(…)` / `hsla(…)` string for the given color. Fully opaque colors will be serialized as `hsl()`, and semi-transparent colors as `hsla()`. All values are rounded to a precision of two digits. The Saturation and Lightness are clamped to the interval `[0%, 100%]`.
-
-```js
-import { formatHsl } from 'culori';
-
-formatHsl('lab(50 0 0 / 25%)');
-// ⇒ 'hsla(194.33, 0%, 46.63%, 0.25)'
-```
-
-<a id="formatCss" href="#formatCss">#</a> **formatCss**(_color_ or _string_) → _string_
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Returns a CSS string for the given color, based on the CSS Color Level 4 specification. A few color spaces, such as `hsl` or `lab`, have their own functional representation in CSS. We use that whenever possible; the `hsl` color space is represented as `hsl(h% s l / alpha)`. Predefined color spaces are represented using the `color()` notation with the appropriate identifier for the color space, e.g. `color(display-p3 r g b / alpha)`. All other colors paces use the `color()` notation with a dashed identifier. For example, `jab` is represented as `color(--jzazbz j a b / alpha)`.
-
-You can find the exact string produced for each color space under the _Serialized as_ entry on the [Color Spaces](/color-spaces) page.
-
-Channel values are serialized as-is, with no change in the precision. To avoid compatibility issues, sRGB colors are represented as `color(srgb r g b / alpha)` rather than `rgb(r, g, b, alpha)`. For the latter, use the [`formatRgb()`](#formatRgb) method instead.
-
-An alpha of exactly `1` is omitted from the representation.
-
-**Note:** The strings returned by these methods are not widely supported in current browsers and should not be used in CSS as-is.
-
-```js
-import { formatCss } from 'culori';
-
-/* 
-	A mode with its own function notation.
-*/
-formatCss({ mode: 'hsl', h: 30, s: 1, l: 0.5, alpha: 0.5 });
-// ⇒ 'hsl(30 100% 50% / 0.5)'
-
-/*
-	A predefined color space.
- */
-formatCss({ mode: 'p3', r: 0.5, s: 0.25, b: 1, alpha: 1 });
-// ⇒ 'color(display-p3 0.5 0.25 1)'
-
-/*
-	sRGB colors.
- */
-formatCss({ mode: 'rgb', r: 0.5, s: 0.25, b: 1, alpha: 0.25 });
-// ⇒ 'color(srgb 0.5 0.25 1 / 0.25)'
-
-/*
-	A custom color space.
- */
-formatCss({ mode: 'lrgb', r: 0.5, s: 0.25, b: 1, alpha: 0.25 });
-// ⇒ 'color(--srgb-linear 0.5 0.25 1 / 0.25)'
-```
-
-## Gamut mapping
-
-Some color spaces (Lab and LCh in particular) allow you to express colors that can't be displayed on-screen. The methods below allow you to identify when that's the case and to produce displayable versions of the colors.
-
-<a id="inGamut" href="#inGamut">#</a> **inGamut**(_mode = "rgb"_) → _function (color | string)_
-
-<span aria-label='Source:'>☞</span> [src/clamp.js]({{codebase}}/src/clamp.js)
-
-Given a color space, returns a function with which to check whether a particular color is within the gamut of that color space. 
-
-This is meant to be used with RGB-based color spaces and their derivates (`hsl`, `hsv`, etc.). If the color space has no gamut limits, the function will always return `true`, regardless of the color passed to it. To find out which color spaces have gamut limits, see the [Color Spaces](/color-spaces/) page.
-
-```js
-import { inGamut } from 'culori';
-
-const inRgb = inGamut('rgb');
-
-inRgb('red');
-// ⇒ true
-
-inRgb('color(srgb 1.1 0 0)');
-// ⇒ false
-```
-
-<a id="displayable" href="#displayable">#</a> **displayable**(_color_ or _string_) → _boolean_
-
-<span aria-label='Source:'>☞</span> [src/clamp.js]({{codebase}}/src/clamp.js)
-
-Checks whether a particular color fits inside the sRGB gamut. Equivalent to `inGamut('rgb')`.
-
-```js
-import { displayable } from 'culori';
-
-displayable('red');
-// ⇒ true
-
-displayable('color(srgb 1.1 0 0)');
-// ⇒ false
-```
-
-<a id="clampRgb" href="#clampRgb">#</a> **clampRgb**(_color_ or _string_) → _color_
-
-<span aria-label='Source:'>☞</span> [src/clamp.js]({{codebase}}/src/clamp.js)
-
-Obtains a displayable version of the color by clamping the `r`, `g`, `b` channel values of the color's RGB representation to the interval `[0, 1]`. The returned color is in the same color space as the original color.
-
-This is the faster, simpler, way to make a color displayable. It's what browsers do when you use a CSS color whose channels exceed the gamut. For example, `rgb(300 100 200)` is interpreted as `rgb(255 100 200)`.
-
-Because clamping individual red, green, and blue values independently can alter their proportions in the final color, it often changes the color's hue.
-
-```js
-import { clampRgb } from 'culori';
-
-// RGB clamping:
-clampRgb('lab(50% 100 100)');
-// ⇒ { mode: "lab", l: 54.29…, a: 80.81…, b: 69.88… }
-```
-
-<a id="clampGamut" href="#clampGamut">#</a> **clampGamut**(_mode = 'rgb'_) → _function(color | string)_
-
-This function extends the functionality of `clampRgb` to other color spaces. Given a color space, it returns a function with which to obtain colors within the gamut of that color space. 
-
-If the color space has no gamut limits, colors are returned unchanged. To find out which color spaces have gamut limits, see the [Color Spaces](/color-spaces/) page.
-
-The in-gamut color is always returned in the color space of the original color.
-
-```js
-import { formatCss, clampGamut } from 'culori';
-
-const crimson = 'color(display-p3 0.8 0.1 0.3)';
-const toRgb = clampGamut('rgb');
-
-formatCss(toRgb(crimson));
-// ⇒ 'color(display-p3 0.801… 0.169… 0.302…)'
-```
-
-<span aria-label='Source:'>☞</span> [src/clamp.js]({{codebase}}/src/clamp.js)
-
-<a id="clampChroma" href="#clampChroma">#</a> **clampChroma**(_color_ or _string_, _mode = 'lch'_, _rgbGamut = 'rgb'_) → _color_
-
-<span aria-label='Source:'>☞</span> [src/clamp.js]({{codebase}}/src/clamp.js)
-
-Obtains a displayable version of the color by converting it to a temporary color space containing a Chroma channel, then looking for the closest Chroma value that's displayable for the given Lightness and Hue. Compared to `clampRgb`, the function has the advantage of preserving the hue of the original color. The displayable color returned by this function will be converted back to the original color space.
-
-```js
-import { clampChroma } from 'culori';
-
-clampChroma('lab(50% 100 100)');
-// ⇒ { mode: 'lab', l:50.00…, a: 63.11…, b: 63.11… }
-```
-
-By default, the color is converted to `lch` to perform the clamping, but any color space that contains a Chroma dimension can be used by sending an explicit `mode` argument.
-
-Likewise, the destination RGB gamut can be overriden with the corresponding parameter.
-
-```js
-import { clampChroma } from 'culori';
-
-clampChroma({ mode: 'oklch', l: 0.5, c: 0.16, h: 180 }, 'oklch');
-// ⇒ { mode: 'oklch', l: 0.5, c: 0.09, h: 180 }
-```
-
-In general, chroma clamping is more accurate and computationally simpler when performed in the color's original space, where possible. Here's some sample code that uses the color's own `mode` for color spaces containing a Chroma dimension, and `lch` otherwise:
-
-```js
-import { clampChroma } from 'culori';
-
-clampChroma(color, color.c !== undefined ? color.mode : 'lch');
-```
-
-If the chroma-finding algorithm fails to find a displayable color (which can happen when not even the achromatic version, with `Chroma = 0`, is displayable), the method falls back to the `clampRgb` method, as a last resort.
-
-The function uses [the bisection method](https://en.wikipedia.org/wiki/Bisection_method) to speed up the search for the largest Chroma value. However, due to discontinuities in the CIELCh color space, the function is not guaranteed to return the optimal result. [See this discussion](https://github.com/d3/d3-color/issues/33) for details.
-
-<a id="toGamut" href="#toGamut">#</a> **toGamut**(_dest = 'rgb'_, _mode = 'oklch'_, _delta = differenceEuclidean('oklch')_, _jnd = 0.02_) → _function (color | string)_
-
-<span aria-label='Source:'>☞</span> [src/clamp.js]({{codebase}}/src/clamp.js)
-
-Obtain a color that's in the `dest` gamut, by first converting it to the `mode` color space and then finding the largest chroma that's in gamut, similar to `clampChroma()`.
-
-The color returned is in the `dest` color space.
-
-```js
-import { p3, toGamut } from 'culori';
-
-const color = 'lch(80% 150 60)';
-
-p3(color);
-// ⇒ { mode: "p3", r: 1.229…, g: 0.547…, b: -0.073… }
-
-const toP3 = toGamut('p3');
-toP3(color);
-// ⇒ { mode: "p3", r: 0.999…, g: 0.696…, b: 0.508… }
-```
-
-To address the shortcomings of `clampChroma`, which can sometimes produce colors more desaturated than necessary, the test used in the binary search is replaced with “is color is roughly in gamut”, by comparing the candidate to the clipped version (obtained with `clampGamut`). The test passes if the colors are not to dissimilar, judged by the `delta` color difference function and an associated `jnd` just-noticeable difference value.
-
-The default arguments for this function correspond to [the gamut mapping algorithm](https://drafts.csswg.org/css-color/#css-gamut-mapping) defined in the CSS Color Module Level 4 spec, but the algorithm itself is slightly different.
-
-The “roughly in gamut” aspect of the algorithm can be disabled by passing `null` for the `delta` color difference function:
-
-```js
-import { toGamut } from 'culori';
-const clampToP3 = toGamut('p3', 'oklch', null);
-```
-
-The algorithm expects an LCH-like color space, containing lightness and chroma components, for the `mode` argument.
-
-## Interpolation
-
-In any color space, colors occupy positions given by their values for each channel. Interpolating colors means tracing a line through the coordinates of these colors, and figuring out what colors reside on the line at various positions.
-
-<img src='{{"/img/red-blue.png" | url }}' height='20' alt='red and blue, linearly interpolated'/>
-
-Above is the path between red and blue in the RGB color space. Going from left to right, we start at red and steadily blend in more and more blue as we progress, until the color is fully blue at destination. This is a _linear interpolation_ between two colors.
-
-<a id="interpolate" href="#interpolate">#</a> **interpolate**(_colors_, _mode = "rgb"_, _overrides_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/interpolate.js]({{codebase}}/src/interpolate/interpolate.js)
-
-Returns an _interpolator_ in the _mode_ color space for an array of _colors_. The interpolator is a function that accepts a value _t_ in the interval `[0, 1]` and returns the interpolated color in the _mode_ color space.
-
-The colors in the array can be in any color space, or they can even be strings.
-
-```js
-import { interpolate } from 'culori';
-
-let grays = interpolate(['#fff', '#000']);
-grays(0.5);
-// ⇒ { mode: 'rgb', r: 0.5, g: 0.5, b: 0.5 }
-```
-
-By default, colors in all spaces are interpolated linearly across all channels. You can override the way specific channels are interpolated with the _overrides_ object, the third argument of `interpolate()`.
-
-```js
-import { interpolate, interpolatorSplineBasis } from 'culori';
-
-let my_interpolator = interpolate(['blue', 'red'], 'lch', {
-	// spline instead of linear interpolation:
-	h: interpolatorSplineBasis
-});
-```
-
-There are a few interpolation methods available, listed below. Depending on the channel, the numeric values can be interpreted/interpolated in various _modes_. The hue channel, for example, is interpolated by taking into account the _shortest path around the hue circle_ (`fixupHue`). And the `fixupAlpha` mode assumes an _undefined_ alpha is `1`.
-
-### Color stop positions
-
-You can specify positions of color stops to interpolate in the way they're defined in the [CSS Images Module Level 4][css-images-4] specification:
-
-```js
-import { interpolate } from 'culori';
-
-interpolate(['red', ['green', 0.25], 'blue']);
-```
-
-In the image below, you can see the effect of interpolating with evenly-spaced colors (1) vs. positioned colors stops (2):
-
-![Evenly spaced vs. positions]({{"/img/evenly-spaced-vs-positions.png" | url }})
-
-To specify a positioned color stop, use an array that contains the color followed by its position. The color stops should be specified in ascending order.
-
-For omitted (implicit) positions, we apply the rules [from the spec][css-images-4]:
-
-1. if the first color doesn't have a position, it's assumed to be `0`; if the last color doesn't have a position, it's assumed to be `1`;
-2. any other color stops that don't have a position will be evenly distributed along the gradient line between the positioned color stops.
-
-### Easing functions
-
-You can add easing functions between any two colors in the array:
-
-```js
-import { interpolate } from 'culori';
-
-const easeIn = t => t * t;
-interpolate(['red', easeIn, 'green']);
-```
-
-Any function in the _colors_ array will be interpreted as an easing function, which is (for our purposes), a function that takes an argument `t ∈ [0, 1]` and returns a value `v ∈ [0, 1]`.
-
-To apply the same easing function between all color pairs, instead of individual ones, add the easing as the first element in the array:
-
-```js
-import { interpolate } from 'culori';
-
-const easeIn = t => t * t;
-
-// this form:
-interpolate([easeIn, 'red', 'green', 'blue']);
-
-// is equivalent to:
-interpolate(['red', easeIn, 'green', easeIn, 'blue']);
-```
-
-The easing function can alternatively be applied the hard way:
-
-```js
-import { interpolate, interpolatorPiecewise, lerp } from 'culori';
-
-const easeIn = t => t * t;
-
-interpolate(
-	['red', 'green', 'blue'],
-	'rgb',
-	interpolatorPiecewise((a, b, t) => lerp(a, b)(easeIn(t)))
-);
-```
-
-This formula can be helpful if you wanted to apply a different easing function per channel:
-
-```js
-import { interpolate, interpolatorPiecewise, lerp } from 'culori';
-function piecewiseEasing(easingFn) {
-	return interpolatorPiecewise((a, b, t) => lerp(a, b)(easingFn(t)));
-}
-
-interpolate(['red', 'green', 'blue'], 'rgb', {
-	r: piecewiseEasing(easeIn),
-	g: piecewiseEasing(easeOut),
-	b: piecewiseEasing(easeInOut)
-});
-```
-
-Culori comes with [just a few](#built-in-easing-functions) easing functions, but you can find several online:
-
--   [some classic easing functions](https://gist.github.com/gre/1650294);
--   [eases](https://github.com/mattdesl/eases) by Matt DesLauriers;
--   [bezier-easing](https://github.com/gre/bezier-easing) by Gaëtan Renaudeau builds `cubic-bezier` easings as defined in the [CSS Easing Functions Level 1][css-easing-1] spec;
--   [d3-scale](https://github.com/d3/d3-scale) lets you set the scale's domain and range to `[0, 1]`.
-
-### Interpolation hints
-
-Any number in the _colors_ array will be interpreted as an [interpolation hint](https://drafts.csswg.org/css-images-4/#color-stop-syntax):
-
-```js
-import { interpolate } from 'culori';
-
-// interpolation hint:
-interpolate(['red', 0.25, 'green']);
-```
-
-As opposed to how current browsers implement the CSS spec ([see discussion](https://github.com/w3c/csswg-drafts/issues/3931)), interpolation hints _do not_ affect color stop positions in Culori.
-
-<h3 id='built-in-easing-functions'>Built-in easing functions</h3>
-
-<a id="easingMidpoint" href="#easingMidpoint">#</a> **easingMidpoint**(_H = 0.5_)
-
-<span aria-label='Source:'>☞</span> [src/easing/midpoint.js]({{codebase}}/src/easing/midpoint.js)
-
-[Proposed here][midpoint], the `midpoint` easing function lets you shift the midpoint of a gradient like in tools such as Adobe Photoshop. You can use it with [`interpolate()`](#interpolate) as an alternative to interpolation hints:
-
-```js
-import { interpolate, easingMidpoint } from 'culori';
-// Explicit midpoint easing:
-interpolate(['red', easingMidpoint(0.25), 'blue']);
-
-// ...is equivalent to:
-interpolate(['red', 0.25, 'blue']);
-```
-
-<a id="easingSmoothstep" href="#easingSmoothstep">#</a> **easingSmoothstep**
-
-<span aria-label='Source:'>☞</span> [src/easing/smoothstep.js]({{codebase}}/src/easing/smoothstep.js)
-
-The [Smoothstep][smoothstep] easing function.
-
-<a id="easingSmoothstepInverse" href="#easingSmoothstepInverse">#</a> **easingSmoothstep**
-
-<span aria-label='Source:'>☞</span> [src/easing/smoothstep.js]({{codebase}}/src/easing/smoothstep.js)
-
-The inverse of the [Smoothstep][smoothstep] easing function.
-
-<a id="easingSmootherstep" href="#easingSmootherstep">#</a> **easingSmootherstep**
-
-<span aria-label='Source:'>☞</span> [src/easing/smootherstep.js]({{codebase}}/src/easing/smootherstep.js)
-
-Smootherstep is a variant of the [Smoothstep][smoothstep] easing function.
-
-<a id="easingInOutSine" href="#easingInOutSine">#</a> **easingInOutSine**
-
-<span aria-label='Source:'>☞</span> [src/easing/inOutSine.js]({{codebase}}/src/easing/inOutSine.js)
-
-Sinusoidal in-out easing. Can be used to create, for example, a cosine interpolation [as described by Paul Bourke](http://paulbourke.net/miscellaneous/interpolation/):
-
-```js
-import { interpolate, easingInOutSine } from 'culori';
-interpolate([easingInOutSine, 'red', 'green', 'blue']);
-```
-
-<a id="easingGamma" href="#easingGamma">#</a> **easingGamma**(_γ = 1_) → _function(t)_
-
-<span aria-label='Source:'>☞</span> [src/easing/gamma.js]({{codebase}}/src/easing/gamma.js)
-
-The [gamma](https://en.wikipedia.org/wiki/Gamma_correction) easing.
-
-```js
-import { samples, easingGamma } from 'culori';
-samples(5).map(easingGamma(2));
-// ⇒ [0, 0.0625, 0.25, 0.5625, 1]
-```
-
-### Interpolation methods
-
-<div class='api-figure-grid'>
-<figure>
-  <img src='/img/interpolator-linear.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorLinear'>
-      <code><strong>interpolatorLinear</strong></code>
-    </a>
-  </figcaption>
-</figure>
-<figure>
-  <img src='/img/interpolator-basis.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorSplineBasis'>
-      <code><strong>interpolatorSplineBasis</strong></code>
-    </a>
-  </figcaption>
-</figure>
-<figure>
-  <img src='/img/interpolator-basis-closed.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorSplineBasisClosed'>
-      <code><strong>interpolatorSplineBasisClosed</strong></code>
-    </a>
-  </figcaption>
-</figure>
-<figure>
-  <img src='/img/interpolator-natural.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorSplineNatural'>
-      <code><strong>interpolatorSplineNatural</strong></code>
-    </a>
-  </figcaption>
-</figure>
-<figure>
-  <img src='/img/interpolator-natural-closed.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorSplineNaturalClosed'>
-      <code><strong>interpolatorSplineNaturalClosed</strong></code>
-    </a>
-  </figcaption>
-</figure>
-<figure>
-  <img src='/img/interpolator-monotone.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorSplineMonotone'>
-      <code><strong>interpolatorSplineMonotone</strong></code>
-    </a>
-  </figcaption>
-</figure>
-<figure>
-  <img src='/img/interpolator-monotone-2.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorSplineMonotone2'>
-      <code><strong>interpolatorSplineMonotone2</strong></code>
-    </a>
-  </figcaption>
-</figure>
-<figure>
-  <img src='/img/interpolator-monotone-closed.svg' width='400' height='80'/>
-  <figcaption>
-    <a href='#interpolatorSplineMonotoneClosed'>
-      <code><strong>interpolatorSplineMonotoneClosed</strong></code>
-    </a>
-  </figcaption>
-</figure>
-</div>
-
-You'll use these methods when you want to override how colors get interpolated in a specific color space, or when defining the default interpolation for custom color spaces.
-
-<a id="interpolatorLinear" href="#interpolatorLinear">#</a> **interpolatorLinear**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/linear.js]({{codebase}}/src/interpolate/linear.js)
-
-<img src='/img/interpolator-linear.svg' width='400' height='80'/>
-
-A linear interpolator for values in a channel.
-
-#### Basis splines
-
-[Basis splines](https://en.wikipedia.org/wiki/B-spline) (also called _B-splines_) are available in the following variants:
-
-<a id="interpolatorSplineBasis" href="#interpolatorSplineBasis">#</a> **interpolatorSplineBasis**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/splineBasis.js]({{codebase}}/src/interpolate/splineBasis.js)
-
-<img src='/img/interpolator-basis.svg' width='400' height='80'/>
-
-A basis spline which uses one-sided finite differences for the slopes at the boundaries.
-
-<a id="interpolatorSplineBasisClosed" href="#interpolatorSplineBasisClosed">#</a> **interpolatorSplineBasisClosed**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/splineBasis.js]({{codebase}}/src/interpolate/splineBasis.js)
-
-<img src='/img/interpolator-basis-closed.svg' width='400' height='80'/>
-
-A basis spline which considers the _values_ array to be periodic.
-
-#### Natural splines
-
-[Natural interpolating splines](https://en.wikipedia.org/wiki/Spline_interpolation) are related to basis splines, as explained in [this handout](https://www.math.ucla.edu/~baker/149.1.02w/handouts/dd_splines.pdf) by Kirby A. Baker (sections 4 and 5).
-
-<a id="interpolatorSplineNatural" href="#interpolatorSplineNatural">#</a> **interpolatorSplineNatural**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/splineNatural.js]({{codebase}}/src/interpolate/splineNatural.js)
-
-<img src='/img/interpolator-natural.svg' width='400' height='80'/>
-
-A natural spline which uses one-sided finite differences for the slopes at the boundaries.
-
-<a id="interpolatorSplineNaturalClosed" href="#interpolatorSplineNaturalClosed">#</a> **interpolatorSplineNaturalClosed**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/splineNatural.js]({{codebase}}/src/interpolate/splineNatural.js)
-
-<img src='/img/interpolator-natural-closed.svg' width='400' height='80'/>
-
-A natural spline which considers the _values_ array to be periodic.
-
-#### Monotone splines
-
-The monotone splines are based on the following paper (via [d3-shape](https://github.com/d3/d3-shape)):
-
-> Steffen, M. [_"A simple method for monotonic interpolation in one dimension."_](https://ui.adsabs.harvard.edu/abs/1990A&A...239..443S) in Astronomy and Astrophysics, Vol. 239, p. 443-450 (Nov. 1990), Provided by the SAO/NASA Astrophysics Data System.
-
-The following variants are available:
-
-<a id="interpolatorSplineMonotone" href="#interpolatorSplineMonotone">#</a> **interpolatorSplineMonotone**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/splineMonotone.js]({{codebase}}/src/interpolate/splineMonotone.js)
-
-<img src='/img/interpolator-monotone.svg' width='400' height='80'/>
-
-A monotone spline that uses one-sided finite differences to find the slopes at the boundaries.
-
-<a id="interpolatorSplineMonotone2" href="#interpolatorSplineMonotone2">#</a> **interpolatorSplineMonotone2**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/splineMonotone.js]({{codebase}}/src/interpolate/splineMonotone.js)
-
-<img src='/img/interpolator-monotone-2.svg' width='400' height='80'/>
-
-A monotone spline for which we derive the slopes at the boundaries by tracing a parabola through the first/last three values.
-
-<a id="interpolatorSplineMonotoneClosed" href="#interpolatorSplineMonotoneClosed">#</a> **interpolatorSplineMonotoneClosed**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate/splineMonotone.js]({{codebase}}/src/interpolate/splineMonotone.js)
-
-<img src='/img/interpolator-monotone-closed.svg' width='400' height='80'/>
-
-A monotone spline which considers the _values_ array to be periodic.
-
-#### Custom piecewise interpolation
-
-<a id='interpolatorPiecewise' href='#interpolatorPiecewise'>#</a> **interpolatorPiecewise**(_interpolator_) [src/interpolate/piecewise.js]({{codebase}}/src/interpolate/piecewise.js)
-
-Use a custom piecewise interpolator function in the form `function (a, b, t) => value`:
-
-```js
-import { interpolate, interpolatorPiecewise } from 'culori';
-
-let linear = (a, b, t) => (1 - t) * a + t * b;
-interpolate(['red', 'green'], interpolatorPiecewise(linear));
-```
-
-When one of the two values to be interpolated is undefined, it will mirror the defined value: `[undefined, b]` becomes `[b, b]`. If both values are undefined, they are left as-is.
-
-The [`interpolatorLinear()`](#interpolatorLinear) function uses `interpolatorPiecewise()` under the hood.
-
-### Interpolation Fixup
-
-By default, channel values that need to be interpolated are treated as normal numbers. However, for some channels, the values hold special singificance and can be fixed up before interpolation for better results.
-
-#### Hue fixup
-
-Hue is a circular value, so there are two directions in which to interpolate between two hues (clockwise and anti-clockwise). The functions below take an array of hues and adjusts them to impose a certain interpolation direction while maintaining the absolute difference between consecutive hues.
-
-Adjusted hues will not necessarily be in the `[0, 360)` interval. All fixup methods leave undefined values, and the values immediately following them, unaltered. The names of the methods come from [this discussion](https://github.com/w3c/csswg-drafts/issues/4735).
-
-<a id="fixupHueShorter" href="#fixupHueShorter">#</a> **fixupHueShorter**(_values_) → _Array_
-
-<span aria-label='Source:'>☞</span> [src/fixup/hue.js]({{codebase}}/src/fixup/hue.js)
-
-Adjusts the hues so that values are interpolated along the _shortest path around the hue circle_.
-
-This is the default in all built-in color spaces using a hue channel. Below is an extract from the definition of the HSL color space:
-
-```js
-/* --- hsl/definition.js --- */
-export default {
-	// ...
-	interpolate: {
-		h: {
-			use: interpolatorLinear,
-			fixup: fixupHueShorter
-		},
-		s: interpolatorLinear,
-		l: interpolatorLinear,
-		alpha: {
-			use: interpolatorLinear,
-			fixup: fixupAlpha
-		}
-	}
-	// ...
-};
-```
-
-To omit the fixup and treat hues as normal numbers, use a custom interpolation on the `h` channel, and overwrite the `fixup` function with an identity function:
-
-```js
-import { interpolate } from 'culori';
-
-let hsl_long = interpolate(['blue', 'red', 'green'], 'hsl', {
-	h: {
-		fixup: arr => arr
-	}
-});
-```
-
-Treating the hues array as-is (with an _identity function_) corresponds to the `specified` fixup method [in the CSSWG issue](https://github.com/w3c/csswg-drafts/issues/4735) mentioned earlier.
-
-<a id="fixupHueLonger" href="#fixupHueLonger">#</a> **fixupHueLonger**(_values_) → _Array_
-
-<span aria-label='Source:'>☞</span> [src/fixup/hue.js]({{codebase}}/src/fixup/hue.js)
-
-Adjusts the hues so that they are interpolated along the _longest path around the hue circle_.
-
-<a id="fixupHueIncreasing" href="#fixupHueIncreasing">#</a> **fixupHueIncreasing**(_values_) → _Array_
-
-<span aria-label='Source:'>☞</span> [src/fixup/hue.js]({{codebase}}/src/fixup/hue.js)
-
-Adjusts the hues so that every hue is larger than the previous.
-
-<a id="fixupHueDecreasing" href="#fixupHueDecreasing">#</a> **fixupHueDecreasing**(_values_) → _Array_
-
-<span aria-label='Source:'>☞</span> [src/fixup/hue.js]({{codebase}}/src/fixup/hue.js)
-
-Adjusts the hues so that every hue is smaller than the previous.
-
-#### Alpha fixup
-
-<a id="fixupAlpha" href="#fixupAlpha">#</a> **fixupAlpha**(_values_) → _Array_
-
-<span aria-label='Source:'>☞</span> [src/fixup/alpha.js]({{codebase}}/src/fixup/alpha.js)
-
-Turns all `undefined` values in the array to `1` (full opacity), unless _all_ values in the array are `undefined`, in which case it leaves the values unaltered.
-
-This is the default method for the alpha channel in all built-in color spaces.
-
-### Evenly-spaced samples
-
-<a id="samples" href="#samples">#</a> **samples**(_n = 2_)
-
-<span aria-label='Source:'>☞</span> [src/samples.js]({{codebase}}/src/samples.js)
-
-Returns an array of _n_ equally-spaced samples in the `[0, 1]` range, with `0` and `1` at the ends.
-
-```js
-import { samples } from 'culori';
-
-samples(3);
-// ⇒ [0, 0.5, 1]
-
-samples(5);
-// ⇒ [0, 0.25, 0.5, 0.75, 1]
-```
-
-The samples are useful for [`interpolate()`](#interpolate) to generate color scales:
-
-```js
-import { samples, interpolate, formatHex } from 'culori';
-
-let grays = interpolate(['#fff', '#000']);
-samples(5).map(grays).map(formatHex);
-// ⇒ ["#ffffff", "#bfbfbf", "#808080", "#404040", "#000000"]
-```
-
-As with the [`interpolate()`](#interpolate) method, you can map the samples through an easing function or scale to obtain a different distribution of the samples.
-
-```js
-import { samples } from 'culori';
-import easing from 'bezier-easing';
-
-// Bezier easing:
-let bezier = easing(0, 0, 1, 0.5);
-samples(10).map(bezier);
-
-// easeInQuad:
-samples(10).map(t => t * t);
-```
-
-### Lerp
-
-<a id="lerp" href="#lerp">#</a> **lerp**(_a_, _b_, _t_) → _value_
-
-<span aria-label='Source:'>☞</span> [src/interpolate/lerp.js]({{codebase}}/src/interpolate/lerp.js)
-
-Interpolates between the values `a` and `b` at the point `t ∈ [0, 1]`.
-
-```js
-import { lerp } from 'culori';
-lerp(5, 10, 0.5);
-// ⇒ 7.5
-```
-
-<a id="unlerp" href="#unlerp">#</a> **unlerp**(_a_, _b_, _v_) → _value_
-
-<span aria-label='Source:'>☞</span> [src/interpolate/lerp.js]({{codebase}}/src/interpolate/lerp.js)
-
-Returns the point `t` at which the value `v` is located between the values `a` and `b`. The inverse of `lerp`.
-
-<a id="blerp" href="#blerp">#</a> **blerp**(_a00_, _a01_, _a10_, _a11_, _tx_, _ty_) → _value_
-
-<span aria-label='Source:'>☞</span> [src/interpolate/lerp.js]({{codebase}}/src/interpolate/lerp.js)
-
-Perform the [bilinear interpolation](https://en.wikipedia.org/wiki/Bilinear_interpolation) of the four values `a00`, `a01`, `a10`, and `a11` at the point `(tx, ty)`, with `tx, ty ∈ [0, 1]`. This is the extension of `lerp` to two dimensions.
-
-<a id="trilerp" href="#trilerp">#</a> **trilerp**(_a000_, _a010_, _a100_, _a110_, _a001_, _a011_, _a101_, _a111_, _tx_, _ty_, _tz_) → _value_
-
-<span aria-label='Source:'>☞</span> [src/interpolate/lerp.js]({{codebase}}/src/interpolate/lerp.js)
-
-Perform the [trilinear interpolation](https://en.wikipedia.org/wiki/Trilinear_interpolation) of the eight values `a000`, `a010`, `a100`, `a110`, `a001`, `a011`, `a101`, and `a111` at the point `(tx, ty, tz)`, with `tx, ty, tz ∈ [0, 1]`. This is the extension of `lerp` to three dimensions.
-
-### Mappings
-
-<a id="mapper" href="#mapper">#</a> **mapper**(_fn_, _mode = "rgb"_) → _function (color | string)_
-
-<span aria-label='Source:'>☞</span> [src/map.js]({{codebase}}/src/map.js)
-
-Creates a mapping that applies _fn_ on each channel of the color in the _mode_ color space.
-
-The resulting function accepts a single argument (a color object or a string), which it converts to the _mode_ color space if necessary.
-
-The _mode_ parameter can be set to `null`, in which case the mapper will iterate through the channels in the color's original color space.
-
-The _fn_ callback has the following signature:
-
-**fn**(_value_, _channel_, _color_, _mode_)
-
-where:
-
--   `value` is the current value;
--   `channel` is the current channel;
--   `color` is a reference to the entire color object;
--   `mode` is forwarded from the call to `mapper`.
-
-Here's the implementation of alpha premultiplication:
-
-```js
-import { mapper } from 'culori';
-
-const multiplyAlpha = mapper((val, ch, color) => {
-	if (ch !== 'alpha') {
-		return (val || 0) / (color.alpha !== undefined ? color.alpha : 1);
-	}
-	return val;
-}, 'rgb');
-
-multiplyAlpha({ r: 1, g: 0.6, b: 0.4, a: 0.5 });
-// ⇒ { mode: 'rgb', r: 0.5, g: 0.3, b: 0.2, a: 0.5 }
-```
-
-All channels, including `alpha`, are included in the mapping. You may want to handle the `alpha` channel differently in the callback function, like in the example above.
-
-Returning `undefined` or `NaN` from the callback function will omit that channel from the resulting color object.
-
-#### Built-in mappings
-
-<a id="mapAlphaMultiply" href="#mapAlphaMultiply">#</a> **mapAlphaMultiply**
-
-<span aria-label='Source:'>☞</span> [src/map.js]({{codebase}}/src/map.js)
-
-Multiplies the color's alpha value into all its other channels:
-
-```js
-import { mapper, mapAlphaMultiply } from 'culori';
-
-let multiplyAlpha = mapper(mapAlphaMultiply, 'rgb');
-multiplyAlpha({ r: 1, g: 0.6, b: 0.4, a: 0.5 });
-// ⇒ { mode: 'rgb', r: 0.5, g: 0.3, b: 0.2, a: 0.5 }
-```
-
-Any `undefined` channel value will be considered to be `0` (zero), to enable alpha-premultiplied interpolation with achromatic colors in hue-based color spaces (HSL, LCh, etc.).
-
-<a id="mapAlphaDivide" href="#mapAlphaDivide">#</a> **mapAlphaDivide**
-
-<span aria-label='Source:'>☞</span> [src/map.js]({{codebase}}/src/map.js)
-
-Divides a color's other channels by its alpha value. It's the opposite of `mapAlphaMultiply`, and is used in interpolation with alpha premultiplication:
-
-```js
-import { mapper, mapAlphaMultiply, mapAlphaDivide } from 'culori';
-
-let multiplyAlpha = mapper(mapAlphaMultiply, 'rgb');
-let divideAlpha = mapper(mapAlphaDivide, 'rgb');
-
-divideAlpha(multiplyAlpha({ r: 1, g: 0.6, b: 0.4, a: 0.5 }));
-// ⇒ { mode: 'rgb', r: 1, g: 0.6, b: 0.4, a: 0.5 }
-```
-
-Any `undefined` channel value will be considered to be `0` (zero), to enable alpha-premultiplied interpolation with achromatic colors in hue-based color spaces (HSL, LCh, etc.).
-
-<a id="mapTransferLinear" href="#mapTransferLinear">#</a> **mapTransferLinear**(_slope = 1_, _intercept = 0_)
-
-<span aria-label='Source:'>☞</span> [src/map.js]({{codebase}}/src/map.js)
-
-<a id="mapTransferGamma" href="#mapTransferGamma">#</a> **mapTransferGamma**(_amplitude = 1_, _exponent = 1_, _offset = 0_)
-
-<span aria-label='Source:'>☞</span> [src/map.js]({{codebase}}/src/map.js)
-
-#### Interpolating with mappings
-
-<a id="interpolateWith" href="#interpolateWith">#</a> **interpolateWith**(_premap_, _postmap_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate.js]({{codebase}}/src/interpolate.js)
-
-Adds a _pre-mapping_ and a _post-mapping_ to an interpolation, to enable things like alpha premultiplication:
-
-```js
-import { interpolateWith, mapAlphaMultiply, mapAlphaDivide } from 'culori';
-
-let interpolateWithAlphaPremult = interpolateWith(
-	mapAlphaMultiply,
-	mapAlphaDivide
-);
-
-interpolateWithAlphaPremult(['red', 'transparent', 'blue'])(0.25);
-```
-
-To chain more than one mapping:
-
-```js
-import { interpolateWith, mapAlphaMultiply, mapAlphaDivide } from 'culori';
-
-const mapChromaMultiply = (v, ch, c, mode) => {
-	// ...
-};
-
-const mapChromaDivide = (v, ch, c, mode) => {
-	// ...
-};
-
-let interpolateWithAlphaChromaPremult = interpolateWith(
-	(...args) => mapChromaMultiply(mapAlphaMultiply(...args)),
-	(...args) => mapAlphaDivide(mapChromaDivide(...args))
-);
-
-interpolateWithAlphaPremult(['red', 'transparent', 'blue'])(0.25);
-```
-
-<a id="interpolateWithPremultipliedAlpha" href="#interpolateWithPremultipliedAlpha">#</a> **interpolateWithPremultipliedAlpha**(_colors_, _mode = "rgb"_, _overrides_)
-
-<span aria-label='Source:'>☞</span> [src/interpolate.js]({{codebase}}/src/interpolate.js)
-
-Takes the same arguments as [`interpolate()`](#interpolate), but applies [alpha premultiplication](https://drafts.csswg.org/css-images-4/#premultiplied).
-
-```js
-import { interpolate, interpolateWithPremultipliedAlpha } from 'culori';
-let colors = ['red', 'transparent', 'blue'];
-
-// alpha ignored for the R/G/B channels:
-interpolate(colors, 'rgb');
-
-// alpha premultiplied into the R/G/B channels:
-interpolateWithPremultipliedAlpha(colors, 'rgb');
-```
-
-## Color Difference
-
-These methods are concerned to finding the [distance between two colors](https://en.wikipedia.org/wiki/Color_difference) based on various formulas. Each of these formulas will return a _function (colorA, colorB)_ that lets you measure the distance between two colors.
-
-### Euclidean distance
-
-<a id="differenceEuclidean" href="#differenceEuclidean">#</a> **differenceEuclidean**(_mode = 'rgb'_, _weights = [1, 1, 1, 0]_)
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Returns a [Euclidean distance](https://en.wikipedia.org/wiki/Color_difference#Euclidean) function in a certain color space.
-
-You can optionally assign different weights to the channels in the color space. See, for example, the [Kotsarenko/Ramos distance](#differenceKotsarenkoRamos) or [ΔE<sub>ITP</sub>](#differenceItp).
-
-The default weights `[1, 1, 1, 0]` mean that the _alpha_, which is the fourth channel in all the color spaces Culori defines, is not taken into account. Send `[1, 1, 1, 1]` as the weights to include it in the computation.
-
-In cylindrical spaces, the hue is factored into the Euclidean distance in a variety of ways. The functions below are used internally:
-
-<a id="differenceHueChroma" href="#differenceHueChroma">#</a> **differenceHueChroma**(_colorA_, _colorB_)
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the hue contribution as the geometric mean of chord lengths belonging to the chromas of the two colors. This is the handling of hue in cylindrical forms of CIE-related color spaces: `lch`, `lchuv`, `dlch`, `oklch`, `jch`.
-
-<a id="differenceHueSaturation" href="#differenceHueSaturation">#</a> **differenceHueSaturation**(_colorA_, _colorB_)
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the hue contribution as the geometric mean of chord lengths belonging to the saturations of the two colors. This is the handling of hue in the HSL / HSV / HSI family of color spaces.
-
-<a id="differenceHueNaive" href="#differenceHueNaive">#</a> **differenceHueNaive**(_colorA_, _colorB_)
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-For remaining color spaces (HWB), we consider hues numbers, but apply a _shortest path around the hue circle_ (analogous to [`fixupHueShorter`](#fixupHueShorter)). If you insist on using Euclidean distances on these spaces, you can use the `weights` to control the contribution of the hue difference towards the total difference.
-
-### CIE color difference formulas
-
-All these color difference functions operate on the `lab65` color space.
-
-<a id="differenceCie76" href="#differenceCie76">#</a> **differenceCie76**()
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the [CIE76][cie76] ΔE\*<sub>ab</sub> color difference between the colors _a_ and _b_. The function is identical to [`differenceEuclidean('lab65')`](#differenceEuclidean).
-
-<a id="differenceCie94" href="#differenceCie94">#</a> **differenceCie94**(_kL = 1_, _K1 = 0.045_, _K2 = 0.015_)
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the [CIE94][cie94] ΔE\*<sub>94</sub> color difference between the colors _a_ and _b_.
-
-<a id="differenceCiede2000" href="#differenceCiede2000">#</a> **differenceCiede2000**(_Kl = 1_, _Kc = 1_, _Kh = 1_)
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the [CIEDE2000][ciede2000] ΔE\*<sub>00</sub> color difference between the colors _a_ and _b_ as implemented by [G. Sharma](http://www2.ece.rochester.edu/~gsharma/ciede2000/).
-
-<a id="differenceCmc" href="#differenceCmc">#</a> **differenceCmc**()
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the [CMC l:c (1984)][cmc] ΔE\*<sub>CMC</sub> color difference between the colors _a_ and _b_.
-
-ΔE\*<sub>CMC</sub> is not considered a metric since it's not symmetrical, that is the distance from _a_ to _b_ is not always equal to the distance from _b_ to _a_. Therefore it cannot be reliably used with [`nearest()`](#nearest).
-
-<a id="differenceHyab" href="#differenceHyab">#</a> **differenceHyab**()
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the HyAB color difference between the colors _a_ and _b_, as proposed in:
-
-> Abasi S, Amani Tehran M, Fairchild MD. _Distance metrics for very large color differences._ Color Res Appl. 2019; 1–16. https://doi.org/10.1002/col.22451 ([PDF](http://markfairchild.org/PDFs/PAP40.pdf))
-
-The HyAB formula combines the Euclidean and [city block](https://en.wikipedia.org/wiki/Taxicab_geometry) distance and has been experimentally shown to work better for large color differences than CIEDE2000, while still holding up well for smaller color differences, making it a _"good candidate formula for image processing and computer vision applications"_.
-
-### Other difference formulas
-
-<a id="differenceKotsarenkoRamos" href="#differenceKotsarenkoRamos">#</a> **differenceKotsarenkoRamos**()
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the [Kotsarenko/Ramos][kotsarekno-ramos] color difference between the colors _a_ and _b_. This is a weighted Euclidean distance in the `yiq` color space.
-
-<a id="differenceItp" href="#differenceItp">#</a> **differenceItp**()
-
-<span aria-label='Source:'>☞</span> [src/difference.js]({{codebase}}/src/difference.js)
-
-Computes the [ΔE<sub>ITP</sub>][eitp-difference] color difference metric between the colors _a_ and _b_. This is a weighted Euclidean distance in the `itp` color space, scaled by a factor of 720 so that a the just-noticeable difference (<abbr>JND</abbr>) corresponds to a value of 1.
-
-### Nearest color(s)
-
-<a id="nearest" href="#nearest">#</a> **nearest**(_colors_, _metric = differenceEuclidean()_, _accessor = identity_) → _function(color, n = 1, τ = Infinity)_
-
-<span aria-label='Source:'>☞</span> [src/nearest.js]({{codebase}}/src/nearest.js)
-
-Takes a _colors_ array and a _metric_ color difference formula, and returns a function with which you can find _n_ colors nearest to _color_, with a maximum distance of _τ_. Use _n = Infinity_ to get all colors in the array with a maximum distance of _τ_.
-
-```js
-/*
-	Example: get three CSS named colors closest to any color
- */
-import { colorsNamed, nearest, differenceCiede2000 } from 'culori';
-
-let colors = Object.keys(colorsNamed);
-let nearestNamedColors = nearest(colors, differenceCiede2000());
-
-nearestNamedColors('lch(50% 70 60)', 3);
-// => ["chocolate", "sienna", "peru"]
-```
-
-By default, _colors_ needs to be an array of color values. If your array contains something other than a simple color value, you can provide the `accessor` argument to point to the color value associated with each item in the array.
-
-The example below shows a common data structure for a color palette: an object whose keys are the names and whose values are their associated color representations.
-
-```js
-import { nearest, differenceEuclidean } from 'culori';
-
-/*
-	Example: get the closest color from a palette
- */
-let palette = {
-	Burgundy: '#914e72',
-	Blue: '#0078bf',
-	Green: '#00a95c',
-	'Medium Blue': '#3255a4',
-	'Bright Red': '#f15060'
-};
-
-let names = Object.keys(palette);
-
-let nearestColors = nearest(
-	names,
-	differenceEuclidean(),
-	name => palette[name]
-);
-
-nearestColors('red', 1);
-// => ["Bright Red"]
-```
-
-## Blending
-
-Culori makes available the separable blend modes defined in the W3C [Compositing and Blending Level 2](https://drafts.fxtf.org/compositing-2/) specification.
-
-<a id="blend" href="#blend">#</a> **blend**(_colors_, _type = 'normal'_, _mode = 'rgb'_) → _color_
-
-<span aria-label='Source:'>☞</span> [src/blend.js]({{codebase}}/src/blend.js)
-
-A separable blend mode is a simple formula that gets applied to each channel in the color space independently. The available blend modes are `color-burn`, `color-dodge`, `darken`, `difference`, `exclusion`, `hard-light`, `lighten`, `multiply`, `normal`, `overlay`, `screen`
-, and `soft-light`. They are designed to work on RGB colors, so _mode_ is expected to be `rgb` or `lrgb`.
-
-An example of blending three colors:
-
-```js
-import { blend } from 'culori';
-
-blend(
-	['rgba(255, 0, 0, 0.5)', 'rgba(0, 255, 0, 0.5)', 'rgba(0, 0, 255, 0.5)'],
-	'screen'
-);
-// ⇒ { mode: 'rgb', alpha: 0.875, r: 0.57…, g: 0.57…, b:0.57… }
-```
-
-In addition to strings, the _type_ parameter supports a _function (b, s) → v_ that takes the values of the _backdrop_ and _source_ color to return the blended value. This allows you to write your own (separable) blending functions. For example, an _average_ blending mode:
-
-```js
-import { blend } from 'culori';
-
-blend(['red', 'green'], function average(b, s) {
-	return (b + s) / 2;
-});
-```
-
-The non-separable blend modes — `color`, `hue`, `saturation`, and `lightness` — are not available. The effect which they mean to produce is better obtained with simple formulas on a cylindrical color space (e.g. HSL).
-
-## Average color
-
-<a id="average" href="#average">#</a> **average**(_colors_, _mode = 'rgb'_, _overrides_)
-
-<span aria-label='Source:'>☞</span> [src/average.js]({{codebase}}/src/average.js)
-
-Returns the average color of the _colors_ array, in the color space specified by the _mode_ argument. The color is obtained by the arithmetic average of values on each individual channel.
-
-Colors with undefined values on a channel don't participate in the average for that channel.
-
-```js
-import { average } from 'culori';
-
-average(['salmon', 'tomato'], 'lab');
-// ⇒ { 'mode': 'lab', l: 65.41…, a: 53.00…, b: 39.01… }
-```
-
-<a id="averageNumber" href="#averageNumber">#</a> **averageNumber**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/average.js]({{codebase}}/src/average.js)
-
-The arithmetic mean of values in the _values_ array.
-
-<a id="averageAngle" href="#averageAngle">#</a> **averageAngle**(_values_)
-
-<span aria-label='Source:'>☞</span> [src/average.js]({{codebase}}/src/average.js)
-
-The function used by default to average hue values in all built-in color spaces, using the formula for [the mean of circular quantities](https://en.wikipedia.org/wiki/Mean_of_circular_quantities).
-
-## Random colors
-
-<a id="random" href="#random">#</a> **random**(_mode = 'rgb'_, _constraints = {}_)
-
-<span aria-label='Source:'>☞</span> [src/random.js]({{codebase}}/src/random.js)
-
-Obtain a random color from a particular color space, with optional constraints. The resulting color will be in the color space from where it has been picked.
-
-Basic usage:
-
-```js
-import { random } from 'culori';
-
-random();
-// ⇒ { mode: 'rgb', r: 0.75, g: 0.12, b: 0.99 }
-```
-
-### Specifying constraints
-
-Random colors are, by definition, all over the color space and not all of them will look particularly nice. Some color spaces, such as HSL or HSV, are also biased towards colors close to black and/or white, because of the way these color spaces stretch the RGB cube into cylinders.
-
-For more control on how the colors are generated, you can specify constraints for each individual channel in the color space. Constraints can be either a _constant number_ or an _interval_ from where to pick the channel value:
-
-```js
-import { random } from 'culori';
-
-random('hsv', {
-	h: 120, // number
-	s: [0.25, 0.75] // interval
-});
-// ⇒ { mode: 'hsv', h: 120, s: 0.51…, v: 0.89… }
-```
-
-The _alpha_ channel is excluded by default. To obtain colors with random alpha values, include a constraint for `alpha`:
-
-```js
-import { random } from 'culori';
-
-random('lrgb');
-// ⇒ { mode: 'lrgb', r: 0.74…, g: 0.15…, b: 0.34… }
-
-random('lrgb', { alpha: [0, 1] });
-// ⇒ { mode: 'lrgb', r: 0.33…, g: 0.72…, b: 0.04…, alpha: 0.12… }
-```
-
-### Displayable random colors
-
-The value for any channel in the color space for which there are no constraints will be picked from the entire range of that channel. However, some color spaces, such as CIELAB or CIELCH, don't have explicit ranges for certain channels; for these, some approximate ranges [have been pre-computed]({{codebase}}/tools/ranges.js) as the limits of the displayable sRGB gamut.
-
-Even with these ranges in place, a combination of channel values may not be displayable. Check if that's the case with [`displayable()`](#displayable), and pass the color through a [`clamp*`](#clampRgb) function to obtain a displayable version.
-
-## WCAG utilities
-
-A couple of utility functions based on the [Web Content Acccessibility Guidelines 2.0 specification](https://www.w3.org/TR/WCAG20/).
-
-<a id="wcagLuminance" href="#wcagLuminance">#</a> **wcagLuminance**(_color_)
-
-<span aria-label='Source:'>☞</span> [src/wcag.js]({{codebase}}/src/wcag.js)
-
-Computes the [relative luminance](https://www.w3.org/TR/WCAG20/#relativeluminancedef) of a color.
-
-```js
-import { wcagLuminance } from 'culori';
-
-wcagLuminance('red');
-// ⇒ 0.2126
-```
-
-<a id="wcagContrast" href="#wcagContrast">#</a> **wcagContrast**(_colorA_, _colorB_)
-
-<span aria-label='Source:'>☞</span> [src/wcag.js]({{codebase}}/src/wcag.js)
-
-Computes the [contrast ratio](https://www.w3.org/TR/WCAG20/#contrast-ratiodef) between two colors.
-
-```js
-import { wcagContrast } from 'culori';
-
-wcagContrast('red', 'black');
-// ⇒ 5.252
-```
-
-## Filters
-
-Filters apply certain graphical effects to a color. Culori currently implements two sets of filter functions:
-
-### CSS Filter Effects
-
-These correspond to the filter effects defined in the W3C [Filter Effects Module Level 1](https://drafts.fxtf.org/filter-effects-1/) specification.
-
-The _amount_ parameter is usually in the `[0, 1]` interval, but may go above `1` for some filters. The filters were designed for RGB colors, so the _mode_ parameter is expected to be `rgb` or `lrgb`.
-
-The resulting color is returned in the color space of the original color.
-
-<a id="filterBrightness" href="#filterBrightness">#</a> **filterBrightness**(_amount = 1_, _mode = 'rgb'_)
-
-<span aria-label='Source:'>☞</span> [src/filter.js]({{codebase}}/src/filter.js)
-
-The [`brightness()`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/brightness) CSS filter. An _amount_ of `1` leaves the color unchanged. Smaller values darken the color (with `0` being fully black), while larger values brighten it.
-
-```js
-import { filterBrightness } from 'culori';
-
-let brighten = filterBrightness(2, 'lrgb');
-brighten('salmon');
-// ⇒ { mode: 'rgb', r: 1.32…, g: 0.68…, b: 0.61… }
-```
-
-<a id="filterContrast" href="#filterContrast">#</a> **filterContrast**(_amount = 1_, _mode = 'rgb'_)
-
-<span aria-label='Source:'>☞</span> [src/filter.js]({{codebase}}/src/filter.js)
-
-The [`contrast()`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/contrast) filter. An _amount_ of `1` leaves the color unchanged. Smaller values decrease the contrast (with `0` being fully gray), while larger values increase it.
-
-<a id="filterSepia" href="#filterSepia">#</a> **filterSepia**(_amount = 1_, _mode = 'rgb'_)
-
-<span aria-label='Source:'>☞</span> [src/filter.js]({{codebase}}/src/filter.js)
-
-The [`sepia()`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/sepia) filter. An _amount_ of `0` leaves the color unchanged, and `1` applies the sepia effect fully.
-
-<a id="filterGrayscale" href="#filterGrayscale">#</a> **filterGrayscale**(_amount = 1_, _mode = 'rgb'_)
-
-<span aria-label='Source:'>☞</span> [src/filter.js]({{codebase}}/src/filter.js)
-
-The [`grayscale()`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/grayscale) filter. An _amount_ of `0` leaves the color unchanged, and `1` makes the color fully achromatic.
-
-<a id="filterSaturate" href="#filterSaturate">#</a> **filterSaturate**(_amount = 1_, _mode = 'rgb'_)
-
-<span aria-label='Source:'>☞</span> [src/filter.js]({{codebase}}/src/filter.js)
-
-The [`saturate()`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/saturate) filter. An _amount_ of `1` leaves the color unchanged. Smaller values desaturate the color (with `0` being fully achromatic), while larger values saturate it.
-
-<a id="filterInvert" href="#filterInvert">#</a> **filterInvert**(_amount = 1_, _mode = 'rgb'_)
-
-<span aria-label='Source:'>☞</span> [src/filter.js]({{codebase}}/src/filter.js)
-
-The [`invert()`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/invert) filter. An _amount_ of `0` leaves the color unchanged, and `1` makes the color fully inverted.
-
-<a id="filterHueRotate" href="#filterHueRotate">#</a> **filterHueRotate**(_degrees = 0_, _mode = 'rgb'_)
-
-<span aria-label='Source:'>☞</span> [src/filter.js]({{codebase}}/src/filter.js)
-
-The [`hue-rotate()`](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function/hue-rotate) filter.
-
-```js
-import { samples, interpolate, filterSepia, formatHex } from 'culori';
-
-samples(5)
-	.map(interpolate(['red', 'green', 'blue']))
-	.map(filterSepia(0.5))
-	.map(formatHex);
-
-// ⇒ ["#751800", "#664200", "#576c00", "#1a3e82", "#0010ff"];
-```
-
-Some of the effects may be obtained more straightforwardly with simple calculations in other color spaces. For example, [hue rotation](#filterHueRotate) can just as well be implemented as `color.h += angle` in a cylindrical color space such as HSL.
-
-### Color vision deficiency (CVD) simulation
-
-Simulate how a color may be perceived by people with color vision deficiencies (CVD).
-
-<a id="filterDeficiencyProt" href="#filterDeficiencyProt">#</a> **filterDeficiencyProt**(_severity = 1_) → _function (color)_
-
-<span aria-label='Source:'>☞</span> [src/deficiency.js]({{codebase}}/src/deficiency.js)
-
-Simulate protanomaly and protanopia. The `severity` parameter is in the interval `[0, 1]`, where `0` corresponds to normal vision and `1` (the default value) corresponds to protanopia.
-
-<a id="filterDeficiencyDeuter" href="#filterDeficiencyDeuter">#</a> **filterDeficiencyDeuter**(_severity = 1_) → _function (color)_
-
-<span aria-label='Source:'>☞</span> [src/deficiency.js]({{codebase}}/src/deficiency.js)
-
-Simulate deuteranomaly and deuteranopia. The `severity` parameter is in the interval `[0, 1]`, where `0` corresponds to normal vision and `1` (the default value) corresponds to deuteranopia.
-
-<a id="filterDeficiencyTrit" href="#filterDeficiencyTrit">#</a> **filterDeficiencyTrit**(_severity = 1_) → _function (color)_
-
-<span aria-label='Source:'>☞</span> [src/deficiency.js]({{codebase}}/src/deficiency.js)
-
-Simuate tritanomaly and tritanopia. The `severity` parameter is in the interval `[0, 1]`, where `0` corresponds to normal vision and `1` (the default value) corresponds to tritanopia.
-
-Examples:
-
-```js
-import { interpolate, filterDeficiencyProt, formatHex } from 'culori';
-culori
-	.samples(5)
-	.map(interpolate(['red', 'green', 'blue']))
-	.map(filterDeficiencyProt(0.5))
-	.map(formatHex);
-
-// ⇒ ["#751800", "#664200", "#576c00", "#1a3e82", "#0010ff"];
-```
-
-Based on the work of Machado, Oliveira and Fernandes (2009), using [precomputed matrices](https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html) provided by the authors. References thanks to the [`colorspace` package for R](http://colorspace.r-forge.r-project.org/reference/simulate_cvd.html).
-
-> G. M. Machado, M. M. Oliveira and L. A. F. Fernandes, _"A Physiologically-based Model for Simulation of Color Vision Deficiency,"_ in IEEE Transactions on Visualization and Computer Graphics, vol. 15, no. 6, pp. 1291-1298, Nov.-Dec. 2009, [doi: 10.1109/TVCG.2009.113](https://doi.ieeecomputersociety.org/10.1109/TVCG.2009.113).
-
-## Miscellaneous
-
-<a id="colorsNamed" href="#colorsNamed">#</a> **colorsNamed**
-
-<span aria-label='Source:'>☞</span> [src/colors/named.js]({{codebase}}/src/colors/named.js)
-
-An object whose keys are all the CSS named colors.
-
-<a id="round" href="#round">#</a> **round**(_n = 8_)
-
-<span aria-label='Source:'>☞</span> [src/round.js]({{codebase}}/src/round.js)
-
-Returns a _rounder_: a function with which to round numbers to at most _n_ digits of precision.
-
-```js
-import { round } from 'culori';
-
-let approx = round(4);
-approx(0.38393993);
-// ⇒ 0.3839
-```
-
-<h2 id='color-spaces'>
-  <a href='#color-spaces'>#</a>
-  Available color spaces
-</h2>
-
-The default import (`culori`) comes with all the color spaces pre-registered into the library. For convenience, you can also import directly `mode` as a shortcut to [`converter(mode)`](#converter). For example, instead of [`converter('hsl')`](#converter), you can import `hsl`:
-
-```js
-// Instead of this:
-import { converter } from 'culori';
-const hsl = converter('hsl');
-
-// You can do this:
-import { hsl } from 'culori';
-```
-
-On the other hand, when importing the [tree-shaken version](/guides/tree-shaking) (`culori/fn`), color spaces need to be registered manually with [`useMode()`](#useMode) based on their __definition object__: 
-
-```js
-import { useMode, modeHsl } from 'culori/fn';
-const hsl = useMode(modeHsl);
-```
-
-The table below summarizes two pieces of information:
-
-* What the `mode` is for a specific color space built into Culori, which is also the name of the shortcut to the converter for that color space.
-* What the definition object for a color space is called.
-
-The available color spaces are discussed into more detail on the [Color Spaces](/color-spaces) page.
-
-Mode | Color space | Definition object
----- | ----------- | -----------------
-`a98` | A98 RGB color space, compatible with Adobe RGB (1998) | `modeA98`
-`cubehelix` | Cubehelix color space | `modeCubehelix`
-`dlab` | DIN99o Lab color space | `modeDlab`
-`dlch` | DIN99o LCh color space | `modeDlch`
-`hsi` | HSI color space | `modeHsi`
-`hsl` | HSL color space | `modeHsl`
-`hsv` | HSV color space | `modeHsv`
-`hwb` | HWB color space | `modeHwb`
-`itp` | IC<sub>t</sub>C<sub>p</sub> color space | `modeItp`
-`jab` | J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space | `modeJab`
-`jch` | J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> in cylindrical form | `modeJch`
-`lab` | CIELAB color space (D50 Illuminant) | `modeLab`
-`lab65` | CIELAB color space (D65 Illuminant) | `modeLab65`
-`lch` | CIELCh color space (D50 Illuminant) | `modeLch`
-`lch65` | CIELCh color space (D65 Illuminant) | `modeLch65`
-`lchuv` | CIELCHuv color space (D50 Illuminant) | `modeLchuv`
-`lrgb` | Linear-light sRGB color space | `modeLrgb`
-`luv` | CIELUV color space (D50 Illuminant) | `modeLuv`
-`oklab` | Oklab color space | `modeOklab`
-`oklch` | Oklab color space, cylindrical form | `modeOklch`
-`p3` | Display P3 color space | `modeP3`
-`prophoto` | ProPhoto RGB color space | `modeProphoto`
-`rec2020` | Rec. 2020 RGB color space | `modeRec2020`
-`rgb` | sRGB color space | `modeRgb`
-`xyb` | XYB color space | `modeXyb`
-`xyz50` | XYZ with D50 white-point | `modeXyz50`
-`xyz65` | XYZ with D65 white-point | `modeXyz65`
-`yiq` | YIQ color space | `modeYiq`
-
-## Extending culori
-
-<a id="useMode" href="#useMode">#</a> **useMode**(_definition_) → _function_.
-
-<span aria-label='Source:'>☞</span> [src/modes.js]({{codebase}}/src/modes.js)
-
-Defines a new color space based on its _definition_. See [Color mode definition](#color-mode-def) for the expected object shape.
-
-Returns a converter function for the newly defined mode.
-
-```js
-import { useMode } from 'culori';
-
-const hsl = useMode({
-	mode: 'hsl'
-	// ...
-});
-
-hsl('hsl(50 100% 100% / 100)');
-```
-
-<a id="getMode" href="#getMode">#</a> **getMode**(_mode_)
-
-<span aria-label='Source:'>☞</span> [src/modes.js]({{codebase}}/src/modes.js)
-
-Returns the definition object for the _mode_ color space.
-
-<h3 id='color-mode-def'>
-  <a href='#color-mode-def'>#</a>
-  Color mode definition
-</h3>
-
-The properties a definition needs are the following:
-
-#### `mode` (_string_)
-
-The string identifier for the color space.
-
-#### `channels` (_array_)
-
-A list of channels for the color space.
-
-#### `toMode` (_object_)
-
-A set of functions to convert from the color space we're defining to other color spaces. At least `rgb` needs to be included; in case a specific conversion pair between two color spaces is missing, RGB is used as the "buffer" for the conversion.
-
-#### `fromMode` (_object_)
-
-The opposite of `toMode`. A set of function to convert from various color spaces to the color space we're defining. At least `rgb` needs to be included.
-
-#### `ranges` (_object_, optional)
-
-The reference ranges for values in specific channels; if left unspecified, defaults to `[0, 1]`.
-
-#### `parse` (_array_, optional)
-
-Any parsers for the color space that can transform strings into colors. These can be either functions, or strings — the latter is used as the color space's identifier to parse the `color(<ident>)` CSS syntax.
-
-#### `serialize` (_function_ or _string_, optional)
-
-Defines how to serialize the color space to a CSS string with [`formatCss()`](#formatCss).
-
-If you pass in a function, it receives a color object as its only argument, and should return a string that can be used in CSS. If you pass in a string, it's used as a color profile identifier, and the color is serialized using the `color()` CSS syntax. When omitted altogether, the default color profile identifier is `--${mode}`.
-
-#### `interpolate`
-
-The default interpolations for the color space, one for each channel. Each interpolation is defined by its interpolator (the `use` key) and its fixup function (the `fixup` key). When defined as a function, a channel interpolation is meant to define its interpolator, with the fixup being a no-op.
-
-#### `difference`
-
-The default Euclidean distance method for each channel in the color space; mostly used for the `h` channel in cylindrical color spaces.
-
-#### `average`
-
-The default average function for each channel in the color space; when left unspecified, defaults to [`averageNumber`](#averageNumber).
-
-All built-in color spaces follow these conventions in regards to the `channels` array follows:
-
--   there are four channels in the color space;
--   the fourth channel is always `alpha`.
-
-This makes sure [`differenceEuclidean()`](#differenceEuclidean) works as expected, but there may be more hidden assumptions in the codebase.
-
-Here's a sample definition for the HSL color space:
-
-```js
-{
-  mode: 'hsl',
-  fromMode: {
-    rgb: convertRgbToHsl
-  },
-  toMode: {
-    rgb: convertHslToRgb
-  },
-  channels: ['h', 's', 'l', 'alpha'],
-  ranges: {
-    h: [0, 360]
-  },
-  parse: [parseHsl],
-  serialize: serializeHsl,
-  interpolate: {
-    h: {
-      use: interpolatorLinear,
-      fixup: fixupHueShorter
-    },
-    s: interpolatorLinear,
-    l: interpolatorLinear,
-    alpha: {
-      use: interpolatorLinear,
-      fixup: fixupAlpha
-    }
-  },
-  difference: {
-    h: differenceHueSaturation
-  },
-  average: {
-    h: averageAngle
-  }
-};
-```
-
-<a id="useParser" href="#useParser">#</a> **useParser**(_parser_, _mode_)
-
-<span aria-label='Source:'>☞</span> [src/modes.js]({{codebase}}/src/modes.js)
-
-Register a new parser. The parser can be:
-
-* a function, in which case the _mode_ argument is not necessary.
-* a string representing the identifier to match in the `color()` syntax, in which case the _mode_ argument is required.
-
-```js
-import { useParser } from 'culori';
-
-// Register custom parser
-useParser(function(str) => {
-  let color = {};
-  // parse the string
-  return color;
-});
-
-// Register `color(--oklab)` syntax
-useParser('--oklab', 'oklab');
-```
-
-<a id="removeParser" href="#removeParser">#</a> **removeParser**(_parser_)
-
-<span aria-label='Source:'>☞</span> [src/modes.js]({{codebase}}/src/modes.js)
-
-Remove a previously registered parser function or string, including parsers registered by default.
-
-```js
-import { parse, parseNamed, removeParser } from 'culori';
-
-parse('tomato');
-// ⇒ Object { mode: "rgb", r: 1, g: 0.38823529411764707, b: 0.2784313725490196 }
-
-removeParser(parseNamed);
-parse('tomato');
-// ⇒ undefined
-```
-
-<h2 id='low-level-api'>
-  <a href='#low-level-api'>#</a>
-  Low-level API
-</h2>
-
-<h3 id='parsing-functions'>
-  <a id="parsing-functions" href="#parsing-functions">#</a>
-  Parsing functions
-</h3>
-
-<a id="parseHex" href="#parseHex">#</a> __parseHex__(_string_) → _color_
-
-Parses hex strings of 3, 4, 6, or 8 characters, with or without the `#` prefix, and returns `rgb` color objects.
-
-```js
-import { parseHex } from 'culori';
-
-parseHex('#abc');
-parseHex('#abcd');
-parseHex('#abcdef');
-parseHex('#abcdef12');
-```
-
-<a id="parseHsl" href="#parseHsl">#</a> __parseHsl__(_string_) → _color_
-
-Parses `hsl(…)` strings in the modern format and returns `hsl` color objects.
-
-<a id="parseHslLegacy" href="#parseHslLegacy">#</a> __parseHslLegacy__(_string_) → _color_
-
-Parses `hsl(…)` / `hsla(…)` strings in the legacy (comma-separated) format and returns `hsl` color objects.
-
-<a id="parseHwb" href="#parseHwb">#</a> __parseHwb__(_string_) → _color_
-
-Parses `hwb(…)` strings and returns `hwb` color objects.
-
-<a id="parseLab" href="#parseLab">#</a> __parseLab__(_string_) → _color_
-
-Parses `lab(…)` strings and returns `lab` color objects.
-
-<a id="parseLch" href="#parseLch">#</a> __parseLch__(_string_) → _color_
-
-Parses `lch(…)` strings and returns `lch` color objects.
-
-<a id="parseNamed" href="#parseNamed">#</a> __parseNamed__(_string_) → _color_
-
-Parses named CSS colors (eg. `tomato`) and returns `rgb` color objects.
-
-<a id="parseOklab" href="#parseOklab">#</a> __parseOklab__(_string_) → _color_
-
-Parses `oklab(…)` strings and returns `oklab` color objects.
-
-<a id="parseOklch" href="#parseOklch">#</a> __parseOklch__(_string_) → _color_
-
-Parses `oklch(…)` strings and returns `oklch` color objects.
-
-<a id="parseRgb" href="#parseRgb">#</a> __parseRgb__(_color_) → _color_
-
-Parses `rgb(…)` strings in the modern syntax and returns `rgb` color objects.
-
-<a id="parseRgbLegacy" href="#parseRgbLegacy">#</a> __parseRgbLegacy__(_color_) → _color_
-
-Parses `rgb(…)` / `rgba(…)` strings in the legacy (comma-separated) syntax and returns `rgb` color objects.
-
-<a id="parseTransparent" href="#parseTransparent">#</a>__parseTransparent__(_string_) → _color_
-
-Parses the `transparent` string and returns a transparent black `rgb` color object.
-
-### Serialization functions
-
-<a id="serializeHex" href="#serializeHex">#</a>__serializeHex__(_color_)
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Serialize a `rgb` _color_ to a 6-character hex code. See [`formatHex()`](#formatHex) for details.
-
-<a id="serializeHex8" href="#serializeHex8">#</a>__serializeHex8__(_color_)
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Serialize a `rgb` _color_ to a 8-character hex code. See [`formatHex8()`](#formatHex8) for details.
-
-<a id="serializeHsl" href="#serializeHsl">#</a>__serializeHsl__(_color_)
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Serialize a `hsl` _color_ to a `hsl(…)` string. See [`formatHsl()`](#formatHsl) for details.
-
-<a id="serializeRgb" href="#serializeRgb">#</a>__serializeRgb__(_color_)
-
-<span aria-label='Source:'>☞</span> [src/formatter.js]({{codebase}}/src/formatter.js)
-
-Serialize a `rgb` _color_ to a `rgb(…)` string. See [`formatRgb()`](#formatRgb) for details.
-
-### Conversion functions
-
-Function | Conversion
--------- | ----------
-__convertA98ToXyz65__(_color_) → _color_ | `a98` → `xyz65`
-__convertCubehelixToRgb__(_color_) → _color_ |  `cubehelix` → `rgb`
-__convertDlchToLab65__(_color_) → _color_ | `dlch` → `lab65`
-__convertHsiToRgb__(_color_) → _color_ | `hsi` → `rgb`
-__convertHslToRgb__(_color_) → _color_ | `hsl` → `rgb`
-__convertHsvToRgb__(_color_) → _color_ | `hsv` → `rgb`
-__convertHwbToRgb__(_color_) → _color_ | `hwb` → `rgb`
-__convertJabToJch__(_color_) → _color_ | `jab` → `jch`
-__convertJabToRgb__(_color_) → _color_ | `jab` → `rgb`
-__convertJabToXyz65__(_color_) → _color_ | `jab` → `xyz65`
-__convertJchToJab__(_color_) → _color_ | `jch` → `jab`
-__convertLab65ToDlch__(_color_) → _color_ | `lab65` → `dlch`
-__convertLab65ToRgb__(_color_) → _color_ | `lab65` → `rgb`
-__convertLab65ToXyz65__(_color_) → _color_ | `lab65` → `xyz65`
-__convertLabToLch__(_color_) → _color_ | `lab` → `lch`
-__convertLabToRgb__(_color_) → _color_ | `lab` → `rgb`
-__convertLabToXyz50__(_color_) → _color_ | `lab` → `xyz50`
-__convertLchToLab__(_color_) → _color_ | `lch` → `lab`
-__convertLchuvToLuv__(_color_) → _color_ | `lchuv` → `luv`
-__convertLrgbToOklab__(_color_) → _color_ | `lrgb` → `oklab`
-__convertLrgbToRgb__(_color_) → _color_ | `lrgb` → `rgb`
-__convertLuvToLchuv__(_color_) → _color_ | `luv` → `lchuv`
-__convertLuvToXyz50__(_color_) → _color_ | `luv` → `xyz50`
-__convertOkhslToOklab__(_color_) → _color_ | `okhsl` → `oklab`
-__convertOkhsvToOklab__(_color_) → _color_ | `okhsv` → `oklab`
-__convertOklabToLrgb__(_color_) → _color_ | `oklab` → `lrgb`
-__convertOklabToOkhsl__(_color_) → _color_ | `oklab` → `okhsl`
-__convertOklabToOkhsv__(_color_) → _color_ | `oklab` → `okhsv`
-__convertOklabToRgb__(_color_) → _color_ | `oklab` → `rgb`
-__convertP3ToXyz65__(_color_) → _color_ | `p3` → `xyz65`
-__convertProphotoToXyz50__(_color_) → _color_ | `prophoto` → `xyz50`
-__convertRec2020ToXyz65__(_color_) → _color_ | `rec2020` → `xyz65`
-__convertRgbToCubehelix__(_color_) → _color_ | `rgb` → `cubehelix`
-__convertRgbToHsi__(_color_) → _color_ | `rgb` → `hsi`
-__convertRgbToHsl__(_color_) → _color_ | `rgb` → `hsl`
-__convertRgbToHsv__(_color_) → _color_ | `rgb` → `hsv`
-__convertRgbToHwb__(_color_) → _color_ | `rgb` → `hwb`
-__convertRgbToJab__(_color_) → _color_ | `rgb` → `jab`
-__convertRgbToLab65__(_color_) → _color_ | `rgb` → `lab65`
-__convertRgbToLab__(_color_) → _color_ | `rgb` → `lab`
-__convertRgbToLrgb__(_color_) → _color_ | `rgb` → `lrgb`
-__convertRgbToOklab__(_color_) → _color_ | `rgb` → `oklab`
-__convertRgbToXyb__(_color_) → _color_ | `rgb` → `xyb`
-__convertRgbToXyz50__(_color_) → _color_ | `rgb` → `xyz50`
-__convertRgbToXyz65__(_color_) → _color_ | `rgb` → `xyz65`
-__convertRgbToYiq__(_color_) → _color_ | `rgb` → `yiq`
-__convertXybToRgb__(_color_) → _color_ | `xyb` → `rgb`
-__convertXyz50ToLab__(_color_) → _color_ | `xyz50` → `lab`
-__convertXyz50ToLuv__(_color_) → _color_ | `xyz50` → `luv`
-__convertXyz50ToProphoto__(_color_) → _color_ | `xyz50` → `prophoto`
-__convertXyz50ToRgb__(_color_) → _color_ | `xyz50` → `rgb`
-__convertXyz50ToXyz65__(_color_) → _color_ | `xyz50` → `xyz65`
-__convertXyz65ToA98__(_color_) → _color_ | `xyz65` → `a98`
-__convertXyz65ToJab__(_color_) → _color_ | `xyz65` → `jab`
-__convertXyz65ToLab65__(_color_) → _color_ | `xyz65` → `lab65`
-__convertXyz65ToP3__(_color_) → _color_ | `xyz65` → `p3`
-__convertXyz65ToRec2020__(_color_) → _color_ | `xyz65` → `rec2020`
-__convertXyz65ToRgb__(_color_) → _color_ | `xyz65` → `rgb`
-__convertXyz65ToXyz50__(_color_) → _color_ | `xyz65` → `xyz50`
-__convertYiqToRgb__(_color_) → _color_ | `yiq` → `rgb`
-
-
-[css-images-4]: https://drafts.csswg.org/css-images-4/#color-stop-syntax
-[css-easing-1]: http://drafts.csswg.org/css-easing-1
-[smoothstep]: https://en.wikipedia.org/wiki/Smoothstep
-[cie76]: https://en.wikipedia.org/wiki/Color_difference#CIE76
-[cie94]: https://en.wikipedia.org/wiki/Color_difference#CIE94
-[ciede2000]: https://en.wikipedia.org/wiki/Color_difference#CIEDE2000
-[cmc]: https://en.wikipedia.org/wiki/Color_difference#CMC_l:c_(1984)
-[kotsarekno-ramos]: http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf
-[din99ode]: https://de.wikipedia.org/wiki/DIN99-Farbraum#Farbabstandsformel
-[midpoint]: https://github.com/w3c/csswg-drafts/issues/3935
-[eitp-difference]: https://www.itu.int/rec/R-REC-BT.2124/en
diff --git a/docs/colophon.md b/docs/colophon.md
deleted file mode 100644
index 7a86356a..00000000
--- a/docs/colophon.md
+++ /dev/null
@@ -1,12 +0,0 @@
----
-layout: default.njk
-title: Colophon
----
-
-Culori is developed by [Dan Burzo](http://danburzo.ro) with the help of many collaborators, and released under the MIT license. 
-
-The library has been inspired by Mike Bostock's [D3.js](https://github.com/d3) and Gregor Aisch's [chroma.js](https://github.com/gka/chroma.js): they have popularized color science in the browser and provided a blueprint for a color manipulation API. I have learned a tremendous amount by reading through the documentation the source code while developing Culori. D3, in particular, has been a treasure trove of ideas and pointers to academic references.
- 
-I pronounce the name of the library as [[kuːlori]](http://ipa-reader.xyz/?text=ku%CB%90lori). Culori is the Romanian word for ‘colors’. The logo is typeset in [Hatch](https://pstypelab.com/hatchfont) by Mark Caneso.
-
-The code is formatted with [Prettier](https://prettier.io), upkept with [ESLint](https://eslint.org/), tested with [tape](https://github.com/ljharb/tape), and bundled with [esbuild](https://esbuild.github.io/). This website is statically generated using [Eleventy](https://11ty.dev) and published to GitHub Pages.
diff --git a/docs/color-spaces.md b/docs/color-spaces.md
deleted file mode 100644
index 83ba783a..00000000
--- a/docs/color-spaces.md
+++ /dev/null
@@ -1,482 +0,0 @@
----
-layout: default.njk
-title: Color Spaces
----
-
-This is an overview of the color spaces built into Culori, listing their channels and expected ranges.
-
-<details>
-<summary>A note on terminology</summary>
-
-A [color model](https://en.wikipedia.org/wiki/Color_model) is a way to describe colors along certain dimensions. RGB, for example, is a color model: color is expressed as a combination of red, green and blue.
-
-A color model, along with a precise description of how colors in the model are to be interpreted, makes a color _space_. sRGB, Display P3 and ProPhoto RGB are all color spaces that employ the RGB model: they describe colors as combination of red, green, and blue primaries; however, they have different notions of how these red, green, and blue primary colors look.
-
-In some color spaces, such as CIELAB or CIELCh, some channels don't have fixed ranges. For these channels, approximate ranges are obtained by converting all sRGB colors defined by `r, g, b ∈ ℕ ⋂ [0, 255]` to that specific color space. Whenever that's the case, the range is marked with the approximation symbol `≈`.
-
-In addition to the channels listed below, all color spaces also take an optional `alpha` channel with the range `[0, 1]`.
-
-</details>
-
-## Built-in color spaces
-
-### The RGB model
-
-The [RGB color model](https://en.wikipedia.org/wiki/RGB_color_model) describes colors as mixtures of red, green, and blue primaries. Culori implements several RGB color spaces, all sharing these channels:
-
-| Channel | Range    | Description   |
-| ------- | -------- | ------------- |
-| `r`     | `[0, 1]` | Red channel   |
-| `g`     | `[0, 1]` | Green channel |
-| `b`     | `[0, 1]` | Blue channel  |
-
-#### `rgb`
-
-The [sRGB color space](https://en.wikipedia.org/wiki/SRGB), which most people refer to when talking about RGB colors.
-
-Serialized as `color(srgb r g b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-#### `lrgb`
-
-The linear-light form of the sRGB color space.
-
-Serialized as `color(srgb-linear r g b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-#### `a98`
-
-The A98 RGB color space, compatible with the [Adobe RGB (1998) color space](https://en.wikipedia.org/wiki/Adobe_RGB_color_space).
-
-Serialized as `color(a98-rgb r g b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-#### `p3`
-
-The [Display P3 color space](https://en.wikipedia.org/wiki/DCI-P3#Display_P3).
-
-Serialized as `color(display-p3 r g b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-#### `prophoto`
-
-The [ProPhoto RGB color space](https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space).
-
-Serialized as `color(prophoto-rgb r g b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-#### `rec2020`
-
-The [Rec. 2020 color space](https://en.wikipedia.org/wiki/Rec._2020).
-
-Serialized as `color(rec2020 r g b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-### The HSL/HSV/HSI family
-
-[HSL, HSV, and HSI](https://en.wikipedia.org/wiki/HSL_and_HSV) are alternative representations of the RGB color model, created in an attempt to provide a more intuitive way to specify colors.
-
-The _hue_ is identical across all color models in this family; however, the _saturaton_ is computed differently in each. The saturation in HSL is **not interchangeable** with the saturation from HSV, nor HSI. Achromatic colors (shades of gray) will have an `undefined` hue.
-
-As color spaces, they relate to the [`sRGB` color space](#rgb).
-
-#### `hsl`
-
-The HSL color space.
-
-| Channel | Range      | Description       |
-| ------- | ---------- | ----------------- |
-| `h`     | `[0, 360)` | Hue               |
-| `s`     | `[0, 1]`   | Saturation in HSL |
-| `l`     | `[0, 1]`   | Lightness         |
-
-Serialized as `hsl(h s% l%)`. A missing hue is serialized as `0`, with the `none` keyword for any other missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-#### `hsv`
-
-The HSV color space.
-
-| Channel | Range      | Description       |
-| ------- | ---------- | ----------------- |
-| `h`     | `[0, 360)` | Hue               |
-| `s`     | `[0, 1]`   | Saturation in HSV |
-| `v`     | `[0, 1]`   | Value             |
-
-Serialized as `color(--hsv h s v)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-#### `hsi`
-
-The HSI color space.
-
-| Channel | Range      | Description       |
-| ------- | ---------- | ----------------- |
-| `h`     | `[0, 360)` | Hue               |
-| `s`     | `[0, 1]`   | Saturation in HSI |
-| `i`     | `[0, 1]`   | Intensity         |
-
-Serialized as `color(--hsi h s i)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-### HWB
-
-[The HWB color model](https://en.wikipedia.org/wiki/HWB_color_model) was developed by Alvy Ray Smith, who also created the HSV color model. It's meant to be more intuitive for humans to use and faster to compute.
-
-| Channel | Range      | Description |
-| ------- | ---------- | ----------- |
-| `h`     | `[0, 360)` | Hue         |
-| `w`     | `[0, 1]`   | Whiteness   |
-| `b`     | `[0, 1]`   | Blackness   |
-
-Serialized as `hwb(h w% b%)`.
-
-Serialized as `hwb(h w% b%)`. A missing hue is serialized as `0`, with the `none` keyword for any other missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Has gamut limits.
-
-> Smith, Alvy Ray (1996) — ["HWB — A More Intuitive Hue-Based Color Model"](http://alvyray.com/Papers/CG/HWB_JGTv208.pdf), Journal of Graphics, GPU and Game tools.
-
-### CIELAB
-
-The [CIELAB color space](https://en.wikipedia.org/wiki/CIELAB_color_space), also known as CIE 1976 L\*a\*b\*, in Cartesian (Lab) and cylindrical (LCh) forms.
-
-#### `lab`
-
-The CIELAB color space using the [D50 standard illuminant](https://en.wikipedia.org/wiki/Standard_illuminant) as the reference white, following the [CSS Color Module Level 4 specification](https://drafts.csswg.org/css-color/#lab-colors).
-
-| Channel | CSS Reference Range                 | Description           |
-| ------- | --------------------- | --------------------- |
-| `l`     | `[0, 100]`            | Lightness             |
-| `a`     | `[-125, 125]`   | Green–red component   |
-| `b`     | `[-125, 125]` | Blue–yellow component |
-
-Serialized as `lab(l a b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `lch`
-
-The CIELCh color space using the D50 standard illuminant.
-
-| Channel | CSS Reference Range           | Description |
-| ------- | --------------- | ----------- |
-| `l`     | `[0, 100]`      | Lightness   |
-| `c`     | `[0, 150]` | Chroma      |
-| `h`     | `[0, 360)`      | Hue         |
-
-Serialized as `lch(l c h)`. A missing hue is serialized as `0`, with the `none` keyword for any other missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `lab65`
-
-CIELAB relative to the D65 standard illuminant.
-
-| Channel | Range                | Description           |
-| ------- | -------------------- | --------------------- |
-| `l`     | `[0, 100]`           | Lightness             |
-| `a`     | `[-125, 125]` | Green–red component   |
-| `b`     | `[-125, 125]` | Blue–yellow component |
-
-Serialized as `color(--lab-d65 l a b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `lch65`
-
-CIELCh relative to the D65 standard illuminant.
-
-| Channel | Range           | Description |
-| ------- | --------------- | ----------- |
-| `l`     | `[0, 100]`      | Lightness   |
-| `c`     | `[0, 150]` | Chroma      |
-| `h`     | `[0, 360)`      | Hue         |
-
-Serialized as `color(--lch-d65 l c h)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-### CIELUV
-
-The [CIELUV color space](https://en.wikipedia.org/wiki/CIELUV) in Cartesian (Luv) and cylindrical (LCh) forms, using the D50 standard illuminant.
-
-CIELuv has an effective Euclidean color difference function:
-
-```js
-let deltaE_uv = culori.colorDifferenceEuclidean('luv');
-```
-
-#### `luv`
-
-| Channel | Range                 | Description           |
-| ------- | --------------------- | --------------------- |
-| `l`     | `[0, 100]`            | Lightness             |
-| `u`     | `[-84.936, 175.042]`≈ | Green–red component   |
-| `v`     | `[-125.882, 87.243]`≈ | Blue–yellow component |
-
-Serialized as `color(--luv l u v)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `lchuv`
-
-| Channel | Range           | Description |
-| ------- | --------------- | ----------- |
-| `l`     | `[0, 100]`      | Lightness   |
-| `c`     | `[0, 176.956]`≈ | Chroma      |
-| `h`     | `[0, 360)`      | Hue         |
-
-Serialized as `color(--lchuv l c h)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-### DIN99 Lab / LCh
-
-The [DIN99](https://de.wikipedia.org/wiki/DIN99-Farbraum) color space "squishes" the CIELAB D65 color space to obtain an [effective color difference](#culoriDifferenceDin99o) metric that can be expressed as a simple Euclidean distance. The latest iteration of the the standard, DIN99o, is available in Cartesian (`dlab`) and polar (`dlch`) form.
-
-> [_Industrial Color Physics_](https://search.worldcat.org/title/Industrial-color-physics/oclc/663097553), Georg A. Klein, Springer (2010)
-> [DIN 6176](https://www.beuth.de/en/standard/din-6176/292836682), _Colorimetric determination of colour differences of object colours according to the DIN99o formula_
-
-#### `dlab`
-
-The DIN99o color space in Cartesian form.
-
-| Channel | Range                | Description |
-| ------- | -------------------- | ----------- |
-| `l`     | `[0, 100]`           | Lightness   |
-| `a`     | `[-40.09, 45.501]`≈  |
-| `b`     | `[-40.469, 44.344]`≈ |
-
-Serialized as `color(--din99o-lab l a b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `dlch`
-
-The DIN99o color space in cylindrical form.
-
-| Channel | Range          | Description |
-| ------- | -------------- | ----------- |
-| `l`     | `[0, 100]`     | Lightness   |
-| `c`     | `[0, 51.484]`≈ | Chroma      |
-| `h`     | `[0, 360)`     | Hue         |
-
-Serialized as `color(--din99o-lch l c h)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-### Oklab, Oklch, Okhsl, Okhsv
-
-The [Oklab color space](https://bottosson.github.io/posts/oklab/), in Cartesian (Lab) and cylindrical (LCh) forms. It uses the D65 standard illuminant. 
-
-See also: [Okhsl and Okhsv, two new color spaces for color picking](https://bottosson.github.io/posts/colorpicker/).
-
-#### `oklab`
-
-The Oklab color space in Cartesian form.
-
-| Channel | CSS Reference Range              | Description           |
-| ------- | ------------------ | --------------------- |
-| `l`     | `[0, 1]`     | Lightness             |
-| `a`     | `[-0.4, 0.4]` | Green–red component   |
-| `b`     | `[-0.4, 0.4]` | Blue–yellow component |
-
-Serialized as `oklab(l a b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `oklch`
-
-The Oklab color space in cylindrical form.
-
-| Channel | Range         | Description |
-| ------- | ------------- | ----------- |
-| `l`     | `[0, 1]` | Lightness   |
-| `c`     | `[0, 0.4]` | Chroma      |
-| `h`     | `[0, 360)`    | Hue         |
-
-Serialized as `oklch(l c h)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-### `okhsl`
-
-| Channel | Range      | Description       |
-| ------- | ---------- | ----------------- |
-| `h`     | `[0, 360)` | Hue               |
-| `s`     | `[0, 1]`   | Saturation (Okhsl) |
-| `l`     | `[0, 1]`   | Lightness         |
-
-Serialized as `color(--okhsl h s l)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-### `okhsv`
-
-| Channel | Range      | Description       |
-| ------- | ---------- | ----------------- |
-| `h`     | `[0, 360)` | Hue               |
-| `s`     | `[0, 1]`   | Saturation (Okhsv) |
-| `v`     | `[0, 1]`   | Value         |
-
-Serialized as `color(--okhsv h s v)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### Further reading
-
-* [An interactive review of Oklab](https://raphlinus.github.io/color/2021/01/18/oklab-critique.html) by Raph Levien
-* [Notes on Oklab](https://github.com/svgeesus/svgeesus.github.io/blob/master/Color/OKLab-notes.md) and [Better than Lab? Gamut reduction CIE Lab & OKLab](https://www.w3.org/Graphics/Color/Workshop/slides/talk/lilley) by Chris Lilley
-* [[css-color] Add OKLab, OKLCH (#6642)](https://github.com/w3c/csswg-drafts/issues/6642)
-
-### J<sub>z</sub>a<sub>z</sub>b<sub>z</sub>
-
-The J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space, as defined by:
-
-> Muhammad Safdar, Guihua Cui, Youn Jin Kim, and Ming Ronnier Luo, [_"Perceptually uniform color space for image signals including high dynamic range and wide gamut"_](https://doi.org/10.1364/OE.25.015131), Opt. Express 25, 15131-15151 (2017)
-
-#### `jab`
-
-The J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space in Cartesian form.
-
-| Channel | Range              | Description           |
-| ------- | ------------------ | --------------------- |
-| `j`     | `[0, 0.222]`≈      | Lightness             |
-| `a`     | `[-0.109, 0.129]`≈ | Green–red component   |
-| `b`     | `[-0.185, 0.134]`≈ | Blue–yellow component |
-
-Serialized as `color(--jzazbz j a b)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `jch`
-
-The J<sub>z</sub>a<sub>z</sub>b<sub>z</sub> color space in cylindrical form.
-
-| Channel | Range         | Description |
-| ------- | ------------- | ----------- |
-| `j`     | `[0, 0.222]`≈ | Lightness   |
-| `c`     | `[0, 0.190]`≈ | Chroma      |
-| `h`     | `[0, 360)`    | Hue         |
-
-Serialized as `color(--jzczhz j c h)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-### YIQ (`yiq`)
-
-[YIQ](https://en.wikipedia.org/wiki/YIQ) is the color space used by the NTSC color TV system. It contains the following channels:
-
-| Channel | Range              | Description                    |
-| ------- | ------------------ | ------------------------------ |
-| `y`       | `[0, 1]`           | Luma                           |
-| `i`       | `[-0.595, 0.595]`≈ | In-phase (orange-blue axis)    |
-| `q`       | `[-0.522, 0.522]`≈ | Quadrature (green-purple axis) |
-
-Serialized as `color(--yiq y i q)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-The conversion matrices between the sRGB and YIQ color spaces are taken from:
-
-> Yuriy Kotsarenko, Fernando Ramos, [_Measuring perceived color difference using YIQ NTSC transmission color space in mobile applications_](http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf), Programación Matemática y Software (2010), Vol. 2, No 2.
-
-### CIE XYZ
-
-The [CIE XYZ color space](https://en.wikipedia.org/wiki/CIE_1931_color_space), also known as the CIE 1931 color space.
-
-#### `xyz50`
-
-The CIE XYZ color space in respect to the D50 standard illuminant.
-
-| Channel | Range         | Description |
-| ------- | ------------- | ----------- |
-| `x`       | `[0, 0.964]`≈ | ?           |
-| `y`       | `[0, 0.999]`≈ | ?           |
-| `z`       | `[0, 0.825]`≈ | ?           |
-
-Serialized as `color(xyz-d50 x y z)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-#### `xyz65`
-
-The CIE XYZ color space in respect to the D65 standard illuminant.
-
-| Channel | Range         | Description |
-| ------- | ------------- | ----------- |
-| `x`       | `[0, 0.950]`≈ | ?           |
-| `y`       | `[0, 1]`≈     | ?           |
-| `z`       | `[0, 1.088]`≈ | ?           |
-
-Serialized as `color(xyz-d65 x y z)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-### XYB 
-
-The XYB color model is part of [the JPEG XL Image Coding System](https://ds.jpeg.org/whitepapers/jpeg-xl-whitepaper.pdf), as an <q>LMS-based colour model inspired by the human visual system, facilitating perceptually uniform quantization. It uses a gamma of 3 for computationally efficient decoding</q>. 
-
-#### `xyb`
-
-The default XYB color space, defined in relationship to sRGB. 
-
-It has the default _Chroma from Luma_ adjustment applied (effectively Y is subtracted from B) so that colors with `{ x: 0, b: 0 }` coordinates are achromatic.
-
-| Channel | Range         | Description |
-| ------- | ------------- | ----------- |
-| `x`       | `[-0.0154, 0.0281]`≈ | Cyan-red component           |
-| `y`       | `[0, 0.8453]`≈     | Luma           |
-| `b`       | `[ -0.2778, 0.3880 ]`≈ | Blue-yellow component           |
-
-Does not have gamut limits.
-
-### <abbr>IC<sub>t</sub>C<sub>p</sub></abbr>
-
-<abbr>IC<sub>t</sub>C<sub>p</sub></abbr> (or <abbr>ITP</abbr>) color space developed by [Dolby Laboratories](https://professional.dolby.com/siteassets/pdfs/ictcp_dolbywhitepaper_v071.pdf), as defined in [<abbr>ITU-R</abbr> Recommendation BT.2100](https://www.itu.int/rec/R-REC-BT.2100). It is included in the <abbr>CSS</abbr> [<abbr>HDR</abbr> Color Module Level 1](https://drafts.csswg.org/css-color-hdr/#ICtCp) specification.
-
-#### `itp`
-
-| Channel | Range             | Description           |
-|---------|-------------------|-----------------------|
-| `i`     | `[0, 0.581]`≈     | Intensity             |
-| `t`    | `[-0.282, 0.278]`≈ | Blue-yellow component (“tritanopia”) |
-| `p`    | `[-0.162, 0.279]`≈ | Green–red component (“protanopia”)  |
-
-Serialized as `color(--ictcp i t p)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
-
-The `itp` color space is the basis of the [ΔE<sub>ITP</sub> color difference](/api/#differenceItp) metric defined in _Objective metric for the assessment of the potential visibility of colour differences in television_ ([Rec. ITU-R BT.2124](https://www.itu.int/rec/R-REC-BT.2124/en)).
-
-### Cubehelix
-
-[The Cubehelix color scheme](https://www.mrao.cam.ac.uk/~dag/CUBEHELIX/) was described by Dave Green in this paper:
-
-> Green, D. A., 2011, [_"A colour scheme for the display of astronomical intensity images"_](http://astron-soc.in/bulletin/11June/289392011.pdf), Bulletin of the Astronomical Society of India, 39, 289. ([2011BASI...39..289G](https://ui.adsabs.harvard.edu/#abs/2011BASI...39..289G) at [ADS](https://ui.adsabs.harvard.edu/))
-
-It was expanded into a cylindrical color space by [Mike Bostock](https://en.wikipedia.org/wiki/Mike_Bostock) and [Jason Davies](https://www.jasondavies.com/) in [D3](https://github.com/d3/d3-color).
-
-#### `cubehelix`
-
-The channels in the `cubehelix` color space maintain the conventions from D3, namely:
-
-| Channel | Range        | Description                                                              |
-| ------- | ------------ | ------------------------------------------------------------------------ |
-| `h`     | `[0, 360)`   | Hue (Based on _start color_ and _rotations_ as defined in Green's paper) |
-| `s`     | `[0, 4.614]` | Saturation (Called _hue_ in op. cit.)                                    |
-| `l`     | `[0, 1]`     | Lightness                                                                |
-
-Serialized as `color(--cubehelix h s l)`, with the `none` keyword for any missing color channel. An explicit `alpha < 1` is included as ` / alpha`.
-
-Does not have gamut limits.
diff --git a/docs/getting-started.md b/docs/getting-started.md
deleted file mode 100644
index 95b35687..00000000
--- a/docs/getting-started.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-layout: default.njk
-title: "Getting Started with Culori"
----
-
-## Install Culori from npm
-
-Culori is distributed [on npm](https://npmjs.com/package/culori) in a variety of formats. Install it with:
-
-```bash
-npm install culori
-```
-
-Then start importing functions from [the API](/api/):
-
-```js
-import { rgb } from 'culori';
-
-rgb('tomato');
-// ⇒ Object { mode: "rgb", r: 1, g: 0.38823529411764707, b: 0.2784313725490196 }
-```
-
-For code that runs in browsers, you may want to streamline the bundle to only include the parts of Culori you're using. See [Optimize bundle size with tree-shaking](/guides/tree-shaking/) for guidance on switching your imports to use `'culori/fn'` instead of `'culori'` once you're done prototyping.
-
-## Fetch Culori from a CDN
-
-You can use Culori from your favorite Content Delivery Network to create quick prototypes in HTML. Here are a few popular choices: 
-
-CDN | URL
---- | ---
-[unpkg](https://unpkg.com/) | `https://unpkg.com/{{pkg.name}}`
-[jsDelivr](https://www.jsdelivr.com/) | `https://cdn.jsdelivr.net/npm/{{pkg.name}}`
-[skypack](https://www.skypack.dev/) | `https://cdn.skypack.dev/{{pkg.name}}`
-
-Use it as an ES module: 
-
-```html
-<script type='module'>
-	import { rgb } from 'https://cdn.skypack.dev/{{pkg.name}}';
-	console.log(rgb('salmon'));
-</script>
-```
-
-...or using a traditional `<script>` tag. The library will be made available under the `culori` global variable:
-
-```html
-<script src="https://unpkg.com/culori"></script>
-<script>
-	console.log(culori.rgb('salmon'));
-</script>
-```
-
-## Use Culori online
-
-### In your browser's console
-
-The library is available on this website as the global variable `culori`, so can try the API in your browser's console as you read through the examples. 
-
-### Observable
-
-If you prefer to see the results visually, [Observable](https://beta.observablehq.com) is a great place to tinker with the library. 
-
-Add this cell and you're good to go:
-
-```js
-culori = import('culori@{{pkg.version}}');
-```
-
-It's often useful to pin the library to a specific version, to make sure your old notebooks don't break if the API changes in a new major version of the library.
-
-## Use Culori in Deno
-
-The library is published to [deno.land/x/culori](https://deno.land/x/culori) for usage in [Deno](https://deno.land/):
-
-```js
-import { rgb } from 'https://deno.land/x/culori@v{{pkg.version}}/index.js';
-
-rgb('tomato');
-```
diff --git a/docs/guides/guides.json b/docs/guides/guides.json
deleted file mode 100644
index 4f41e337..00000000
--- a/docs/guides/guides.json
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-	"layout": "default.njk"
-}
diff --git a/docs/guides/index.md b/docs/guides/index.md
deleted file mode 100644
index e7ab2032..00000000
--- a/docs/guides/index.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: 'Guides'
----
-
-## Working with Culori 
-
-### [Optimize bundle size with tree-shaking](./tree-shaking/)
-
-Once you're done prototyping and you're ready to ship an optimized bundle, switch your imports over to the fully tree-shakeable version.
-
-### [Migration guide](./migration/)
-
-This guide documents the breaking changes in each new major release of the library and how to address them in your code.
-
-## Elsewhere
-
-[Coloring With Code — A Programmatic Approach To Design](https://tympanus.net/codrops/2021/12/07/coloring-with-code-a-programmatic-approach-to-design/), a tutorial by George Francis.
diff --git a/docs/guides/migration.md b/docs/guides/migration.md
deleted file mode 100644
index 2adcd79c..00000000
--- a/docs/guides/migration.md
+++ /dev/null
@@ -1,179 +0,0 @@
----
-title: 'Migration guide'
----
-
-## From v2 to v3
-
-### Custom identifiers removed from the `color()` syntax
-
-For better alignment with the CSS Color Level 4 specification, support for the following formats has changed:
-
-* `color(--oklab)` removed in favor of `oklab()`
-* `color(--oklch)` removed in favor of `oklch()`
-* `color(--srgb-linear)` removed in favor of `color(srgb-linear)`
-* `color(--xyz-d50)` removed in favor of `color(xyz-d50)`
-* `color(--xyz-d65)` removed in favor of `color(xyz)` and `color(xyz-d65)`
-
-The custom identifiers removed in this release can be re-registered with [`useParser()`](/api/#useParser), using string arguments:
-
-```js
-import { useParser } from 'culori';
-
-useParser('--oklab', 'oklab');
-useParser('--oklch', 'oklch');
-useParser('--srgb-linear', 'lrgb');
-useParser('--xyz-d50', 'xyz50');
-useParser('--xyz-d65', 'xyz65');
-```
-
-### Parsing modern vs. legacy syntaxes for `rgb()` and `hsl()`
-
-The parsing of the [modern syntax](https://w3c.github.io/csswg-drafts/css-color-4/#color-syntax-modern) (space-separated) and the [legacy syntax](https://w3c.github.io/csswg-drafts/css-color-4/#color-syntax-legacy) (comma-separated) for the `rgb` and `hsl` color spaces has been split to separate functions:
-
-* `parseRgb()` now parses just the modern `rgb()` / `rgba()` syntax
-* `parseHsl()` now parses just the modern `hsl()` / `hsla()` syntax
-* `parseRgbLegacy()` has been added to the API to parse the legacy `rgb()` / `rgba()` syntax
-* `parseHslLegacy()` has been added to the API to parse the legacy `hsl()` / `hsla()` syntax
-
-## From v1 to v2
-
-* all color components in all CSS color syntaxes now accept the `none` keyword. ([w3c/csswg-drafts#6107](https://github.com/w3c/csswg-drafts/issues/6107))
-
-### XYZ D50 vs. D65
-
-The CSS Color Module Level 4 specification has been updated to include separate predefined color profiles for the XYZ color space for the two most common white points: `xyz-d50` for the D50 illuminant, and `xyz-d65` for the D65 illuminant. The `xyz` predefined color profile is now an alias for the D65-relative XYZ color space. ([w3c/csswg-drafts#6722](https://github.com/w3c/csswg-drafts/issues/6722)). 
-
-In Culori, the D50-relative XYZ color space has been changed to use `mode: 'xyz50'` instead of `mode: 'xyz'`. __The latter mode is no longer supported.__ If you store color objects in your application, they will have to have their `mode` property updated accordingly:
-
-```js
-import { formatHex } from 'culori';
-
-let color = getFavoriteColor();
-
-if (color.mode === 'xyz') {
-	color.mode = 'xyz50';
-}
-
-formatHex(color);
-```
-
-When parsing strings, CSS colors in the `color(xyz x y z)` format will be parsed as `mode: 'xyz65'` instead of `mode: 'xyz'`:
-
-```js
-import { parse } from 'culori';
-
-// In culori@1.x:
-parse('color(xyz 0.5 0.25 1)');
-// ⇒ { mode: 'xyz', x: 0.5, y: 0.25, z: 1 }
-
-// In culori@2.0:
-parse('color(xyz 0.5 0.25 1)');
-// ⇒ { mode: 'xyz65', x: 0.5, y: 0.25, z: 1 }
-```
-
-When serializing with the [`formatCss()`](/api#formatCss) method, the `xyz50` and `xyz65` modes now use the predefined identifiers `xyz-d50` and `xyz-d65`, as opposed to the custom identifiers `--xyz-d50` and `--xyx-d65` from 1.x:
-
-```js
-import { formatCss } from 'culori';
-
-// In culori@1.x:
-formatCss({ mode: 'xyz65', x: 0.5, y: 0.25, z: 1 });
-// ⇒ color(--xyz-d65 0.5 0.25 1)
-
-// In culori@2.0:
-formatCss({ mode: 'xyz65', x: 0.5, y: 0.25, z: 1 });
-// ⇒ color(xyz-d65 0.5 0.25 1)
-```
-
-The following exports have been renamed in [all applicable entry points](/guides/tree-shaking):
-
-* <code>modeXyz</code> → <code>modeXyz<strong>50</strong></code>
-* <code>xyz</code> → <code>xyz<strong>50</strong></code>
-* <code>convertLabToXyz</code> → <code>convertLabToXyz<strong>50</strong></code>
-* <code>convertLuvToXyz</code> → <code>convertLuvToXyz<strong>50</strong></code>
-* <code>convertProphotoToXyz</code> → <code>convertProphotoToXyz<strong>50</strong></code>
-* <code>convertRgbToXyz</code> → <code>convertRgbToXyz<strong>50</strong></code>
-* <code>convertXyz65ToXyz</code> → <code>convertXyz65ToXyz<strong>50</strong></code>
-* <code>convertXyzToLab</code> → <code>convertXyz<strong>50</strong>ToLab</code>
-* <code>convertXyzToLuv</code> → <code>convertXyz<strong>50</strong>ToLuv</code>
-* <code>convertXyzToProphoto</code> → <code>convertXyz<strong>50</strong>ToProphoto</code>
-* <code>convertXyzToRgb</code> → <code>convertXyz<strong>50</strong>ToRgb</code>
-* <code>convertXyzToXyz65</code> → <code>convertXyz<strong>50</strong>ToXyz65</code>
-
-### `<number>` for L no longer valid in `lab()` and `lch()`
-
-CSS defines the `lab` syntax as `lab(<percentage> <number> <number>)`, for example:
-
-```css
-lab(75% 40 30)
-```
-
-...and the `lch` syntax as `lch(<percentage> <number> <hue>)`:
-
-```css
-lch(75% 50 15deg)
-```
-
-Culori used to support `<number>` as the L channel, so these colors used to be also valid:
-
-```css
-lab(75 40 30)
-lch(75 50 15deg)
-```
-
-In version 2.0, we drop this quirk and bring Culori in line with the specification.
-
-
-## From v0.x to v1
-
-### Using the library
-
-Starting with version 1.0, Culori will be published to npm as an ES Module (ESM) package, with `type: module` and a set of `exports` in its `package.json` file.
-
-If you're using Node.js 10, you should be able to continue using Culori as before. 
-
-If you're on Node.js 12 or later, and you've switched to native ES modules (by adding `type: module` to your `package.json`), you need to use `import`:
-
-```js
-import * as culori from 'culori';
-```
-
-If you're on Node.js 12 or later, and you're still using CommonJS modules, there's a separate export that can be used with `require()` calls:
-
-```js
-const culori = require('culori/require');
-```
-
-### Removed methods
-
-The `clamp(method)` function has been removed. Use `clampRgb()` and `clampChroma()` instead.
-
-The `formatter(method)` function has been removed. Use `formatHex()`, `formatRgb()` etc. instead.
-
-The following undocumented interpolation functions have been removed (note the `interpolate` prefix):
-
--   `interpolateLinear()`
--   `interpolateCosine()`
--   `interpolateSplineBasis()`
--   `interpolateSplineNatural()`
--   `interpolateSplineMonotone()`
-
-The `differenceDino99()` color difference function has been removed. Use `differenceEuclidean('dlab')` instead.
-
-The methods `deficiencyProt`, `deficiencyDeuter`, and `deficiencyTrit` have been removed. Use `filterDeficiencyProt`, `filterDeficiencyDeuter`, and `filterDeficiencyTrit` instead.
-
-### Renamed methods
-
-The following methods have been renamed:
-
--   `defineMode()` → `useMode()`;
--   `getModeDefinition()` → `getMode()`.
-
-### Color space definitions
-
-A few properties on the [color space definition object](/api#color-space-def) have been changed for better clarity.
-
--   `input` → `fromMode`
--   `output` → `toMode`
--   `parsers` → `parse`
--   `serialize` as string now only includes the color profile identifier, without the `color(` prefix, eg. from `serialize: "color(--hsv "` to `serialize: "--hsv"`.
diff --git a/docs/guides/tree-shaking.md b/docs/guides/tree-shaking.md
deleted file mode 100644
index e58bc5dc..00000000
--- a/docs/guides/tree-shaking.md
+++ /dev/null
@@ -1,135 +0,0 @@
----
-title: 'Optimize bundle size with tree-shaking'
----
-
-The default `culori` import comes with the full set of color spaces and functions to let you prototype quickly and with fewer errors. However, the way color spaces are initialized prevents the library from being tree-shaken, so when you use a bundler (such as [esbuild](https://esbuild.github.io/), [Vite](https://vitejs.dev/), or [Parcel](https://parceljs.org/)), the entire Culori library is bundled regardless of what you're actually using.
-
-This guides walks you through switching your imports to the tree-shakeable version once you're done prototyping and you're ready to ship an optimized bundle.
-
-## Using `culori/fn`
-
-To optimize the bundle size, you can opt into the tree-shakeable version by importing from `culori/fn` instead of `culori`:
-
-```js
-import { …, …, … } from 'culori/fn';
-```
-
-It works like the default import, with one key difference: __none of the color spaces are pre-registered into the library__. In fact, if you'd try to `parse()` a valid CSS color without having registered any color space, you'd get back `undefined`:
-
-```js
-import { parse } from 'culori/fn';
-
-parse('tomato');
-// ⇒ undefined
-```
-
-Instead, you need to import the definitions of the color spaces you want to support and register them manually with the `useMode()` method.
-
-Since none of the color spaces are pre-registered the shortcuts to `converter(mode)`, such as `culori.rgb` or `culori.hsl`, are also missing. They are, however, helpfully returned by `useMode()`:
-
-```js
-import { useMode, modeRgb } from 'culori/fn';
-
-const rgb = useMode(modeRgb);
-
-console.log(rgb('tomato'));
-// ⇒ Object { mode: "rgb", r: 1, g: 0.38823529411764707, b: 0.2784313725490196 }
-```
-
-To recreate a subset of Culori that only deals with valid CSS colors, you would use this: 
-
-```js
-import {
-	useMode,
-	modeA98,
-	modeHsl,
-	modeHwb,
-	modeLab,
-	modeLch,
-	modeOklab,
-	modeOklch,
-	modeP3,
-	modeProphoto,
-	modeRec2020,
-	modeRgb,
-	modeXyz50,
-	modeXyz65
-} from 'culori/fn';
-
-const a98 = useMode(modeA98);
-const hsl = useMode(modeHsl);
-const hwb = useMode(modeHwb);
-const lab = useMode(modeLab);
-const lch = useMode(modeLch);
-const oklab = useMode(modeOklab);
-const oklch = useMode(modeOklch);
-const p3 = useMode(modeP3);
-const prophoto = useMode(modeProphoto);
-const rec2020 = useMode(modeRec2020);
-const rgb = useMode(modeRgb);
-const xyz50 = useMode(modeXyz50);
-const xyz65 = useMode(modeXyz65);
-```
-
-You don't need to do all of this manually. You can import the [CSS bundle](#culori-css) instead.
-
-### Using Culori without registering color spaces
-
-You can import and use the [low-level parsing and conversion functions](/api#low-level-api) without registering any color space beforehand:
-
-__hex-to-hsl-string.js__
-```js
-import { parseHex, convertRgbToHsl, serializeHsl } from 'culori/fn';
-
-console.log(
-	serializeHsl(
-		convertRgbToHsl(
-			parseHex('#ffcc00')
-		)
-	)
-);
-// ⇒ hsl(48, 100%, 50%)
-```
-
-When using a bundler such as [esbuild](https://esbuild.github.io/), a minified build fits on the back of a napkin.
-
-<details>
-<summary>Show esbuild output for code above</summary>
-
-```bash
-esbuild --bundle --minify hex-to-hsl-string.js
-```
-
-<code style='word-break: break-all;'>(()=>{var b=(e,o)=>{if(typeof e=="number"){if(o===3)return{mode:"rgb",r:(e>>8&15|e>>4&240)/255,g:(e>>4&15|e&240)/255,b:(e&15|e<<4&240)/255};if(o===4)return{mode:"rgb",r:(e>>12&15|e>>8&240)/255,g:(e>>8&15|e>>4&240)/255,b:(e>>4&15|e&240)/255,alpha:(e&15|e<<4&240)/255};if(o===6)return{mode:"rgb",r:(e>>16&255)/255,g:(e>>8&255)/255,b:(e&255)/255};if(o===8)return{mode:"rgb",r:(e>>24&255)/255,g:(e>>16&255)/255,b:(e>>8&255)/255,alpha:(e&255)/255}}},u=b;var c=/^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i,x=e=>{let o;return(o=e.match(c))?u(parseInt(o[1],16),o[1].length):void 0},l=x;function f({r:e,g:o,b:t,alpha:s}){let r=Math.max(e,o,t),a=Math.min(e,o,t),i={mode:"hsl",s:r===a?0:(r-a)/(1-Math.abs(r+a-1)),l:.5*(r+a)};return r-a!=0&&(i.h=(r===e?(o-t)/(r-a)+(o<t)*6:r===o?(t-e)/(r-a)+2:(e-o)/(r-a)+4)*60),s!==void 0&&(i.alpha=s),i}function p(e=4){return o=>typeof o=="number"?Math.round(o*(e=Math.pow(10,e)))/e:o}var n=p(2),d=e=>Math.max(0,Math.min(1,e));var m=e=>{if(e===void 0)return;let o=n(e.h||0),t=n(d(e.s)*100),s=n(d(e.l)*100);return e.alpha===void 0||e.alpha===1?`hsl(${o}, ${t}%, ${s}%)`:`hsla(${o}, ${t}%, ${s}%, ${n(d(e.alpha))})`};console.log(m(f(l("#ffcc00"))));})();
-</code>
-</details>
-
-## Bootstrap packages
-
-For convenience, a couple of bootstrap packages are available.
-
-<h3 id='culori-css'><code>culori/css</code></h3>
-
-Bootstrap all the color spaces available in CSS, plus a handful of  related ones we get for free, since they are used under the hood. 
-
-It provides the following named exports: `a98`, `hsl`, `hsv`, `hwb`, `lab`, `lab65`, `lch`, `lch65`, `lrgb`, `oklab`, `oklch`, `p3`, `prophoto`, `rec2020`, `rgb`, `xyz50`, and `xyz65`.
-
-```js
-import 'culori/css';
-import { interpolate } from 'culori/fn';
-
-interpolate(['red', 'green'], 'lch');
-```
-
-### `culori/all` 
-
-Bootstrap all the color spaces available in Culori.
-
-It provides the following named exports: `a98`, `cubehelix`, `dlab`, `dlch`, `hsi`, `hsl`, `hsv`, `hwb`, `itp`, `jab`, `jch`, `lab`, `lab65`, `lch`, `lch65`, `lchuv`, `lrgb`, `luv`, `okhsl`, `okhsv`, `oklab`, `oklch`, `p3`, `prophoto`, `rec2020`, `rgb`, `xyb`, `xyz50`, `xyz65`, and `yiq`.
-
-```js
-import 'culori/all';
-import { interpolate } from 'culori/fn';
-
-interpolate(['red', 'green'], 'xyb');
-```
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
deleted file mode 100644
index 379b1e03..00000000
--- a/docs/index.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Color functions for JavaScript
-homepage: true
-layout: default.njk
----
-
-[css4-colors]: https://drafts.csswg.org/css-color/
-[css4-named-colors]: https://drafts.csswg.org/css-color/#named-colors
-[din99o]: https://de.wikipedia.org/wiki/DIN99-Farbraum
-[hex-colors]: https://drafts.csswg.org/css-color/#hex-notation
-[rgb-colors]: https://drafts.csswg.org/css-color/#rgb-functions
-[hsl-colors]: https://drafts.csswg.org/css-color/#the-hsl-notation
-[hwb-colors]: https://drafts.csswg.org/css-color/#the-hwb-notation
-[lab-colors]: https://drafts.csswg.org/css-color/#lab-colors
-
-Culori is a JavaScript color library that supports the conversion and manipulation of all formats defined in the [CSS Colors Level 4][css4-colors] specification, plus [additional color spaces](./color-spaces). It handles [color differences](https://en.wikipedia.org/wiki/Color_difference), interpolation, gradients, blend modes [and much more](/api/).
-
-```bash
-npm install culori
-```
-
-<a class='btn-link' href='./getting-started'>Get started</a>
-
-## What sets Culori apart?
-
-__A function-oriented API.__ Colors are represented as plain JavaScript objects you pass through a series of [functions](./api), which makes it super easy to extend.
-
-__Accurate alpha.__ On the `alpha` channel, the library doesn't equate an `undefined` value with an opaque color, but rather with a color for which we don't care about the opacity. This gives you the opportunity to interpret `undefined` as you see fit. The hex string <kbd>#ff0000</kbd> _should_ probably be rendered as fully opaque red, but for running functions on colors it's useful to discern <kbd>#ff0000</kbd> from <kbd>#ff0000ff</kbd> — the former has an implicit alpha of 1, while for the latter it's explicit.
-
-__Comprehensive functionality.__ Build advanced color tools with Culori's rich collection of color spaces and functions.
-
-__Tree-shakeable version available.__ When you're ready to optimize for bundle size, switch to [a tree-shakeable version of the library](./guides/tree-shaking).
diff --git a/docs/resources.md b/docs/resources.md
deleted file mode 100644
index b1ae751b..00000000
--- a/docs/resources.md
+++ /dev/null
@@ -1,63 +0,0 @@
----
-layout: default.njk
-title: Resources
----
-
-## Culori extras
-
-These projects add more functionality to Culori, but they're separate as to keep the core bundle small:
-
--   [culori-scales](https://github.com/evercoder/culori-scales) — color scales (ColorBrewer, matplotlib, etc).
--   [culori-names](https://github.com/evercoder/culori-names) — More named colors, from a variety of sources.
--   [d3-color-difference](https://github.com/evercoder/d3-color-difference) — a separate D3.js plugin to compute color differences
-
-## Products using Culori
-
--   [Moqups](https://moqups.com) — all our color-manipulation functions are handled by Culori.
--   [Schemist](https://github.com/felixgirault/schemist) — color schemes builder backed by Culori.
--   [Color Name API](https://github.com/meodai/color-name-api) — a REST API for color names that makes use Culori's [differenceCiede2000](https://culorijs.org/api/#differenceCiede2000) to return a fitting name for every color.
--   [Atmos](https://atmos.style) - a toolbox based on (OK)LCH color space for creating professional color palettes. Utilizing Culori for color manipulation allowed us to concentrate on our product's essence rather than getting bogged down in implementation details.
--   [huetiful-js](https://github.com/prjctimg/huetiful) - Open source Typescript library for manipulating color and generating custom color scales based on Culori. With utilities for sorting, filtering and querying collections of colors, this library opens new ways of working with color programmatically.
--   [oklch.com/](https://oklch.com/) - OKLCH picker with pretty plotting
-
-_Does your product/project use Culori? Create a PR and add yourself to this list._
-
-## Similar projects
-
--   [d3-color](https://github.com/d3/d3-color) by [Mike Bostock](https://bost.ocks.org/mike/) (JavaScript)
--   [chroma.js](https://github.com/gka/chroma.js) by [Gregor Aisch](https://driven-by-data.net/) (JavaScript)
--   [colorjs.io](https://github.com/LeaVerou/color.js) by [Lea Verou](http://lea.verou.me/) and [Chris Lilley](https://svgees.us/) (JavaScript)
--   [@texel/color](https://github.com/texel-org/color/) by [Matt DesLauriers](https://www.mattdesl.com/) (JavaScript)
--   [Colour](https://www.colour-science.org/) (Python)
-- [ColorAide](https://github.com/facelessuser/coloraide) by Isaac Muse (Python)
--   [colorio](https://github.com/nschloe/colorio) by Nico Schlömer (Python)
--   [`colorspace` package](http://colorspace.r-forge.r-project.org/) (R)
--   [`Colors` package](https://github.com/JuliaGraphics/Colors.jl) (Julia)
-- [`linebender/color`](https://github.com/linebender/color) by Raph Levien & collaborators (Rust)
-
-## Further reading
-
-### Specifications
-
-- [CSS Color Module Level 4](https://drafts.csswg.org/css-color-4/) [[changelog](https://github.com/w3c/csswg-drafts/commits/main/css-color-4), [issues](https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Acss-color-4)]
-- [CSS Color Module Level 5](https://drafts.csswg.org/css-color-5/) [[changelog](https://github.com/w3c/csswg-drafts/commits/main/css-color-5), [issues](https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Acss-color-5)]
-- [CSS Color HDR Module Level 1](https://drafts.csswg.org/css-color-hdr/) [[changelog](https://github.com/w3c/csswg-drafts/commits/main/css-color-hdr), [issues](https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Acss-color-hdr)]
-
-### Websites
-
--   David Briggs’s [The Dimensions of Color](http://www.huevaluechroma.com/)
--   Bruce Lindbloom’s [Useful Color Math](http://www.brucelindbloom.com/index.html?Math.html)
--   Rune Madsen’s [Programming Design Systems](https://programmingdesignsystems.com/)
-
-### Articles
-
--   [Color: From Hexcodes to Eyeballs](http://jamie-wong.com/post/color/) by Jamie Wong
--   [Okay, color spaces](https://ericportis.com/posts/2024/okay-color-spaces/) by Eric Portis
--   [How to generate color palettes for design systems](https://matthewstrom.com/writing/generating-color-palettes/) by Matthew Ström
-
-### Books
-
--   [Fairchild, Mark D.](http://markfairchild.org/) — [_Color Appearance Models_](https://www.wiley.com/en-us/Color+Appearance+Models%2C+3rd+Edition-p-9781119967033), 3rd Edition, Wiley, 2013.
-- Green, Phil (ed.) — [_Fundamentals and Applications of Colour Engineering_](https://onlinelibrary.wiley.com/doi/book/10.1002/9781119827214), Wiley, 2023.
-- Morovič, Ján — [_Color Gamut Mapping_](https://www.wiley.com/en-ie/Color+Gamut+Mapping-p-9780470030325), Wiley, 2008.
--   [Poynton, Charles](http://poynton.ca/) — [_Digital Video and HD Algorithms and Interfaces_](https://www.elsevier.com/books/digital-video-and-hd/poynton/978-0-12-391926-7), 2nd Edition, Morgan Kaufmann, 2012.
diff --git a/eleventy.config.cjs b/eleventy.config.cjs
deleted file mode 100644
index 883bf443..00000000
--- a/eleventy.config.cjs
+++ /dev/null
@@ -1,28 +0,0 @@
-const highlight = require('@11ty/eleventy-plugin-syntaxhighlight');
-
-module.exports = function (env) {
-	env.addPassthroughCopy('docs/img');
-	env.addPassthroughCopy('docs/css');
-	env.addPassthroughCopy({ 'docs/static': '.' });
-
-	env.addFilter('sortby', function (arr, key) {
-		return arr.slice().sort((a, b) => {
-			if (a.data[key] > b.data[key]) {
-				return 1;
-			}
-			if (a.data[key] < b.data[key]) {
-				return -1;
-			}
-			return 0;
-		});
-	});
-	env.addPlugin(highlight);
-	return {
-		pathPrefix: '/',
-		dir: {
-			input: 'docs',
-			output: 'www'
-		},
-		htmlTemplateEngine: 'njk'
-	};
-};
diff --git a/docs/static/favicon.png b/favicon.png
similarity index 100%
rename from docs/static/favicon.png
rename to favicon.png
diff --git a/getting-started/index.html b/getting-started/index.html
new file mode 100644
index 00000000..e549bb13
--- /dev/null
+++ b/getting-started/index.html
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 Getting Started with Culori &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li class="active">
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li >
+							<a href="/api/">API reference</a>
+						</li>
+						<li >
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>Getting Started with Culori</h1>
+				<h2>Install Culori from npm</h2>
+<p>Culori is distributed <a href="https://npmjs.com/package/culori">on npm</a> in a variety of formats. Install it with:</p>
+<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> culori</code></pre>
+<p>Then start importing functions from <a href="/api/">the API</a>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> rgb <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">rgb</span><span class="token punctuation">(</span><span class="token string">'tomato'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ Object { mode: "rgb", r: 1, g: 0.38823529411764707, b: 0.2784313725490196 }</span></code></pre>
+<p>For code that runs in browsers, you may want to streamline the bundle to only include the parts of Culori you're using. See <a href="/guides/tree-shaking/">Optimize bundle size with tree-shaking</a> for guidance on switching your imports to use <code>'culori/fn'</code> instead of <code>'culori'</code> once you're done prototyping.</p>
+<h2>Fetch Culori from a CDN</h2>
+<p>You can use Culori from your favorite Content Delivery Network to create quick prototypes in HTML. Here are a few popular choices:</p>
+<table>
+<thead>
+<tr>
+<th>CDN</th>
+<th>URL</th>
+</tr>
+</thead>
+<tbody>
+<tr>
+<td><a href="https://unpkg.com/">unpkg</a></td>
+<td><code>https://unpkg.com/culori</code></td>
+</tr>
+<tr>
+<td><a href="https://www.jsdelivr.com/">jsDelivr</a></td>
+<td><code>https://cdn.jsdelivr.net/npm/culori</code></td>
+</tr>
+<tr>
+<td><a href="https://www.skypack.dev/">skypack</a></td>
+<td><code>https://cdn.skypack.dev/culori</code></td>
+</tr>
+</tbody>
+</table>
+<p>Use it as an ES module:</p>
+<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">'</span>module<span class="token punctuation">'</span></span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
+	<span class="token keyword">import</span> <span class="token punctuation">{</span> rgb <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'https://cdn.skypack.dev/culori'</span><span class="token punctuation">;</span>
+	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">rgb</span><span class="token punctuation">(</span><span class="token string">'salmon'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
+<p>...or using a traditional <code>&lt;script&gt;</code> tag. The library will be made available under the <code>culori</code> global variable:</p>
+<pre class="language-html"><code class="language-html"><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">src</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>https://unpkg.com/culori<span class="token punctuation">"</span></span><span class="token punctuation">></span></span><span class="token script"></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span>
+<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span><span class="token punctuation">></span></span><span class="token script"><span class="token language-javascript">
+	console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>culori<span class="token punctuation">.</span><span class="token function">rgb</span><span class="token punctuation">(</span><span class="token string">'salmon'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">></span></span></code></pre>
+<h2>Use Culori online</h2>
+<h3>In your browser's console</h3>
+<p>The library is available on this website as the global variable <code>culori</code>, so can try the API in your browser's console as you read through the examples.</p>
+<h3>Observable</h3>
+<p>If you prefer to see the results visually, <a href="https://beta.observablehq.com">Observable</a> is a great place to tinker with the library.</p>
+<p>Add this cell and you're good to go:</p>
+<pre class="language-js"><code class="language-js">culori <span class="token operator">=</span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'culori@4.0.2'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>It's often useful to pin the library to a specific version, to make sure your old notebooks don't break if the API changes in a new major version of the library.</p>
+<h2>Use Culori in Deno</h2>
+<p>The library is published to <a href="https://deno.land/x/culori">deno.land/x/culori</a> for usage in <a href="https://deno.land/">Deno</a>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> rgb <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'https://deno.land/x/culori@v4.0.2/index.js'</span><span class="token punctuation">;</span>
+
+<span class="token function">rgb</span><span class="token punctuation">(</span><span class="token string">'tomato'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/getting-started.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/docs/_includes/default.njk b/guides/index.html
similarity index 62%
rename from docs/_includes/default.njk
rename to guides/index.html
index 0cf75625..2b708106 100644
--- a/docs/_includes/default.njk
+++ b/guides/index.html
@@ -4,39 +4,38 @@
 		<meta charset="utf-8" />
 		<meta name="viewport" content="width=device-width,initial-scale=1" />
 		<title>
-			{% if title %} {{ title }} &middot; culori {% else %} culori {%
-			endif %}
+			 Guides &middot; culori 
 		</title>
 
-		<link rel="icon" type="image/png" href='{{"/favicon.png" | url }}' />
-		<link rel="stylesheet" href='{{"/css/main.css" | url }}' />
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
 	</head>
 	<body>
 		<header>
 			<div class="container">
 				<div class="logo">
-					<a href='{{"/" | url }}'>
+					<a href='/'>
 						<img
 							width="132"
 							height="30"
-							src='{{ "/img/culori.svg" | url }}'
+							src='/img/culori.svg'
 							alt="culori"
 						/>
 					</a>
-					<a href="https://github.com/evercoder/culori/releases">v{{ pkg.version }}</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
 				</div>
 				<nav>
 					<ul class='nav'>
-						<li {% if page.url == '/getting-started/' %}class="active"{% endif %}>
+						<li >
 							<a href="/getting-started/">Get started</a>
 						</li>
-						<li {% if page.url == '/api/' %}class="active"{% endif %}>
+						<li >
 							<a href="/api/">API reference</a>
 						</li>
-						<li {% if page.url == '/color-spaces/' %}class="active"{% endif %}>
+						<li >
 							<a href="/color-spaces/">Color spaces</a>
 						</li>
-						<li {% if page.url == '/guides/' %}class="active"{% endif %}>
+						<li class="active">
 							<a href="/guides/">Guides</a>
 						</li>
 						<li>
@@ -51,8 +50,15 @@
 
 		<div class="container">
 			<article>
-				<h1>{{ title }}</h1>
-				{{ content | safe }}
+				<h1>Guides</h1>
+				<h2>Working with Culori</h2>
+<h3><a href="./tree-shaking/">Optimize bundle size with tree-shaking</a></h3>
+<p>Once you're done prototyping and you're ready to ship an optimized bundle, switch your imports over to the fully tree-shakeable version.</p>
+<h3><a href="./migration/">Migration guide</a></h3>
+<p>This guide documents the breaking changes in each new major release of the library and how to address them in your code.</p>
+<h2>Elsewhere</h2>
+<p><a href="https://tympanus.net/codrops/2021/12/07/coloring-with-code-a-programmatic-approach-to-design/">Coloring With Code — A Programmatic Approach To Design</a>, a tutorial by George Francis.</p>
+
 			</article>
 		</div>
 		<footer>
@@ -65,7 +71,7 @@ <h1>{{ title }}</h1>
 				<p>
 					Can this page be improved?
 					<a
-						href="https://github.com/Evercoder/culori/blob/main/{{ page.inputPath }}"
+						href="https://github.com/Evercoder/culori/blob/main/./docs/guides/index.md"
 						>Edit it on GitHub</a
 					>
 				</p>
diff --git a/guides/migration/index.html b/guides/migration/index.html
new file mode 100644
index 00000000..4fa43f2c
--- /dev/null
+++ b/guides/migration/index.html
@@ -0,0 +1,218 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 Migration guide &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li >
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li >
+							<a href="/api/">API reference</a>
+						</li>
+						<li >
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>Migration guide</h1>
+				<h2>From v2 to v3</h2>
+<h3>Custom identifiers removed from the <code>color()</code> syntax</h3>
+<p>For better alignment with the CSS Color Level 4 specification, support for the following formats has changed:</p>
+<ul>
+<li><code>color(--oklab)</code> removed in favor of <code>oklab()</code></li>
+<li><code>color(--oklch)</code> removed in favor of <code>oklch()</code></li>
+<li><code>color(--srgb-linear)</code> removed in favor of <code>color(srgb-linear)</code></li>
+<li><code>color(--xyz-d50)</code> removed in favor of <code>color(xyz-d50)</code></li>
+<li><code>color(--xyz-d65)</code> removed in favor of <code>color(xyz)</code> and <code>color(xyz-d65)</code></li>
+</ul>
+<p>The custom identifiers removed in this release can be re-registered with <a href="/api/#useParser"><code>useParser()</code></a>, using string arguments:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useParser <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token function">useParser</span><span class="token punctuation">(</span><span class="token string">'--oklab'</span><span class="token punctuation">,</span> <span class="token string">'oklab'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">useParser</span><span class="token punctuation">(</span><span class="token string">'--oklch'</span><span class="token punctuation">,</span> <span class="token string">'oklch'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">useParser</span><span class="token punctuation">(</span><span class="token string">'--srgb-linear'</span><span class="token punctuation">,</span> <span class="token string">'lrgb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">useParser</span><span class="token punctuation">(</span><span class="token string">'--xyz-d50'</span><span class="token punctuation">,</span> <span class="token string">'xyz50'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token function">useParser</span><span class="token punctuation">(</span><span class="token string">'--xyz-d65'</span><span class="token punctuation">,</span> <span class="token string">'xyz65'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<h3>Parsing modern vs. legacy syntaxes for <code>rgb()</code> and <code>hsl()</code></h3>
+<p>The parsing of the <a href="https://w3c.github.io/csswg-drafts/css-color-4/#color-syntax-modern">modern syntax</a> (space-separated) and the <a href="https://w3c.github.io/csswg-drafts/css-color-4/#color-syntax-legacy">legacy syntax</a> (comma-separated) for the <code>rgb</code> and <code>hsl</code> color spaces has been split to separate functions:</p>
+<ul>
+<li><code>parseRgb()</code> now parses just the modern <code>rgb()</code> / <code>rgba()</code> syntax</li>
+<li><code>parseHsl()</code> now parses just the modern <code>hsl()</code> / <code>hsla()</code> syntax</li>
+<li><code>parseRgbLegacy()</code> has been added to the API to parse the legacy <code>rgb()</code> / <code>rgba()</code> syntax</li>
+<li><code>parseHslLegacy()</code> has been added to the API to parse the legacy <code>hsl()</code> / <code>hsla()</code> syntax</li>
+</ul>
+<h2>From v1 to v2</h2>
+<ul>
+<li>all color components in all CSS color syntaxes now accept the <code>none</code> keyword. (<a href="https://github.com/w3c/csswg-drafts/issues/6107">w3c/csswg-drafts#6107</a>)</li>
+</ul>
+<h3>XYZ D50 vs. D65</h3>
+<p>The CSS Color Module Level 4 specification has been updated to include separate predefined color profiles for the XYZ color space for the two most common white points: <code>xyz-d50</code> for the D50 illuminant, and <code>xyz-d65</code> for the D65 illuminant. The <code>xyz</code> predefined color profile is now an alias for the D65-relative XYZ color space. (<a href="https://github.com/w3c/csswg-drafts/issues/6722">w3c/csswg-drafts#6722</a>).</p>
+<p>In Culori, the D50-relative XYZ color space has been changed to use <code>mode: 'xyz50'</code> instead of <code>mode: 'xyz'</code>. <strong>The latter mode is no longer supported.</strong> If you store color objects in your application, they will have to have their <code>mode</code> property updated accordingly:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatHex <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">let</span> color <span class="token operator">=</span> <span class="token function">getFavoriteColor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+<span class="token keyword">if</span> <span class="token punctuation">(</span>color<span class="token punctuation">.</span>mode <span class="token operator">===</span> <span class="token string">'xyz'</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
+	color<span class="token punctuation">.</span>mode <span class="token operator">=</span> <span class="token string">'xyz50'</span><span class="token punctuation">;</span>
+<span class="token punctuation">}</span>
+
+<span class="token function">formatHex</span><span class="token punctuation">(</span>color<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>When parsing strings, CSS colors in the <code>color(xyz x y z)</code> format will be parsed as <code>mode: 'xyz65'</code> instead of <code>mode: 'xyz'</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> parse <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">// In culori@1.x:</span>
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'color(xyz 0.5 0.25 1)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'xyz', x: 0.5, y: 0.25, z: 1 }</span>
+
+<span class="token comment">// In culori@2.0:</span>
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'color(xyz 0.5 0.25 1)'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ { mode: 'xyz65', x: 0.5, y: 0.25, z: 1 }</span></code></pre>
+<p>When serializing with the <a href="/api#formatCss"><code>formatCss()</code></a> method, the <code>xyz50</code> and <code>xyz65</code> modes now use the predefined identifiers <code>xyz-d50</code> and <code>xyz-d65</code>, as opposed to the custom identifiers <code>--xyz-d50</code> and <code>--xyx-d65</code> from 1.x:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> formatCss <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span>
+
+<span class="token comment">// In culori@1.x:</span>
+<span class="token function">formatCss</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'xyz65'</span><span class="token punctuation">,</span> <span class="token literal-property property">x</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token literal-property property">y</span><span class="token operator">:</span> <span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token literal-property property">z</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ color(--xyz-d65 0.5 0.25 1)</span>
+
+<span class="token comment">// In culori@2.0:</span>
+<span class="token function">formatCss</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">mode</span><span class="token operator">:</span> <span class="token string">'xyz65'</span><span class="token punctuation">,</span> <span class="token literal-property property">x</span><span class="token operator">:</span> <span class="token number">0.5</span><span class="token punctuation">,</span> <span class="token literal-property property">y</span><span class="token operator">:</span> <span class="token number">0.25</span><span class="token punctuation">,</span> <span class="token literal-property property">z</span><span class="token operator">:</span> <span class="token number">1</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ color(xyz-d65 0.5 0.25 1)</span></code></pre>
+<p>The following exports have been renamed in <a href="/guides/tree-shaking">all applicable entry points</a>:</p>
+<ul>
+<li><code>modeXyz</code> → <code>modeXyz<strong>50</strong></code></li>
+<li><code>xyz</code> → <code>xyz<strong>50</strong></code></li>
+<li><code>convertLabToXyz</code> → <code>convertLabToXyz<strong>50</strong></code></li>
+<li><code>convertLuvToXyz</code> → <code>convertLuvToXyz<strong>50</strong></code></li>
+<li><code>convertProphotoToXyz</code> → <code>convertProphotoToXyz<strong>50</strong></code></li>
+<li><code>convertRgbToXyz</code> → <code>convertRgbToXyz<strong>50</strong></code></li>
+<li><code>convertXyz65ToXyz</code> → <code>convertXyz65ToXyz<strong>50</strong></code></li>
+<li><code>convertXyzToLab</code> → <code>convertXyz<strong>50</strong>ToLab</code></li>
+<li><code>convertXyzToLuv</code> → <code>convertXyz<strong>50</strong>ToLuv</code></li>
+<li><code>convertXyzToProphoto</code> → <code>convertXyz<strong>50</strong>ToProphoto</code></li>
+<li><code>convertXyzToRgb</code> → <code>convertXyz<strong>50</strong>ToRgb</code></li>
+<li><code>convertXyzToXyz65</code> → <code>convertXyz<strong>50</strong>ToXyz65</code></li>
+</ul>
+<h3><code>&lt;number&gt;</code> for L no longer valid in <code>lab()</code> and <code>lch()</code></h3>
+<p>CSS defines the <code>lab</code> syntax as <code>lab(&lt;percentage&gt; &lt;number&gt; &lt;number&gt;)</code>, for example:</p>
+<pre class="language-css"><code class="language-css"><span class="token function">lab</span><span class="token punctuation">(</span>75% 40 30<span class="token punctuation">)</span></code></pre>
+<p>...and the <code>lch</code> syntax as <code>lch(&lt;percentage&gt; &lt;number&gt; &lt;hue&gt;)</code>:</p>
+<pre class="language-css"><code class="language-css"><span class="token function">lch</span><span class="token punctuation">(</span>75% 50 15deg<span class="token punctuation">)</span></code></pre>
+<p>Culori used to support <code>&lt;number&gt;</code> as the L channel, so these colors used to be also valid:</p>
+<pre class="language-css"><code class="language-css"><span class="token function">lab</span><span class="token punctuation">(</span>75 40 30<span class="token punctuation">)</span>
+<span class="token function">lch</span><span class="token punctuation">(</span>75 50 15deg<span class="token punctuation">)</span></code></pre>
+<p>In version 2.0, we drop this quirk and bring Culori in line with the specification.</p>
+<h2>From v0.x to v1</h2>
+<h3>Using the library</h3>
+<p>Starting with version 1.0, Culori will be published to npm as an ES Module (ESM) package, with <code>type: module</code> and a set of <code>exports</code> in its <code>package.json</code> file.</p>
+<p>If you're using Node.js 10, you should be able to continue using Culori as before.</p>
+<p>If you're on Node.js 12 or later, and you've switched to native ES modules (by adding <code>type: module</code> to your <code>package.json</code>), you need to use <code>import</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token operator">*</span> <span class="token keyword">as</span> culori <span class="token keyword">from</span> <span class="token string">'culori'</span><span class="token punctuation">;</span></code></pre>
+<p>If you're on Node.js 12 or later, and you're still using CommonJS modules, there's a separate export that can be used with <code>require()</code> calls:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">const</span> culori <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">'culori/require'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<h3>Removed methods</h3>
+<p>The <code>clamp(method)</code> function has been removed. Use <code>clampRgb()</code> and <code>clampChroma()</code> instead.</p>
+<p>The <code>formatter(method)</code> function has been removed. Use <code>formatHex()</code>, <code>formatRgb()</code> etc. instead.</p>
+<p>The following undocumented interpolation functions have been removed (note the <code>interpolate</code> prefix):</p>
+<ul>
+<li><code>interpolateLinear()</code></li>
+<li><code>interpolateCosine()</code></li>
+<li><code>interpolateSplineBasis()</code></li>
+<li><code>interpolateSplineNatural()</code></li>
+<li><code>interpolateSplineMonotone()</code></li>
+</ul>
+<p>The <code>differenceDino99()</code> color difference function has been removed. Use <code>differenceEuclidean('dlab')</code> instead.</p>
+<p>The methods <code>deficiencyProt</code>, <code>deficiencyDeuter</code>, and <code>deficiencyTrit</code> have been removed. Use <code>filterDeficiencyProt</code>, <code>filterDeficiencyDeuter</code>, and <code>filterDeficiencyTrit</code> instead.</p>
+<h3>Renamed methods</h3>
+<p>The following methods have been renamed:</p>
+<ul>
+<li><code>defineMode()</code> → <code>useMode()</code>;</li>
+<li><code>getModeDefinition()</code> → <code>getMode()</code>.</li>
+</ul>
+<h3>Color space definitions</h3>
+<p>A few properties on the <a href="/api#color-space-def">color space definition object</a> have been changed for better clarity.</p>
+<ul>
+<li><code>input</code> → <code>fromMode</code></li>
+<li><code>output</code> → <code>toMode</code></li>
+<li><code>parsers</code> → <code>parse</code></li>
+<li><code>serialize</code> as string now only includes the color profile identifier, without the <code>color(</code> prefix, eg. from <code>serialize: &quot;color(--hsv &quot;</code> to <code>serialize: &quot;--hsv&quot;</code>.</li>
+</ul>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/guides/migration.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/guides/tree-shaking/index.html b/guides/tree-shaking/index.html
new file mode 100644
index 00000000..6db926f1
--- /dev/null
+++ b/guides/tree-shaking/index.html
@@ -0,0 +1,183 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 Optimize bundle size with tree-shaking &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li >
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li >
+							<a href="/api/">API reference</a>
+						</li>
+						<li >
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>Optimize bundle size with tree-shaking</h1>
+				<p>The default <code>culori</code> import comes with the full set of color spaces and functions to let you prototype quickly and with fewer errors. However, the way color spaces are initialized prevents the library from being tree-shaken, so when you use a bundler (such as <a href="https://esbuild.github.io/">esbuild</a>, <a href="https://vitejs.dev/">Vite</a>, or <a href="https://parceljs.org/">Parcel</a>), the entire Culori library is bundled regardless of what you're actually using.</p>
+<p>This guides walks you through switching your imports to the tree-shakeable version once you're done prototyping and you're ready to ship an optimized bundle.</p>
+<h2>Using <code>culori/fn</code></h2>
+<p>To optimize the bundle size, you can opt into the tree-shakeable version by importing from <code>culori/fn</code> instead of <code>culori</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> …<span class="token punctuation">,</span> …<span class="token punctuation">,</span> … <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span></code></pre>
+<p>It works like the default import, with one key difference: <strong>none of the color spaces are pre-registered into the library</strong>. In fact, if you'd try to <code>parse()</code> a valid CSS color without having registered any color space, you'd get back <code>undefined</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> parse <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span>
+
+<span class="token function">parse</span><span class="token punctuation">(</span><span class="token string">'tomato'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ undefined</span></code></pre>
+<p>Instead, you need to import the definitions of the color spaces you want to support and register them manually with the <code>useMode()</code> method.</p>
+<p>Since none of the color spaces are pre-registered the shortcuts to <code>converter(mode)</code>, such as <code>culori.rgb</code> or <code>culori.hsl</code>, are also missing. They are, however, helpfully returned by <code>useMode()</code>:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> useMode<span class="token punctuation">,</span> modeRgb <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> rgb <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeRgb<span class="token punctuation">)</span><span class="token punctuation">;</span>
+
+console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token function">rgb</span><span class="token punctuation">(</span><span class="token string">'tomato'</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ Object { mode: "rgb", r: 1, g: 0.38823529411764707, b: 0.2784313725490196 }</span></code></pre>
+<p>To recreate a subset of Culori that only deals with valid CSS colors, you would use this:</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span>
+	useMode<span class="token punctuation">,</span>
+	modeA98<span class="token punctuation">,</span>
+	modeHsl<span class="token punctuation">,</span>
+	modeHwb<span class="token punctuation">,</span>
+	modeLab<span class="token punctuation">,</span>
+	modeLch<span class="token punctuation">,</span>
+	modeOklab<span class="token punctuation">,</span>
+	modeOklch<span class="token punctuation">,</span>
+	modeP3<span class="token punctuation">,</span>
+	modeProphoto<span class="token punctuation">,</span>
+	modeRec2020<span class="token punctuation">,</span>
+	modeRgb<span class="token punctuation">,</span>
+	modeXyz50<span class="token punctuation">,</span>
+	modeXyz65
+<span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span>
+
+<span class="token keyword">const</span> a98 <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeA98<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> hsl <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeHsl<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> hwb <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeHwb<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> lab <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeLab<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> lch <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeLch<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> oklab <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeOklab<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> oklch <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeOklch<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> p3 <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeP3<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> prophoto <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeProphoto<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> rec2020 <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeRec2020<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> rgb <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeRgb<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> xyz50 <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeXyz50<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token keyword">const</span> xyz65 <span class="token operator">=</span> <span class="token function">useMode</span><span class="token punctuation">(</span>modeXyz65<span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<p>You don't need to do all of this manually. You can import the <a href="#culori-css">CSS bundle</a> instead.</p>
+<h3>Using Culori without registering color spaces</h3>
+<p>You can import and use the <a href="/api#low-level-api">low-level parsing and conversion functions</a> without registering any color space beforehand:</p>
+<p><strong>hex-to-hsl-string.js</strong></p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token punctuation">{</span> parseHex<span class="token punctuation">,</span> convertRgbToHsl<span class="token punctuation">,</span> serializeHsl <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span>
+
+console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>
+	<span class="token function">serializeHsl</span><span class="token punctuation">(</span>
+		<span class="token function">convertRgbToHsl</span><span class="token punctuation">(</span>
+			<span class="token function">parseHex</span><span class="token punctuation">(</span><span class="token string">'#ffcc00'</span><span class="token punctuation">)</span>
+		<span class="token punctuation">)</span>
+	<span class="token punctuation">)</span>
+<span class="token punctuation">)</span><span class="token punctuation">;</span>
+<span class="token comment">// ⇒ hsl(48, 100%, 50%)</span></code></pre>
+<p>When using a bundler such as <a href="https://esbuild.github.io/">esbuild</a>, a minified build fits on the back of a napkin.</p>
+<details>
+<summary>Show esbuild output for code above</summary>
+<pre class="language-bash"><code class="language-bash">esbuild <span class="token parameter variable">--bundle</span> <span class="token parameter variable">--minify</span> hex-to-hsl-string.js</code></pre>
+<p><code style='word-break: break-all;'>(()=&gt;{var b=(e,o)=&gt;{if(typeof e==&quot;number&quot;){if(o===3)return{mode:&quot;rgb&quot;,r:(e&gt;&gt;8&amp;15|e&gt;&gt;4&amp;240)/255,g:(e&gt;&gt;4&amp;15|e&amp;240)/255,b:(e&amp;15|e&lt;&lt;4&amp;240)/255};if(o===4)return{mode:&quot;rgb&quot;,r:(e&gt;&gt;12&amp;15|e&gt;&gt;8&amp;240)/255,g:(e&gt;&gt;8&amp;15|e&gt;&gt;4&amp;240)/255,b:(e&gt;&gt;4&amp;15|e&amp;240)/255,alpha:(e&amp;15|e&lt;&lt;4&amp;240)/255};if(o===6)return{mode:&quot;rgb&quot;,r:(e&gt;&gt;16&amp;255)/255,g:(e&gt;&gt;8&amp;255)/255,b:(e&amp;255)/255};if(o===8)return{mode:&quot;rgb&quot;,r:(e&gt;&gt;24&amp;255)/255,g:(e&gt;&gt;16&amp;255)/255,b:(e&gt;&gt;8&amp;255)/255,alpha:(e&amp;255)/255}}},u=b;var c=/^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i,x=e=&gt;{let o;return(o=e.match(c))?u(parseInt(o[1],16),o[1].length):void 0},l=x;function f({r:e,g:o,b:t,alpha:s}){let r=Math.max(e,o,t),a=Math.min(e,o,t),i={mode:&quot;hsl&quot;,s:r===a?0:(r-a)/(1-Math.abs(r+a-1)),l:.5*(r+a)};return r-a!=0&amp;&amp;(i.h=(r===e?(o-t)/(r-a)+(o&lt;t)*6:r===o?(t-e)/(r-a)+2:(e-o)/(r-a)+4)<em>60),s!==void 0&amp;&amp;(i.alpha=s),i}function p(e=4){return o=&gt;typeof o==&quot;number&quot;?Math.round(o</em>(e=Math.pow(10,e)))/e:o}var n=p(2),d=e=&gt;Math.max(0,Math.min(1,e));var m=e=&gt;{if(e===void 0)return;let o=n(e.h||0),t=n(d(e.s)*100),s=n(d(e.l)*100);return e.alpha===void 0||e.alpha===1?<code>hsl(${o}, ${t}%, ${s}%)</code>:<code>hsla(${o}, ${t}%, ${s}%, ${n(d(e.alpha))})</code>};console.log(m(f(l(&quot;#ffcc00&quot;))));})();
+</code></p>
+</details>
+<h2>Bootstrap packages</h2>
+<p>For convenience, a couple of bootstrap packages are available.</p>
+<h3 id='culori-css'><code>culori/css</code></h3>
+<p>Bootstrap all the color spaces available in CSS, plus a handful of  related ones we get for free, since they are used under the hood.</p>
+<p>It provides the following named exports: <code>a98</code>, <code>hsl</code>, <code>hsv</code>, <code>hwb</code>, <code>lab</code>, <code>lab65</code>, <code>lch</code>, <code>lch65</code>, <code>lrgb</code>, <code>oklab</code>, <code>oklch</code>, <code>p3</code>, <code>prophoto</code>, <code>rec2020</code>, <code>rgb</code>, <code>xyz50</code>, and <code>xyz65</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'culori/css'</span><span class="token punctuation">;</span>
+<span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span>
+
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'lch'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+<h3><code>culori/all</code></h3>
+<p>Bootstrap all the color spaces available in Culori.</p>
+<p>It provides the following named exports: <code>a98</code>, <code>cubehelix</code>, <code>dlab</code>, <code>dlch</code>, <code>hsi</code>, <code>hsl</code>, <code>hsv</code>, <code>hwb</code>, <code>itp</code>, <code>jab</code>, <code>jch</code>, <code>lab</code>, <code>lab65</code>, <code>lch</code>, <code>lch65</code>, <code>lchuv</code>, <code>lrgb</code>, <code>luv</code>, <code>okhsl</code>, <code>okhsv</code>, <code>oklab</code>, <code>oklch</code>, <code>p3</code>, <code>prophoto</code>, <code>rec2020</code>, <code>rgb</code>, <code>xyb</code>, <code>xyz50</code>, <code>xyz65</code>, and <code>yiq</code>.</p>
+<pre class="language-js"><code class="language-js"><span class="token keyword">import</span> <span class="token string">'culori/all'</span><span class="token punctuation">;</span>
+<span class="token keyword">import</span> <span class="token punctuation">{</span> interpolate <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'culori/fn'</span><span class="token punctuation">;</span>
+
+<span class="token function">interpolate</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token string">'red'</span><span class="token punctuation">,</span> <span class="token string">'green'</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token string">'xyb'</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/guides/tree-shaking.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/docs/img/culori.svg b/img/culori.svg
similarity index 100%
rename from docs/img/culori.svg
rename to img/culori.svg
diff --git a/docs/img/evenly-spaced-vs-positions.png b/img/evenly-spaced-vs-positions.png
similarity index 100%
rename from docs/img/evenly-spaced-vs-positions.png
rename to img/evenly-spaced-vs-positions.png
diff --git a/docs/img/interpolator-basis-closed.svg b/img/interpolator-basis-closed.svg
similarity index 100%
rename from docs/img/interpolator-basis-closed.svg
rename to img/interpolator-basis-closed.svg
diff --git a/docs/img/interpolator-basis.svg b/img/interpolator-basis.svg
similarity index 100%
rename from docs/img/interpolator-basis.svg
rename to img/interpolator-basis.svg
diff --git a/docs/img/interpolator-linear.svg b/img/interpolator-linear.svg
similarity index 100%
rename from docs/img/interpolator-linear.svg
rename to img/interpolator-linear.svg
diff --git a/docs/img/interpolator-monotone-2.svg b/img/interpolator-monotone-2.svg
similarity index 100%
rename from docs/img/interpolator-monotone-2.svg
rename to img/interpolator-monotone-2.svg
diff --git a/docs/img/interpolator-monotone-closed.svg b/img/interpolator-monotone-closed.svg
similarity index 100%
rename from docs/img/interpolator-monotone-closed.svg
rename to img/interpolator-monotone-closed.svg
diff --git a/docs/img/interpolator-monotone.svg b/img/interpolator-monotone.svg
similarity index 100%
rename from docs/img/interpolator-monotone.svg
rename to img/interpolator-monotone.svg
diff --git a/docs/img/interpolator-natural-closed.svg b/img/interpolator-natural-closed.svg
similarity index 100%
rename from docs/img/interpolator-natural-closed.svg
rename to img/interpolator-natural-closed.svg
diff --git a/docs/img/interpolator-natural.svg b/img/interpolator-natural.svg
similarity index 100%
rename from docs/img/interpolator-natural.svg
rename to img/interpolator-natural.svg
diff --git a/docs/img/red-blue.png b/img/red-blue.png
similarity index 100%
rename from docs/img/red-blue.png
rename to img/red-blue.png
diff --git a/index.html b/index.html
new file mode 100644
index 00000000..e78023e5
--- /dev/null
+++ b/index.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 Color functions for JavaScript &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li >
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li >
+							<a href="/api/">API reference</a>
+						</li>
+						<li >
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>Color functions for JavaScript</h1>
+				<p>Culori is a JavaScript color library that supports the conversion and manipulation of all formats defined in the <a href="https://drafts.csswg.org/css-color/">CSS Colors Level 4</a> specification, plus <a href="./color-spaces">additional color spaces</a>. It handles <a href="https://en.wikipedia.org/wiki/Color_difference">color differences</a>, interpolation, gradients, blend modes <a href="/api/">and much more</a>.</p>
+<pre class="language-bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> culori</code></pre>
+<p><a class='btn-link' href='./getting-started'>Get started</a></p>
+<h2>What sets Culori apart?</h2>
+<p><strong>A function-oriented API.</strong> Colors are represented as plain JavaScript objects you pass through a series of <a href="./api">functions</a>, which makes it super easy to extend.</p>
+<p><strong>Accurate alpha.</strong> On the <code>alpha</code> channel, the library doesn't equate an <code>undefined</code> value with an opaque color, but rather with a color for which we don't care about the opacity. This gives you the opportunity to interpret <code>undefined</code> as you see fit. The hex string <kbd>#ff0000</kbd> <em>should</em> probably be rendered as fully opaque red, but for running functions on colors it's useful to discern <kbd>#ff0000</kbd> from <kbd>#ff0000ff</kbd> — the former has an implicit alpha of 1, while for the latter it's explicit.</p>
+<p><strong>Comprehensive functionality.</strong> Build advanced color tools with Culori's rich collection of color spaces and functions.</p>
+<p><strong>Tree-shakeable version available.</strong> When you're ready to optimize for bundle size, switch to <a href="./guides/tree-shaking">a tree-shakeable version of the library</a>.</p>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/index.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 7b054bac..00000000
--- a/package-lock.json
+++ /dev/null
@@ -1,9740 +0,0 @@
-{
-	"name": "culori",
-	"version": "4.0.2",
-	"lockfileVersion": 2,
-	"requires": true,
-	"packages": {
-		"": {
-			"name": "culori",
-			"version": "4.0.2",
-			"license": "MIT",
-			"devDependencies": {
-				"@11ty/eleventy": "^3.0.0",
-				"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
-				"esbuild": "^0.24.0",
-				"eslint": "^8.57.1",
-				"eslint-plugin-import": "^2.31.0",
-				"gh-pages": "^6.2.0",
-				"prettier": "^3.4.1",
-				"pretty-quick": "^4.0.0"
-			},
-			"engines": {
-				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-			}
-		},
-		"node_modules/@11ty/dependency-tree": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/@11ty/dependency-tree/-/dependency-tree-3.0.1.tgz",
-			"integrity": "sha512-aZizxcL4Z/clm3KPRx8i9ohW9R2gLssXfUSy7qQmQRXb4CUOyvmqk2gKeJqRmXIfMi2bB9w03SgtN5v1YwqpiA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@11ty/eleventy-utils": "^1.0.2"
-			}
-		},
-		"node_modules/@11ty/dependency-tree-esm": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/dependency-tree-esm/-/dependency-tree-esm-1.0.0.tgz",
-			"integrity": "sha512-Z3KN1Fkv50UM/ZzTR3VBbyOY52HnmhIVCsAV1hn2UzFsGAjyF1Cw8uohhVtheDOSuBR7ZSeo1unwkz1HxFlUtQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@11ty/eleventy-utils": "^1.0.2",
-				"acorn": "^8.10.0",
-				"dependency-graph": "^0.11.0",
-				"normalize-path": "^3.0.0"
-			}
-		},
-		"node_modules/@11ty/dependency-tree-esm/node_modules/dependency-graph": {
-			"version": "0.11.0",
-			"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz",
-			"integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.6.0"
-			}
-		},
-		"node_modules/@11ty/eleventy": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-3.0.0.tgz",
-			"integrity": "sha512-0P0ZsJXVW2QiNdhd7z+GYy6n+ivh0enx1DRdua5ta6NlzY2AhbkeWBY6U+FKA8lPS3H4+XsTpfLLfIScpPZLaQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@11ty/dependency-tree": "^3.0.1",
-				"@11ty/dependency-tree-esm": "^1.0.0",
-				"@11ty/eleventy-dev-server": "^2.0.4",
-				"@11ty/eleventy-plugin-bundle": "^3.0.0",
-				"@11ty/eleventy-utils": "^1.0.3",
-				"@11ty/lodash-custom": "^4.17.21",
-				"@11ty/posthtml-urls": "^1.0.0",
-				"@11ty/recursive-copy": "^3.0.0",
-				"@sindresorhus/slugify": "^2.2.1",
-				"bcp-47-normalize": "^2.3.0",
-				"chardet": "^2.0.0",
-				"chokidar": "^3.6.0",
-				"cross-spawn": "^7.0.3",
-				"debug": "^4.3.7",
-				"dependency-graph": "^1.0.0",
-				"entities": "^5.0.0",
-				"fast-glob": "^3.3.2",
-				"filesize": "^10.1.6",
-				"graceful-fs": "^4.2.11",
-				"gray-matter": "^4.0.3",
-				"is-glob": "^4.0.3",
-				"iso-639-1": "^3.1.3",
-				"js-yaml": "^4.1.0",
-				"kleur": "^4.1.5",
-				"liquidjs": "^10.17.0",
-				"luxon": "^3.5.0",
-				"markdown-it": "^14.1.0",
-				"micromatch": "^4.0.8",
-				"minimist": "^1.2.8",
-				"moo": "^0.5.2",
-				"node-retrieve-globals": "^6.0.0",
-				"normalize-path": "^3.0.0",
-				"nunjucks": "^3.2.4",
-				"please-upgrade-node": "^3.2.0",
-				"posthtml": "^0.16.6",
-				"posthtml-match-helper": "^2.0.2",
-				"semver": "^7.6.3",
-				"slugify": "^1.6.6"
-			},
-			"bin": {
-				"eleventy": "cmd.cjs"
-			},
-			"engines": {
-				"node": ">=18"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/11ty"
-			}
-		},
-		"node_modules/@11ty/eleventy-dev-server": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-2.0.4.tgz",
-			"integrity": "sha512-d0CuufX6yPtVz+RW0oJZg1pVoxo1jOrPmpXYacoiKLJm0MMC9MkPQOCXlimguHVaceHejFo5+aZB9/aGB2RR0A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@11ty/eleventy-utils": "^1.0.3",
-				"chokidar": "^3.6.0",
-				"debug": "^4.3.7",
-				"dev-ip": "^1.0.1",
-				"finalhandler": "^1.3.0",
-				"mime": "^3.0.0",
-				"minimist": "^1.2.8",
-				"morphdom": "^2.7.4",
-				"please-upgrade-node": "^3.2.0",
-				"send": "^0.19.0",
-				"ssri": "^11.0.0",
-				"urlpattern-polyfill": "^10.0.0",
-				"ws": "^8.18.0"
-			},
-			"bin": {
-				"eleventy-dev-server": "cmd.js"
-			},
-			"engines": {
-				"node": ">=18"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/11ty"
-			}
-		},
-		"node_modules/@11ty/eleventy-plugin-bundle": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-3.0.0.tgz",
-			"integrity": "sha512-JSnqehT+sWSPi6e44jTXUW+KiV9284YF9fzPQvfGB4cXlk/m/SJk17CavHCleIvKXDN+jrUw9TZkwAwr85ONWQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"debug": "^4.3.4",
-				"posthtml-match-helper": "^2.0.2"
-			},
-			"engines": {
-				"node": ">=18"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/11ty"
-			}
-		},
-		"node_modules/@11ty/eleventy-plugin-syntaxhighlight": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-syntaxhighlight/-/eleventy-plugin-syntaxhighlight-5.0.0.tgz",
-			"integrity": "sha512-y9BUmP1GofmbJgxM1+ky/UpFCpD8JSOeLeKItUs0WApgnrHk9haHziW7lS86lbArX5SiCVo4zTTw9x53gvRCaA==",
-			"dev": true,
-			"dependencies": {
-				"prismjs": "^1.29.0"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/11ty"
-			}
-		},
-		"node_modules/@11ty/eleventy-utils": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-1.0.3.tgz",
-			"integrity": "sha512-nULO91om7vQw4Y/UBjM8i7nJ1xl+/nyK4rImZ41lFxiY2d+XUz7ChAj1CDYFjrLZeu0utAYJTZ45LlcHTkUG4g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"normalize-path": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/11ty"
-			}
-		},
-		"node_modules/@11ty/eleventy/node_modules/argparse": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-			"dev": true,
-			"license": "Python-2.0"
-		},
-		"node_modules/@11ty/eleventy/node_modules/js-yaml": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"argparse": "^2.0.1"
-			},
-			"bin": {
-				"js-yaml": "bin/js-yaml.js"
-			}
-		},
-		"node_modules/@11ty/lodash-custom": {
-			"version": "4.17.21",
-			"resolved": "https://registry.npmjs.org/@11ty/lodash-custom/-/lodash-custom-4.17.21.tgz",
-			"integrity": "sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw==",
-			"dev": true,
-			"engines": {
-				"node": ">=14"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/11ty"
-			}
-		},
-		"node_modules/@11ty/posthtml-urls": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/posthtml-urls/-/posthtml-urls-1.0.0.tgz",
-			"integrity": "sha512-CcsRdI933x613u7CjM+QGs7iD/m8SaDup3Apohg1+7dybigrEUHc2jGS3mcMgQKvF2+IphqmepD/FrKLlPkPEg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"evaluate-value": "^2.0.0",
-				"http-equiv-refresh": "^2.0.1",
-				"list-to-array": "^1.1.0",
-				"object.entries": "^1.1.7",
-				"parse-srcset": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 6"
-			}
-		},
-		"node_modules/@11ty/recursive-copy": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/recursive-copy/-/recursive-copy-3.0.0.tgz",
-			"integrity": "sha512-v1Mr7dWx5nk69/HRRtDHUYDV9N8+cE12IGiKSFOwML7HjOzUXwTP88e3cGuhqoVstkBil1ZEIaOB0KPP1zwqXA==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"errno": "^0.1.2",
-				"graceful-fs": "^4.2.11",
-				"junk": "^1.0.1",
-				"maximatch": "^0.1.0",
-				"mkdirp": "^3.0.1",
-				"pify": "^2.3.0",
-				"promise": "^7.0.1",
-				"rimraf": "^5.0.7",
-				"slash": "^1.0.0"
-			}
-		},
-		"node_modules/@aashutoshrathi/word-wrap": {
-			"version": "1.2.6",
-			"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
-			"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/@esbuild/aix-ppc64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
-			"integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==",
-			"cpu": [
-				"ppc64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"aix"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/android-arm": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz",
-			"integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==",
-			"cpu": [
-				"arm"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"android"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/android-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz",
-			"integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"android"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/android-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz",
-			"integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"android"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/darwin-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz",
-			"integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"darwin"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/darwin-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz",
-			"integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"darwin"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/freebsd-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz",
-			"integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"freebsd"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/freebsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz",
-			"integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"freebsd"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-arm": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz",
-			"integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==",
-			"cpu": [
-				"arm"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz",
-			"integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-ia32": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz",
-			"integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==",
-			"cpu": [
-				"ia32"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-loong64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz",
-			"integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==",
-			"cpu": [
-				"loong64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-mips64el": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz",
-			"integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==",
-			"cpu": [
-				"mips64el"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-ppc64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz",
-			"integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==",
-			"cpu": [
-				"ppc64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-riscv64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz",
-			"integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==",
-			"cpu": [
-				"riscv64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-s390x": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz",
-			"integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==",
-			"cpu": [
-				"s390x"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/linux-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz",
-			"integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"linux"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/netbsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz",
-			"integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"netbsd"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/openbsd-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz",
-			"integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"openbsd"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/openbsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz",
-			"integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"openbsd"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/sunos-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz",
-			"integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"sunos"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/win32-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz",
-			"integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==",
-			"cpu": [
-				"arm64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"win32"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/win32-ia32": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz",
-			"integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==",
-			"cpu": [
-				"ia32"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"win32"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@esbuild/win32-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz",
-			"integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==",
-			"cpu": [
-				"x64"
-			],
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"os": [
-				"win32"
-			],
-			"engines": {
-				"node": ">=18"
-			}
-		},
-		"node_modules/@eslint-community/eslint-utils": {
-			"version": "4.4.0",
-			"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
-			"integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
-			"dev": true,
-			"dependencies": {
-				"eslint-visitor-keys": "^3.3.0"
-			},
-			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-			},
-			"peerDependencies": {
-				"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
-			}
-		},
-		"node_modules/@eslint-community/regexpp": {
-			"version": "4.12.1",
-			"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
-			"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": "^12.0.0 || ^14.0.0 || >=16.0.0"
-			}
-		},
-		"node_modules/@eslint/eslintrc": {
-			"version": "2.1.4",
-			"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
-			"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ajv": "^6.12.4",
-				"debug": "^4.3.2",
-				"espree": "^9.6.0",
-				"globals": "^13.19.0",
-				"ignore": "^5.2.0",
-				"import-fresh": "^3.2.1",
-				"js-yaml": "^4.1.0",
-				"minimatch": "^3.1.2",
-				"strip-json-comments": "^3.1.1"
-			},
-			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-			},
-			"funding": {
-				"url": "https://opencollective.com/eslint"
-			}
-		},
-		"node_modules/@eslint/eslintrc/node_modules/argparse": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-			"dev": true,
-			"license": "Python-2.0"
-		},
-		"node_modules/@eslint/eslintrc/node_modules/js-yaml": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"argparse": "^2.0.1"
-			},
-			"bin": {
-				"js-yaml": "bin/js-yaml.js"
-			}
-		},
-		"node_modules/@eslint/js": {
-			"version": "8.57.1",
-			"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
-			"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-			}
-		},
-		"node_modules/@humanwhocodes/config-array": {
-			"version": "0.13.0",
-			"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
-			"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
-			"deprecated": "Use @eslint/config-array instead",
-			"dev": true,
-			"license": "Apache-2.0",
-			"dependencies": {
-				"@humanwhocodes/object-schema": "^2.0.3",
-				"debug": "^4.3.1",
-				"minimatch": "^3.0.5"
-			},
-			"engines": {
-				"node": ">=10.10.0"
-			}
-		},
-		"node_modules/@humanwhocodes/module-importer": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-			"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
-			"dev": true,
-			"engines": {
-				"node": ">=12.22"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/nzakas"
-			}
-		},
-		"node_modules/@humanwhocodes/object-schema": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
-			"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
-			"deprecated": "Use @eslint/object-schema instead",
-			"dev": true,
-			"license": "BSD-3-Clause"
-		},
-		"node_modules/@isaacs/cliui": {
-			"version": "8.0.2",
-			"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
-			"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"string-width": "^5.1.2",
-				"string-width-cjs": "npm:string-width@^4.2.0",
-				"strip-ansi": "^7.0.1",
-				"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
-				"wrap-ansi": "^8.1.0",
-				"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
-			},
-			"engines": {
-				"node": ">=12"
-			}
-		},
-		"node_modules/@nodelib/fs.scandir": {
-			"version": "2.1.5",
-			"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-			"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@nodelib/fs.stat": "2.0.5",
-				"run-parallel": "^1.1.9"
-			},
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/@nodelib/fs.stat": {
-			"version": "2.0.5",
-			"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-			"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/@nodelib/fs.walk": {
-			"version": "1.2.8",
-			"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-			"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@nodelib/fs.scandir": "2.1.5",
-				"fastq": "^1.6.0"
-			},
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/@pkgjs/parseargs": {
-			"version": "0.11.0",
-			"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
-			"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
-			"dev": true,
-			"license": "MIT",
-			"optional": true,
-			"engines": {
-				"node": ">=14"
-			}
-		},
-		"node_modules/@rtsao/scc": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
-			"integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/@sindresorhus/slugify": {
-			"version": "2.2.1",
-			"resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz",
-			"integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@sindresorhus/transliterate": "^1.0.0",
-				"escape-string-regexp": "^5.0.0"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/@sindresorhus/slugify/node_modules/escape-string-regexp": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-			"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/@sindresorhus/transliterate": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz",
-			"integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"escape-string-regexp": "^5.0.0"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/@sindresorhus/transliterate/node_modules/escape-string-regexp": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-			"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/@types/json5": {
-			"version": "0.0.29",
-			"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
-			"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
-			"dev": true
-		},
-		"node_modules/@ungap/structured-clone": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
-			"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
-			"dev": true,
-			"license": "ISC"
-		},
-		"node_modules/a-sync-waterfall": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
-			"integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
-			"dev": true
-		},
-		"node_modules/acorn": {
-			"version": "8.14.0",
-			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
-			"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
-			"dev": true,
-			"license": "MIT",
-			"bin": {
-				"acorn": "bin/acorn"
-			},
-			"engines": {
-				"node": ">=0.4.0"
-			}
-		},
-		"node_modules/acorn-jsx": {
-			"version": "5.3.2",
-			"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
-			"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
-			"dev": true,
-			"license": "MIT",
-			"peerDependencies": {
-				"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
-			}
-		},
-		"node_modules/acorn-walk": {
-			"version": "8.3.4",
-			"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
-			"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"acorn": "^8.11.0"
-			},
-			"engines": {
-				"node": ">=0.4.0"
-			}
-		},
-		"node_modules/ajv": {
-			"version": "6.12.6",
-			"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-			"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"fast-deep-equal": "^3.1.1",
-				"fast-json-stable-stringify": "^2.0.0",
-				"json-schema-traverse": "^0.4.1",
-				"uri-js": "^4.2.2"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/epoberezkin"
-			}
-		},
-		"node_modules/ansi-regex": {
-			"version": "6.1.0",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
-			"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-regex?sponsor=1"
-			}
-		},
-		"node_modules/ansi-styles": {
-			"version": "6.2.1",
-			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
-			"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
-			}
-		},
-		"node_modules/anymatch": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
-			"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
-			"dev": true,
-			"dependencies": {
-				"normalize-path": "^3.0.0",
-				"picomatch": "^2.0.4"
-			},
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/argparse": {
-			"version": "1.0.10",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-			"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-			"dev": true,
-			"dependencies": {
-				"sprintf-js": "~1.0.2"
-			}
-		},
-		"node_modules/array-buffer-byte-length": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
-			"integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.5",
-				"is-array-buffer": "^3.0.4"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/array-differ": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
-			"integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/array-includes": {
-			"version": "3.1.8",
-			"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
-			"integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2",
-				"es-object-atoms": "^1.0.0",
-				"get-intrinsic": "^1.2.4",
-				"is-string": "^1.0.7"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/array-union": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-			"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/array-uniq": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-			"integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/array.prototype.findlastindex": {
-			"version": "1.2.5",
-			"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
-			"integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2",
-				"es-errors": "^1.3.0",
-				"es-object-atoms": "^1.0.0",
-				"es-shim-unscopables": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/array.prototype.flat": {
-			"version": "1.3.2",
-			"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
-			"integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
-			"dev": true,
-			"dependencies": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1",
-				"es-shim-unscopables": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/array.prototype.flatmap": {
-			"version": "1.3.2",
-			"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
-			"integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
-			"dev": true,
-			"dependencies": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1",
-				"es-shim-unscopables": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/arraybuffer.prototype.slice": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
-			"integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"array-buffer-byte-length": "^1.0.1",
-				"call-bind": "^1.0.5",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.22.3",
-				"es-errors": "^1.2.1",
-				"get-intrinsic": "^1.2.3",
-				"is-array-buffer": "^3.0.4",
-				"is-shared-array-buffer": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/arrify": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
-			"integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/asap": {
-			"version": "2.0.6",
-			"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-			"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
-			"dev": true
-		},
-		"node_modules/async": {
-			"version": "3.2.4",
-			"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
-			"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
-			"dev": true
-		},
-		"node_modules/available-typed-arrays": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
-			"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"possible-typed-array-names": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/balanced-match": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-			"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-			"dev": true
-		},
-		"node_modules/bcp-47": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz",
-			"integrity": "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"is-alphabetical": "^2.0.0",
-				"is-alphanumerical": "^2.0.0",
-				"is-decimal": "^2.0.0"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/wooorm"
-			}
-		},
-		"node_modules/bcp-47-match": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz",
-			"integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==",
-			"dev": true,
-			"license": "MIT",
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/wooorm"
-			}
-		},
-		"node_modules/bcp-47-normalize": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/bcp-47-normalize/-/bcp-47-normalize-2.3.0.tgz",
-			"integrity": "sha512-8I/wfzqQvttUFz7HVJgIZ7+dj3vUaIyIxYXaTRP1YWoSDfzt6TUmxaKZeuXR62qBmYr+nvuWINFRl6pZ5DlN4Q==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"bcp-47": "^2.0.0",
-				"bcp-47-match": "^2.0.0"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/wooorm"
-			}
-		},
-		"node_modules/binary-extensions": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-			"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-			"dev": true,
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/brace-expansion": {
-			"version": "1.1.11",
-			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-			"dev": true,
-			"dependencies": {
-				"balanced-match": "^1.0.0",
-				"concat-map": "0.0.1"
-			}
-		},
-		"node_modules/braces": {
-			"version": "3.0.3",
-			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
-			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"fill-range": "^7.1.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/call-bind": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
-			"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"es-define-property": "^1.0.0",
-				"es-errors": "^1.3.0",
-				"function-bind": "^1.1.2",
-				"get-intrinsic": "^1.2.4",
-				"set-function-length": "^1.2.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/callsites": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-			"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/chalk": {
-			"version": "4.1.1",
-			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
-			"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
-			"dev": true,
-			"dependencies": {
-				"ansi-styles": "^4.1.0",
-				"supports-color": "^7.1.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/chalk?sponsor=1"
-			}
-		},
-		"node_modules/chalk/node_modules/ansi-styles": {
-			"version": "4.3.0",
-			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-			"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-			"dev": true,
-			"dependencies": {
-				"color-convert": "^2.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
-			}
-		},
-		"node_modules/chalk/node_modules/supports-color": {
-			"version": "7.2.0",
-			"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-			"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-			"dev": true,
-			"dependencies": {
-				"has-flag": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/chardet": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/chardet/-/chardet-2.0.0.tgz",
-			"integrity": "sha512-xVgPpulCooDjY6zH4m9YW3jbkaBe3FKIAvF5sj5t7aBNsVl2ljIE+xwJ4iNgiDZHFQvNIpjdKdVOQvvk5ZfxbQ==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/chokidar": {
-			"version": "3.6.0",
-			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-			"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"anymatch": "~3.1.2",
-				"braces": "~3.0.2",
-				"glob-parent": "~5.1.2",
-				"is-binary-path": "~2.1.0",
-				"is-glob": "~4.0.1",
-				"normalize-path": "~3.0.0",
-				"readdirp": "~3.6.0"
-			},
-			"engines": {
-				"node": ">= 8.10.0"
-			},
-			"funding": {
-				"url": "https://paulmillr.com/funding/"
-			},
-			"optionalDependencies": {
-				"fsevents": "~2.3.2"
-			}
-		},
-		"node_modules/color-convert": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-			"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-			"dev": true,
-			"dependencies": {
-				"color-name": "~1.1.4"
-			},
-			"engines": {
-				"node": ">=7.0.0"
-			}
-		},
-		"node_modules/color-name": {
-			"version": "1.1.4",
-			"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-			"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-			"dev": true
-		},
-		"node_modules/commander": {
-			"version": "11.1.0",
-			"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
-			"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
-			"dev": true,
-			"engines": {
-				"node": ">=16"
-			}
-		},
-		"node_modules/commondir": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-			"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
-			"dev": true
-		},
-		"node_modules/concat-map": {
-			"version": "0.0.1",
-			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-			"dev": true
-		},
-		"node_modules/cross-spawn": {
-			"version": "7.0.6",
-			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
-			"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"path-key": "^3.1.0",
-				"shebang-command": "^2.0.0",
-				"which": "^2.0.1"
-			},
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/data-view-buffer": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
-			"integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.6",
-				"es-errors": "^1.3.0",
-				"is-data-view": "^1.0.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/data-view-byte-length": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
-			"integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"es-errors": "^1.3.0",
-				"is-data-view": "^1.0.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/data-view-byte-offset": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
-			"integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.6",
-				"es-errors": "^1.3.0",
-				"is-data-view": "^1.0.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/debug": {
-			"version": "4.3.7",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
-			"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ms": "^2.1.3"
-			},
-			"engines": {
-				"node": ">=6.0"
-			},
-			"peerDependenciesMeta": {
-				"supports-color": {
-					"optional": true
-				}
-			}
-		},
-		"node_modules/deep-is": {
-			"version": "0.1.4",
-			"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-			"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-			"dev": true
-		},
-		"node_modules/define-data-property": {
-			"version": "1.1.4",
-			"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
-			"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"es-define-property": "^1.0.0",
-				"es-errors": "^1.3.0",
-				"gopd": "^1.0.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/define-properties": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
-			"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
-			"dev": true,
-			"dependencies": {
-				"define-data-property": "^1.0.1",
-				"has-property-descriptors": "^1.0.0",
-				"object-keys": "^1.1.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/depd": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-			"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/dependency-graph": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
-			"integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/destroy": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
-			"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.8",
-				"npm": "1.2.8000 || >= 1.4.16"
-			}
-		},
-		"node_modules/dev-ip": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz",
-			"integrity": "sha512-LmVkry/oDShEgSZPNgqCIp2/TlqtExeGmymru3uCELnfyjY11IzpAproLYs+1X88fXO6DBoYP3ul2Xo2yz2j6A==",
-			"dev": true,
-			"bin": {
-				"dev-ip": "lib/dev-ip.js"
-			},
-			"engines": {
-				"node": ">= 0.8.0"
-			}
-		},
-		"node_modules/dir-glob": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
-			"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"path-type": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/doctrine": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-			"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
-			"dev": true,
-			"license": "Apache-2.0",
-			"dependencies": {
-				"esutils": "^2.0.2"
-			},
-			"engines": {
-				"node": ">=6.0.0"
-			}
-		},
-		"node_modules/domelementtype": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
-			"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
-			"dev": true,
-			"funding": [
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/fb55"
-				}
-			]
-		},
-		"node_modules/eastasianwidth": {
-			"version": "0.2.0",
-			"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
-			"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/ee-first": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-			"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/email-addresses": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz",
-			"integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
-			"dev": true
-		},
-		"node_modules/emoji-regex": {
-			"version": "9.2.2",
-			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
-			"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/encodeurl": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
-			"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/entities": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz",
-			"integrity": "sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==",
-			"dev": true,
-			"license": "BSD-2-Clause",
-			"engines": {
-				"node": ">=0.12"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/entities?sponsor=1"
-			}
-		},
-		"node_modules/errno": {
-			"version": "0.1.8",
-			"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
-			"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"prr": "~1.0.1"
-			},
-			"bin": {
-				"errno": "cli.js"
-			}
-		},
-		"node_modules/es-abstract": {
-			"version": "1.23.5",
-			"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz",
-			"integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"array-buffer-byte-length": "^1.0.1",
-				"arraybuffer.prototype.slice": "^1.0.3",
-				"available-typed-arrays": "^1.0.7",
-				"call-bind": "^1.0.7",
-				"data-view-buffer": "^1.0.1",
-				"data-view-byte-length": "^1.0.1",
-				"data-view-byte-offset": "^1.0.0",
-				"es-define-property": "^1.0.0",
-				"es-errors": "^1.3.0",
-				"es-object-atoms": "^1.0.0",
-				"es-set-tostringtag": "^2.0.3",
-				"es-to-primitive": "^1.2.1",
-				"function.prototype.name": "^1.1.6",
-				"get-intrinsic": "^1.2.4",
-				"get-symbol-description": "^1.0.2",
-				"globalthis": "^1.0.4",
-				"gopd": "^1.0.1",
-				"has-property-descriptors": "^1.0.2",
-				"has-proto": "^1.0.3",
-				"has-symbols": "^1.0.3",
-				"hasown": "^2.0.2",
-				"internal-slot": "^1.0.7",
-				"is-array-buffer": "^3.0.4",
-				"is-callable": "^1.2.7",
-				"is-data-view": "^1.0.1",
-				"is-negative-zero": "^2.0.3",
-				"is-regex": "^1.1.4",
-				"is-shared-array-buffer": "^1.0.3",
-				"is-string": "^1.0.7",
-				"is-typed-array": "^1.1.13",
-				"is-weakref": "^1.0.2",
-				"object-inspect": "^1.13.3",
-				"object-keys": "^1.1.1",
-				"object.assign": "^4.1.5",
-				"regexp.prototype.flags": "^1.5.3",
-				"safe-array-concat": "^1.1.2",
-				"safe-regex-test": "^1.0.3",
-				"string.prototype.trim": "^1.2.9",
-				"string.prototype.trimend": "^1.0.8",
-				"string.prototype.trimstart": "^1.0.8",
-				"typed-array-buffer": "^1.0.2",
-				"typed-array-byte-length": "^1.0.1",
-				"typed-array-byte-offset": "^1.0.2",
-				"typed-array-length": "^1.0.6",
-				"unbox-primitive": "^1.0.2",
-				"which-typed-array": "^1.1.15"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/es-define-property": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
-			"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"get-intrinsic": "^1.2.4"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/es-errors": {
-			"version": "1.3.0",
-			"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
-			"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/es-object-atoms": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
-			"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"es-errors": "^1.3.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/es-set-tostringtag": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
-			"integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"get-intrinsic": "^1.2.4",
-				"has-tostringtag": "^1.0.2",
-				"hasown": "^2.0.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/es-shim-unscopables": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
-			"integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
-			"dev": true,
-			"dependencies": {
-				"hasown": "^2.0.0"
-			}
-		},
-		"node_modules/es-to-primitive": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-			"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
-			"dev": true,
-			"dependencies": {
-				"is-callable": "^1.1.4",
-				"is-date-object": "^1.0.1",
-				"is-symbol": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/esbuild": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz",
-			"integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==",
-			"dev": true,
-			"hasInstallScript": true,
-			"license": "MIT",
-			"bin": {
-				"esbuild": "bin/esbuild"
-			},
-			"engines": {
-				"node": ">=18"
-			},
-			"optionalDependencies": {
-				"@esbuild/aix-ppc64": "0.24.0",
-				"@esbuild/android-arm": "0.24.0",
-				"@esbuild/android-arm64": "0.24.0",
-				"@esbuild/android-x64": "0.24.0",
-				"@esbuild/darwin-arm64": "0.24.0",
-				"@esbuild/darwin-x64": "0.24.0",
-				"@esbuild/freebsd-arm64": "0.24.0",
-				"@esbuild/freebsd-x64": "0.24.0",
-				"@esbuild/linux-arm": "0.24.0",
-				"@esbuild/linux-arm64": "0.24.0",
-				"@esbuild/linux-ia32": "0.24.0",
-				"@esbuild/linux-loong64": "0.24.0",
-				"@esbuild/linux-mips64el": "0.24.0",
-				"@esbuild/linux-ppc64": "0.24.0",
-				"@esbuild/linux-riscv64": "0.24.0",
-				"@esbuild/linux-s390x": "0.24.0",
-				"@esbuild/linux-x64": "0.24.0",
-				"@esbuild/netbsd-x64": "0.24.0",
-				"@esbuild/openbsd-arm64": "0.24.0",
-				"@esbuild/openbsd-x64": "0.24.0",
-				"@esbuild/sunos-x64": "0.24.0",
-				"@esbuild/win32-arm64": "0.24.0",
-				"@esbuild/win32-ia32": "0.24.0",
-				"@esbuild/win32-x64": "0.24.0"
-			}
-		},
-		"node_modules/escape-html": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-			"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/escape-string-regexp": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.8.0"
-			}
-		},
-		"node_modules/eslint": {
-			"version": "8.57.1",
-			"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
-			"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
-			"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@eslint-community/eslint-utils": "^4.2.0",
-				"@eslint-community/regexpp": "^4.6.1",
-				"@eslint/eslintrc": "^2.1.4",
-				"@eslint/js": "8.57.1",
-				"@humanwhocodes/config-array": "^0.13.0",
-				"@humanwhocodes/module-importer": "^1.0.1",
-				"@nodelib/fs.walk": "^1.2.8",
-				"@ungap/structured-clone": "^1.2.0",
-				"ajv": "^6.12.4",
-				"chalk": "^4.0.0",
-				"cross-spawn": "^7.0.2",
-				"debug": "^4.3.2",
-				"doctrine": "^3.0.0",
-				"escape-string-regexp": "^4.0.0",
-				"eslint-scope": "^7.2.2",
-				"eslint-visitor-keys": "^3.4.3",
-				"espree": "^9.6.1",
-				"esquery": "^1.4.2",
-				"esutils": "^2.0.2",
-				"fast-deep-equal": "^3.1.3",
-				"file-entry-cache": "^6.0.1",
-				"find-up": "^5.0.0",
-				"glob-parent": "^6.0.2",
-				"globals": "^13.19.0",
-				"graphemer": "^1.4.0",
-				"ignore": "^5.2.0",
-				"imurmurhash": "^0.1.4",
-				"is-glob": "^4.0.0",
-				"is-path-inside": "^3.0.3",
-				"js-yaml": "^4.1.0",
-				"json-stable-stringify-without-jsonify": "^1.0.1",
-				"levn": "^0.4.1",
-				"lodash.merge": "^4.6.2",
-				"minimatch": "^3.1.2",
-				"natural-compare": "^1.4.0",
-				"optionator": "^0.9.3",
-				"strip-ansi": "^6.0.1",
-				"text-table": "^0.2.0"
-			},
-			"bin": {
-				"eslint": "bin/eslint.js"
-			},
-			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-			},
-			"funding": {
-				"url": "https://opencollective.com/eslint"
-			}
-		},
-		"node_modules/eslint-import-resolver-node": {
-			"version": "0.3.9",
-			"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
-			"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
-			"dev": true,
-			"dependencies": {
-				"debug": "^3.2.7",
-				"is-core-module": "^2.13.0",
-				"resolve": "^1.22.4"
-			}
-		},
-		"node_modules/eslint-import-resolver-node/node_modules/debug": {
-			"version": "3.2.7",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-			"dev": true,
-			"dependencies": {
-				"ms": "^2.1.1"
-			}
-		},
-		"node_modules/eslint-import-resolver-node/node_modules/resolve": {
-			"version": "1.22.8",
-			"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
-			"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
-			"dev": true,
-			"dependencies": {
-				"is-core-module": "^2.13.0",
-				"path-parse": "^1.0.7",
-				"supports-preserve-symlinks-flag": "^1.0.0"
-			},
-			"bin": {
-				"resolve": "bin/resolve"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/eslint-module-utils": {
-			"version": "2.12.0",
-			"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
-			"integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"debug": "^3.2.7"
-			},
-			"engines": {
-				"node": ">=4"
-			},
-			"peerDependenciesMeta": {
-				"eslint": {
-					"optional": true
-				}
-			}
-		},
-		"node_modules/eslint-module-utils/node_modules/debug": {
-			"version": "3.2.7",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ms": "^2.1.1"
-			}
-		},
-		"node_modules/eslint-plugin-import": {
-			"version": "2.31.0",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
-			"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@rtsao/scc": "^1.1.0",
-				"array-includes": "^3.1.8",
-				"array.prototype.findlastindex": "^1.2.5",
-				"array.prototype.flat": "^1.3.2",
-				"array.prototype.flatmap": "^1.3.2",
-				"debug": "^3.2.7",
-				"doctrine": "^2.1.0",
-				"eslint-import-resolver-node": "^0.3.9",
-				"eslint-module-utils": "^2.12.0",
-				"hasown": "^2.0.2",
-				"is-core-module": "^2.15.1",
-				"is-glob": "^4.0.3",
-				"minimatch": "^3.1.2",
-				"object.fromentries": "^2.0.8",
-				"object.groupby": "^1.0.3",
-				"object.values": "^1.2.0",
-				"semver": "^6.3.1",
-				"string.prototype.trimend": "^1.0.8",
-				"tsconfig-paths": "^3.15.0"
-			},
-			"engines": {
-				"node": ">=4"
-			},
-			"peerDependencies": {
-				"eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
-			}
-		},
-		"node_modules/eslint-plugin-import/node_modules/debug": {
-			"version": "3.2.7",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-			"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-			"dev": true,
-			"dependencies": {
-				"ms": "^2.1.1"
-			}
-		},
-		"node_modules/eslint-plugin-import/node_modules/doctrine": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
-			"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
-			"dev": true,
-			"dependencies": {
-				"esutils": "^2.0.2"
-			},
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/eslint-plugin-import/node_modules/semver": {
-			"version": "6.3.1",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-			"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-			"dev": true,
-			"bin": {
-				"semver": "bin/semver.js"
-			}
-		},
-		"node_modules/eslint-scope": {
-			"version": "7.2.2",
-			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
-			"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
-			"dev": true,
-			"license": "BSD-2-Clause",
-			"dependencies": {
-				"esrecurse": "^4.3.0",
-				"estraverse": "^5.2.0"
-			},
-			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-			},
-			"funding": {
-				"url": "https://opencollective.com/eslint"
-			}
-		},
-		"node_modules/eslint-visitor-keys": {
-			"version": "3.4.3",
-			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-			"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-			"dev": true,
-			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-			},
-			"funding": {
-				"url": "https://opencollective.com/eslint"
-			}
-		},
-		"node_modules/eslint/node_modules/ansi-regex": {
-			"version": "5.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/eslint/node_modules/argparse": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-			"dev": true,
-			"license": "Python-2.0"
-		},
-		"node_modules/eslint/node_modules/escape-string-regexp": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-			"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-			"dev": true,
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/eslint/node_modules/glob-parent": {
-			"version": "6.0.2",
-			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-			"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
-			"dev": true,
-			"dependencies": {
-				"is-glob": "^4.0.3"
-			},
-			"engines": {
-				"node": ">=10.13.0"
-			}
-		},
-		"node_modules/eslint/node_modules/js-yaml": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-			"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"argparse": "^2.0.1"
-			},
-			"bin": {
-				"js-yaml": "bin/js-yaml.js"
-			}
-		},
-		"node_modules/eslint/node_modules/strip-ansi": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ansi-regex": "^5.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/esm-import-transformer": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/esm-import-transformer/-/esm-import-transformer-3.0.2.tgz",
-			"integrity": "sha512-PgvO0wro44lTDM9pYeeOIfpS0lGF80jA+rjT7sBd3b07rxv1AxeNMEI5kSCqRKke2W6SPEz17W3kHOLjaiD7Cw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"acorn": "^8.11.2"
-			}
-		},
-		"node_modules/espree": {
-			"version": "9.6.1",
-			"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
-			"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
-			"dev": true,
-			"license": "BSD-2-Clause",
-			"dependencies": {
-				"acorn": "^8.9.0",
-				"acorn-jsx": "^5.3.2",
-				"eslint-visitor-keys": "^3.4.1"
-			},
-			"engines": {
-				"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
-			},
-			"funding": {
-				"url": "https://opencollective.com/eslint"
-			}
-		},
-		"node_modules/esprima": {
-			"version": "4.0.1",
-			"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-			"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-			"dev": true,
-			"bin": {
-				"esparse": "bin/esparse.js",
-				"esvalidate": "bin/esvalidate.js"
-			},
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/esquery": {
-			"version": "1.5.0",
-			"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
-			"integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
-			"dev": true,
-			"dependencies": {
-				"estraverse": "^5.1.0"
-			},
-			"engines": {
-				"node": ">=0.10"
-			}
-		},
-		"node_modules/esrecurse": {
-			"version": "4.3.0",
-			"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-			"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
-			"dev": true,
-			"license": "BSD-2-Clause",
-			"dependencies": {
-				"estraverse": "^5.2.0"
-			},
-			"engines": {
-				"node": ">=4.0"
-			}
-		},
-		"node_modules/estraverse": {
-			"version": "5.3.0",
-			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-			"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-			"dev": true,
-			"engines": {
-				"node": ">=4.0"
-			}
-		},
-		"node_modules/esutils": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-			"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/etag": {
-			"version": "1.8.1",
-			"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-			"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.6"
-			}
-		},
-		"node_modules/evaluate-value": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/evaluate-value/-/evaluate-value-2.0.0.tgz",
-			"integrity": "sha512-VonfiuDJc0z4sOO7W0Pd130VLsXN6vmBWZlrog1mCb/o7o/Nl5Lr25+Kj/nkCCAhG+zqeeGjxhkK9oHpkgTHhQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/execa": {
-			"version": "5.1.1",
-			"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
-			"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
-			"dev": true,
-			"dependencies": {
-				"cross-spawn": "^7.0.3",
-				"get-stream": "^6.0.0",
-				"human-signals": "^2.1.0",
-				"is-stream": "^2.0.0",
-				"merge-stream": "^2.0.0",
-				"npm-run-path": "^4.0.1",
-				"onetime": "^5.1.2",
-				"signal-exit": "^3.0.3",
-				"strip-final-newline": "^2.0.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sindresorhus/execa?sponsor=1"
-			}
-		},
-		"node_modules/extend-shallow": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-			"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-			"dev": true,
-			"dependencies": {
-				"is-extendable": "^0.1.0"
-			},
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/fast-deep-equal": {
-			"version": "3.1.3",
-			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/fast-glob": {
-			"version": "3.3.2",
-			"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
-			"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"@nodelib/fs.stat": "^2.0.2",
-				"@nodelib/fs.walk": "^1.2.3",
-				"glob-parent": "^5.1.2",
-				"merge2": "^1.3.0",
-				"micromatch": "^4.0.4"
-			},
-			"engines": {
-				"node": ">=8.6.0"
-			}
-		},
-		"node_modules/fast-json-stable-stringify": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-			"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/fast-levenshtein": {
-			"version": "2.0.6",
-			"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-			"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
-			"dev": true
-		},
-		"node_modules/fastq": {
-			"version": "1.17.1",
-			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
-			"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"reusify": "^1.0.4"
-			}
-		},
-		"node_modules/file-entry-cache": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-			"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"flat-cache": "^3.0.4"
-			},
-			"engines": {
-				"node": "^10.12.0 || >=12.0.0"
-			}
-		},
-		"node_modules/filename-reserved-regex": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
-			"integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
-			"dev": true,
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/filenamify": {
-			"version": "4.3.0",
-			"resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
-			"integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
-			"dev": true,
-			"dependencies": {
-				"filename-reserved-regex": "^2.0.0",
-				"strip-outer": "^1.0.1",
-				"trim-repeated": "^1.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/filesize": {
-			"version": "10.1.6",
-			"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz",
-			"integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==",
-			"dev": true,
-			"license": "BSD-3-Clause",
-			"engines": {
-				"node": ">= 10.4.0"
-			}
-		},
-		"node_modules/fill-range": {
-			"version": "7.1.1",
-			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
-			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"to-regex-range": "^5.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/finalhandler": {
-			"version": "1.3.1",
-			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
-			"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"debug": "2.6.9",
-				"encodeurl": "~2.0.0",
-				"escape-html": "~1.0.3",
-				"on-finished": "2.4.1",
-				"parseurl": "~1.3.3",
-				"statuses": "2.0.1",
-				"unpipe": "~1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/finalhandler/node_modules/debug": {
-			"version": "2.6.9",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ms": "2.0.0"
-			}
-		},
-		"node_modules/finalhandler/node_modules/ms": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-			"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/find-cache-dir": {
-			"version": "3.3.1",
-			"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
-			"integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
-			"dev": true,
-			"dependencies": {
-				"commondir": "^1.0.1",
-				"make-dir": "^3.0.2",
-				"pkg-dir": "^4.1.0"
-			},
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/avajs/find-cache-dir?sponsor=1"
-			}
-		},
-		"node_modules/find-up": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-			"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-			"dev": true,
-			"dependencies": {
-				"locate-path": "^6.0.0",
-				"path-exists": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/flat-cache": {
-			"version": "3.2.0",
-			"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
-			"integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"flatted": "^3.2.9",
-				"keyv": "^4.5.3",
-				"rimraf": "^3.0.2"
-			},
-			"engines": {
-				"node": "^10.12.0 || >=12.0.0"
-			}
-		},
-		"node_modules/flat-cache/node_modules/glob": {
-			"version": "7.2.3",
-			"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-			"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-			"deprecated": "Glob versions prior to v9 are no longer supported",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"fs.realpath": "^1.0.0",
-				"inflight": "^1.0.4",
-				"inherits": "2",
-				"minimatch": "^3.1.1",
-				"once": "^1.3.0",
-				"path-is-absolute": "^1.0.0"
-			},
-			"engines": {
-				"node": "*"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/flat-cache/node_modules/rimraf": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-			"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-			"deprecated": "Rimraf versions prior to v4 are no longer supported",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"glob": "^7.1.3"
-			},
-			"bin": {
-				"rimraf": "bin.js"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/flatted": {
-			"version": "3.3.2",
-			"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
-			"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
-			"dev": true,
-			"license": "ISC"
-		},
-		"node_modules/for-each": {
-			"version": "0.3.3",
-			"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
-			"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"is-callable": "^1.1.3"
-			}
-		},
-		"node_modules/foreground-child": {
-			"version": "3.3.0",
-			"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
-			"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"cross-spawn": "^7.0.0",
-				"signal-exit": "^4.0.1"
-			},
-			"engines": {
-				"node": ">=14"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/foreground-child/node_modules/signal-exit": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
-			"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
-			"dev": true,
-			"license": "ISC",
-			"engines": {
-				"node": ">=14"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/fresh": {
-			"version": "0.5.2",
-			"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-			"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.6"
-			}
-		},
-		"node_modules/fs-extra": {
-			"version": "11.2.0",
-			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
-			"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
-			"dev": true,
-			"dependencies": {
-				"graceful-fs": "^4.2.0",
-				"jsonfile": "^6.0.1",
-				"universalify": "^2.0.0"
-			},
-			"engines": {
-				"node": ">=14.14"
-			}
-		},
-		"node_modules/fs.realpath": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-			"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-			"dev": true,
-			"license": "ISC"
-		},
-		"node_modules/fsevents": {
-			"version": "2.3.2",
-			"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-			"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-			"dev": true,
-			"hasInstallScript": true,
-			"optional": true,
-			"os": [
-				"darwin"
-			],
-			"engines": {
-				"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
-			}
-		},
-		"node_modules/function-bind": {
-			"version": "1.1.2",
-			"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
-			"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-			"dev": true,
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/function.prototype.name": {
-			"version": "1.1.6",
-			"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
-			"integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
-			"dev": true,
-			"dependencies": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1",
-				"functions-have-names": "^1.2.3"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/functions-have-names": {
-			"version": "1.2.3",
-			"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
-			"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
-			"dev": true,
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/get-intrinsic": {
-			"version": "1.2.4",
-			"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
-			"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"es-errors": "^1.3.0",
-				"function-bind": "^1.1.2",
-				"has-proto": "^1.0.1",
-				"has-symbols": "^1.0.3",
-				"hasown": "^2.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/get-stream": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
-			"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
-			"dev": true,
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/get-symbol-description": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
-			"integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.5",
-				"es-errors": "^1.3.0",
-				"get-intrinsic": "^1.2.4"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/gh-pages": {
-			"version": "6.2.0",
-			"resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.2.0.tgz",
-			"integrity": "sha512-HMXJ8th9u5wRXaZCnLcs/d3oVvCHiZkaP5KQExQljYGwJjQbSPyTdHe/Gc1IvYUR/rWiZLxNobIqfoMHKTKjHQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"async": "^3.2.4",
-				"commander": "^11.0.0",
-				"email-addresses": "^5.0.0",
-				"filenamify": "^4.3.0",
-				"find-cache-dir": "^3.3.1",
-				"fs-extra": "^11.1.1",
-				"globby": "^11.1.0"
-			},
-			"bin": {
-				"gh-pages": "bin/gh-pages.js",
-				"gh-pages-clean": "bin/gh-pages-clean.js"
-			},
-			"engines": {
-				"node": ">=10"
-			}
-		},
-		"node_modules/glob": {
-			"version": "10.4.5",
-			"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
-			"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"foreground-child": "^3.1.0",
-				"jackspeak": "^3.1.2",
-				"minimatch": "^9.0.4",
-				"minipass": "^7.1.2",
-				"package-json-from-dist": "^1.0.0",
-				"path-scurry": "^1.11.1"
-			},
-			"bin": {
-				"glob": "dist/esm/bin.mjs"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/glob-parent": {
-			"version": "5.1.2",
-			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-			"dev": true,
-			"dependencies": {
-				"is-glob": "^4.0.1"
-			},
-			"engines": {
-				"node": ">= 6"
-			}
-		},
-		"node_modules/glob/node_modules/brace-expansion": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-			"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"balanced-match": "^1.0.0"
-			}
-		},
-		"node_modules/glob/node_modules/minimatch": {
-			"version": "9.0.5",
-			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
-			"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"brace-expansion": "^2.0.1"
-			},
-			"engines": {
-				"node": ">=16 || 14 >=14.17"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/globals": {
-			"version": "13.24.0",
-			"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
-			"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"type-fest": "^0.20.2"
-			},
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/globalthis": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
-			"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"define-properties": "^1.2.1",
-				"gopd": "^1.0.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/globby": {
-			"version": "11.1.0",
-			"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
-			"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"array-union": "^2.1.0",
-				"dir-glob": "^3.0.1",
-				"fast-glob": "^3.2.9",
-				"ignore": "^5.2.0",
-				"merge2": "^1.4.1",
-				"slash": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/globby/node_modules/slash": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-			"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/gopd": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
-			"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-			"dev": true,
-			"dependencies": {
-				"get-intrinsic": "^1.1.3"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/graceful-fs": {
-			"version": "4.2.11",
-			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
-			"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
-			"dev": true
-		},
-		"node_modules/graphemer": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-			"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/gray-matter": {
-			"version": "4.0.3",
-			"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
-			"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
-			"dev": true,
-			"dependencies": {
-				"js-yaml": "^3.13.1",
-				"kind-of": "^6.0.2",
-				"section-matter": "^1.0.0",
-				"strip-bom-string": "^1.0.0"
-			},
-			"engines": {
-				"node": ">=6.0"
-			}
-		},
-		"node_modules/has-bigints": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
-			"integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
-			"dev": true,
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/has-flag": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-			"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-			"dev": true,
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/has-property-descriptors": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
-			"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"es-define-property": "^1.0.0"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/has-proto": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
-			"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/has-symbols": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-			"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
-			"dev": true,
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/has-tostringtag": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
-			"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"has-symbols": "^1.0.3"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/hasown": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
-			"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"function-bind": "^1.1.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/http-equiv-refresh": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/http-equiv-refresh/-/http-equiv-refresh-2.0.1.tgz",
-			"integrity": "sha512-XJpDL/MLkV3dKwLzHwr2dY05dYNfBNlyPu4STQ8WvKCFdc6vC5tPXuq28of663+gHVg03C+16pHHs/+FmmDjcw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 6"
-			}
-		},
-		"node_modules/http-errors": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
-			"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"depd": "2.0.0",
-				"inherits": "2.0.4",
-				"setprototypeof": "1.2.0",
-				"statuses": "2.0.1",
-				"toidentifier": "1.0.1"
-			},
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/human-signals": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
-			"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
-			"dev": true,
-			"engines": {
-				"node": ">=10.17.0"
-			}
-		},
-		"node_modules/ignore": {
-			"version": "5.3.0",
-			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
-			"integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
-			"dev": true,
-			"engines": {
-				"node": ">= 4"
-			}
-		},
-		"node_modules/import-fresh": {
-			"version": "3.3.0",
-			"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
-			"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"parent-module": "^1.0.0",
-				"resolve-from": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=6"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/imurmurhash": {
-			"version": "0.1.4",
-			"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-			"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.8.19"
-			}
-		},
-		"node_modules/inflight": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-			"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-			"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"once": "^1.3.0",
-				"wrappy": "1"
-			}
-		},
-		"node_modules/inherits": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-			"dev": true,
-			"license": "ISC"
-		},
-		"node_modules/internal-slot": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
-			"integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"es-errors": "^1.3.0",
-				"hasown": "^2.0.0",
-				"side-channel": "^1.0.4"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/is-alphabetical": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
-			"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
-			"dev": true,
-			"license": "MIT",
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/wooorm"
-			}
-		},
-		"node_modules/is-alphanumerical": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
-			"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"is-alphabetical": "^2.0.0",
-				"is-decimal": "^2.0.0"
-			},
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/wooorm"
-			}
-		},
-		"node_modules/is-array-buffer": {
-			"version": "3.0.4",
-			"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
-			"integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.2",
-				"get-intrinsic": "^1.2.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-async-function": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
-			"integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"has-tostringtag": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-bigint": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
-			"integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
-			"dev": true,
-			"dependencies": {
-				"has-bigints": "^1.0.1"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-binary-path": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-			"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-			"dev": true,
-			"dependencies": {
-				"binary-extensions": "^2.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/is-boolean-object": {
-			"version": "1.1.2",
-			"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
-			"integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
-			"dev": true,
-			"dependencies": {
-				"call-bind": "^1.0.2",
-				"has-tostringtag": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-callable": {
-			"version": "1.2.7",
-			"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
-			"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
-			"dev": true,
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-core-module": {
-			"version": "2.15.1",
-			"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
-			"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"hasown": "^2.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-data-view": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
-			"integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"is-typed-array": "^1.1.13"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-date-object": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
-			"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
-			"dev": true,
-			"dependencies": {
-				"has-tostringtag": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-decimal": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
-			"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
-			"dev": true,
-			"license": "MIT",
-			"funding": {
-				"type": "github",
-				"url": "https://github.com/sponsors/wooorm"
-			}
-		},
-		"node_modules/is-extendable": {
-			"version": "0.1.1",
-			"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
-			"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/is-extglob": {
-			"version": "2.1.1",
-			"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-			"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/is-finalizationregistry": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz",
-			"integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-fullwidth-code-point": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/is-generator-function": {
-			"version": "1.0.10",
-			"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
-			"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"has-tostringtag": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-glob": {
-			"version": "4.0.3",
-			"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-			"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-			"dev": true,
-			"dependencies": {
-				"is-extglob": "^2.1.1"
-			},
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/is-json": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
-			"integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
-			"dev": true
-		},
-		"node_modules/is-map": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
-			"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-negative-zero": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
-			"integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-number": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.12.0"
-			}
-		},
-		"node_modules/is-number-object": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
-			"integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
-			"dev": true,
-			"dependencies": {
-				"has-tostringtag": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-path-inside": {
-			"version": "3.0.3",
-			"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-			"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/is-regex": {
-			"version": "1.1.4",
-			"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
-			"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.2",
-				"has-tostringtag": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-set": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
-			"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-shared-array-buffer": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
-			"integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-stream": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-			"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
-			"dev": true,
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/is-string": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
-			"integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
-			"dev": true,
-			"dependencies": {
-				"has-tostringtag": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-symbol": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
-			"integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
-			"dev": true,
-			"dependencies": {
-				"has-symbols": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-typed-array": {
-			"version": "1.1.13",
-			"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
-			"integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"which-typed-array": "^1.1.14"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-weakmap": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
-			"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-weakref": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
-			"integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
-			"dev": true,
-			"dependencies": {
-				"call-bind": "^1.0.2"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/is-weakset": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
-			"integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"get-intrinsic": "^1.2.4"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/isarray": {
-			"version": "2.0.5",
-			"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-			"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/isexe": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-			"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
-			"dev": true
-		},
-		"node_modules/iso-639-1": {
-			"version": "3.1.3",
-			"resolved": "https://registry.npmjs.org/iso-639-1/-/iso-639-1-3.1.3.tgz",
-			"integrity": "sha512-1jz0Wh9hyLMRwqEPchb/KZCiTqfFWtc9R3nm7GHPygBAKS8wdKJ3FH4lvLsri6UtAE5Kz5SnowtXZa//6bqMyw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=6.0"
-			}
-		},
-		"node_modules/jackspeak": {
-			"version": "3.4.3",
-			"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
-			"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
-			"dev": true,
-			"license": "BlueOak-1.0.0",
-			"dependencies": {
-				"@isaacs/cliui": "^8.0.2"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			},
-			"optionalDependencies": {
-				"@pkgjs/parseargs": "^0.11.0"
-			}
-		},
-		"node_modules/js-yaml": {
-			"version": "3.14.1",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-			"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
-			"dev": true,
-			"dependencies": {
-				"argparse": "^1.0.7",
-				"esprima": "^4.0.0"
-			},
-			"bin": {
-				"js-yaml": "bin/js-yaml.js"
-			}
-		},
-		"node_modules/json-buffer": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
-			"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/json-schema-traverse": {
-			"version": "0.4.1",
-			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-			"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/json-stable-stringify-without-jsonify": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-			"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
-			"dev": true
-		},
-		"node_modules/json5": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-			"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-			"dev": true,
-			"dependencies": {
-				"minimist": "^1.2.0"
-			},
-			"bin": {
-				"json5": "lib/cli.js"
-			}
-		},
-		"node_modules/jsonfile": {
-			"version": "6.1.0",
-			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
-			"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-			"dev": true,
-			"dependencies": {
-				"universalify": "^2.0.0"
-			},
-			"optionalDependencies": {
-				"graceful-fs": "^4.1.6"
-			}
-		},
-		"node_modules/junk": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/junk/-/junk-1.0.3.tgz",
-			"integrity": "sha512-3KF80UaaSSxo8jVnRYtMKNGFOoVPBdkkVPsw+Ad0y4oxKXPduS6G6iHkrf69yJVff/VAaYXkV42rtZ7daJxU3w==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/keyv": {
-			"version": "4.5.4",
-			"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
-			"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"json-buffer": "3.0.1"
-			}
-		},
-		"node_modules/kind-of": {
-			"version": "6.0.3",
-			"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
-			"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/kleur": {
-			"version": "4.1.5",
-			"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
-			"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
-			"dev": true,
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/levn": {
-			"version": "0.4.1",
-			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
-			"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
-			"dev": true,
-			"dependencies": {
-				"prelude-ls": "^1.2.1",
-				"type-check": "~0.4.0"
-			},
-			"engines": {
-				"node": ">= 0.8.0"
-			}
-		},
-		"node_modules/linkify-it": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
-			"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"uc.micro": "^2.0.0"
-			}
-		},
-		"node_modules/liquidjs": {
-			"version": "10.19.0",
-			"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.19.0.tgz",
-			"integrity": "sha512-dNINmbNJ/bp3B8n25BtZQV/GbrmFf0o2InGdMdfQXa+LxfzTFXOkUnBsOLZUb82sLzxaiWv5Jc381Kn4zHjTsQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"commander": "^10.0.0"
-			},
-			"bin": {
-				"liquid": "bin/liquid.js",
-				"liquidjs": "bin/liquid.js"
-			},
-			"engines": {
-				"node": ">=14"
-			},
-			"funding": {
-				"type": "opencollective",
-				"url": "https://opencollective.com/liquidjs"
-			}
-		},
-		"node_modules/liquidjs/node_modules/commander": {
-			"version": "10.0.1",
-			"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
-			"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=14"
-			}
-		},
-		"node_modules/list-to-array": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/list-to-array/-/list-to-array-1.1.0.tgz",
-			"integrity": "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/locate-path": {
-			"version": "6.0.0",
-			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-			"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-			"dev": true,
-			"dependencies": {
-				"p-locate": "^5.0.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/lodash.merge": {
-			"version": "4.6.2",
-			"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-			"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-			"dev": true
-		},
-		"node_modules/lru-cache": {
-			"version": "10.4.3",
-			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
-			"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
-			"dev": true,
-			"license": "ISC"
-		},
-		"node_modules/luxon": {
-			"version": "3.5.0",
-			"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
-			"integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=12"
-			}
-		},
-		"node_modules/make-dir": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-			"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-			"dev": true,
-			"dependencies": {
-				"semver": "^6.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/make-dir/node_modules/semver": {
-			"version": "6.3.1",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-			"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-			"dev": true,
-			"bin": {
-				"semver": "bin/semver.js"
-			}
-		},
-		"node_modules/markdown-it": {
-			"version": "14.1.0",
-			"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
-			"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"argparse": "^2.0.1",
-				"entities": "^4.4.0",
-				"linkify-it": "^5.0.0",
-				"mdurl": "^2.0.0",
-				"punycode.js": "^2.3.1",
-				"uc.micro": "^2.1.0"
-			},
-			"bin": {
-				"markdown-it": "bin/markdown-it.mjs"
-			}
-		},
-		"node_modules/markdown-it/node_modules/argparse": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-			"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-			"dev": true,
-			"license": "Python-2.0"
-		},
-		"node_modules/markdown-it/node_modules/entities": {
-			"version": "4.5.0",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
-			"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
-			"dev": true,
-			"license": "BSD-2-Clause",
-			"engines": {
-				"node": ">=0.12"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/entities?sponsor=1"
-			}
-		},
-		"node_modules/maximatch": {
-			"version": "0.1.0",
-			"resolved": "https://registry.npmjs.org/maximatch/-/maximatch-0.1.0.tgz",
-			"integrity": "sha512-9ORVtDUFk4u/NFfo0vG/ND/z7UQCVZBL539YW0+U1I7H1BkZwizcPx5foFv7LCPcBnm2U6RjFnQOsIvN4/Vm2A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"array-differ": "^1.0.0",
-				"array-union": "^1.0.1",
-				"arrify": "^1.0.0",
-				"minimatch": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/maximatch/node_modules/array-union": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
-			"integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"array-uniq": "^1.0.1"
-			},
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/mdurl": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
-			"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/merge-stream": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
-			"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
-			"dev": true
-		},
-		"node_modules/merge2": {
-			"version": "1.4.1",
-			"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-			"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/micromatch": {
-			"version": "4.0.8",
-			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
-			"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"braces": "^3.0.3",
-				"picomatch": "^2.3.1"
-			},
-			"engines": {
-				"node": ">=8.6"
-			}
-		},
-		"node_modules/mime": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
-			"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
-			"dev": true,
-			"license": "MIT",
-			"bin": {
-				"mime": "cli.js"
-			},
-			"engines": {
-				"node": ">=10.0.0"
-			}
-		},
-		"node_modules/mimic-fn": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
-			"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
-			"dev": true,
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/minimatch": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-			"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-			"dev": true,
-			"dependencies": {
-				"brace-expansion": "^1.1.7"
-			},
-			"engines": {
-				"node": "*"
-			}
-		},
-		"node_modules/minimist": {
-			"version": "1.2.8",
-			"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-			"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-			"dev": true,
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/minipass": {
-			"version": "7.1.2",
-			"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
-			"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
-			"dev": true,
-			"license": "ISC",
-			"engines": {
-				"node": ">=16 || 14 >=14.17"
-			}
-		},
-		"node_modules/mkdirp": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
-			"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
-			"dev": true,
-			"license": "MIT",
-			"bin": {
-				"mkdirp": "dist/cjs/src/bin.js"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/moo": {
-			"version": "0.5.2",
-			"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
-			"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
-			"dev": true
-		},
-		"node_modules/morphdom": {
-			"version": "2.7.4",
-			"resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.4.tgz",
-			"integrity": "sha512-ATTbWMgGa+FaMU3FhnFYB6WgulCqwf6opOll4CBzmVDTLvPMmUPrEv8CudmLPK0MESa64+6B89fWOxP3+YIlxQ==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/mri": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
-			"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
-			"dev": true,
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/ms": {
-			"version": "2.1.3",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/natural-compare": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-			"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
-			"dev": true
-		},
-		"node_modules/node-retrieve-globals": {
-			"version": "6.0.0",
-			"resolved": "https://registry.npmjs.org/node-retrieve-globals/-/node-retrieve-globals-6.0.0.tgz",
-			"integrity": "sha512-VoEp6WMN/JcbBrJr6LnFE11kdzpKiBKNPFrHCEK2GgFWtiYpeL85WgcZpZFFnWxAU0O65+b+ipQAy4Oxy/+Pdg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"acorn": "^8.1.3",
-				"acorn-walk": "^8.3.2",
-				"esm-import-transformer": "^3.0.2"
-			}
-		},
-		"node_modules/normalize-path": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-			"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/npm-run-path": {
-			"version": "4.0.1",
-			"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-			"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
-			"dev": true,
-			"dependencies": {
-				"path-key": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/nunjucks": {
-			"version": "3.2.4",
-			"resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz",
-			"integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==",
-			"dev": true,
-			"dependencies": {
-				"a-sync-waterfall": "^1.0.0",
-				"asap": "^2.0.3",
-				"commander": "^5.1.0"
-			},
-			"bin": {
-				"nunjucks-precompile": "bin/precompile"
-			},
-			"engines": {
-				"node": ">= 6.9.0"
-			},
-			"peerDependencies": {
-				"chokidar": "^3.3.0"
-			},
-			"peerDependenciesMeta": {
-				"chokidar": {
-					"optional": true
-				}
-			}
-		},
-		"node_modules/nunjucks/node_modules/commander": {
-			"version": "5.1.0",
-			"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
-			"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
-			"dev": true,
-			"engines": {
-				"node": ">= 6"
-			}
-		},
-		"node_modules/object-inspect": {
-			"version": "1.13.3",
-			"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
-			"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/object-keys": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-			"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-			"dev": true,
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/object.assign": {
-			"version": "4.1.5",
-			"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
-			"integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
-			"dev": true,
-			"dependencies": {
-				"call-bind": "^1.0.5",
-				"define-properties": "^1.2.1",
-				"has-symbols": "^1.0.3",
-				"object-keys": "^1.1.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/object.entries": {
-			"version": "1.1.8",
-			"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
-			"integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/object.fromentries": {
-			"version": "2.0.8",
-			"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
-			"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2",
-				"es-object-atoms": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/object.groupby": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
-			"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/object.values": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
-			"integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/on-finished": {
-			"version": "2.4.1",
-			"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
-			"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ee-first": "1.1.1"
-			},
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/once": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-			"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"wrappy": "1"
-			}
-		},
-		"node_modules/onetime": {
-			"version": "5.1.2",
-			"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
-			"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
-			"dev": true,
-			"dependencies": {
-				"mimic-fn": "^2.1.0"
-			},
-			"engines": {
-				"node": ">=6"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/optionator": {
-			"version": "0.9.3",
-			"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
-			"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
-			"dev": true,
-			"dependencies": {
-				"@aashutoshrathi/word-wrap": "^1.2.3",
-				"deep-is": "^0.1.3",
-				"fast-levenshtein": "^2.0.6",
-				"levn": "^0.4.1",
-				"prelude-ls": "^1.2.1",
-				"type-check": "^0.4.0"
-			},
-			"engines": {
-				"node": ">= 0.8.0"
-			}
-		},
-		"node_modules/p-limit": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-			"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-			"dev": true,
-			"dependencies": {
-				"p-try": "^2.0.0"
-			},
-			"engines": {
-				"node": ">=6"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/p-locate": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-			"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-			"dev": true,
-			"dependencies": {
-				"p-limit": "^3.0.2"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/p-locate/node_modules/p-limit": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-			"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-			"dev": true,
-			"dependencies": {
-				"yocto-queue": "^0.1.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/p-try": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-			"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-			"dev": true,
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/package-json-from-dist": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
-			"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
-			"dev": true,
-			"license": "BlueOak-1.0.0"
-		},
-		"node_modules/parent-module": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-			"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"callsites": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/parse-srcset": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
-			"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/parseurl": {
-			"version": "1.3.3",
-			"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-			"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/path-exists": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-			"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-			"dev": true,
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/path-is-absolute": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-			"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/path-key": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-			"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-			"dev": true,
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/path-parse": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-			"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-			"dev": true
-		},
-		"node_modules/path-scurry": {
-			"version": "1.11.1",
-			"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
-			"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
-			"dev": true,
-			"license": "BlueOak-1.0.0",
-			"dependencies": {
-				"lru-cache": "^10.2.0",
-				"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
-			},
-			"engines": {
-				"node": ">=16 || 14 >=14.18"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/path-type": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/picocolors": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-			"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-			"dev": true
-		},
-		"node_modules/picomatch": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-			"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-			"dev": true,
-			"engines": {
-				"node": ">=8.6"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/jonschlinkert"
-			}
-		},
-		"node_modules/pify": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-			"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/pkg-dir": {
-			"version": "4.2.0",
-			"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-			"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
-			"dev": true,
-			"dependencies": {
-				"find-up": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/pkg-dir/node_modules/find-up": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-			"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-			"dev": true,
-			"dependencies": {
-				"locate-path": "^5.0.0",
-				"path-exists": "^4.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/pkg-dir/node_modules/locate-path": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-			"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-			"dev": true,
-			"dependencies": {
-				"p-locate": "^4.1.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/pkg-dir/node_modules/p-locate": {
-			"version": "4.1.0",
-			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-			"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-			"dev": true,
-			"dependencies": {
-				"p-limit": "^2.2.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/please-upgrade-node": {
-			"version": "3.2.0",
-			"resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
-			"integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"semver-compare": "^1.0.0"
-			}
-		},
-		"node_modules/possible-typed-array-names": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
-			"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/posthtml": {
-			"version": "0.16.6",
-			"resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
-			"integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
-			"dev": true,
-			"dependencies": {
-				"posthtml-parser": "^0.11.0",
-				"posthtml-render": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=12.0.0"
-			}
-		},
-		"node_modules/posthtml-match-helper": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/posthtml-match-helper/-/posthtml-match-helper-2.0.2.tgz",
-			"integrity": "sha512-ehnazjlSwcGa3P2LlFYmTmcnaembTSt9dLWIRRDVHDPidf6InWAr9leKeeLvUXgnU32g6BrFS64Je+c2Ld+l9g==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=18"
-			},
-			"peerDependencies": {
-				"posthtml": "^0.16.6"
-			}
-		},
-		"node_modules/posthtml-parser": {
-			"version": "0.11.0",
-			"resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
-			"integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
-			"dev": true,
-			"dependencies": {
-				"htmlparser2": "^7.1.1"
-			},
-			"engines": {
-				"node": ">=12"
-			}
-		},
-		"node_modules/posthtml-parser/node_modules/dom-serializer": {
-			"version": "1.4.1",
-			"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
-			"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
-			"dev": true,
-			"dependencies": {
-				"domelementtype": "^2.0.1",
-				"domhandler": "^4.2.0",
-				"entities": "^2.0.0"
-			},
-			"funding": {
-				"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
-			}
-		},
-		"node_modules/posthtml-parser/node_modules/dom-serializer/node_modules/entities": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
-			"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
-			"dev": true,
-			"funding": {
-				"url": "https://github.com/fb55/entities?sponsor=1"
-			}
-		},
-		"node_modules/posthtml-parser/node_modules/domhandler": {
-			"version": "4.3.1",
-			"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
-			"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
-			"dev": true,
-			"dependencies": {
-				"domelementtype": "^2.2.0"
-			},
-			"engines": {
-				"node": ">= 4"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/domhandler?sponsor=1"
-			}
-		},
-		"node_modules/posthtml-parser/node_modules/domutils": {
-			"version": "2.8.0",
-			"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
-			"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
-			"dev": true,
-			"dependencies": {
-				"dom-serializer": "^1.0.1",
-				"domelementtype": "^2.2.0",
-				"domhandler": "^4.2.0"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/domutils?sponsor=1"
-			}
-		},
-		"node_modules/posthtml-parser/node_modules/entities": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
-			"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
-			"dev": true,
-			"engines": {
-				"node": ">=0.12"
-			},
-			"funding": {
-				"url": "https://github.com/fb55/entities?sponsor=1"
-			}
-		},
-		"node_modules/posthtml-parser/node_modules/htmlparser2": {
-			"version": "7.2.0",
-			"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
-			"integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
-			"dev": true,
-			"funding": [
-				"https://github.com/fb55/htmlparser2?sponsor=1",
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/fb55"
-				}
-			],
-			"dependencies": {
-				"domelementtype": "^2.0.1",
-				"domhandler": "^4.2.2",
-				"domutils": "^2.8.0",
-				"entities": "^3.0.1"
-			}
-		},
-		"node_modules/posthtml-render": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
-			"integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
-			"dev": true,
-			"dependencies": {
-				"is-json": "^2.0.1"
-			},
-			"engines": {
-				"node": ">=12"
-			}
-		},
-		"node_modules/prelude-ls": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-			"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-			"dev": true,
-			"engines": {
-				"node": ">= 0.8.0"
-			}
-		},
-		"node_modules/prettier": {
-			"version": "3.4.1",
-			"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz",
-			"integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==",
-			"dev": true,
-			"license": "MIT",
-			"bin": {
-				"prettier": "bin/prettier.cjs"
-			},
-			"engines": {
-				"node": ">=14"
-			},
-			"funding": {
-				"url": "https://github.com/prettier/prettier?sponsor=1"
-			}
-		},
-		"node_modules/pretty-quick": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-4.0.0.tgz",
-			"integrity": "sha512-M+2MmeufXb/M7Xw3Afh1gxcYpj+sK0AxEfnfF958ktFeAyi5MsKY5brymVURQLgPLV1QaF5P4pb2oFJ54H3yzQ==",
-			"dev": true,
-			"dependencies": {
-				"execa": "^5.1.1",
-				"find-up": "^5.0.0",
-				"ignore": "^5.3.0",
-				"mri": "^1.2.0",
-				"picocolors": "^1.0.0",
-				"picomatch": "^3.0.1",
-				"tslib": "^2.6.2"
-			},
-			"bin": {
-				"pretty-quick": "lib/cli.mjs"
-			},
-			"engines": {
-				"node": ">=14"
-			},
-			"peerDependencies": {
-				"prettier": "^3.0.0"
-			}
-		},
-		"node_modules/pretty-quick/node_modules/picomatch": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
-			"integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==",
-			"dev": true,
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/jonschlinkert"
-			}
-		},
-		"node_modules/prismjs": {
-			"version": "1.29.0",
-			"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
-			"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
-			"dev": true,
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/promise": {
-			"version": "7.3.1",
-			"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
-			"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"asap": "~2.0.3"
-			}
-		},
-		"node_modules/prr": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-			"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/punycode": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-			"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/punycode.js": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
-			"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/queue-microtask": {
-			"version": "1.2.3",
-			"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-			"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-			"dev": true,
-			"funding": [
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/feross"
-				},
-				{
-					"type": "patreon",
-					"url": "https://www.patreon.com/feross"
-				},
-				{
-					"type": "consulting",
-					"url": "https://feross.org/support"
-				}
-			],
-			"license": "MIT"
-		},
-		"node_modules/range-parser": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-			"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.6"
-			}
-		},
-		"node_modules/readdirp": {
-			"version": "3.6.0",
-			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-			"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-			"dev": true,
-			"dependencies": {
-				"picomatch": "^2.2.1"
-			},
-			"engines": {
-				"node": ">=8.10.0"
-			}
-		},
-		"node_modules/reflect.getprototypeof": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz",
-			"integrity": "sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.5",
-				"es-errors": "^1.3.0",
-				"get-intrinsic": "^1.2.4",
-				"gopd": "^1.0.1",
-				"which-builtin-type": "^1.1.4"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/regexp.prototype.flags": {
-			"version": "1.5.3",
-			"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
-			"integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-errors": "^1.3.0",
-				"set-function-name": "^2.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/resolve-from": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-			"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/reusify": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
-			"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"iojs": ">=1.0.0",
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/rimraf": {
-			"version": "5.0.10",
-			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
-			"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"glob": "^10.3.7"
-			},
-			"bin": {
-				"rimraf": "dist/esm/bin.mjs"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/isaacs"
-			}
-		},
-		"node_modules/run-parallel": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
-			"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
-			"dev": true,
-			"funding": [
-				{
-					"type": "github",
-					"url": "https://github.com/sponsors/feross"
-				},
-				{
-					"type": "patreon",
-					"url": "https://www.patreon.com/feross"
-				},
-				{
-					"type": "consulting",
-					"url": "https://feross.org/support"
-				}
-			],
-			"license": "MIT",
-			"dependencies": {
-				"queue-microtask": "^1.2.2"
-			}
-		},
-		"node_modules/safe-array-concat": {
-			"version": "1.1.2",
-			"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
-			"integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"get-intrinsic": "^1.2.4",
-				"has-symbols": "^1.0.3",
-				"isarray": "^2.0.5"
-			},
-			"engines": {
-				"node": ">=0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/safe-regex-test": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
-			"integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.6",
-				"es-errors": "^1.3.0",
-				"is-regex": "^1.1.4"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/section-matter": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
-			"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
-			"dev": true,
-			"dependencies": {
-				"extend-shallow": "^2.0.1",
-				"kind-of": "^6.0.0"
-			},
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/semver": {
-			"version": "7.6.3",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
-			"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
-			"dev": true,
-			"license": "ISC",
-			"bin": {
-				"semver": "bin/semver.js"
-			},
-			"engines": {
-				"node": ">=10"
-			}
-		},
-		"node_modules/semver-compare": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
-			"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/send": {
-			"version": "0.19.1",
-			"resolved": "https://registry.npmjs.org/send/-/send-0.19.1.tgz",
-			"integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"debug": "2.6.9",
-				"depd": "2.0.0",
-				"destroy": "1.2.0",
-				"encodeurl": "~2.0.0",
-				"escape-html": "~1.0.3",
-				"etag": "~1.8.1",
-				"fresh": "0.5.2",
-				"http-errors": "2.0.0",
-				"mime": "1.6.0",
-				"ms": "2.1.3",
-				"on-finished": "2.4.1",
-				"range-parser": "~1.2.1",
-				"statuses": "2.0.1"
-			},
-			"engines": {
-				"node": ">= 0.8.0"
-			}
-		},
-		"node_modules/send/node_modules/debug": {
-			"version": "2.6.9",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-			"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ms": "2.0.0"
-			}
-		},
-		"node_modules/send/node_modules/debug/node_modules/ms": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-			"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/send/node_modules/mime": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-			"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-			"dev": true,
-			"license": "MIT",
-			"bin": {
-				"mime": "cli.js"
-			},
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/set-function-length": {
-			"version": "1.2.2",
-			"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
-			"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"define-data-property": "^1.1.4",
-				"es-errors": "^1.3.0",
-				"function-bind": "^1.1.2",
-				"get-intrinsic": "^1.2.4",
-				"gopd": "^1.0.1",
-				"has-property-descriptors": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/set-function-name": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
-			"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"define-data-property": "^1.1.4",
-				"es-errors": "^1.3.0",
-				"functions-have-names": "^1.2.3",
-				"has-property-descriptors": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/setprototypeof": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
-			"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
-			"dev": true,
-			"license": "ISC"
-		},
-		"node_modules/shebang-command": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-			"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-			"dev": true,
-			"dependencies": {
-				"shebang-regex": "^3.0.0"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/shebang-regex": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-			"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-			"dev": true,
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/side-channel": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
-			"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"es-errors": "^1.3.0",
-				"get-intrinsic": "^1.2.4",
-				"object-inspect": "^1.13.1"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/signal-exit": {
-			"version": "3.0.7",
-			"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
-			"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
-			"dev": true
-		},
-		"node_modules/slash": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
-			"integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/slugify": {
-			"version": "1.6.6",
-			"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
-			"integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
-			"dev": true,
-			"engines": {
-				"node": ">=8.0.0"
-			}
-		},
-		"node_modules/sprintf-js": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-			"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-			"dev": true
-		},
-		"node_modules/ssri": {
-			"version": "11.0.0",
-			"resolved": "https://registry.npmjs.org/ssri/-/ssri-11.0.0.tgz",
-			"integrity": "sha512-aZpUoMN/Jj2MqA4vMCeiKGnc/8SuSyHbGSBdgFbZxP8OJGF/lFkIuElzPxsN0q8TQQ+prw3P4EDfB3TBHHgfXw==",
-			"dev": true,
-			"license": "ISC",
-			"dependencies": {
-				"minipass": "^7.0.3"
-			},
-			"engines": {
-				"node": "^16.14.0 || >=18.0.0"
-			}
-		},
-		"node_modules/statuses": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
-			"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/string-width": {
-			"version": "5.1.2",
-			"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
-			"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"eastasianwidth": "^0.2.0",
-				"emoji-regex": "^9.2.2",
-				"strip-ansi": "^7.0.1"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/string-width-cjs": {
-			"name": "string-width",
-			"version": "4.2.3",
-			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"emoji-regex": "^8.0.0",
-				"is-fullwidth-code-point": "^3.0.0",
-				"strip-ansi": "^6.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/string-width-cjs/node_modules/ansi-regex": {
-			"version": "5.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/string-width-cjs/node_modules/emoji-regex": {
-			"version": "8.0.0",
-			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/string-width-cjs/node_modules/strip-ansi": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ansi-regex": "^5.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/string.prototype.trim": {
-			"version": "1.2.9",
-			"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
-			"integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.0",
-				"es-object-atoms": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/string.prototype.trimend": {
-			"version": "1.0.8",
-			"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
-			"integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/string.prototype.trimstart": {
-			"version": "1.0.8",
-			"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
-			"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/strip-ansi": {
-			"version": "7.1.0",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-			"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ansi-regex": "^6.0.1"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/strip-ansi?sponsor=1"
-			}
-		},
-		"node_modules/strip-ansi-cjs": {
-			"name": "strip-ansi",
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ansi-regex": "^5.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
-			"version": "5.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/strip-bom": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-			"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
-			"dev": true,
-			"engines": {
-				"node": ">=4"
-			}
-		},
-		"node_modules/strip-bom-string": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
-			"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
-			"dev": true,
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/strip-final-newline": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
-			"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
-			"dev": true,
-			"engines": {
-				"node": ">=6"
-			}
-		},
-		"node_modules/strip-json-comments": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-			"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/strip-outer": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
-			"integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
-			"dev": true,
-			"dependencies": {
-				"escape-string-regexp": "^1.0.2"
-			},
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/supports-preserve-symlinks-flag": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-			"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-			"dev": true,
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/text-table": {
-			"version": "0.2.0",
-			"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-			"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/to-regex-range": {
-			"version": "5.0.1",
-			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"is-number": "^7.0.0"
-			},
-			"engines": {
-				"node": ">=8.0"
-			}
-		},
-		"node_modules/toidentifier": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
-			"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=0.6"
-			}
-		},
-		"node_modules/trim-repeated": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
-			"integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
-			"dev": true,
-			"dependencies": {
-				"escape-string-regexp": "^1.0.2"
-			},
-			"engines": {
-				"node": ">=0.10.0"
-			}
-		},
-		"node_modules/tsconfig-paths": {
-			"version": "3.15.0",
-			"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
-			"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
-			"dev": true,
-			"dependencies": {
-				"@types/json5": "^0.0.29",
-				"json5": "^1.0.2",
-				"minimist": "^1.2.6",
-				"strip-bom": "^3.0.0"
-			}
-		},
-		"node_modules/tslib": {
-			"version": "2.6.2",
-			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
-			"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
-			"dev": true
-		},
-		"node_modules/type-check": {
-			"version": "0.4.0",
-			"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
-			"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
-			"dev": true,
-			"dependencies": {
-				"prelude-ls": "^1.2.1"
-			},
-			"engines": {
-				"node": ">= 0.8.0"
-			}
-		},
-		"node_modules/type-fest": {
-			"version": "0.20.2",
-			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-			"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-			"dev": true,
-			"license": "(MIT OR CC0-1.0)",
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		},
-		"node_modules/typed-array-buffer": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
-			"integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"es-errors": "^1.3.0",
-				"is-typed-array": "^1.1.13"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			}
-		},
-		"node_modules/typed-array-byte-length": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
-			"integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"has-proto": "^1.0.3",
-				"is-typed-array": "^1.1.13"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/typed-array-byte-offset": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz",
-			"integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"available-typed-arrays": "^1.0.7",
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"has-proto": "^1.0.3",
-				"is-typed-array": "^1.1.13",
-				"reflect.getprototypeof": "^1.0.6"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/typed-array-length": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
-			"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"is-typed-array": "^1.1.13",
-				"possible-typed-array-names": "^1.0.0",
-				"reflect.getprototypeof": "^1.0.6"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/uc.micro": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
-			"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/unbox-primitive": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
-			"integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
-			"dev": true,
-			"dependencies": {
-				"call-bind": "^1.0.2",
-				"has-bigints": "^1.0.2",
-				"has-symbols": "^1.0.3",
-				"which-boxed-primitive": "^1.0.2"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/universalify": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
-			"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
-			"dev": true,
-			"engines": {
-				"node": ">= 10.0.0"
-			}
-		},
-		"node_modules/unpipe": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-			"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">= 0.8"
-			}
-		},
-		"node_modules/uri-js": {
-			"version": "4.4.1",
-			"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
-			"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
-			"dev": true,
-			"license": "BSD-2-Clause",
-			"dependencies": {
-				"punycode": "^2.1.0"
-			}
-		},
-		"node_modules/urlpattern-polyfill": {
-			"version": "10.0.0",
-			"resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz",
-			"integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/which": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-			"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-			"dev": true,
-			"dependencies": {
-				"isexe": "^2.0.0"
-			},
-			"bin": {
-				"node-which": "bin/node-which"
-			},
-			"engines": {
-				"node": ">= 8"
-			}
-		},
-		"node_modules/which-boxed-primitive": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
-			"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
-			"dev": true,
-			"dependencies": {
-				"is-bigint": "^1.0.1",
-				"is-boolean-object": "^1.1.0",
-				"is-number-object": "^1.0.4",
-				"is-string": "^1.0.5",
-				"is-symbol": "^1.0.3"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/which-builtin-type": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz",
-			"integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"call-bind": "^1.0.7",
-				"function.prototype.name": "^1.1.6",
-				"has-tostringtag": "^1.0.2",
-				"is-async-function": "^2.0.0",
-				"is-date-object": "^1.0.5",
-				"is-finalizationregistry": "^1.1.0",
-				"is-generator-function": "^1.0.10",
-				"is-regex": "^1.1.4",
-				"is-weakref": "^1.0.2",
-				"isarray": "^2.0.5",
-				"which-boxed-primitive": "^1.0.2",
-				"which-collection": "^1.0.2",
-				"which-typed-array": "^1.1.15"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/which-collection": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
-			"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"is-map": "^2.0.3",
-				"is-set": "^2.0.3",
-				"is-weakmap": "^2.0.2",
-				"is-weakset": "^2.0.3"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/which-typed-array": {
-			"version": "1.1.15",
-			"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
-			"integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"available-typed-arrays": "^1.0.7",
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"has-tostringtag": "^1.0.2"
-			},
-			"engines": {
-				"node": ">= 0.4"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/ljharb"
-			}
-		},
-		"node_modules/wrap-ansi": {
-			"version": "8.1.0",
-			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
-			"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ansi-styles": "^6.1.0",
-				"string-width": "^5.0.1",
-				"strip-ansi": "^7.0.1"
-			},
-			"engines": {
-				"node": ">=12"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-			}
-		},
-		"node_modules/wrap-ansi-cjs": {
-			"name": "wrap-ansi",
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-			"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ansi-styles": "^4.0.0",
-				"string-width": "^4.1.0",
-				"strip-ansi": "^6.0.0"
-			},
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
-			}
-		},
-		"node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
-			"version": "5.0.1",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-			"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/wrap-ansi-cjs/node_modules/ansi-styles": {
-			"version": "4.3.0",
-			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-			"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"color-convert": "^2.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			},
-			"funding": {
-				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
-			}
-		},
-		"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
-			"version": "8.0.0",
-			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-			"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-			"dev": true,
-			"license": "MIT"
-		},
-		"node_modules/wrap-ansi-cjs/node_modules/string-width": {
-			"version": "4.2.3",
-			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"emoji-regex": "^8.0.0",
-				"is-fullwidth-code-point": "^3.0.0",
-				"strip-ansi": "^6.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-			"dev": true,
-			"license": "MIT",
-			"dependencies": {
-				"ansi-regex": "^5.0.1"
-			},
-			"engines": {
-				"node": ">=8"
-			}
-		},
-		"node_modules/wrappy": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-			"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-			"dev": true,
-			"license": "ISC"
-		},
-		"node_modules/ws": {
-			"version": "8.18.0",
-			"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
-			"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
-			"dev": true,
-			"license": "MIT",
-			"engines": {
-				"node": ">=10.0.0"
-			},
-			"peerDependencies": {
-				"bufferutil": "^4.0.1",
-				"utf-8-validate": ">=5.0.2"
-			},
-			"peerDependenciesMeta": {
-				"bufferutil": {
-					"optional": true
-				},
-				"utf-8-validate": {
-					"optional": true
-				}
-			}
-		},
-		"node_modules/yocto-queue": {
-			"version": "0.1.0",
-			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
-			"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
-			"dev": true,
-			"engines": {
-				"node": ">=10"
-			},
-			"funding": {
-				"url": "https://github.com/sponsors/sindresorhus"
-			}
-		}
-	},
-	"dependencies": {
-		"@11ty/dependency-tree": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/@11ty/dependency-tree/-/dependency-tree-3.0.1.tgz",
-			"integrity": "sha512-aZizxcL4Z/clm3KPRx8i9ohW9R2gLssXfUSy7qQmQRXb4CUOyvmqk2gKeJqRmXIfMi2bB9w03SgtN5v1YwqpiA==",
-			"dev": true,
-			"requires": {
-				"@11ty/eleventy-utils": "^1.0.2"
-			}
-		},
-		"@11ty/dependency-tree-esm": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/dependency-tree-esm/-/dependency-tree-esm-1.0.0.tgz",
-			"integrity": "sha512-Z3KN1Fkv50UM/ZzTR3VBbyOY52HnmhIVCsAV1hn2UzFsGAjyF1Cw8uohhVtheDOSuBR7ZSeo1unwkz1HxFlUtQ==",
-			"dev": true,
-			"requires": {
-				"@11ty/eleventy-utils": "^1.0.2",
-				"acorn": "^8.10.0",
-				"dependency-graph": "^0.11.0",
-				"normalize-path": "^3.0.0"
-			},
-			"dependencies": {
-				"dependency-graph": {
-					"version": "0.11.0",
-					"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.11.0.tgz",
-					"integrity": "sha512-JeMq7fEshyepOWDfcfHK06N3MhyPhz++vtqWhMT5O9A3K42rdsEDpfdVqjaqaAhsw6a+ZqeDvQVtD0hFHQWrzg==",
-					"dev": true
-				}
-			}
-		},
-		"@11ty/eleventy": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy/-/eleventy-3.0.0.tgz",
-			"integrity": "sha512-0P0ZsJXVW2QiNdhd7z+GYy6n+ivh0enx1DRdua5ta6NlzY2AhbkeWBY6U+FKA8lPS3H4+XsTpfLLfIScpPZLaQ==",
-			"dev": true,
-			"requires": {
-				"@11ty/dependency-tree": "^3.0.1",
-				"@11ty/dependency-tree-esm": "^1.0.0",
-				"@11ty/eleventy-dev-server": "^2.0.4",
-				"@11ty/eleventy-plugin-bundle": "^3.0.0",
-				"@11ty/eleventy-utils": "^1.0.3",
-				"@11ty/lodash-custom": "^4.17.21",
-				"@11ty/posthtml-urls": "^1.0.0",
-				"@11ty/recursive-copy": "^3.0.0",
-				"@sindresorhus/slugify": "^2.2.1",
-				"bcp-47-normalize": "^2.3.0",
-				"chardet": "^2.0.0",
-				"chokidar": "^3.6.0",
-				"cross-spawn": "^7.0.3",
-				"debug": "^4.3.7",
-				"dependency-graph": "^1.0.0",
-				"entities": "^5.0.0",
-				"fast-glob": "^3.3.2",
-				"filesize": "^10.1.6",
-				"graceful-fs": "^4.2.11",
-				"gray-matter": "^4.0.3",
-				"is-glob": "^4.0.3",
-				"iso-639-1": "^3.1.3",
-				"js-yaml": "^4.1.0",
-				"kleur": "^4.1.5",
-				"liquidjs": "^10.17.0",
-				"luxon": "^3.5.0",
-				"markdown-it": "^14.1.0",
-				"micromatch": "^4.0.8",
-				"minimist": "^1.2.8",
-				"moo": "^0.5.2",
-				"node-retrieve-globals": "^6.0.0",
-				"normalize-path": "^3.0.0",
-				"nunjucks": "^3.2.4",
-				"please-upgrade-node": "^3.2.0",
-				"posthtml": "^0.16.6",
-				"posthtml-match-helper": "^2.0.2",
-				"semver": "^7.6.3",
-				"slugify": "^1.6.6"
-			},
-			"dependencies": {
-				"argparse": {
-					"version": "2.0.1",
-					"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-					"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-					"dev": true
-				},
-				"js-yaml": {
-					"version": "4.1.0",
-					"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-					"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-					"dev": true,
-					"requires": {
-						"argparse": "^2.0.1"
-					}
-				}
-			}
-		},
-		"@11ty/eleventy-dev-server": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-dev-server/-/eleventy-dev-server-2.0.4.tgz",
-			"integrity": "sha512-d0CuufX6yPtVz+RW0oJZg1pVoxo1jOrPmpXYacoiKLJm0MMC9MkPQOCXlimguHVaceHejFo5+aZB9/aGB2RR0A==",
-			"dev": true,
-			"requires": {
-				"@11ty/eleventy-utils": "^1.0.3",
-				"chokidar": "^3.6.0",
-				"debug": "^4.3.7",
-				"dev-ip": "^1.0.1",
-				"finalhandler": "^1.3.0",
-				"mime": "^3.0.0",
-				"minimist": "^1.2.8",
-				"morphdom": "^2.7.4",
-				"please-upgrade-node": "^3.2.0",
-				"send": "^0.19.0",
-				"ssri": "^11.0.0",
-				"urlpattern-polyfill": "^10.0.0",
-				"ws": "^8.18.0"
-			}
-		},
-		"@11ty/eleventy-plugin-bundle": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-bundle/-/eleventy-plugin-bundle-3.0.0.tgz",
-			"integrity": "sha512-JSnqehT+sWSPi6e44jTXUW+KiV9284YF9fzPQvfGB4cXlk/m/SJk17CavHCleIvKXDN+jrUw9TZkwAwr85ONWQ==",
-			"dev": true,
-			"requires": {
-				"debug": "^4.3.4",
-				"posthtml-match-helper": "^2.0.2"
-			}
-		},
-		"@11ty/eleventy-plugin-syntaxhighlight": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-plugin-syntaxhighlight/-/eleventy-plugin-syntaxhighlight-5.0.0.tgz",
-			"integrity": "sha512-y9BUmP1GofmbJgxM1+ky/UpFCpD8JSOeLeKItUs0WApgnrHk9haHziW7lS86lbArX5SiCVo4zTTw9x53gvRCaA==",
-			"dev": true,
-			"requires": {
-				"prismjs": "^1.29.0"
-			}
-		},
-		"@11ty/eleventy-utils": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/@11ty/eleventy-utils/-/eleventy-utils-1.0.3.tgz",
-			"integrity": "sha512-nULO91om7vQw4Y/UBjM8i7nJ1xl+/nyK4rImZ41lFxiY2d+XUz7ChAj1CDYFjrLZeu0utAYJTZ45LlcHTkUG4g==",
-			"dev": true,
-			"requires": {
-				"normalize-path": "^3.0.0"
-			}
-		},
-		"@11ty/lodash-custom": {
-			"version": "4.17.21",
-			"resolved": "https://registry.npmjs.org/@11ty/lodash-custom/-/lodash-custom-4.17.21.tgz",
-			"integrity": "sha512-Mqt6im1xpb1Ykn3nbcCovWXK3ggywRJa+IXIdoz4wIIK+cvozADH63lexcuPpGS/gJ6/m2JxyyXDyupkMr5DHw==",
-			"dev": true
-		},
-		"@11ty/posthtml-urls": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/posthtml-urls/-/posthtml-urls-1.0.0.tgz",
-			"integrity": "sha512-CcsRdI933x613u7CjM+QGs7iD/m8SaDup3Apohg1+7dybigrEUHc2jGS3mcMgQKvF2+IphqmepD/FrKLlPkPEg==",
-			"dev": true,
-			"requires": {
-				"evaluate-value": "^2.0.0",
-				"http-equiv-refresh": "^2.0.1",
-				"list-to-array": "^1.1.0",
-				"object.entries": "^1.1.7",
-				"parse-srcset": "^1.0.2"
-			}
-		},
-		"@11ty/recursive-copy": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/@11ty/recursive-copy/-/recursive-copy-3.0.0.tgz",
-			"integrity": "sha512-v1Mr7dWx5nk69/HRRtDHUYDV9N8+cE12IGiKSFOwML7HjOzUXwTP88e3cGuhqoVstkBil1ZEIaOB0KPP1zwqXA==",
-			"dev": true,
-			"requires": {
-				"errno": "^0.1.2",
-				"graceful-fs": "^4.2.11",
-				"junk": "^1.0.1",
-				"maximatch": "^0.1.0",
-				"mkdirp": "^3.0.1",
-				"pify": "^2.3.0",
-				"promise": "^7.0.1",
-				"rimraf": "^5.0.7",
-				"slash": "^1.0.0"
-			}
-		},
-		"@aashutoshrathi/word-wrap": {
-			"version": "1.2.6",
-			"resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
-			"integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
-			"dev": true
-		},
-		"@esbuild/aix-ppc64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.24.0.tgz",
-			"integrity": "sha512-WtKdFM7ls47zkKHFVzMz8opM7LkcsIp9amDUBIAWirg70RM71WRSjdILPsY5Uv1D42ZpUfaPILDlfactHgsRkw==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/android-arm": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.24.0.tgz",
-			"integrity": "sha512-arAtTPo76fJ/ICkXWetLCc9EwEHKaeya4vMrReVlEIUCAUncH7M4bhMQ+M9Vf+FFOZJdTNMXNBrWwW+OXWpSew==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/android-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.24.0.tgz",
-			"integrity": "sha512-Vsm497xFM7tTIPYK9bNTYJyF/lsP590Qc1WxJdlB6ljCbdZKU9SY8i7+Iin4kyhV/KV5J2rOKsBQbB77Ab7L/w==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/android-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.24.0.tgz",
-			"integrity": "sha512-t8GrvnFkiIY7pa7mMgJd7p8p8qqYIz1NYiAoKc75Zyv73L3DZW++oYMSHPRarcotTKuSs6m3hTOa5CKHaS02TQ==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/darwin-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.24.0.tgz",
-			"integrity": "sha512-CKyDpRbK1hXwv79soeTJNHb5EiG6ct3efd/FTPdzOWdbZZfGhpbcqIpiD0+vwmpu0wTIL97ZRPZu8vUt46nBSw==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/darwin-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.24.0.tgz",
-			"integrity": "sha512-rgtz6flkVkh58od4PwTRqxbKH9cOjaXCMZgWD905JOzjFKW+7EiUObfd/Kav+A6Gyud6WZk9w+xu6QLytdi2OA==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/freebsd-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.24.0.tgz",
-			"integrity": "sha512-6Mtdq5nHggwfDNLAHkPlyLBpE5L6hwsuXZX8XNmHno9JuL2+bg2BX5tRkwjyfn6sKbxZTq68suOjgWqCicvPXA==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/freebsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.24.0.tgz",
-			"integrity": "sha512-D3H+xh3/zphoX8ck4S2RxKR6gHlHDXXzOf6f/9dbFt/NRBDIE33+cVa49Kil4WUjxMGW0ZIYBYtaGCa2+OsQwQ==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-arm": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.24.0.tgz",
-			"integrity": "sha512-gJKIi2IjRo5G6Glxb8d3DzYXlxdEj2NlkixPsqePSZMhLudqPhtZ4BUrpIuTjJYXxvF9njql+vRjB2oaC9XpBw==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.24.0.tgz",
-			"integrity": "sha512-TDijPXTOeE3eaMkRYpcy3LarIg13dS9wWHRdwYRnzlwlA370rNdZqbcp0WTyyV/k2zSxfko52+C7jU5F9Tfj1g==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-ia32": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.24.0.tgz",
-			"integrity": "sha512-K40ip1LAcA0byL05TbCQ4yJ4swvnbzHscRmUilrmP9Am7//0UjPreh4lpYzvThT2Quw66MhjG//20mrufm40mA==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-loong64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.24.0.tgz",
-			"integrity": "sha512-0mswrYP/9ai+CU0BzBfPMZ8RVm3RGAN/lmOMgW4aFUSOQBjA31UP8Mr6DDhWSuMwj7jaWOT0p0WoZ6jeHhrD7g==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-mips64el": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.24.0.tgz",
-			"integrity": "sha512-hIKvXm0/3w/5+RDtCJeXqMZGkI2s4oMUGj3/jM0QzhgIASWrGO5/RlzAzm5nNh/awHE0A19h/CvHQe6FaBNrRA==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-ppc64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.24.0.tgz",
-			"integrity": "sha512-HcZh5BNq0aC52UoocJxaKORfFODWXZxtBaaZNuN3PUX3MoDsChsZqopzi5UupRhPHSEHotoiptqikjN/B77mYQ==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-riscv64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.24.0.tgz",
-			"integrity": "sha512-bEh7dMn/h3QxeR2KTy1DUszQjUrIHPZKyO6aN1X4BCnhfYhuQqedHaa5MxSQA/06j3GpiIlFGSsy1c7Gf9padw==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-s390x": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.24.0.tgz",
-			"integrity": "sha512-ZcQ6+qRkw1UcZGPyrCiHHkmBaj9SiCD8Oqd556HldP+QlpUIe2Wgn3ehQGVoPOvZvtHm8HPx+bH20c9pvbkX3g==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/linux-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.24.0.tgz",
-			"integrity": "sha512-vbutsFqQ+foy3wSSbmjBXXIJ6PL3scghJoM8zCL142cGaZKAdCZHyf+Bpu/MmX9zT9Q0zFBVKb36Ma5Fzfa8xA==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/netbsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.24.0.tgz",
-			"integrity": "sha512-hjQ0R/ulkO8fCYFsG0FZoH+pWgTTDreqpqY7UnQntnaKv95uP5iW3+dChxnx7C3trQQU40S+OgWhUVwCjVFLvg==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/openbsd-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.24.0.tgz",
-			"integrity": "sha512-MD9uzzkPQbYehwcN583yx3Tu5M8EIoTD+tUgKF982WYL9Pf5rKy9ltgD0eUgs8pvKnmizxjXZyLt0z6DC3rRXg==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/openbsd-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.24.0.tgz",
-			"integrity": "sha512-4ir0aY1NGUhIC1hdoCzr1+5b43mw99uNwVzhIq1OY3QcEwPDO3B7WNXBzaKY5Nsf1+N11i1eOfFcq+D/gOS15Q==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/sunos-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.24.0.tgz",
-			"integrity": "sha512-jVzdzsbM5xrotH+W5f1s+JtUy1UWgjU0Cf4wMvffTB8m6wP5/kx0KiaLHlbJO+dMgtxKV8RQ/JvtlFcdZ1zCPA==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/win32-arm64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.24.0.tgz",
-			"integrity": "sha512-iKc8GAslzRpBytO2/aN3d2yb2z8XTVfNV0PjGlCxKo5SgWmNXx82I/Q3aG1tFfS+A2igVCY97TJ8tnYwpUWLCA==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/win32-ia32": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.24.0.tgz",
-			"integrity": "sha512-vQW36KZolfIudCcTnaTpmLQ24Ha1RjygBo39/aLkM2kmjkWmZGEJ5Gn9l5/7tzXA42QGIoWbICfg6KLLkIw6yw==",
-			"dev": true,
-			"optional": true
-		},
-		"@esbuild/win32-x64": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.24.0.tgz",
-			"integrity": "sha512-7IAFPrjSQIJrGsK6flwg7NFmwBoSTyF3rl7If0hNUFQU4ilTsEPL6GuMuU9BfIWVVGuRnuIidkSMC+c0Otu8IA==",
-			"dev": true,
-			"optional": true
-		},
-		"@eslint-community/eslint-utils": {
-			"version": "4.4.0",
-			"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
-			"integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
-			"dev": true,
-			"requires": {
-				"eslint-visitor-keys": "^3.3.0"
-			}
-		},
-		"@eslint-community/regexpp": {
-			"version": "4.12.1",
-			"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz",
-			"integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==",
-			"dev": true
-		},
-		"@eslint/eslintrc": {
-			"version": "2.1.4",
-			"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
-			"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
-			"dev": true,
-			"requires": {
-				"ajv": "^6.12.4",
-				"debug": "^4.3.2",
-				"espree": "^9.6.0",
-				"globals": "^13.19.0",
-				"ignore": "^5.2.0",
-				"import-fresh": "^3.2.1",
-				"js-yaml": "^4.1.0",
-				"minimatch": "^3.1.2",
-				"strip-json-comments": "^3.1.1"
-			},
-			"dependencies": {
-				"argparse": {
-					"version": "2.0.1",
-					"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-					"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-					"dev": true
-				},
-				"js-yaml": {
-					"version": "4.1.0",
-					"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-					"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-					"dev": true,
-					"requires": {
-						"argparse": "^2.0.1"
-					}
-				}
-			}
-		},
-		"@eslint/js": {
-			"version": "8.57.1",
-			"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz",
-			"integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==",
-			"dev": true
-		},
-		"@humanwhocodes/config-array": {
-			"version": "0.13.0",
-			"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
-			"integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
-			"dev": true,
-			"requires": {
-				"@humanwhocodes/object-schema": "^2.0.3",
-				"debug": "^4.3.1",
-				"minimatch": "^3.0.5"
-			}
-		},
-		"@humanwhocodes/module-importer": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz",
-			"integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==",
-			"dev": true
-		},
-		"@humanwhocodes/object-schema": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
-			"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
-			"dev": true
-		},
-		"@isaacs/cliui": {
-			"version": "8.0.2",
-			"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
-			"integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
-			"dev": true,
-			"requires": {
-				"string-width": "^5.1.2",
-				"string-width-cjs": "npm:string-width@^4.2.0",
-				"strip-ansi": "^7.0.1",
-				"strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
-				"wrap-ansi": "^8.1.0",
-				"wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
-			}
-		},
-		"@nodelib/fs.scandir": {
-			"version": "2.1.5",
-			"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
-			"integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
-			"dev": true,
-			"requires": {
-				"@nodelib/fs.stat": "2.0.5",
-				"run-parallel": "^1.1.9"
-			}
-		},
-		"@nodelib/fs.stat": {
-			"version": "2.0.5",
-			"resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
-			"integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
-			"dev": true
-		},
-		"@nodelib/fs.walk": {
-			"version": "1.2.8",
-			"resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
-			"integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
-			"dev": true,
-			"requires": {
-				"@nodelib/fs.scandir": "2.1.5",
-				"fastq": "^1.6.0"
-			}
-		},
-		"@pkgjs/parseargs": {
-			"version": "0.11.0",
-			"resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
-			"integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
-			"dev": true,
-			"optional": true
-		},
-		"@rtsao/scc": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
-			"integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
-			"dev": true
-		},
-		"@sindresorhus/slugify": {
-			"version": "2.2.1",
-			"resolved": "https://registry.npmjs.org/@sindresorhus/slugify/-/slugify-2.2.1.tgz",
-			"integrity": "sha512-MkngSCRZ8JdSOCHRaYd+D01XhvU3Hjy6MGl06zhOk614hp9EOAp5gIkBeQg7wtmxpitU6eAL4kdiRMcJa2dlrw==",
-			"dev": true,
-			"requires": {
-				"@sindresorhus/transliterate": "^1.0.0",
-				"escape-string-regexp": "^5.0.0"
-			},
-			"dependencies": {
-				"escape-string-regexp": {
-					"version": "5.0.0",
-					"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-					"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
-					"dev": true
-				}
-			}
-		},
-		"@sindresorhus/transliterate": {
-			"version": "1.6.0",
-			"resolved": "https://registry.npmjs.org/@sindresorhus/transliterate/-/transliterate-1.6.0.tgz",
-			"integrity": "sha512-doH1gimEu3A46VX6aVxpHTeHrytJAG6HgdxntYnCFiIFHEM/ZGpG8KiZGBChchjQmG0XFIBL552kBTjVcMZXwQ==",
-			"dev": true,
-			"requires": {
-				"escape-string-regexp": "^5.0.0"
-			},
-			"dependencies": {
-				"escape-string-regexp": {
-					"version": "5.0.0",
-					"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz",
-					"integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==",
-					"dev": true
-				}
-			}
-		},
-		"@types/json5": {
-			"version": "0.0.29",
-			"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
-			"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
-			"dev": true
-		},
-		"@ungap/structured-clone": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
-			"integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==",
-			"dev": true
-		},
-		"a-sync-waterfall": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.1.tgz",
-			"integrity": "sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==",
-			"dev": true
-		},
-		"acorn": {
-			"version": "8.14.0",
-			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
-			"integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==",
-			"dev": true
-		},
-		"acorn-jsx": {
-			"version": "5.3.2",
-			"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
-			"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
-			"dev": true,
-			"requires": {}
-		},
-		"acorn-walk": {
-			"version": "8.3.4",
-			"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
-			"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
-			"dev": true,
-			"requires": {
-				"acorn": "^8.11.0"
-			}
-		},
-		"ajv": {
-			"version": "6.12.6",
-			"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
-			"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
-			"dev": true,
-			"requires": {
-				"fast-deep-equal": "^3.1.1",
-				"fast-json-stable-stringify": "^2.0.0",
-				"json-schema-traverse": "^0.4.1",
-				"uri-js": "^4.2.2"
-			}
-		},
-		"ansi-regex": {
-			"version": "6.1.0",
-			"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
-			"integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
-			"dev": true
-		},
-		"ansi-styles": {
-			"version": "6.2.1",
-			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
-			"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
-			"dev": true
-		},
-		"anymatch": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
-			"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
-			"dev": true,
-			"requires": {
-				"normalize-path": "^3.0.0",
-				"picomatch": "^2.0.4"
-			}
-		},
-		"argparse": {
-			"version": "1.0.10",
-			"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-			"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-			"dev": true,
-			"requires": {
-				"sprintf-js": "~1.0.2"
-			}
-		},
-		"array-buffer-byte-length": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
-			"integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.5",
-				"is-array-buffer": "^3.0.4"
-			}
-		},
-		"array-differ": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
-			"integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==",
-			"dev": true
-		},
-		"array-includes": {
-			"version": "3.1.8",
-			"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
-			"integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2",
-				"es-object-atoms": "^1.0.0",
-				"get-intrinsic": "^1.2.4",
-				"is-string": "^1.0.7"
-			}
-		},
-		"array-union": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
-			"integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
-			"dev": true
-		},
-		"array-uniq": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
-			"integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
-			"dev": true
-		},
-		"array.prototype.findlastindex": {
-			"version": "1.2.5",
-			"resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
-			"integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2",
-				"es-errors": "^1.3.0",
-				"es-object-atoms": "^1.0.0",
-				"es-shim-unscopables": "^1.0.2"
-			}
-		},
-		"array.prototype.flat": {
-			"version": "1.3.2",
-			"resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
-			"integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1",
-				"es-shim-unscopables": "^1.0.0"
-			}
-		},
-		"array.prototype.flatmap": {
-			"version": "1.3.2",
-			"resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
-			"integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1",
-				"es-shim-unscopables": "^1.0.0"
-			}
-		},
-		"arraybuffer.prototype.slice": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
-			"integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
-			"dev": true,
-			"requires": {
-				"array-buffer-byte-length": "^1.0.1",
-				"call-bind": "^1.0.5",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.22.3",
-				"es-errors": "^1.2.1",
-				"get-intrinsic": "^1.2.3",
-				"is-array-buffer": "^3.0.4",
-				"is-shared-array-buffer": "^1.0.2"
-			}
-		},
-		"arrify": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
-			"integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==",
-			"dev": true
-		},
-		"asap": {
-			"version": "2.0.6",
-			"resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
-			"integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=",
-			"dev": true
-		},
-		"async": {
-			"version": "3.2.4",
-			"resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz",
-			"integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==",
-			"dev": true
-		},
-		"available-typed-arrays": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
-			"integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
-			"dev": true,
-			"requires": {
-				"possible-typed-array-names": "^1.0.0"
-			}
-		},
-		"balanced-match": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-			"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
-			"dev": true
-		},
-		"bcp-47": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/bcp-47/-/bcp-47-2.1.0.tgz",
-			"integrity": "sha512-9IIS3UPrvIa1Ej+lVDdDwO7zLehjqsaByECw0bu2RRGP73jALm6FYbzI5gWbgHLvNdkvfXB5YrSbocZdOS0c0w==",
-			"dev": true,
-			"requires": {
-				"is-alphabetical": "^2.0.0",
-				"is-alphanumerical": "^2.0.0",
-				"is-decimal": "^2.0.0"
-			}
-		},
-		"bcp-47-match": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/bcp-47-match/-/bcp-47-match-2.0.3.tgz",
-			"integrity": "sha512-JtTezzbAibu8G0R9op9zb3vcWZd9JF6M0xOYGPn0fNCd7wOpRB1mU2mH9T8gaBGbAAyIIVgB2G7xG0GP98zMAQ==",
-			"dev": true
-		},
-		"bcp-47-normalize": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/bcp-47-normalize/-/bcp-47-normalize-2.3.0.tgz",
-			"integrity": "sha512-8I/wfzqQvttUFz7HVJgIZ7+dj3vUaIyIxYXaTRP1YWoSDfzt6TUmxaKZeuXR62qBmYr+nvuWINFRl6pZ5DlN4Q==",
-			"dev": true,
-			"requires": {
-				"bcp-47": "^2.0.0",
-				"bcp-47-match": "^2.0.0"
-			}
-		},
-		"binary-extensions": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
-			"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
-			"dev": true
-		},
-		"brace-expansion": {
-			"version": "1.1.11",
-			"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-			"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-			"dev": true,
-			"requires": {
-				"balanced-match": "^1.0.0",
-				"concat-map": "0.0.1"
-			}
-		},
-		"braces": {
-			"version": "3.0.3",
-			"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
-			"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
-			"dev": true,
-			"requires": {
-				"fill-range": "^7.1.1"
-			}
-		},
-		"call-bind": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
-			"integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
-			"dev": true,
-			"requires": {
-				"es-define-property": "^1.0.0",
-				"es-errors": "^1.3.0",
-				"function-bind": "^1.1.2",
-				"get-intrinsic": "^1.2.4",
-				"set-function-length": "^1.2.1"
-			}
-		},
-		"callsites": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
-			"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
-			"dev": true
-		},
-		"chalk": {
-			"version": "4.1.1",
-			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
-			"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
-			"dev": true,
-			"requires": {
-				"ansi-styles": "^4.1.0",
-				"supports-color": "^7.1.0"
-			},
-			"dependencies": {
-				"ansi-styles": {
-					"version": "4.3.0",
-					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-					"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-					"dev": true,
-					"requires": {
-						"color-convert": "^2.0.1"
-					}
-				},
-				"supports-color": {
-					"version": "7.2.0",
-					"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
-					"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
-					"dev": true,
-					"requires": {
-						"has-flag": "^4.0.0"
-					}
-				}
-			}
-		},
-		"chardet": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/chardet/-/chardet-2.0.0.tgz",
-			"integrity": "sha512-xVgPpulCooDjY6zH4m9YW3jbkaBe3FKIAvF5sj5t7aBNsVl2ljIE+xwJ4iNgiDZHFQvNIpjdKdVOQvvk5ZfxbQ==",
-			"dev": true
-		},
-		"chokidar": {
-			"version": "3.6.0",
-			"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
-			"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
-			"dev": true,
-			"requires": {
-				"anymatch": "~3.1.2",
-				"braces": "~3.0.2",
-				"fsevents": "~2.3.2",
-				"glob-parent": "~5.1.2",
-				"is-binary-path": "~2.1.0",
-				"is-glob": "~4.0.1",
-				"normalize-path": "~3.0.0",
-				"readdirp": "~3.6.0"
-			}
-		},
-		"color-convert": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
-			"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
-			"dev": true,
-			"requires": {
-				"color-name": "~1.1.4"
-			}
-		},
-		"color-name": {
-			"version": "1.1.4",
-			"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-			"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
-			"dev": true
-		},
-		"commander": {
-			"version": "11.1.0",
-			"resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz",
-			"integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==",
-			"dev": true
-		},
-		"commondir": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-			"integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
-			"dev": true
-		},
-		"concat-map": {
-			"version": "0.0.1",
-			"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-			"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
-			"dev": true
-		},
-		"cross-spawn": {
-			"version": "7.0.6",
-			"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
-			"integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==",
-			"dev": true,
-			"requires": {
-				"path-key": "^3.1.0",
-				"shebang-command": "^2.0.0",
-				"which": "^2.0.1"
-			}
-		},
-		"data-view-buffer": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
-			"integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.6",
-				"es-errors": "^1.3.0",
-				"is-data-view": "^1.0.1"
-			}
-		},
-		"data-view-byte-length": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
-			"integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"es-errors": "^1.3.0",
-				"is-data-view": "^1.0.1"
-			}
-		},
-		"data-view-byte-offset": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
-			"integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.6",
-				"es-errors": "^1.3.0",
-				"is-data-view": "^1.0.1"
-			}
-		},
-		"debug": {
-			"version": "4.3.7",
-			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz",
-			"integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==",
-			"dev": true,
-			"requires": {
-				"ms": "^2.1.3"
-			}
-		},
-		"deep-is": {
-			"version": "0.1.4",
-			"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
-			"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==",
-			"dev": true
-		},
-		"define-data-property": {
-			"version": "1.1.4",
-			"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
-			"integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
-			"dev": true,
-			"requires": {
-				"es-define-property": "^1.0.0",
-				"es-errors": "^1.3.0",
-				"gopd": "^1.0.1"
-			}
-		},
-		"define-properties": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
-			"integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
-			"dev": true,
-			"requires": {
-				"define-data-property": "^1.0.1",
-				"has-property-descriptors": "^1.0.0",
-				"object-keys": "^1.1.1"
-			}
-		},
-		"depd": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
-			"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
-			"dev": true
-		},
-		"dependency-graph": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-1.0.0.tgz",
-			"integrity": "sha512-cW3gggJ28HZ/LExwxP2B++aiKxhJXMSIt9K48FOXQkm+vuG5gyatXnLsONRJdzO/7VfjDIiaOOa/bs4l464Lwg==",
-			"dev": true
-		},
-		"destroy": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
-			"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
-			"dev": true
-		},
-		"dev-ip": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz",
-			"integrity": "sha512-LmVkry/oDShEgSZPNgqCIp2/TlqtExeGmymru3uCELnfyjY11IzpAproLYs+1X88fXO6DBoYP3ul2Xo2yz2j6A==",
-			"dev": true
-		},
-		"dir-glob": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
-			"integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
-			"dev": true,
-			"requires": {
-				"path-type": "^4.0.0"
-			}
-		},
-		"doctrine": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
-			"integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
-			"dev": true,
-			"requires": {
-				"esutils": "^2.0.2"
-			}
-		},
-		"domelementtype": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz",
-			"integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==",
-			"dev": true
-		},
-		"eastasianwidth": {
-			"version": "0.2.0",
-			"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
-			"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
-			"dev": true
-		},
-		"ee-first": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-			"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==",
-			"dev": true
-		},
-		"email-addresses": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz",
-			"integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==",
-			"dev": true
-		},
-		"emoji-regex": {
-			"version": "9.2.2",
-			"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
-			"integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
-			"dev": true
-		},
-		"encodeurl": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
-			"integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
-			"dev": true
-		},
-		"entities": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/entities/-/entities-5.0.0.tgz",
-			"integrity": "sha512-BeJFvFRJddxobhvEdm5GqHzRV/X+ACeuw0/BuuxsCh1EUZcAIz8+kYmBp/LrQuloy6K1f3a0M7+IhmZ7QnkISA==",
-			"dev": true
-		},
-		"errno": {
-			"version": "0.1.8",
-			"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz",
-			"integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==",
-			"dev": true,
-			"requires": {
-				"prr": "~1.0.1"
-			}
-		},
-		"es-abstract": {
-			"version": "1.23.5",
-			"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz",
-			"integrity": "sha512-vlmniQ0WNPwXqA0BnmwV3Ng7HxiGlh6r5U6JcTMNx8OilcAGqVJBHJcPjqOMaczU9fRuRK5Px2BdVyPRnKMMVQ==",
-			"dev": true,
-			"requires": {
-				"array-buffer-byte-length": "^1.0.1",
-				"arraybuffer.prototype.slice": "^1.0.3",
-				"available-typed-arrays": "^1.0.7",
-				"call-bind": "^1.0.7",
-				"data-view-buffer": "^1.0.1",
-				"data-view-byte-length": "^1.0.1",
-				"data-view-byte-offset": "^1.0.0",
-				"es-define-property": "^1.0.0",
-				"es-errors": "^1.3.0",
-				"es-object-atoms": "^1.0.0",
-				"es-set-tostringtag": "^2.0.3",
-				"es-to-primitive": "^1.2.1",
-				"function.prototype.name": "^1.1.6",
-				"get-intrinsic": "^1.2.4",
-				"get-symbol-description": "^1.0.2",
-				"globalthis": "^1.0.4",
-				"gopd": "^1.0.1",
-				"has-property-descriptors": "^1.0.2",
-				"has-proto": "^1.0.3",
-				"has-symbols": "^1.0.3",
-				"hasown": "^2.0.2",
-				"internal-slot": "^1.0.7",
-				"is-array-buffer": "^3.0.4",
-				"is-callable": "^1.2.7",
-				"is-data-view": "^1.0.1",
-				"is-negative-zero": "^2.0.3",
-				"is-regex": "^1.1.4",
-				"is-shared-array-buffer": "^1.0.3",
-				"is-string": "^1.0.7",
-				"is-typed-array": "^1.1.13",
-				"is-weakref": "^1.0.2",
-				"object-inspect": "^1.13.3",
-				"object-keys": "^1.1.1",
-				"object.assign": "^4.1.5",
-				"regexp.prototype.flags": "^1.5.3",
-				"safe-array-concat": "^1.1.2",
-				"safe-regex-test": "^1.0.3",
-				"string.prototype.trim": "^1.2.9",
-				"string.prototype.trimend": "^1.0.8",
-				"string.prototype.trimstart": "^1.0.8",
-				"typed-array-buffer": "^1.0.2",
-				"typed-array-byte-length": "^1.0.1",
-				"typed-array-byte-offset": "^1.0.2",
-				"typed-array-length": "^1.0.6",
-				"unbox-primitive": "^1.0.2",
-				"which-typed-array": "^1.1.15"
-			}
-		},
-		"es-define-property": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
-			"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
-			"dev": true,
-			"requires": {
-				"get-intrinsic": "^1.2.4"
-			}
-		},
-		"es-errors": {
-			"version": "1.3.0",
-			"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
-			"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
-			"dev": true
-		},
-		"es-object-atoms": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
-			"integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
-			"dev": true,
-			"requires": {
-				"es-errors": "^1.3.0"
-			}
-		},
-		"es-set-tostringtag": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
-			"integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
-			"dev": true,
-			"requires": {
-				"get-intrinsic": "^1.2.4",
-				"has-tostringtag": "^1.0.2",
-				"hasown": "^2.0.1"
-			}
-		},
-		"es-shim-unscopables": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
-			"integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
-			"dev": true,
-			"requires": {
-				"hasown": "^2.0.0"
-			}
-		},
-		"es-to-primitive": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
-			"integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
-			"dev": true,
-			"requires": {
-				"is-callable": "^1.1.4",
-				"is-date-object": "^1.0.1",
-				"is-symbol": "^1.0.2"
-			}
-		},
-		"esbuild": {
-			"version": "0.24.0",
-			"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.24.0.tgz",
-			"integrity": "sha512-FuLPevChGDshgSicjisSooU0cemp/sGXR841D5LHMB7mTVOmsEHcAxaH3irL53+8YDIeVNQEySh4DaYU/iuPqQ==",
-			"dev": true,
-			"requires": {
-				"@esbuild/aix-ppc64": "0.24.0",
-				"@esbuild/android-arm": "0.24.0",
-				"@esbuild/android-arm64": "0.24.0",
-				"@esbuild/android-x64": "0.24.0",
-				"@esbuild/darwin-arm64": "0.24.0",
-				"@esbuild/darwin-x64": "0.24.0",
-				"@esbuild/freebsd-arm64": "0.24.0",
-				"@esbuild/freebsd-x64": "0.24.0",
-				"@esbuild/linux-arm": "0.24.0",
-				"@esbuild/linux-arm64": "0.24.0",
-				"@esbuild/linux-ia32": "0.24.0",
-				"@esbuild/linux-loong64": "0.24.0",
-				"@esbuild/linux-mips64el": "0.24.0",
-				"@esbuild/linux-ppc64": "0.24.0",
-				"@esbuild/linux-riscv64": "0.24.0",
-				"@esbuild/linux-s390x": "0.24.0",
-				"@esbuild/linux-x64": "0.24.0",
-				"@esbuild/netbsd-x64": "0.24.0",
-				"@esbuild/openbsd-arm64": "0.24.0",
-				"@esbuild/openbsd-x64": "0.24.0",
-				"@esbuild/sunos-x64": "0.24.0",
-				"@esbuild/win32-arm64": "0.24.0",
-				"@esbuild/win32-ia32": "0.24.0",
-				"@esbuild/win32-x64": "0.24.0"
-			}
-		},
-		"escape-html": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-			"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
-			"dev": true
-		},
-		"escape-string-regexp": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-			"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
-			"dev": true
-		},
-		"eslint": {
-			"version": "8.57.1",
-			"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz",
-			"integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==",
-			"dev": true,
-			"requires": {
-				"@eslint-community/eslint-utils": "^4.2.0",
-				"@eslint-community/regexpp": "^4.6.1",
-				"@eslint/eslintrc": "^2.1.4",
-				"@eslint/js": "8.57.1",
-				"@humanwhocodes/config-array": "^0.13.0",
-				"@humanwhocodes/module-importer": "^1.0.1",
-				"@nodelib/fs.walk": "^1.2.8",
-				"@ungap/structured-clone": "^1.2.0",
-				"ajv": "^6.12.4",
-				"chalk": "^4.0.0",
-				"cross-spawn": "^7.0.2",
-				"debug": "^4.3.2",
-				"doctrine": "^3.0.0",
-				"escape-string-regexp": "^4.0.0",
-				"eslint-scope": "^7.2.2",
-				"eslint-visitor-keys": "^3.4.3",
-				"espree": "^9.6.1",
-				"esquery": "^1.4.2",
-				"esutils": "^2.0.2",
-				"fast-deep-equal": "^3.1.3",
-				"file-entry-cache": "^6.0.1",
-				"find-up": "^5.0.0",
-				"glob-parent": "^6.0.2",
-				"globals": "^13.19.0",
-				"graphemer": "^1.4.0",
-				"ignore": "^5.2.0",
-				"imurmurhash": "^0.1.4",
-				"is-glob": "^4.0.0",
-				"is-path-inside": "^3.0.3",
-				"js-yaml": "^4.1.0",
-				"json-stable-stringify-without-jsonify": "^1.0.1",
-				"levn": "^0.4.1",
-				"lodash.merge": "^4.6.2",
-				"minimatch": "^3.1.2",
-				"natural-compare": "^1.4.0",
-				"optionator": "^0.9.3",
-				"strip-ansi": "^6.0.1",
-				"text-table": "^0.2.0"
-			},
-			"dependencies": {
-				"ansi-regex": {
-					"version": "5.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-					"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-					"dev": true
-				},
-				"argparse": {
-					"version": "2.0.1",
-					"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-					"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-					"dev": true
-				},
-				"escape-string-regexp": {
-					"version": "4.0.0",
-					"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
-					"integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==",
-					"dev": true
-				},
-				"glob-parent": {
-					"version": "6.0.2",
-					"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
-					"integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
-					"dev": true,
-					"requires": {
-						"is-glob": "^4.0.3"
-					}
-				},
-				"js-yaml": {
-					"version": "4.1.0",
-					"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz",
-					"integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==",
-					"dev": true,
-					"requires": {
-						"argparse": "^2.0.1"
-					}
-				},
-				"strip-ansi": {
-					"version": "6.0.1",
-					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-					"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-					"dev": true,
-					"requires": {
-						"ansi-regex": "^5.0.1"
-					}
-				}
-			}
-		},
-		"eslint-import-resolver-node": {
-			"version": "0.3.9",
-			"resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz",
-			"integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==",
-			"dev": true,
-			"requires": {
-				"debug": "^3.2.7",
-				"is-core-module": "^2.13.0",
-				"resolve": "^1.22.4"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "3.2.7",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-					"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-					"dev": true,
-					"requires": {
-						"ms": "^2.1.1"
-					}
-				},
-				"resolve": {
-					"version": "1.22.8",
-					"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
-					"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
-					"dev": true,
-					"requires": {
-						"is-core-module": "^2.13.0",
-						"path-parse": "^1.0.7",
-						"supports-preserve-symlinks-flag": "^1.0.0"
-					}
-				}
-			}
-		},
-		"eslint-module-utils": {
-			"version": "2.12.0",
-			"resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz",
-			"integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==",
-			"dev": true,
-			"requires": {
-				"debug": "^3.2.7"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "3.2.7",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-					"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-					"dev": true,
-					"requires": {
-						"ms": "^2.1.1"
-					}
-				}
-			}
-		},
-		"eslint-plugin-import": {
-			"version": "2.31.0",
-			"resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz",
-			"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
-			"dev": true,
-			"requires": {
-				"@rtsao/scc": "^1.1.0",
-				"array-includes": "^3.1.8",
-				"array.prototype.findlastindex": "^1.2.5",
-				"array.prototype.flat": "^1.3.2",
-				"array.prototype.flatmap": "^1.3.2",
-				"debug": "^3.2.7",
-				"doctrine": "^2.1.0",
-				"eslint-import-resolver-node": "^0.3.9",
-				"eslint-module-utils": "^2.12.0",
-				"hasown": "^2.0.2",
-				"is-core-module": "^2.15.1",
-				"is-glob": "^4.0.3",
-				"minimatch": "^3.1.2",
-				"object.fromentries": "^2.0.8",
-				"object.groupby": "^1.0.3",
-				"object.values": "^1.2.0",
-				"semver": "^6.3.1",
-				"string.prototype.trimend": "^1.0.8",
-				"tsconfig-paths": "^3.15.0"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "3.2.7",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
-					"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
-					"dev": true,
-					"requires": {
-						"ms": "^2.1.1"
-					}
-				},
-				"doctrine": {
-					"version": "2.1.0",
-					"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
-					"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
-					"dev": true,
-					"requires": {
-						"esutils": "^2.0.2"
-					}
-				},
-				"semver": {
-					"version": "6.3.1",
-					"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-					"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-					"dev": true
-				}
-			}
-		},
-		"eslint-scope": {
-			"version": "7.2.2",
-			"resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
-			"integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
-			"dev": true,
-			"requires": {
-				"esrecurse": "^4.3.0",
-				"estraverse": "^5.2.0"
-			}
-		},
-		"eslint-visitor-keys": {
-			"version": "3.4.3",
-			"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
-			"integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
-			"dev": true
-		},
-		"esm-import-transformer": {
-			"version": "3.0.2",
-			"resolved": "https://registry.npmjs.org/esm-import-transformer/-/esm-import-transformer-3.0.2.tgz",
-			"integrity": "sha512-PgvO0wro44lTDM9pYeeOIfpS0lGF80jA+rjT7sBd3b07rxv1AxeNMEI5kSCqRKke2W6SPEz17W3kHOLjaiD7Cw==",
-			"dev": true,
-			"requires": {
-				"acorn": "^8.11.2"
-			}
-		},
-		"espree": {
-			"version": "9.6.1",
-			"resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
-			"integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
-			"dev": true,
-			"requires": {
-				"acorn": "^8.9.0",
-				"acorn-jsx": "^5.3.2",
-				"eslint-visitor-keys": "^3.4.1"
-			}
-		},
-		"esprima": {
-			"version": "4.0.1",
-			"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
-			"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
-			"dev": true
-		},
-		"esquery": {
-			"version": "1.5.0",
-			"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz",
-			"integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==",
-			"dev": true,
-			"requires": {
-				"estraverse": "^5.1.0"
-			}
-		},
-		"esrecurse": {
-			"version": "4.3.0",
-			"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz",
-			"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
-			"dev": true,
-			"requires": {
-				"estraverse": "^5.2.0"
-			}
-		},
-		"estraverse": {
-			"version": "5.3.0",
-			"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
-			"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
-			"dev": true
-		},
-		"esutils": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
-			"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
-			"dev": true
-		},
-		"etag": {
-			"version": "1.8.1",
-			"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-			"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
-			"dev": true
-		},
-		"evaluate-value": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/evaluate-value/-/evaluate-value-2.0.0.tgz",
-			"integrity": "sha512-VonfiuDJc0z4sOO7W0Pd130VLsXN6vmBWZlrog1mCb/o7o/Nl5Lr25+Kj/nkCCAhG+zqeeGjxhkK9oHpkgTHhQ==",
-			"dev": true
-		},
-		"execa": {
-			"version": "5.1.1",
-			"resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz",
-			"integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==",
-			"dev": true,
-			"requires": {
-				"cross-spawn": "^7.0.3",
-				"get-stream": "^6.0.0",
-				"human-signals": "^2.1.0",
-				"is-stream": "^2.0.0",
-				"merge-stream": "^2.0.0",
-				"npm-run-path": "^4.0.1",
-				"onetime": "^5.1.2",
-				"signal-exit": "^3.0.3",
-				"strip-final-newline": "^2.0.0"
-			}
-		},
-		"extend-shallow": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-			"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-			"dev": true,
-			"requires": {
-				"is-extendable": "^0.1.0"
-			}
-		},
-		"fast-deep-equal": {
-			"version": "3.1.3",
-			"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
-			"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==",
-			"dev": true
-		},
-		"fast-glob": {
-			"version": "3.3.2",
-			"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
-			"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
-			"dev": true,
-			"requires": {
-				"@nodelib/fs.stat": "^2.0.2",
-				"@nodelib/fs.walk": "^1.2.3",
-				"glob-parent": "^5.1.2",
-				"merge2": "^1.3.0",
-				"micromatch": "^4.0.4"
-			}
-		},
-		"fast-json-stable-stringify": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
-			"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==",
-			"dev": true
-		},
-		"fast-levenshtein": {
-			"version": "2.0.6",
-			"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-			"integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==",
-			"dev": true
-		},
-		"fastq": {
-			"version": "1.17.1",
-			"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
-			"integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
-			"dev": true,
-			"requires": {
-				"reusify": "^1.0.4"
-			}
-		},
-		"file-entry-cache": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
-			"integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
-			"dev": true,
-			"requires": {
-				"flat-cache": "^3.0.4"
-			}
-		},
-		"filename-reserved-regex": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz",
-			"integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=",
-			"dev": true
-		},
-		"filenamify": {
-			"version": "4.3.0",
-			"resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz",
-			"integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==",
-			"dev": true,
-			"requires": {
-				"filename-reserved-regex": "^2.0.0",
-				"strip-outer": "^1.0.1",
-				"trim-repeated": "^1.0.0"
-			}
-		},
-		"filesize": {
-			"version": "10.1.6",
-			"resolved": "https://registry.npmjs.org/filesize/-/filesize-10.1.6.tgz",
-			"integrity": "sha512-sJslQKU2uM33qH5nqewAwVB2QgR6w1aMNsYUp3aN5rMRyXEwJGmZvaWzeJFNTOXWlHQyBFCWrdj3fV/fsTOX8w==",
-			"dev": true
-		},
-		"fill-range": {
-			"version": "7.1.1",
-			"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
-			"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
-			"dev": true,
-			"requires": {
-				"to-regex-range": "^5.0.1"
-			}
-		},
-		"finalhandler": {
-			"version": "1.3.1",
-			"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
-			"integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
-			"dev": true,
-			"requires": {
-				"debug": "2.6.9",
-				"encodeurl": "~2.0.0",
-				"escape-html": "~1.0.3",
-				"on-finished": "2.4.1",
-				"parseurl": "~1.3.3",
-				"statuses": "2.0.1",
-				"unpipe": "~1.0.0"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "2.6.9",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-					"dev": true,
-					"requires": {
-						"ms": "2.0.0"
-					}
-				},
-				"ms": {
-					"version": "2.0.0",
-					"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-					"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-					"dev": true
-				}
-			}
-		},
-		"find-cache-dir": {
-			"version": "3.3.1",
-			"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
-			"integrity": "sha512-t2GDMt3oGC/v+BMwzmllWDuJF/xcDtE5j/fCGbqDD7OLuJkj0cfh1YSA5VKPvwMeLFLNDBkwOKZ2X85jGLVftQ==",
-			"dev": true,
-			"requires": {
-				"commondir": "^1.0.1",
-				"make-dir": "^3.0.2",
-				"pkg-dir": "^4.1.0"
-			}
-		},
-		"find-up": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz",
-			"integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==",
-			"dev": true,
-			"requires": {
-				"locate-path": "^6.0.0",
-				"path-exists": "^4.0.0"
-			}
-		},
-		"flat-cache": {
-			"version": "3.2.0",
-			"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
-			"integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
-			"dev": true,
-			"requires": {
-				"flatted": "^3.2.9",
-				"keyv": "^4.5.3",
-				"rimraf": "^3.0.2"
-			},
-			"dependencies": {
-				"glob": {
-					"version": "7.2.3",
-					"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
-					"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
-					"dev": true,
-					"requires": {
-						"fs.realpath": "^1.0.0",
-						"inflight": "^1.0.4",
-						"inherits": "2",
-						"minimatch": "^3.1.1",
-						"once": "^1.3.0",
-						"path-is-absolute": "^1.0.0"
-					}
-				},
-				"rimraf": {
-					"version": "3.0.2",
-					"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
-					"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
-					"dev": true,
-					"requires": {
-						"glob": "^7.1.3"
-					}
-				}
-			}
-		},
-		"flatted": {
-			"version": "3.3.2",
-			"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz",
-			"integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==",
-			"dev": true
-		},
-		"for-each": {
-			"version": "0.3.3",
-			"resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
-			"integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
-			"dev": true,
-			"requires": {
-				"is-callable": "^1.1.3"
-			}
-		},
-		"foreground-child": {
-			"version": "3.3.0",
-			"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
-			"integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==",
-			"dev": true,
-			"requires": {
-				"cross-spawn": "^7.0.0",
-				"signal-exit": "^4.0.1"
-			},
-			"dependencies": {
-				"signal-exit": {
-					"version": "4.1.0",
-					"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
-					"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
-					"dev": true
-				}
-			}
-		},
-		"fresh": {
-			"version": "0.5.2",
-			"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-			"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
-			"dev": true
-		},
-		"fs-extra": {
-			"version": "11.2.0",
-			"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz",
-			"integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==",
-			"dev": true,
-			"requires": {
-				"graceful-fs": "^4.2.0",
-				"jsonfile": "^6.0.1",
-				"universalify": "^2.0.0"
-			}
-		},
-		"fs.realpath": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-			"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
-			"dev": true
-		},
-		"fsevents": {
-			"version": "2.3.2",
-			"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
-			"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
-			"dev": true,
-			"optional": true
-		},
-		"function-bind": {
-			"version": "1.1.2",
-			"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
-			"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
-			"dev": true
-		},
-		"function.prototype.name": {
-			"version": "1.1.6",
-			"resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
-			"integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2",
-				"define-properties": "^1.2.0",
-				"es-abstract": "^1.22.1",
-				"functions-have-names": "^1.2.3"
-			}
-		},
-		"functions-have-names": {
-			"version": "1.2.3",
-			"resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
-			"integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
-			"dev": true
-		},
-		"get-intrinsic": {
-			"version": "1.2.4",
-			"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
-			"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
-			"dev": true,
-			"requires": {
-				"es-errors": "^1.3.0",
-				"function-bind": "^1.1.2",
-				"has-proto": "^1.0.1",
-				"has-symbols": "^1.0.3",
-				"hasown": "^2.0.0"
-			}
-		},
-		"get-stream": {
-			"version": "6.0.1",
-			"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
-			"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
-			"dev": true
-		},
-		"get-symbol-description": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
-			"integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.5",
-				"es-errors": "^1.3.0",
-				"get-intrinsic": "^1.2.4"
-			}
-		},
-		"gh-pages": {
-			"version": "6.2.0",
-			"resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.2.0.tgz",
-			"integrity": "sha512-HMXJ8th9u5wRXaZCnLcs/d3oVvCHiZkaP5KQExQljYGwJjQbSPyTdHe/Gc1IvYUR/rWiZLxNobIqfoMHKTKjHQ==",
-			"dev": true,
-			"requires": {
-				"async": "^3.2.4",
-				"commander": "^11.0.0",
-				"email-addresses": "^5.0.0",
-				"filenamify": "^4.3.0",
-				"find-cache-dir": "^3.3.1",
-				"fs-extra": "^11.1.1",
-				"globby": "^11.1.0"
-			}
-		},
-		"glob": {
-			"version": "10.4.5",
-			"resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
-			"integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
-			"dev": true,
-			"requires": {
-				"foreground-child": "^3.1.0",
-				"jackspeak": "^3.1.2",
-				"minimatch": "^9.0.4",
-				"minipass": "^7.1.2",
-				"package-json-from-dist": "^1.0.0",
-				"path-scurry": "^1.11.1"
-			},
-			"dependencies": {
-				"brace-expansion": {
-					"version": "2.0.1",
-					"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
-					"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
-					"dev": true,
-					"requires": {
-						"balanced-match": "^1.0.0"
-					}
-				},
-				"minimatch": {
-					"version": "9.0.5",
-					"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
-					"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
-					"dev": true,
-					"requires": {
-						"brace-expansion": "^2.0.1"
-					}
-				}
-			}
-		},
-		"glob-parent": {
-			"version": "5.1.2",
-			"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
-			"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
-			"dev": true,
-			"requires": {
-				"is-glob": "^4.0.1"
-			}
-		},
-		"globals": {
-			"version": "13.24.0",
-			"resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
-			"integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
-			"dev": true,
-			"requires": {
-				"type-fest": "^0.20.2"
-			}
-		},
-		"globalthis": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz",
-			"integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==",
-			"dev": true,
-			"requires": {
-				"define-properties": "^1.2.1",
-				"gopd": "^1.0.1"
-			}
-		},
-		"globby": {
-			"version": "11.1.0",
-			"resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
-			"integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
-			"dev": true,
-			"requires": {
-				"array-union": "^2.1.0",
-				"dir-glob": "^3.0.1",
-				"fast-glob": "^3.2.9",
-				"ignore": "^5.2.0",
-				"merge2": "^1.4.1",
-				"slash": "^3.0.0"
-			},
-			"dependencies": {
-				"slash": {
-					"version": "3.0.0",
-					"resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
-					"integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
-					"dev": true
-				}
-			}
-		},
-		"gopd": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
-			"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
-			"dev": true,
-			"requires": {
-				"get-intrinsic": "^1.1.3"
-			}
-		},
-		"graceful-fs": {
-			"version": "4.2.11",
-			"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
-			"integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
-			"dev": true
-		},
-		"graphemer": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
-			"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
-			"dev": true
-		},
-		"gray-matter": {
-			"version": "4.0.3",
-			"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
-			"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
-			"dev": true,
-			"requires": {
-				"js-yaml": "^3.13.1",
-				"kind-of": "^6.0.2",
-				"section-matter": "^1.0.0",
-				"strip-bom-string": "^1.0.0"
-			}
-		},
-		"has-bigints": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
-			"integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
-			"dev": true
-		},
-		"has-flag": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
-			"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
-			"dev": true
-		},
-		"has-property-descriptors": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
-			"integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
-			"dev": true,
-			"requires": {
-				"es-define-property": "^1.0.0"
-			}
-		},
-		"has-proto": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
-			"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
-			"dev": true
-		},
-		"has-symbols": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
-			"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
-			"dev": true
-		},
-		"has-tostringtag": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
-			"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
-			"dev": true,
-			"requires": {
-				"has-symbols": "^1.0.3"
-			}
-		},
-		"hasown": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
-			"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-			"dev": true,
-			"requires": {
-				"function-bind": "^1.1.2"
-			}
-		},
-		"http-equiv-refresh": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/http-equiv-refresh/-/http-equiv-refresh-2.0.1.tgz",
-			"integrity": "sha512-XJpDL/MLkV3dKwLzHwr2dY05dYNfBNlyPu4STQ8WvKCFdc6vC5tPXuq28of663+gHVg03C+16pHHs/+FmmDjcw==",
-			"dev": true
-		},
-		"http-errors": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
-			"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
-			"dev": true,
-			"requires": {
-				"depd": "2.0.0",
-				"inherits": "2.0.4",
-				"setprototypeof": "1.2.0",
-				"statuses": "2.0.1",
-				"toidentifier": "1.0.1"
-			}
-		},
-		"human-signals": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
-			"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
-			"dev": true
-		},
-		"ignore": {
-			"version": "5.3.0",
-			"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
-			"integrity": "sha512-g7dmpshy+gD7mh88OC9NwSGTKoc3kyLAZQRU1mt53Aw/vnvfXnbC+F/7F7QoYVKbV+KNvJx8wArewKy1vXMtlg==",
-			"dev": true
-		},
-		"import-fresh": {
-			"version": "3.3.0",
-			"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
-			"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
-			"dev": true,
-			"requires": {
-				"parent-module": "^1.0.0",
-				"resolve-from": "^4.0.0"
-			}
-		},
-		"imurmurhash": {
-			"version": "0.1.4",
-			"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-			"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
-			"dev": true
-		},
-		"inflight": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-			"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
-			"dev": true,
-			"requires": {
-				"once": "^1.3.0",
-				"wrappy": "1"
-			}
-		},
-		"inherits": {
-			"version": "2.0.4",
-			"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-			"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
-			"dev": true
-		},
-		"internal-slot": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
-			"integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
-			"dev": true,
-			"requires": {
-				"es-errors": "^1.3.0",
-				"hasown": "^2.0.0",
-				"side-channel": "^1.0.4"
-			}
-		},
-		"is-alphabetical": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
-			"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
-			"dev": true
-		},
-		"is-alphanumerical": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
-			"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
-			"dev": true,
-			"requires": {
-				"is-alphabetical": "^2.0.0",
-				"is-decimal": "^2.0.0"
-			}
-		},
-		"is-array-buffer": {
-			"version": "3.0.4",
-			"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
-			"integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2",
-				"get-intrinsic": "^1.2.1"
-			}
-		},
-		"is-async-function": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
-			"integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
-			"dev": true,
-			"requires": {
-				"has-tostringtag": "^1.0.0"
-			}
-		},
-		"is-bigint": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
-			"integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
-			"dev": true,
-			"requires": {
-				"has-bigints": "^1.0.1"
-			}
-		},
-		"is-binary-path": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
-			"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
-			"dev": true,
-			"requires": {
-				"binary-extensions": "^2.0.0"
-			}
-		},
-		"is-boolean-object": {
-			"version": "1.1.2",
-			"resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
-			"integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2",
-				"has-tostringtag": "^1.0.0"
-			}
-		},
-		"is-callable": {
-			"version": "1.2.7",
-			"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
-			"integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
-			"dev": true
-		},
-		"is-core-module": {
-			"version": "2.15.1",
-			"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
-			"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
-			"dev": true,
-			"requires": {
-				"hasown": "^2.0.2"
-			}
-		},
-		"is-data-view": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
-			"integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
-			"dev": true,
-			"requires": {
-				"is-typed-array": "^1.1.13"
-			}
-		},
-		"is-date-object": {
-			"version": "1.0.5",
-			"resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
-			"integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
-			"dev": true,
-			"requires": {
-				"has-tostringtag": "^1.0.0"
-			}
-		},
-		"is-decimal": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
-			"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
-			"dev": true
-		},
-		"is-extendable": {
-			"version": "0.1.1",
-			"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
-			"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
-			"dev": true
-		},
-		"is-extglob": {
-			"version": "2.1.1",
-			"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-			"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-			"dev": true
-		},
-		"is-finalizationregistry": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.0.tgz",
-			"integrity": "sha512-qfMdqbAQEwBw78ZyReKnlA8ezmPdb9BemzIIip/JkjaZUhitfXDkkr+3QTboW0JrSXT1QWyYShpvnNHGZ4c4yA==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7"
-			}
-		},
-		"is-fullwidth-code-point": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
-			"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
-			"dev": true
-		},
-		"is-generator-function": {
-			"version": "1.0.10",
-			"resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
-			"integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
-			"dev": true,
-			"requires": {
-				"has-tostringtag": "^1.0.0"
-			}
-		},
-		"is-glob": {
-			"version": "4.0.3",
-			"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
-			"integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
-			"dev": true,
-			"requires": {
-				"is-extglob": "^2.1.1"
-			}
-		},
-		"is-json": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-json/-/is-json-2.0.1.tgz",
-			"integrity": "sha512-6BEnpVn1rcf3ngfmViLM6vjUjGErbdrL4rwlv+u1NO1XO8kqT4YGL8+19Q+Z/bas8tY90BTWMk2+fW1g6hQjbA==",
-			"dev": true
-		},
-		"is-map": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
-			"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
-			"dev": true
-		},
-		"is-negative-zero": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz",
-			"integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==",
-			"dev": true
-		},
-		"is-number": {
-			"version": "7.0.0",
-			"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
-			"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
-			"dev": true
-		},
-		"is-number-object": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
-			"integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
-			"dev": true,
-			"requires": {
-				"has-tostringtag": "^1.0.0"
-			}
-		},
-		"is-path-inside": {
-			"version": "3.0.3",
-			"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
-			"integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
-			"dev": true
-		},
-		"is-regex": {
-			"version": "1.1.4",
-			"resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
-			"integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2",
-				"has-tostringtag": "^1.0.0"
-			}
-		},
-		"is-set": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
-			"integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
-			"dev": true
-		},
-		"is-shared-array-buffer": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
-			"integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7"
-			}
-		},
-		"is-stream": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
-			"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
-			"dev": true
-		},
-		"is-string": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
-			"integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
-			"dev": true,
-			"requires": {
-				"has-tostringtag": "^1.0.0"
-			}
-		},
-		"is-symbol": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
-			"integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
-			"dev": true,
-			"requires": {
-				"has-symbols": "^1.0.2"
-			}
-		},
-		"is-typed-array": {
-			"version": "1.1.13",
-			"resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
-			"integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
-			"dev": true,
-			"requires": {
-				"which-typed-array": "^1.1.14"
-			}
-		},
-		"is-weakmap": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
-			"integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
-			"dev": true
-		},
-		"is-weakref": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
-			"integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2"
-			}
-		},
-		"is-weakset": {
-			"version": "2.0.3",
-			"resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
-			"integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"get-intrinsic": "^1.2.4"
-			}
-		},
-		"isarray": {
-			"version": "2.0.5",
-			"resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
-			"integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==",
-			"dev": true
-		},
-		"isexe": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-			"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
-			"dev": true
-		},
-		"iso-639-1": {
-			"version": "3.1.3",
-			"resolved": "https://registry.npmjs.org/iso-639-1/-/iso-639-1-3.1.3.tgz",
-			"integrity": "sha512-1jz0Wh9hyLMRwqEPchb/KZCiTqfFWtc9R3nm7GHPygBAKS8wdKJ3FH4lvLsri6UtAE5Kz5SnowtXZa//6bqMyw==",
-			"dev": true
-		},
-		"jackspeak": {
-			"version": "3.4.3",
-			"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
-			"integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
-			"dev": true,
-			"requires": {
-				"@isaacs/cliui": "^8.0.2",
-				"@pkgjs/parseargs": "^0.11.0"
-			}
-		},
-		"js-yaml": {
-			"version": "3.14.1",
-			"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
-			"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
-			"dev": true,
-			"requires": {
-				"argparse": "^1.0.7",
-				"esprima": "^4.0.0"
-			}
-		},
-		"json-buffer": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
-			"integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==",
-			"dev": true
-		},
-		"json-schema-traverse": {
-			"version": "0.4.1",
-			"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-			"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
-			"dev": true
-		},
-		"json-stable-stringify-without-jsonify": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz",
-			"integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=",
-			"dev": true
-		},
-		"json5": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
-			"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
-			"dev": true,
-			"requires": {
-				"minimist": "^1.2.0"
-			}
-		},
-		"jsonfile": {
-			"version": "6.1.0",
-			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
-			"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
-			"dev": true,
-			"requires": {
-				"graceful-fs": "^4.1.6",
-				"universalify": "^2.0.0"
-			}
-		},
-		"junk": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/junk/-/junk-1.0.3.tgz",
-			"integrity": "sha512-3KF80UaaSSxo8jVnRYtMKNGFOoVPBdkkVPsw+Ad0y4oxKXPduS6G6iHkrf69yJVff/VAaYXkV42rtZ7daJxU3w==",
-			"dev": true
-		},
-		"keyv": {
-			"version": "4.5.4",
-			"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
-			"integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
-			"dev": true,
-			"requires": {
-				"json-buffer": "3.0.1"
-			}
-		},
-		"kind-of": {
-			"version": "6.0.3",
-			"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
-			"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
-			"dev": true
-		},
-		"kleur": {
-			"version": "4.1.5",
-			"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
-			"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
-			"dev": true
-		},
-		"levn": {
-			"version": "0.4.1",
-			"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
-			"integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
-			"dev": true,
-			"requires": {
-				"prelude-ls": "^1.2.1",
-				"type-check": "~0.4.0"
-			}
-		},
-		"linkify-it": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz",
-			"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==",
-			"dev": true,
-			"requires": {
-				"uc.micro": "^2.0.0"
-			}
-		},
-		"liquidjs": {
-			"version": "10.19.0",
-			"resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.19.0.tgz",
-			"integrity": "sha512-dNINmbNJ/bp3B8n25BtZQV/GbrmFf0o2InGdMdfQXa+LxfzTFXOkUnBsOLZUb82sLzxaiWv5Jc381Kn4zHjTsQ==",
-			"dev": true,
-			"requires": {
-				"commander": "^10.0.0"
-			},
-			"dependencies": {
-				"commander": {
-					"version": "10.0.1",
-					"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
-					"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
-					"dev": true
-				}
-			}
-		},
-		"list-to-array": {
-			"version": "1.1.0",
-			"resolved": "https://registry.npmjs.org/list-to-array/-/list-to-array-1.1.0.tgz",
-			"integrity": "sha512-+dAZZ2mM+/m+vY9ezfoueVvrgnHIGi5FvgSymbIgJOFwiznWyA59mav95L+Mc6xPtL3s9gm5eNTlNtxJLbNM1g==",
-			"dev": true
-		},
-		"locate-path": {
-			"version": "6.0.0",
-			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
-			"integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==",
-			"dev": true,
-			"requires": {
-				"p-locate": "^5.0.0"
-			}
-		},
-		"lodash.merge": {
-			"version": "4.6.2",
-			"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
-			"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
-			"dev": true
-		},
-		"lru-cache": {
-			"version": "10.4.3",
-			"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
-			"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
-			"dev": true
-		},
-		"luxon": {
-			"version": "3.5.0",
-			"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.5.0.tgz",
-			"integrity": "sha512-rh+Zjr6DNfUYR3bPwJEnuwDdqMbxZW7LOQfUN4B54+Cl+0o5zaU9RJ6bcidfDtC1cWCZXQ+nvX8bf6bAji37QQ==",
-			"dev": true
-		},
-		"make-dir": {
-			"version": "3.1.0",
-			"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
-			"integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==",
-			"dev": true,
-			"requires": {
-				"semver": "^6.0.0"
-			},
-			"dependencies": {
-				"semver": {
-					"version": "6.3.1",
-					"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
-					"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
-					"dev": true
-				}
-			}
-		},
-		"markdown-it": {
-			"version": "14.1.0",
-			"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz",
-			"integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==",
-			"dev": true,
-			"requires": {
-				"argparse": "^2.0.1",
-				"entities": "^4.4.0",
-				"linkify-it": "^5.0.0",
-				"mdurl": "^2.0.0",
-				"punycode.js": "^2.3.1",
-				"uc.micro": "^2.1.0"
-			},
-			"dependencies": {
-				"argparse": {
-					"version": "2.0.1",
-					"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
-					"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
-					"dev": true
-				},
-				"entities": {
-					"version": "4.5.0",
-					"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
-					"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
-					"dev": true
-				}
-			}
-		},
-		"maximatch": {
-			"version": "0.1.0",
-			"resolved": "https://registry.npmjs.org/maximatch/-/maximatch-0.1.0.tgz",
-			"integrity": "sha512-9ORVtDUFk4u/NFfo0vG/ND/z7UQCVZBL539YW0+U1I7H1BkZwizcPx5foFv7LCPcBnm2U6RjFnQOsIvN4/Vm2A==",
-			"dev": true,
-			"requires": {
-				"array-differ": "^1.0.0",
-				"array-union": "^1.0.1",
-				"arrify": "^1.0.0",
-				"minimatch": "^3.0.0"
-			},
-			"dependencies": {
-				"array-union": {
-					"version": "1.0.2",
-					"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
-					"integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==",
-					"dev": true,
-					"requires": {
-						"array-uniq": "^1.0.1"
-					}
-				}
-			}
-		},
-		"mdurl": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz",
-			"integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==",
-			"dev": true
-		},
-		"merge-stream": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
-			"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
-			"dev": true
-		},
-		"merge2": {
-			"version": "1.4.1",
-			"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
-			"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
-			"dev": true
-		},
-		"micromatch": {
-			"version": "4.0.8",
-			"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
-			"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
-			"dev": true,
-			"requires": {
-				"braces": "^3.0.3",
-				"picomatch": "^2.3.1"
-			}
-		},
-		"mime": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/mime/-/mime-3.0.0.tgz",
-			"integrity": "sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==",
-			"dev": true
-		},
-		"mimic-fn": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
-			"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
-			"dev": true
-		},
-		"minimatch": {
-			"version": "3.1.2",
-			"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
-			"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
-			"dev": true,
-			"requires": {
-				"brace-expansion": "^1.1.7"
-			}
-		},
-		"minimist": {
-			"version": "1.2.8",
-			"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
-			"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
-			"dev": true
-		},
-		"minipass": {
-			"version": "7.1.2",
-			"resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
-			"integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
-			"dev": true
-		},
-		"mkdirp": {
-			"version": "3.0.1",
-			"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
-			"integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
-			"dev": true
-		},
-		"moo": {
-			"version": "0.5.2",
-			"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
-			"integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==",
-			"dev": true
-		},
-		"morphdom": {
-			"version": "2.7.4",
-			"resolved": "https://registry.npmjs.org/morphdom/-/morphdom-2.7.4.tgz",
-			"integrity": "sha512-ATTbWMgGa+FaMU3FhnFYB6WgulCqwf6opOll4CBzmVDTLvPMmUPrEv8CudmLPK0MESa64+6B89fWOxP3+YIlxQ==",
-			"dev": true
-		},
-		"mri": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz",
-			"integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==",
-			"dev": true
-		},
-		"ms": {
-			"version": "2.1.3",
-			"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
-			"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
-			"dev": true
-		},
-		"natural-compare": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-			"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
-			"dev": true
-		},
-		"node-retrieve-globals": {
-			"version": "6.0.0",
-			"resolved": "https://registry.npmjs.org/node-retrieve-globals/-/node-retrieve-globals-6.0.0.tgz",
-			"integrity": "sha512-VoEp6WMN/JcbBrJr6LnFE11kdzpKiBKNPFrHCEK2GgFWtiYpeL85WgcZpZFFnWxAU0O65+b+ipQAy4Oxy/+Pdg==",
-			"dev": true,
-			"requires": {
-				"acorn": "^8.1.3",
-				"acorn-walk": "^8.3.2",
-				"esm-import-transformer": "^3.0.2"
-			}
-		},
-		"normalize-path": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
-			"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
-			"dev": true
-		},
-		"npm-run-path": {
-			"version": "4.0.1",
-			"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
-			"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
-			"dev": true,
-			"requires": {
-				"path-key": "^3.0.0"
-			}
-		},
-		"nunjucks": {
-			"version": "3.2.4",
-			"resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.2.4.tgz",
-			"integrity": "sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==",
-			"dev": true,
-			"requires": {
-				"a-sync-waterfall": "^1.0.0",
-				"asap": "^2.0.3",
-				"commander": "^5.1.0"
-			},
-			"dependencies": {
-				"commander": {
-					"version": "5.1.0",
-					"resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
-					"integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
-					"dev": true
-				}
-			}
-		},
-		"object-inspect": {
-			"version": "1.13.3",
-			"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
-			"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
-			"dev": true
-		},
-		"object-keys": {
-			"version": "1.1.1",
-			"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
-			"integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
-			"dev": true
-		},
-		"object.assign": {
-			"version": "4.1.5",
-			"resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
-			"integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.5",
-				"define-properties": "^1.2.1",
-				"has-symbols": "^1.0.3",
-				"object-keys": "^1.1.1"
-			}
-		},
-		"object.entries": {
-			"version": "1.1.8",
-			"resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
-			"integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			}
-		},
-		"object.fromentries": {
-			"version": "2.0.8",
-			"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz",
-			"integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2",
-				"es-object-atoms": "^1.0.0"
-			}
-		},
-		"object.groupby": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
-			"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.2"
-			}
-		},
-		"object.values": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
-			"integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			}
-		},
-		"on-finished": {
-			"version": "2.4.1",
-			"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
-			"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
-			"dev": true,
-			"requires": {
-				"ee-first": "1.1.1"
-			}
-		},
-		"once": {
-			"version": "1.4.0",
-			"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-			"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
-			"dev": true,
-			"requires": {
-				"wrappy": "1"
-			}
-		},
-		"onetime": {
-			"version": "5.1.2",
-			"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
-			"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
-			"dev": true,
-			"requires": {
-				"mimic-fn": "^2.1.0"
-			}
-		},
-		"optionator": {
-			"version": "0.9.3",
-			"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
-			"integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
-			"dev": true,
-			"requires": {
-				"@aashutoshrathi/word-wrap": "^1.2.3",
-				"deep-is": "^0.1.3",
-				"fast-levenshtein": "^2.0.6",
-				"levn": "^0.4.1",
-				"prelude-ls": "^1.2.1",
-				"type-check": "^0.4.0"
-			}
-		},
-		"p-limit": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
-			"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
-			"dev": true,
-			"requires": {
-				"p-try": "^2.0.0"
-			}
-		},
-		"p-locate": {
-			"version": "5.0.0",
-			"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz",
-			"integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==",
-			"dev": true,
-			"requires": {
-				"p-limit": "^3.0.2"
-			},
-			"dependencies": {
-				"p-limit": {
-					"version": "3.1.0",
-					"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
-					"integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==",
-					"dev": true,
-					"requires": {
-						"yocto-queue": "^0.1.0"
-					}
-				}
-			}
-		},
-		"p-try": {
-			"version": "2.2.0",
-			"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
-			"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==",
-			"dev": true
-		},
-		"package-json-from-dist": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
-			"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
-			"dev": true
-		},
-		"parent-module": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
-			"integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
-			"dev": true,
-			"requires": {
-				"callsites": "^3.0.0"
-			}
-		},
-		"parse-srcset": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
-			"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
-			"dev": true
-		},
-		"parseurl": {
-			"version": "1.3.3",
-			"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-			"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
-			"dev": true
-		},
-		"path-exists": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
-			"integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==",
-			"dev": true
-		},
-		"path-is-absolute": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-			"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
-			"dev": true
-		},
-		"path-key": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
-			"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
-			"dev": true
-		},
-		"path-parse": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
-			"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
-			"dev": true
-		},
-		"path-scurry": {
-			"version": "1.11.1",
-			"resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
-			"integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
-			"dev": true,
-			"requires": {
-				"lru-cache": "^10.2.0",
-				"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
-			}
-		},
-		"path-type": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
-			"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
-			"dev": true
-		},
-		"picocolors": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
-			"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
-			"dev": true
-		},
-		"picomatch": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
-			"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
-			"dev": true
-		},
-		"pify": {
-			"version": "2.3.0",
-			"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-			"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
-			"dev": true
-		},
-		"pkg-dir": {
-			"version": "4.2.0",
-			"resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz",
-			"integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==",
-			"dev": true,
-			"requires": {
-				"find-up": "^4.0.0"
-			},
-			"dependencies": {
-				"find-up": {
-					"version": "4.1.0",
-					"resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz",
-					"integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==",
-					"dev": true,
-					"requires": {
-						"locate-path": "^5.0.0",
-						"path-exists": "^4.0.0"
-					}
-				},
-				"locate-path": {
-					"version": "5.0.0",
-					"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
-					"integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==",
-					"dev": true,
-					"requires": {
-						"p-locate": "^4.1.0"
-					}
-				},
-				"p-locate": {
-					"version": "4.1.0",
-					"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz",
-					"integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==",
-					"dev": true,
-					"requires": {
-						"p-limit": "^2.2.0"
-					}
-				}
-			}
-		},
-		"please-upgrade-node": {
-			"version": "3.2.0",
-			"resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz",
-			"integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==",
-			"dev": true,
-			"requires": {
-				"semver-compare": "^1.0.0"
-			}
-		},
-		"possible-typed-array-names": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
-			"integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
-			"dev": true
-		},
-		"posthtml": {
-			"version": "0.16.6",
-			"resolved": "https://registry.npmjs.org/posthtml/-/posthtml-0.16.6.tgz",
-			"integrity": "sha512-JcEmHlyLK/o0uGAlj65vgg+7LIms0xKXe60lcDOTU7oVX/3LuEuLwrQpW3VJ7de5TaFKiW4kWkaIpJL42FEgxQ==",
-			"dev": true,
-			"requires": {
-				"posthtml-parser": "^0.11.0",
-				"posthtml-render": "^3.0.0"
-			}
-		},
-		"posthtml-match-helper": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/posthtml-match-helper/-/posthtml-match-helper-2.0.2.tgz",
-			"integrity": "sha512-ehnazjlSwcGa3P2LlFYmTmcnaembTSt9dLWIRRDVHDPidf6InWAr9leKeeLvUXgnU32g6BrFS64Je+c2Ld+l9g==",
-			"dev": true,
-			"requires": {}
-		},
-		"posthtml-parser": {
-			"version": "0.11.0",
-			"resolved": "https://registry.npmjs.org/posthtml-parser/-/posthtml-parser-0.11.0.tgz",
-			"integrity": "sha512-QecJtfLekJbWVo/dMAA+OSwY79wpRmbqS5TeXvXSX+f0c6pW4/SE6inzZ2qkU7oAMCPqIDkZDvd/bQsSFUnKyw==",
-			"dev": true,
-			"requires": {
-				"htmlparser2": "^7.1.1"
-			},
-			"dependencies": {
-				"dom-serializer": {
-					"version": "1.4.1",
-					"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz",
-					"integrity": "sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==",
-					"dev": true,
-					"requires": {
-						"domelementtype": "^2.0.1",
-						"domhandler": "^4.2.0",
-						"entities": "^2.0.0"
-					},
-					"dependencies": {
-						"entities": {
-							"version": "2.2.0",
-							"resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz",
-							"integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==",
-							"dev": true
-						}
-					}
-				},
-				"domhandler": {
-					"version": "4.3.1",
-					"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.3.1.tgz",
-					"integrity": "sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==",
-					"dev": true,
-					"requires": {
-						"domelementtype": "^2.2.0"
-					}
-				},
-				"domutils": {
-					"version": "2.8.0",
-					"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz",
-					"integrity": "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==",
-					"dev": true,
-					"requires": {
-						"dom-serializer": "^1.0.1",
-						"domelementtype": "^2.2.0",
-						"domhandler": "^4.2.0"
-					}
-				},
-				"entities": {
-					"version": "3.0.1",
-					"resolved": "https://registry.npmjs.org/entities/-/entities-3.0.1.tgz",
-					"integrity": "sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==",
-					"dev": true
-				},
-				"htmlparser2": {
-					"version": "7.2.0",
-					"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-7.2.0.tgz",
-					"integrity": "sha512-H7MImA4MS6cw7nbyURtLPO1Tms7C5H602LRETv95z1MxO/7CP7rDVROehUYeYBUYEON94NXXDEPmZuq+hX4sog==",
-					"dev": true,
-					"requires": {
-						"domelementtype": "^2.0.1",
-						"domhandler": "^4.2.2",
-						"domutils": "^2.8.0",
-						"entities": "^3.0.1"
-					}
-				}
-			}
-		},
-		"posthtml-render": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/posthtml-render/-/posthtml-render-3.0.0.tgz",
-			"integrity": "sha512-z+16RoxK3fUPgwaIgH9NGnK1HKY9XIDpydky5eQGgAFVXTCSezalv9U2jQuNV+Z9qV1fDWNzldcw4eK0SSbqKA==",
-			"dev": true,
-			"requires": {
-				"is-json": "^2.0.1"
-			}
-		},
-		"prelude-ls": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
-			"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
-			"dev": true
-		},
-		"prettier": {
-			"version": "3.4.1",
-			"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz",
-			"integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==",
-			"dev": true
-		},
-		"pretty-quick": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-4.0.0.tgz",
-			"integrity": "sha512-M+2MmeufXb/M7Xw3Afh1gxcYpj+sK0AxEfnfF958ktFeAyi5MsKY5brymVURQLgPLV1QaF5P4pb2oFJ54H3yzQ==",
-			"dev": true,
-			"requires": {
-				"execa": "^5.1.1",
-				"find-up": "^5.0.0",
-				"ignore": "^5.3.0",
-				"mri": "^1.2.0",
-				"picocolors": "^1.0.0",
-				"picomatch": "^3.0.1",
-				"tslib": "^2.6.2"
-			},
-			"dependencies": {
-				"picomatch": {
-					"version": "3.0.1",
-					"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz",
-					"integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==",
-					"dev": true
-				}
-			}
-		},
-		"prismjs": {
-			"version": "1.29.0",
-			"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
-			"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
-			"dev": true
-		},
-		"promise": {
-			"version": "7.3.1",
-			"resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz",
-			"integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==",
-			"dev": true,
-			"requires": {
-				"asap": "~2.0.3"
-			}
-		},
-		"prr": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-			"integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==",
-			"dev": true
-		},
-		"punycode": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
-			"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
-			"dev": true
-		},
-		"punycode.js": {
-			"version": "2.3.1",
-			"resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz",
-			"integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==",
-			"dev": true
-		},
-		"queue-microtask": {
-			"version": "1.2.3",
-			"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
-			"integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
-			"dev": true
-		},
-		"range-parser": {
-			"version": "1.2.1",
-			"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-			"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
-			"dev": true
-		},
-		"readdirp": {
-			"version": "3.6.0",
-			"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
-			"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
-			"dev": true,
-			"requires": {
-				"picomatch": "^2.2.1"
-			}
-		},
-		"reflect.getprototypeof": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.7.tgz",
-			"integrity": "sha512-bMvFGIUKlc/eSfXNX+aZ+EL95/EgZzuwA0OBPTbZZDEJw/0AkentjMuM1oiRfwHrshqk4RzdgiTg5CcDalXN5g==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.5",
-				"es-errors": "^1.3.0",
-				"get-intrinsic": "^1.2.4",
-				"gopd": "^1.0.1",
-				"which-builtin-type": "^1.1.4"
-			}
-		},
-		"regexp.prototype.flags": {
-			"version": "1.5.3",
-			"resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz",
-			"integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-errors": "^1.3.0",
-				"set-function-name": "^2.0.2"
-			}
-		},
-		"resolve-from": {
-			"version": "4.0.0",
-			"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
-			"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
-			"dev": true
-		},
-		"reusify": {
-			"version": "1.0.4",
-			"resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
-			"integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
-			"dev": true
-		},
-		"rimraf": {
-			"version": "5.0.10",
-			"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
-			"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
-			"dev": true,
-			"requires": {
-				"glob": "^10.3.7"
-			}
-		},
-		"run-parallel": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
-			"integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
-			"dev": true,
-			"requires": {
-				"queue-microtask": "^1.2.2"
-			}
-		},
-		"safe-array-concat": {
-			"version": "1.1.2",
-			"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
-			"integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"get-intrinsic": "^1.2.4",
-				"has-symbols": "^1.0.3",
-				"isarray": "^2.0.5"
-			}
-		},
-		"safe-regex-test": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
-			"integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.6",
-				"es-errors": "^1.3.0",
-				"is-regex": "^1.1.4"
-			}
-		},
-		"section-matter": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
-			"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
-			"dev": true,
-			"requires": {
-				"extend-shallow": "^2.0.1",
-				"kind-of": "^6.0.0"
-			}
-		},
-		"semver": {
-			"version": "7.6.3",
-			"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz",
-			"integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==",
-			"dev": true
-		},
-		"semver-compare": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz",
-			"integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==",
-			"dev": true
-		},
-		"send": {
-			"version": "0.19.1",
-			"resolved": "https://registry.npmjs.org/send/-/send-0.19.1.tgz",
-			"integrity": "sha512-p4rRk4f23ynFEfcD9LA0xRYngj+IyGiEYyqqOak8kaN0TvNmuxC2dcVeBn62GpCeR2CpWqyHCNScTP91QbAVFg==",
-			"dev": true,
-			"requires": {
-				"debug": "2.6.9",
-				"depd": "2.0.0",
-				"destroy": "1.2.0",
-				"encodeurl": "~2.0.0",
-				"escape-html": "~1.0.3",
-				"etag": "~1.8.1",
-				"fresh": "0.5.2",
-				"http-errors": "2.0.0",
-				"mime": "1.6.0",
-				"ms": "2.1.3",
-				"on-finished": "2.4.1",
-				"range-parser": "~1.2.1",
-				"statuses": "2.0.1"
-			},
-			"dependencies": {
-				"debug": {
-					"version": "2.6.9",
-					"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-					"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-					"dev": true,
-					"requires": {
-						"ms": "2.0.0"
-					},
-					"dependencies": {
-						"ms": {
-							"version": "2.0.0",
-							"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-							"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
-							"dev": true
-						}
-					}
-				},
-				"mime": {
-					"version": "1.6.0",
-					"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-					"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-					"dev": true
-				}
-			}
-		},
-		"set-function-length": {
-			"version": "1.2.2",
-			"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
-			"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
-			"dev": true,
-			"requires": {
-				"define-data-property": "^1.1.4",
-				"es-errors": "^1.3.0",
-				"function-bind": "^1.1.2",
-				"get-intrinsic": "^1.2.4",
-				"gopd": "^1.0.1",
-				"has-property-descriptors": "^1.0.2"
-			}
-		},
-		"set-function-name": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
-			"integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
-			"dev": true,
-			"requires": {
-				"define-data-property": "^1.1.4",
-				"es-errors": "^1.3.0",
-				"functions-have-names": "^1.2.3",
-				"has-property-descriptors": "^1.0.2"
-			}
-		},
-		"setprototypeof": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
-			"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==",
-			"dev": true
-		},
-		"shebang-command": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
-			"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
-			"dev": true,
-			"requires": {
-				"shebang-regex": "^3.0.0"
-			}
-		},
-		"shebang-regex": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
-			"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
-			"dev": true
-		},
-		"side-channel": {
-			"version": "1.0.6",
-			"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
-			"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"es-errors": "^1.3.0",
-				"get-intrinsic": "^1.2.4",
-				"object-inspect": "^1.13.1"
-			}
-		},
-		"signal-exit": {
-			"version": "3.0.7",
-			"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
-			"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
-			"dev": true
-		},
-		"slash": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
-			"integrity": "sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg==",
-			"dev": true
-		},
-		"slugify": {
-			"version": "1.6.6",
-			"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz",
-			"integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==",
-			"dev": true
-		},
-		"sprintf-js": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-			"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-			"dev": true
-		},
-		"ssri": {
-			"version": "11.0.0",
-			"resolved": "https://registry.npmjs.org/ssri/-/ssri-11.0.0.tgz",
-			"integrity": "sha512-aZpUoMN/Jj2MqA4vMCeiKGnc/8SuSyHbGSBdgFbZxP8OJGF/lFkIuElzPxsN0q8TQQ+prw3P4EDfB3TBHHgfXw==",
-			"dev": true,
-			"requires": {
-				"minipass": "^7.0.3"
-			}
-		},
-		"statuses": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
-			"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
-			"dev": true
-		},
-		"string-width": {
-			"version": "5.1.2",
-			"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
-			"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
-			"dev": true,
-			"requires": {
-				"eastasianwidth": "^0.2.0",
-				"emoji-regex": "^9.2.2",
-				"strip-ansi": "^7.0.1"
-			}
-		},
-		"string-width-cjs": {
-			"version": "npm:string-width@4.2.3",
-			"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-			"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-			"dev": true,
-			"requires": {
-				"emoji-regex": "^8.0.0",
-				"is-fullwidth-code-point": "^3.0.0",
-				"strip-ansi": "^6.0.1"
-			},
-			"dependencies": {
-				"ansi-regex": {
-					"version": "5.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-					"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-					"dev": true
-				},
-				"emoji-regex": {
-					"version": "8.0.0",
-					"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-					"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-					"dev": true
-				},
-				"strip-ansi": {
-					"version": "6.0.1",
-					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-					"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-					"dev": true,
-					"requires": {
-						"ansi-regex": "^5.0.1"
-					}
-				}
-			}
-		},
-		"string.prototype.trim": {
-			"version": "1.2.9",
-			"resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
-			"integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-abstract": "^1.23.0",
-				"es-object-atoms": "^1.0.0"
-			}
-		},
-		"string.prototype.trimend": {
-			"version": "1.0.8",
-			"resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
-			"integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			}
-		},
-		"string.prototype.trimstart": {
-			"version": "1.0.8",
-			"resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz",
-			"integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"define-properties": "^1.2.1",
-				"es-object-atoms": "^1.0.0"
-			}
-		},
-		"strip-ansi": {
-			"version": "7.1.0",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
-			"integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
-			"dev": true,
-			"requires": {
-				"ansi-regex": "^6.0.1"
-			}
-		},
-		"strip-ansi-cjs": {
-			"version": "npm:strip-ansi@6.0.1",
-			"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-			"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-			"dev": true,
-			"requires": {
-				"ansi-regex": "^5.0.1"
-			},
-			"dependencies": {
-				"ansi-regex": {
-					"version": "5.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-					"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-					"dev": true
-				}
-			}
-		},
-		"strip-bom": {
-			"version": "3.0.0",
-			"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-			"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
-			"dev": true
-		},
-		"strip-bom-string": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
-			"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
-			"dev": true
-		},
-		"strip-final-newline": {
-			"version": "2.0.0",
-			"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
-			"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==",
-			"dev": true
-		},
-		"strip-json-comments": {
-			"version": "3.1.1",
-			"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
-			"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
-			"dev": true
-		},
-		"strip-outer": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
-			"integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
-			"dev": true,
-			"requires": {
-				"escape-string-regexp": "^1.0.2"
-			}
-		},
-		"supports-preserve-symlinks-flag": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
-			"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
-			"dev": true
-		},
-		"text-table": {
-			"version": "0.2.0",
-			"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-			"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
-			"dev": true
-		},
-		"to-regex-range": {
-			"version": "5.0.1",
-			"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
-			"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
-			"dev": true,
-			"requires": {
-				"is-number": "^7.0.0"
-			}
-		},
-		"toidentifier": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
-			"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
-			"dev": true
-		},
-		"trim-repeated": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz",
-			"integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=",
-			"dev": true,
-			"requires": {
-				"escape-string-regexp": "^1.0.2"
-			}
-		},
-		"tsconfig-paths": {
-			"version": "3.15.0",
-			"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
-			"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
-			"dev": true,
-			"requires": {
-				"@types/json5": "^0.0.29",
-				"json5": "^1.0.2",
-				"minimist": "^1.2.6",
-				"strip-bom": "^3.0.0"
-			}
-		},
-		"tslib": {
-			"version": "2.6.2",
-			"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
-			"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
-			"dev": true
-		},
-		"type-check": {
-			"version": "0.4.0",
-			"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
-			"integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==",
-			"dev": true,
-			"requires": {
-				"prelude-ls": "^1.2.1"
-			}
-		},
-		"type-fest": {
-			"version": "0.20.2",
-			"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
-			"integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
-			"dev": true
-		},
-		"typed-array-buffer": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
-			"integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"es-errors": "^1.3.0",
-				"is-typed-array": "^1.1.13"
-			}
-		},
-		"typed-array-byte-length": {
-			"version": "1.0.1",
-			"resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
-			"integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"has-proto": "^1.0.3",
-				"is-typed-array": "^1.1.13"
-			}
-		},
-		"typed-array-byte-offset": {
-			"version": "1.0.3",
-			"resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.3.tgz",
-			"integrity": "sha512-GsvTyUHTriq6o/bHcTd0vM7OQ9JEdlvluu9YISaA7+KzDzPaIzEeDFNkTfhdE3MYcNhNi0vq/LlegYgIs5yPAw==",
-			"dev": true,
-			"requires": {
-				"available-typed-arrays": "^1.0.7",
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"has-proto": "^1.0.3",
-				"is-typed-array": "^1.1.13",
-				"reflect.getprototypeof": "^1.0.6"
-			}
-		},
-		"typed-array-length": {
-			"version": "1.0.7",
-			"resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz",
-			"integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"is-typed-array": "^1.1.13",
-				"possible-typed-array-names": "^1.0.0",
-				"reflect.getprototypeof": "^1.0.6"
-			}
-		},
-		"uc.micro": {
-			"version": "2.1.0",
-			"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
-			"integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==",
-			"dev": true
-		},
-		"unbox-primitive": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
-			"integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.2",
-				"has-bigints": "^1.0.2",
-				"has-symbols": "^1.0.3",
-				"which-boxed-primitive": "^1.0.2"
-			}
-		},
-		"universalify": {
-			"version": "2.0.1",
-			"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
-			"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
-			"dev": true
-		},
-		"unpipe": {
-			"version": "1.0.0",
-			"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-			"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
-			"dev": true
-		},
-		"uri-js": {
-			"version": "4.4.1",
-			"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
-			"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
-			"dev": true,
-			"requires": {
-				"punycode": "^2.1.0"
-			}
-		},
-		"urlpattern-polyfill": {
-			"version": "10.0.0",
-			"resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz",
-			"integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==",
-			"dev": true
-		},
-		"which": {
-			"version": "2.0.2",
-			"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
-			"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
-			"dev": true,
-			"requires": {
-				"isexe": "^2.0.0"
-			}
-		},
-		"which-boxed-primitive": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
-			"integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
-			"dev": true,
-			"requires": {
-				"is-bigint": "^1.0.1",
-				"is-boolean-object": "^1.1.0",
-				"is-number-object": "^1.0.4",
-				"is-string": "^1.0.5",
-				"is-symbol": "^1.0.3"
-			}
-		},
-		"which-builtin-type": {
-			"version": "1.2.0",
-			"resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.0.tgz",
-			"integrity": "sha512-I+qLGQ/vucCby4tf5HsLmGueEla4ZhwTBSqaooS+Y0BuxN4Cp+okmGuV+8mXZ84KDI9BA+oklo+RzKg0ONdSUA==",
-			"dev": true,
-			"requires": {
-				"call-bind": "^1.0.7",
-				"function.prototype.name": "^1.1.6",
-				"has-tostringtag": "^1.0.2",
-				"is-async-function": "^2.0.0",
-				"is-date-object": "^1.0.5",
-				"is-finalizationregistry": "^1.1.0",
-				"is-generator-function": "^1.0.10",
-				"is-regex": "^1.1.4",
-				"is-weakref": "^1.0.2",
-				"isarray": "^2.0.5",
-				"which-boxed-primitive": "^1.0.2",
-				"which-collection": "^1.0.2",
-				"which-typed-array": "^1.1.15"
-			}
-		},
-		"which-collection": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz",
-			"integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==",
-			"dev": true,
-			"requires": {
-				"is-map": "^2.0.3",
-				"is-set": "^2.0.3",
-				"is-weakmap": "^2.0.2",
-				"is-weakset": "^2.0.3"
-			}
-		},
-		"which-typed-array": {
-			"version": "1.1.15",
-			"resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
-			"integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
-			"dev": true,
-			"requires": {
-				"available-typed-arrays": "^1.0.7",
-				"call-bind": "^1.0.7",
-				"for-each": "^0.3.3",
-				"gopd": "^1.0.1",
-				"has-tostringtag": "^1.0.2"
-			}
-		},
-		"wrap-ansi": {
-			"version": "8.1.0",
-			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
-			"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
-			"dev": true,
-			"requires": {
-				"ansi-styles": "^6.1.0",
-				"string-width": "^5.0.1",
-				"strip-ansi": "^7.0.1"
-			}
-		},
-		"wrap-ansi-cjs": {
-			"version": "npm:wrap-ansi@7.0.0",
-			"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
-			"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
-			"dev": true,
-			"requires": {
-				"ansi-styles": "^4.0.0",
-				"string-width": "^4.1.0",
-				"strip-ansi": "^6.0.0"
-			},
-			"dependencies": {
-				"ansi-regex": {
-					"version": "5.0.1",
-					"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
-					"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
-					"dev": true
-				},
-				"ansi-styles": {
-					"version": "4.3.0",
-					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
-					"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
-					"dev": true,
-					"requires": {
-						"color-convert": "^2.0.1"
-					}
-				},
-				"emoji-regex": {
-					"version": "8.0.0",
-					"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
-					"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
-					"dev": true
-				},
-				"string-width": {
-					"version": "4.2.3",
-					"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
-					"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
-					"dev": true,
-					"requires": {
-						"emoji-regex": "^8.0.0",
-						"is-fullwidth-code-point": "^3.0.0",
-						"strip-ansi": "^6.0.1"
-					}
-				},
-				"strip-ansi": {
-					"version": "6.0.1",
-					"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
-					"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
-					"dev": true,
-					"requires": {
-						"ansi-regex": "^5.0.1"
-					}
-				}
-			}
-		},
-		"wrappy": {
-			"version": "1.0.2",
-			"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-			"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
-			"dev": true
-		},
-		"ws": {
-			"version": "8.18.0",
-			"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
-			"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
-			"dev": true,
-			"requires": {}
-		},
-		"yocto-queue": {
-			"version": "0.1.0",
-			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
-			"integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==",
-			"dev": true
-		}
-	}
-}
diff --git a/package.json b/package.json
deleted file mode 100644
index e16bdbd7..00000000
--- a/package.json
+++ /dev/null
@@ -1,89 +0,0 @@
-{
-	"name": "culori",
-	"version": "4.0.2",
-	"type": "module",
-	"main": "./bundled/culori.cjs",
-	"module": "./bundled/culori.min.mjs",
-	"browser": "./bundled/culori.min.js",
-	"jsdelivr": "./bundled/culori.umd.js",
-	"exports": {
-		".": {
-			"require": "./bundled/culori.cjs",
-			"import": "./src/index.js"
-		},
-		"./require": "./bundled/culori.cjs",
-		"./css": "./src/bootstrap/css.js",
-		"./all": "./src/bootstrap/all.js",
-		"./fn": "./src/index-fn.js",
-		"./package.json": "./package.json"
-	},
-	"repository": "git@github.com:Evercoder/culori.git",
-	"author": "Dan Burzo <dan@danburzo.ro>",
-	"description": "A general-purpose color library for JavaScript",
-	"keywords": [
-		"blend",
-		"ciede2000",
-		"cielab",
-		"color",
-		"color-difference",
-		"cubehelix",
-		"din99",
-		"gradients",
-		"hsi",
-		"hsl",
-		"hsv",
-		"hwb",
-		"interpolation",
-		"lab",
-		"lch",
-		"lrgb",
-		"mix",
-		"rgb",
-		"yiq"
-	],
-	"license": "MIT",
-	"files": [
-		"bundled",
-		"src"
-	],
-	"devDependencies": {
-		"@11ty/eleventy": "^3.0.0",
-		"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
-		"esbuild": "^0.24.0",
-		"eslint": "^8.57.1",
-		"eslint-plugin-import": "^2.31.0",
-		"gh-pages": "^6.2.0",
-		"prettier": "^3.4.1",
-		"pretty-quick": "^4.0.0"
-	},
-	"scripts": {
-		"prepare": "git config core.hooksPath .git-hooks",
-		"test": "node --test 'test/**/*.test.js'",
-		"start": "npx esbuild --servedir=.",
-		"build": "node build.js",
-		"benchmark": "node benchmark/index.js",
-		"prepublishOnly": "npm run lint && npm run build && npm run test",
-		"docs:start": "eleventy --config=eleventy.config.cjs --serve",
-		"docs:build": "npm run build && rm -rf www && eleventy --config=eleventy.config.cjs && cp bundled/culori.min.mjs www/",
-		"docs:deploy": "npm run docs:build && gh-pages -d www --dotfiles",
-		"lint": "eslint '{src,test}/**/*.js'"
-	},
-	"prettier": {
-		"bracketSpacing": true,
-		"semi": true,
-		"singleQuote": true,
-		"trailingComma": "none",
-		"useTabs": true,
-		"tabWidth": 4,
-		"arrowParens": "avoid",
-		"printWidth": 80
-	},
-	"sideEffects": [
-		"src/index.js",
-		"src/bootstrap/all.js",
-		"src/bootstrap/css.js"
-	],
-	"engines": {
-		"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-	}
-}
diff --git a/resources/index.html b/resources/index.html
new file mode 100644
index 00000000..7753d995
--- /dev/null
+++ b/resources/index.html
@@ -0,0 +1,153 @@
+<!DOCTYPE html>
+<html>
+	<head>
+		<meta charset="utf-8" />
+		<meta name="viewport" content="width=device-width,initial-scale=1" />
+		<title>
+			 Resources &middot; culori 
+		</title>
+
+		<link rel="icon" type="image/png" href='/favicon.png' />
+		<link rel="stylesheet" href='/css/main.css' />
+	</head>
+	<body>
+		<header>
+			<div class="container">
+				<div class="logo">
+					<a href='/'>
+						<img
+							width="132"
+							height="30"
+							src='/img/culori.svg'
+							alt="culori"
+						/>
+					</a>
+					<a href="https://github.com/evercoder/culori/releases">v4.0.2</a>
+				</div>
+				<nav>
+					<ul class='nav'>
+						<li >
+							<a href="/getting-started/">Get started</a>
+						</li>
+						<li >
+							<a href="/api/">API reference</a>
+						</li>
+						<li >
+							<a href="/color-spaces/">Color spaces</a>
+						</li>
+						<li >
+							<a href="/guides/">Guides</a>
+						</li>
+						<li>
+							<a href="https://github.com/Evercoder/culori"
+								>GitHub <span aria-hidden="true">↗</span></a
+							>
+						</li>
+					</ul>
+				</nav>
+			</div>
+		</header>
+
+		<div class="container">
+			<article>
+				<h1>Resources</h1>
+				<h2>Culori extras</h2>
+<p>These projects add more functionality to Culori, but they're separate as to keep the core bundle small:</p>
+<ul>
+<li><a href="https://github.com/evercoder/culori-scales">culori-scales</a> — color scales (ColorBrewer, matplotlib, etc).</li>
+<li><a href="https://github.com/evercoder/culori-names">culori-names</a> — More named colors, from a variety of sources.</li>
+<li><a href="https://github.com/evercoder/d3-color-difference">d3-color-difference</a> — a separate D3.js plugin to compute color differences</li>
+</ul>
+<h2>Products using Culori</h2>
+<ul>
+<li><a href="https://moqups.com">Moqups</a> — all our color-manipulation functions are handled by Culori.</li>
+<li><a href="https://github.com/felixgirault/schemist">Schemist</a> — color schemes builder backed by Culori.</li>
+<li><a href="https://github.com/meodai/color-name-api">Color Name API</a> — a REST API for color names that makes use Culori's <a href="https://culorijs.org/api/#differenceCiede2000">differenceCiede2000</a> to return a fitting name for every color.</li>
+<li><a href="https://atmos.style">Atmos</a> - a toolbox based on (OK)LCH color space for creating professional color palettes. Utilizing Culori for color manipulation allowed us to concentrate on our product's essence rather than getting bogged down in implementation details.</li>
+<li><a href="https://github.com/prjctimg/huetiful">huetiful-js</a> - Open source Typescript library for manipulating color and generating custom color scales based on Culori. With utilities for sorting, filtering and querying collections of colors, this library opens new ways of working with color programmatically.</li>
+<li><a href="https://oklch.com/">oklch.com/</a> - OKLCH picker with pretty plotting</li>
+</ul>
+<p><em>Does your product/project use Culori? Create a PR and add yourself to this list.</em></p>
+<h2>Similar projects</h2>
+<ul>
+<li><a href="https://github.com/d3/d3-color">d3-color</a> by <a href="https://bost.ocks.org/mike/">Mike Bostock</a> (JavaScript)</li>
+<li><a href="https://github.com/gka/chroma.js">chroma.js</a> by <a href="https://driven-by-data.net/">Gregor Aisch</a> (JavaScript)</li>
+<li><a href="https://github.com/LeaVerou/color.js">colorjs.io</a> by <a href="http://lea.verou.me/">Lea Verou</a> and <a href="https://svgees.us/">Chris Lilley</a> (JavaScript)</li>
+<li><a href="https://github.com/texel-org/color/">@texel/color</a> by <a href="https://www.mattdesl.com/">Matt DesLauriers</a> (JavaScript)</li>
+<li><a href="https://www.colour-science.org/">Colour</a> (Python)</li>
+<li><a href="https://github.com/facelessuser/coloraide">ColorAide</a> by Isaac Muse (Python)</li>
+<li><a href="https://github.com/nschloe/colorio">colorio</a> by Nico Schlömer (Python)</li>
+<li><a href="http://colorspace.r-forge.r-project.org/"><code>colorspace</code> package</a> (R)</li>
+<li><a href="https://github.com/JuliaGraphics/Colors.jl"><code>Colors</code> package</a> (Julia)</li>
+<li><a href="https://github.com/linebender/color"><code>linebender/color</code></a> by Raph Levien &amp; collaborators (Rust)</li>
+</ul>
+<h2>Further reading</h2>
+<h3>Specifications</h3>
+<ul>
+<li><a href="https://drafts.csswg.org/css-color-4/">CSS Color Module Level 4</a> [<a href="https://github.com/w3c/csswg-drafts/commits/main/css-color-4">changelog</a>, <a href="https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Acss-color-4">issues</a>]</li>
+<li><a href="https://drafts.csswg.org/css-color-5/">CSS Color Module Level 5</a> [<a href="https://github.com/w3c/csswg-drafts/commits/main/css-color-5">changelog</a>, <a href="https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Acss-color-5">issues</a>]</li>
+<li><a href="https://drafts.csswg.org/css-color-hdr/">CSS Color HDR Module Level 1</a> [<a href="https://github.com/w3c/csswg-drafts/commits/main/css-color-hdr">changelog</a>, <a href="https://github.com/w3c/csswg-drafts/issues?q=is%3Aissue+is%3Aopen+label%3Acss-color-hdr">issues</a>]</li>
+</ul>
+<h3>Websites</h3>
+<ul>
+<li>David Briggs’s <a href="http://www.huevaluechroma.com/">The Dimensions of Color</a></li>
+<li>Bruce Lindbloom’s <a href="http://www.brucelindbloom.com/index.html?Math.html">Useful Color Math</a></li>
+<li>Rune Madsen’s <a href="https://programmingdesignsystems.com/">Programming Design Systems</a></li>
+</ul>
+<h3>Articles</h3>
+<ul>
+<li><a href="http://jamie-wong.com/post/color/">Color: From Hexcodes to Eyeballs</a> by Jamie Wong</li>
+<li><a href="https://ericportis.com/posts/2024/okay-color-spaces/">Okay, color spaces</a> by Eric Portis</li>
+<li><a href="https://matthewstrom.com/writing/generating-color-palettes/">How to generate color palettes for design systems</a> by Matthew Ström</li>
+</ul>
+<h3>Books</h3>
+<ul>
+<li><a href="http://markfairchild.org/">Fairchild, Mark D.</a> — <a href="https://www.wiley.com/en-us/Color+Appearance+Models%2C+3rd+Edition-p-9781119967033"><em>Color Appearance Models</em></a>, 3rd Edition, Wiley, 2013.</li>
+<li>Green, Phil (ed.) — <a href="https://onlinelibrary.wiley.com/doi/book/10.1002/9781119827214"><em>Fundamentals and Applications of Colour Engineering</em></a>, Wiley, 2023.</li>
+<li>Morovič, Ján — <a href="https://www.wiley.com/en-ie/Color+Gamut+Mapping-p-9780470030325"><em>Color Gamut Mapping</em></a>, Wiley, 2008.</li>
+<li><a href="http://poynton.ca/">Poynton, Charles</a> — <a href="https://www.elsevier.com/books/digital-video-and-hd/poynton/978-0-12-391926-7"><em>Digital Video and HD Algorithms and Interfaces</em></a>, 2nd Edition, Morgan Kaufmann, 2012.</li>
+</ul>
+
+			</article>
+		</div>
+		<footer>
+			<div class="container">
+
+				<p>
+					Culori is built by <a href="https://moqups.com">Moqups</a> &middot; <a href="/colophon/">Colophon</a> &middot; <a href="/resources/">Resources</a> 
+				<p>
+
+				<p>
+					Can this page be improved?
+					<a
+						href="https://github.com/Evercoder/culori/blob/main/./docs/resources.md"
+						>Edit it on GitHub</a
+					>
+				</p>
+			</div>
+		</footer>
+
+
+		<script type="module">
+			import * as culori from '/culori.min.mjs';
+
+			/* Expose as global variable */
+			window.culori = culori;
+
+			const { p3, random, formatCss, formatHex } = culori;
+
+			const r = () => random('lch', { l: [30, 80], c: [60, 90] });
+			let r1 = r();
+			let r2 = r();
+			if (CSS.supports('color: color(display-p3 0 0 0)')) {
+				r1 = formatCss(p3(r1));
+				r2 = formatCss(p3(r2));
+			} else {
+				r1 = formatHex(r1);
+				r2 = formatHex(r2);
+			}
+			document.body.style.setProperty('--random-1', r1);
+			document.body.style.setProperty('--random-2', r2);
+		</script>
+	</body>
+</html>
diff --git a/src/_prepare.js b/src/_prepare.js
deleted file mode 100644
index 2a6a5023..00000000
--- a/src/_prepare.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import parse from './parse.js';
-
-const prepare = (color, mode) =>
-	color === undefined
-		? undefined
-		: typeof color !== 'object'
-		? parse(color)
-		: color.mode !== undefined
-		? color
-		: mode
-		? { ...color, mode }
-		: undefined;
-
-export default prepare;
diff --git a/src/a98/convertA98ToXyz65.js b/src/a98/convertA98ToXyz65.js
deleted file mode 100644
index ace02df3..00000000
--- a/src/a98/convertA98ToXyz65.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-	Convert A98 RGB values to CIE XYZ D65
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-		* https://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
-*/
-
-const linearize = (v = 0) => Math.pow(Math.abs(v), 563 / 256) * Math.sign(v);
-
-const convertA98ToXyz65 = a98 => {
-	let r = linearize(a98.r);
-	let g = linearize(a98.g);
-	let b = linearize(a98.b);
-	let res = {
-		mode: 'xyz65',
-		x:
-			0.5766690429101305 * r +
-			0.1855582379065463 * g +
-			0.1882286462349947 * b,
-		y:
-			0.297344975250536 * r +
-			0.6273635662554661 * g +
-			0.0752914584939979 * b,
-		z:
-			0.0270313613864123 * r +
-			0.0706888525358272 * g +
-			0.9913375368376386 * b
-	};
-	if (a98.alpha !== undefined) {
-		res.alpha = a98.alpha;
-	}
-	return res;
-};
-
-export default convertA98ToXyz65;
diff --git a/src/a98/convertXyz65ToA98.js b/src/a98/convertXyz65ToA98.js
deleted file mode 100644
index e30dc025..00000000
--- a/src/a98/convertXyz65ToA98.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-	Convert CIE XYZ D65 values to A98 RGB
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-*/
-
-const gamma = v => Math.pow(Math.abs(v), 256 / 563) * Math.sign(v);
-
-const convertXyz65ToA98 = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = {
-		mode: 'a98',
-		r: gamma(
-			x * 2.0415879038107465 -
-				y * 0.5650069742788597 -
-				0.3447313507783297 * z
-		),
-		g: gamma(
-			x * -0.9692436362808798 +
-				y * 1.8759675015077206 +
-				0.0415550574071756 * z
-		),
-		b: gamma(
-			x * 0.0134442806320312 -
-				y * 0.1183623922310184 +
-				1.0151749943912058 * z
-		)
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz65ToA98;
diff --git a/src/a98/definition.js b/src/a98/definition.js
deleted file mode 100644
index 6c35d078..00000000
--- a/src/a98/definition.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import rgb from '../rgb/definition.js';
-
-import convertA98ToXyz65 from './convertA98ToXyz65.js';
-import convertXyz65ToA98 from './convertXyz65ToA98.js';
-import convertRgbToXyz65 from '../xyz65/convertRgbToXyz65.js';
-import convertXyz65ToRgb from '../xyz65/convertXyz65ToRgb.js';
-
-const definition = {
-	...rgb,
-	mode: 'a98',
-	parse: ['a98-rgb'],
-	serialize: 'a98-rgb',
-
-	fromMode: {
-		rgb: color => convertXyz65ToA98(convertRgbToXyz65(color)),
-		xyz65: convertXyz65ToA98
-	},
-
-	toMode: {
-		rgb: color => convertXyz65ToRgb(convertA98ToXyz65(color)),
-		xyz65: convertA98ToXyz65
-	}
-};
-
-export default definition;
diff --git a/src/average.js b/src/average.js
deleted file mode 100644
index 817eefbb..00000000
--- a/src/average.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import converter from './converter.js';
-import { getMode } from './modes.js';
-
-const averageAngle = val => {
-	// See: https://en.wikipedia.org/wiki/Mean_of_circular_quantities
-	let sum = val.reduce(
-		(sum, val) => {
-			if (val !== undefined) {
-				let rad = (val * Math.PI) / 180;
-				sum.sin += Math.sin(rad);
-				sum.cos += Math.cos(rad);
-			}
-			return sum;
-		},
-		{ sin: 0, cos: 0 }
-	);
-	let angle = (Math.atan2(sum.sin, sum.cos) * 180) / Math.PI;
-	return angle < 0 ? 360 + angle : angle;
-};
-
-const averageNumber = val => {
-	let a = val.filter(v => v !== undefined);
-	return a.length ? a.reduce((sum, v) => sum + v, 0) / a.length : undefined;
-};
-
-const isfn = o => typeof o === 'function';
-
-function average(colors, mode = 'rgb', overrides) {
-	let def = getMode(mode);
-	let cc = colors.map(converter(mode));
-	return def.channels.reduce(
-		(res, ch) => {
-			let arr = cc.map(c => c[ch]).filter(val => val !== undefined);
-			if (arr.length) {
-				let fn;
-				if (isfn(overrides)) {
-					fn = overrides;
-				} else if (overrides && isfn(overrides[ch])) {
-					fn = overrides[ch];
-				} else if (def.average && isfn(def.average[ch])) {
-					fn = def.average[ch];
-				} else {
-					fn = averageNumber;
-				}
-				res[ch] = fn(arr, ch);
-			}
-			return res;
-		},
-		{ mode }
-	);
-}
-
-export { average, averageAngle, averageNumber };
diff --git a/src/blend.js b/src/blend.js
deleted file mode 100644
index 451b35d9..00000000
--- a/src/blend.js
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
-	Color blend modes, as defined in the 
-	CSS Compositing Level 4 spec
-
-	https://drafts.fxtf.org/compositing-2/
-	https://en.wikipedia.org/wiki/Blend_modes
-	https://en.wikipedia.org/wiki/Alpha_compositing
-	https://keithp.com/~keithp/porterduff/p253-porter.pdf
- */
-
-import converter from './converter.js';
-import { getMode } from './modes.js';
-
-const BLENDS = {
-	normal: (b, s) => s,
-	multiply: (b, s) => b * s,
-	screen: (b, s) => b + s - b * s,
-	'hard-light': (b, s) => (s < 0.5 ? b * 2 * s : 2 * s * (1 - b) - 1),
-	overlay: (b, s) => (b < 0.5 ? s * 2 * b : 2 * b * (1 - s) - 1),
-	darken: (b, s) => Math.min(b, s),
-	lighten: (b, s) => Math.max(b, s),
-	'color-dodge': (b, s) =>
-		b === 0 ? 0 : s === 1 ? 1 : Math.min(1, b / (1 - s)),
-	'color-burn': (b, s) =>
-		b === 1 ? 1 : s === 0 ? 0 : 1 - Math.min(1, (1 - b) / s),
-	'soft-light': (b, s) =>
-		s < 0.5
-			? b - (1 - 2 * s) * b * (1 - b)
-			: b +
-			  (2 * s - 1) *
-					((b < 0.25 ? ((16 * b - 12) * b + 4) * b : Math.sqrt(b)) -
-						b),
-	difference: (b, s) => Math.abs(b - s),
-	exclusion: (b, s) => b + s - 2 * b * s
-};
-
-const blend = (colors, type = 'normal', mode = 'rgb') => {
-	let fn = typeof type === 'function' ? type : BLENDS[type];
-
-	let conv = converter(mode);
-
-	// get mode channels
-	let channels = getMode(mode).channels;
-
-	// convert all colors to the mode
-	// and assume undefined alphas are 1
-	let converted = colors.map(c => {
-		let cc = conv(c);
-		if (cc.alpha === undefined) {
-			cc.alpha = 1;
-		}
-		return cc;
-	});
-
-	return converted.reduce((b, s) => {
-		if (b === undefined) return s;
-		// blend backdrop and source
-		let alpha = s.alpha + b.alpha * (1 - s.alpha);
-		return channels.reduce(
-			(res, ch) => {
-				if (ch !== 'alpha') {
-					if (alpha === 0) {
-						res[ch] = 0;
-					} else {
-						res[ch] =
-							s.alpha * (1 - b.alpha) * s[ch] +
-							s.alpha * b.alpha * fn(b[ch], s[ch]) +
-							(1 - s.alpha) * b.alpha * b[ch];
-						// TODO fix() assumes [0, 1] colors
-						// and is only true for RGB / LRGB
-						res[ch] = Math.max(0, Math.min(1, res[ch] / alpha));
-					}
-				}
-				return res;
-			},
-			{ mode, alpha }
-		);
-	});
-};
-
-export default blend;
diff --git a/src/bootstrap/all.js b/src/bootstrap/all.js
deleted file mode 100644
index ec3e5d32..00000000
--- a/src/bootstrap/all.js
+++ /dev/null
@@ -1,63 +0,0 @@
-// Color space definitions
-import modeA98 from '../a98/definition.js';
-import modeCubehelix from '../cubehelix/definition.js';
-import modeDlab from '../dlab/definition.js';
-import modeDlch from '../dlch/definition.js';
-import modeHsi from '../hsi/definition.js';
-import modeHsl from '../hsl/definition.js';
-import modeHsv from '../hsv/definition.js';
-import modeHwb from '../hwb/definition.js';
-import modeItp from '../itp/definition.js';
-import modeJab from '../jab/definition.js';
-import modeJch from '../jch/definition.js';
-import modeLab from '../lab/definition.js';
-import modeLab65 from '../lab65/definition.js';
-import modeLch from '../lch/definition.js';
-import modeLch65 from '../lch65/definition.js';
-import modeLchuv from '../lchuv/definition.js';
-import modeLrgb from '../lrgb/definition.js';
-import modeLuv from '../luv/definition.js';
-import modeOkhsl from '../okhsl/modeOkhsl.js';
-import modeOkhsv from '../okhsv/modeOkhsv.js';
-import modeOklab from '../oklab/definition.js';
-import modeOklch from '../oklch/definition.js';
-import modeP3 from '../p3/definition.js';
-import modeProphoto from '../prophoto/definition.js';
-import modeRec2020 from '../rec2020/definition.js';
-import modeRgb from '../rgb/definition.js';
-import modeXyb from '../xyb/definition.js';
-import modeXyz50 from '../xyz50/definition.js';
-import modeXyz65 from '../xyz65/definition.js';
-import modeYiq from '../yiq/definition.js';
-import { useMode } from '../modes.js';
-
-export const a98 = useMode(modeA98);
-export const cubehelix = useMode(modeCubehelix);
-export const dlab = useMode(modeDlab);
-export const dlch = useMode(modeDlch);
-export const hsi = useMode(modeHsi);
-export const hsl = useMode(modeHsl);
-export const hsv = useMode(modeHsv);
-export const hwb = useMode(modeHwb);
-export const itp = useMode(modeItp);
-export const jab = useMode(modeJab);
-export const jch = useMode(modeJch);
-export const lab = useMode(modeLab);
-export const lab65 = useMode(modeLab65);
-export const lch = useMode(modeLch);
-export const lch65 = useMode(modeLch65);
-export const lchuv = useMode(modeLchuv);
-export const lrgb = useMode(modeLrgb);
-export const luv = useMode(modeLuv);
-export const okhsl = useMode(modeOkhsl);
-export const okhsv = useMode(modeOkhsv);
-export const oklab = useMode(modeOklab);
-export const oklch = useMode(modeOklch);
-export const p3 = useMode(modeP3);
-export const prophoto = useMode(modeProphoto);
-export const rec2020 = useMode(modeRec2020);
-export const rgb = useMode(modeRgb);
-export const xyb = useMode(modeXyb);
-export const xyz50 = useMode(modeXyz50);
-export const xyz65 = useMode(modeXyz65);
-export const yiq = useMode(modeYiq);
diff --git a/src/bootstrap/css.js b/src/bootstrap/css.js
deleted file mode 100644
index 6719c7ce..00000000
--- a/src/bootstrap/css.js
+++ /dev/null
@@ -1,37 +0,0 @@
-// Color space definitions
-import modeA98 from '../a98/definition.js';
-import modeHsl from '../hsl/definition.js';
-import modeHsv from '../hsv/definition.js';
-import modeHwb from '../hwb/definition.js';
-import modeLab from '../lab/definition.js';
-import modeLab65 from '../lab65/definition.js';
-import modeLch from '../lch/definition.js';
-import modeLch65 from '../lch65/definition.js';
-import modeLrgb from '../lrgb/definition.js';
-import modeOklab from '../oklab/definition.js';
-import modeOklch from '../oklch/definition.js';
-import modeP3 from '../p3/definition.js';
-import modeProphoto from '../prophoto/definition.js';
-import modeRec2020 from '../rec2020/definition.js';
-import modeRgb from '../rgb/definition.js';
-import modeXyz50 from '../xyz50/definition.js';
-import modeXyz65 from '../xyz65/definition.js';
-import { useMode } from '../modes.js';
-
-export const a98 = useMode(modeA98);
-export const hsl = useMode(modeHsl);
-export const hsv = useMode(modeHsv);
-export const hwb = useMode(modeHwb);
-export const lab = useMode(modeLab);
-export const lab65 = useMode(modeLab65);
-export const lch = useMode(modeLch);
-export const lch65 = useMode(modeLch65);
-export const lrgb = useMode(modeLrgb);
-export const oklab = useMode(modeOklab);
-export const oklch = useMode(modeOklch);
-export const p3 = useMode(modeP3);
-export const prophoto = useMode(modeProphoto);
-export const rec2020 = useMode(modeRec2020);
-export const rgb = useMode(modeRgb);
-export const xyz50 = useMode(modeXyz50);
-export const xyz65 = useMode(modeXyz65);
diff --git a/src/clamp.js b/src/clamp.js
deleted file mode 100644
index 8ade9744..00000000
--- a/src/clamp.js
+++ /dev/null
@@ -1,259 +0,0 @@
-import converter from './converter.js';
-import prepare from './_prepare.js';
-import { getMode } from './modes.js';
-import { differenceEuclidean } from './difference.js';
-
-const rgb = converter('rgb');
-const fixup_rgb = c => {
-	const res = {
-		mode: c.mode,
-		r: Math.max(0, Math.min(c.r !== undefined ? c.r : 0, 1)),
-		g: Math.max(0, Math.min(c.g !== undefined ? c.g : 0, 1)),
-		b: Math.max(0, Math.min(c.b !== undefined ? c.b : 0, 1))
-	};
-	if (c.alpha !== undefined) {
-		res.alpha = c.alpha;
-	}
-	return res;
-};
-
-const to_displayable_srgb = c => fixup_rgb(rgb(c));
-
-const inrange_rgb = c => {
-	return (
-		c !== undefined &&
-		(c.r === undefined || (c.r >= 0 && c.r <= 1)) &&
-		(c.g === undefined || (c.g >= 0 && c.g <= 1)) &&
-		(c.b === undefined || (c.b >= 0 && c.b <= 1))
-	);
-};
-
-/*
-	Returns whether the color is in the sRGB gamut.
- */
-export function displayable(color) {
-	return inrange_rgb(rgb(color));
-}
-
-/*
-	Given a color space `mode`, returns a function
-	with which to check whether a color is 
-	in that color space's gamut.
- */
-export function inGamut(mode = 'rgb') {
-	const { gamut } = getMode(mode);
-	if (!gamut) {
-		return color => true;
-	}
-	const conv = converter(typeof gamut === 'string' ? gamut : mode);
-	return color => inrange_rgb(conv(color));
-}
-
-/*
-	Obtain a color that's in the sRGB gamut
-	by converting it to sRGB and clipping the channel values
-	so that they're within the [0, 1] range.
-
-	The result is returned in the color's original color space.
- */
-export function clampRgb(color) {
-	color = prepare(color);
-
-	// if the color is undefined or displayable, return it directly
-	if (color === undefined || displayable(color)) return color;
-
-	// keep track of color's original mode
-	let conv = converter(color.mode);
-
-	return conv(to_displayable_srgb(color));
-}
-
-/*
-	Given the `mode` color space, returns a function
-	with which to obtain a color that's in gamut for
-	the `mode` color space by clipping the channel values
-	so that they fit in their respective ranges.
-
-	It's similar to `clampRgb`, but works for any 
-	bounded color space (RGB or not) for which 
-	any combination of in-range channel values
-	produces an in-gamut color.
- */
-export function clampGamut(mode = 'rgb') {
-	const { gamut } = getMode(mode);
-	if (!gamut) {
-		return color => prepare(color);
-	}
-	const destMode = typeof gamut === 'string' ? gamut : mode;
-	const destConv = converter(destMode);
-	const inDestGamut = inGamut(destMode);
-	return color => {
-		const original = prepare(color);
-		if (!original) {
-			return undefined;
-		}
-		const converted = destConv(original);
-		if (inDestGamut(converted)) {
-			return original;
-		}
-		const clamped = fixup_rgb(converted);
-		if (original.mode === clamped.mode) {
-			return clamped;
-		}
-		return converter(original.mode)(clamped);
-	};
-}
-
-/*
-	Obtain a color that’s in a RGB gamut (by default sRGB)
-	by first converting it to `mode` and then finding 
-	the greatest chroma value that fits the gamut.
-
-	By default, the CIELCh color space is used,
-	but any color that has a chroma component will do.
-
-	The result is returned in the color's original color space.
- */
-export function clampChroma(color, mode = 'lch', rgbGamut = 'rgb') {
-	color = prepare(color);
-
-	let inDestinationGamut =
-		rgbGamut === 'rgb' ? displayable : inGamut(rgbGamut);
-	let clipToGamut =
-		rgbGamut === 'rgb' ? to_displayable_srgb : clampGamut(rgbGamut);
-
-	// if the color is undefined or displayable, return it directly
-	if (color === undefined || inDestinationGamut(color)) return color;
-
-	// keep track of color's original mode
-	let conv = converter(color.mode);
-
-	// convert to the provided `mode` for clamping
-	color = converter(mode)(color);
-
-	// try with chroma = 0
-	let clamped = { ...color, c: 0 };
-
-	// if not even chroma = 0 is displayable
-	// fall back to RGB clamping
-	if (!inDestinationGamut(clamped)) {
-		return conv(clipToGamut(clamped));
-	}
-
-	// By this time we know chroma = 0 is displayable and our current chroma is not.
-	// Find the displayable chroma through the bisection method.
-	let start = 0;
-	let end = color.c !== undefined ? color.c : 0;
-	let range = getMode(mode).ranges.c;
-	let resolution = (range[1] - range[0]) / Math.pow(2, 13);
-	let _last_good_c = clamped.c;
-
-	while (end - start > resolution) {
-		clamped.c = start + (end - start) * 0.5;
-		if (inDestinationGamut(clamped)) {
-			_last_good_c = clamped.c;
-			start = clamped.c;
-		} else {
-			end = clamped.c;
-		}
-	}
-
-	return conv(
-		inDestinationGamut(clamped) ? clamped : { ...clamped, c: _last_good_c }
-	);
-}
-
-/*
-	Obtain a color that's in the `dest` gamut,
-	by first converting it to the `mode` color space
-	and then finding the largest chroma that's in gamut,
-	similar to `clampChroma`. 
-
-	The color returned is in the `dest` color space.
-
-	To address the shortcomings of `clampChroma`, which can
-	sometimes produce colors more desaturated than necessary,
-	the test used in the binary search is replaced with
-	"is color is roughly in gamut", by comparing the candidate 
-	to the clipped version (obtained with `clampGamut`).
-	The test passes if the colors are not too dissimilar, 
-	judged by the `delta` color difference function 
-	and an associated `jnd` just-noticeable difference value.
-
-	The default arguments for this function correspond to the
-	gamut mapping algorithm defined in CSS Color Level 4:
-	https://drafts.csswg.org/css-color/#css-gamut-mapping
-
-	To disable the “roughly in gamut” part, pass either
-	`null` for the `delta` parameter, or zero for `jnd`.
- */
-export function toGamut(
-	dest = 'rgb',
-	mode = 'oklch',
-	delta = differenceEuclidean('oklch'),
-	jnd = 0.02
-) {
-	const destConv = converter(dest);
-	const destMode = getMode(dest);
-
-	if (!destMode.gamut) {
-		return color => destConv(color);
-	}
-
-	const inDestinationGamut = inGamut(dest);
-	const clipToGamut = clampGamut(dest);
-
-	const ucs = converter(mode);
-	const { ranges } = getMode(mode);
-
-	if (!ranges.l || !ranges.c) {
-		throw new Error('LCH-like space expected');
-	}
-
-	return color => {
-		color = prepare(color);
-		if (color === undefined) {
-			return undefined;
-		}
-		const candidate = { ...ucs(color) };
-
-		// account for missing components
-		if (candidate.l === undefined) candidate.l = 0;
-		if (candidate.c === undefined) candidate.c = 0;
-
-		if (candidate.l >= ranges.l[1]) {
-			const res = { ...destMode.white, mode: dest };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (candidate.l <= ranges.l[0]) {
-			const res = { ...destMode.black, mode: dest };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (inDestinationGamut(candidate)) {
-			return destConv(candidate);
-		}
-		let start = 0;
-		let end = candidate.c;
-		let epsilon = (ranges.c[1] - ranges.c[0]) / 4000; // 0.0001 for oklch()
-		let clipped = clipToGamut(candidate);
-		while (end - start > epsilon) {
-			candidate.c = (start + end) * 0.5;
-			clipped = clipToGamut(candidate);
-			if (
-				inDestinationGamut(candidate) ||
-				(delta && jnd > 0 && delta(candidate, clipped) <= jnd)
-			) {
-				start = candidate.c;
-			} else {
-				end = candidate.c;
-			}
-		}
-		return destConv(inDestinationGamut(candidate) ? candidate : clipped);
-	};
-}
diff --git a/src/colors/named.js b/src/colors/named.js
deleted file mode 100644
index 2e8bb597..00000000
--- a/src/colors/named.js
+++ /dev/null
@@ -1,156 +0,0 @@
-const named = {
-	aliceblue: 0xf0f8ff,
-	antiquewhite: 0xfaebd7,
-	aqua: 0x00ffff,
-	aquamarine: 0x7fffd4,
-	azure: 0xf0ffff,
-	beige: 0xf5f5dc,
-	bisque: 0xffe4c4,
-	black: 0x000000,
-	blanchedalmond: 0xffebcd,
-	blue: 0x0000ff,
-	blueviolet: 0x8a2be2,
-	brown: 0xa52a2a,
-	burlywood: 0xdeb887,
-	cadetblue: 0x5f9ea0,
-	chartreuse: 0x7fff00,
-	chocolate: 0xd2691e,
-	coral: 0xff7f50,
-	cornflowerblue: 0x6495ed,
-	cornsilk: 0xfff8dc,
-	crimson: 0xdc143c,
-	cyan: 0x00ffff,
-	darkblue: 0x00008b,
-	darkcyan: 0x008b8b,
-	darkgoldenrod: 0xb8860b,
-	darkgray: 0xa9a9a9,
-	darkgreen: 0x006400,
-	darkgrey: 0xa9a9a9,
-	darkkhaki: 0xbdb76b,
-	darkmagenta: 0x8b008b,
-	darkolivegreen: 0x556b2f,
-	darkorange: 0xff8c00,
-	darkorchid: 0x9932cc,
-	darkred: 0x8b0000,
-	darksalmon: 0xe9967a,
-	darkseagreen: 0x8fbc8f,
-	darkslateblue: 0x483d8b,
-	darkslategray: 0x2f4f4f,
-	darkslategrey: 0x2f4f4f,
-	darkturquoise: 0x00ced1,
-	darkviolet: 0x9400d3,
-	deeppink: 0xff1493,
-	deepskyblue: 0x00bfff,
-	dimgray: 0x696969,
-	dimgrey: 0x696969,
-	dodgerblue: 0x1e90ff,
-	firebrick: 0xb22222,
-	floralwhite: 0xfffaf0,
-	forestgreen: 0x228b22,
-	fuchsia: 0xff00ff,
-	gainsboro: 0xdcdcdc,
-	ghostwhite: 0xf8f8ff,
-	gold: 0xffd700,
-	goldenrod: 0xdaa520,
-	gray: 0x808080,
-	green: 0x008000,
-	greenyellow: 0xadff2f,
-	grey: 0x808080,
-	honeydew: 0xf0fff0,
-	hotpink: 0xff69b4,
-	indianred: 0xcd5c5c,
-	indigo: 0x4b0082,
-	ivory: 0xfffff0,
-	khaki: 0xf0e68c,
-	lavender: 0xe6e6fa,
-	lavenderblush: 0xfff0f5,
-	lawngreen: 0x7cfc00,
-	lemonchiffon: 0xfffacd,
-	lightblue: 0xadd8e6,
-	lightcoral: 0xf08080,
-	lightcyan: 0xe0ffff,
-	lightgoldenrodyellow: 0xfafad2,
-	lightgray: 0xd3d3d3,
-	lightgreen: 0x90ee90,
-	lightgrey: 0xd3d3d3,
-	lightpink: 0xffb6c1,
-	lightsalmon: 0xffa07a,
-	lightseagreen: 0x20b2aa,
-	lightskyblue: 0x87cefa,
-	lightslategray: 0x778899,
-	lightslategrey: 0x778899,
-	lightsteelblue: 0xb0c4de,
-	lightyellow: 0xffffe0,
-	lime: 0x00ff00,
-	limegreen: 0x32cd32,
-	linen: 0xfaf0e6,
-	magenta: 0xff00ff,
-	maroon: 0x800000,
-	mediumaquamarine: 0x66cdaa,
-	mediumblue: 0x0000cd,
-	mediumorchid: 0xba55d3,
-	mediumpurple: 0x9370db,
-	mediumseagreen: 0x3cb371,
-	mediumslateblue: 0x7b68ee,
-	mediumspringgreen: 0x00fa9a,
-	mediumturquoise: 0x48d1cc,
-	mediumvioletred: 0xc71585,
-	midnightblue: 0x191970,
-	mintcream: 0xf5fffa,
-	mistyrose: 0xffe4e1,
-	moccasin: 0xffe4b5,
-	navajowhite: 0xffdead,
-	navy: 0x000080,
-	oldlace: 0xfdf5e6,
-	olive: 0x808000,
-	olivedrab: 0x6b8e23,
-	orange: 0xffa500,
-	orangered: 0xff4500,
-	orchid: 0xda70d6,
-	palegoldenrod: 0xeee8aa,
-	palegreen: 0x98fb98,
-	paleturquoise: 0xafeeee,
-	palevioletred: 0xdb7093,
-	papayawhip: 0xffefd5,
-	peachpuff: 0xffdab9,
-	peru: 0xcd853f,
-	pink: 0xffc0cb,
-	plum: 0xdda0dd,
-	powderblue: 0xb0e0e6,
-	purple: 0x800080,
-
-	// Added in CSS Colors Level 4:
-	// https://drafts.csswg.org/css-color/#changes-from-3
-	rebeccapurple: 0x663399,
-
-	red: 0xff0000,
-	rosybrown: 0xbc8f8f,
-	royalblue: 0x4169e1,
-	saddlebrown: 0x8b4513,
-	salmon: 0xfa8072,
-	sandybrown: 0xf4a460,
-	seagreen: 0x2e8b57,
-	seashell: 0xfff5ee,
-	sienna: 0xa0522d,
-	silver: 0xc0c0c0,
-	skyblue: 0x87ceeb,
-	slateblue: 0x6a5acd,
-	slategray: 0x708090,
-	slategrey: 0x708090,
-	snow: 0xfffafa,
-	springgreen: 0x00ff7f,
-	steelblue: 0x4682b4,
-	tan: 0xd2b48c,
-	teal: 0x008080,
-	thistle: 0xd8bfd8,
-	tomato: 0xff6347,
-	turquoise: 0x40e0d0,
-	violet: 0xee82ee,
-	wheat: 0xf5deb3,
-	white: 0xffffff,
-	whitesmoke: 0xf5f5f5,
-	yellow: 0xffff00,
-	yellowgreen: 0x9acd32
-};
-
-export default named;
diff --git a/src/constants.js b/src/constants.js
deleted file mode 100644
index d80aea96..00000000
--- a/src/constants.js
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
-	The XYZ tristimulus values (white point)
-	of standard illuminants for the CIE 1931 2° 
-	standard observer.
-
-	See: https://en.wikipedia.org/wiki/Standard_illuminant
- */
-
-export const D50 = {
-	X: 0.3457 / 0.3585,
-	Y: 1,
-	Z: (1 - 0.3457 - 0.3585) / 0.3585
-};
-
-export const D65 = {
-	X: 0.3127 / 0.329,
-	Y: 1,
-	Z: (1 - 0.3127 - 0.329) / 0.329
-};
-
-export const k = Math.pow(29, 3) / Math.pow(3, 3);
-export const e = Math.pow(6, 3) / Math.pow(29, 3);
diff --git a/src/converter.js b/src/converter.js
deleted file mode 100644
index 0eabd3df..00000000
--- a/src/converter.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import { converters } from './modes.js';
-import prepare from './_prepare.js';
-
-const converter =
-	(target_mode = 'rgb') =>
-	color =>
-		(color = prepare(color, target_mode)) !== undefined
-			? // if the color's mode corresponds to our target mode
-			  color.mode === target_mode
-				? // then just return the color
-				  color
-				: // otherwise check to see if we have a dedicated
-				// converter for the target mode
-				converters[color.mode][target_mode]
-				? // and return its result...
-				  converters[color.mode][target_mode](color)
-				: // ...otherwise pass through RGB as an intermediary step.
-				// if the target mode is RGB...
-				target_mode === 'rgb'
-				? // just return the RGB
-				  converters[color.mode].rgb(color)
-				: // otherwise convert color.mode -> RGB -> target_mode
-				  converters.rgb[target_mode](converters[color.mode].rgb(color))
-			: undefined;
-
-export default converter;
diff --git a/src/cubehelix/constants.js b/src/cubehelix/constants.js
deleted file mode 100644
index 7a90b348..00000000
--- a/src/cubehelix/constants.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export const M = [-0.14861, 1.78277, -0.29227, -0.90649, 1.97294, 0];
-
-export const degToRad = Math.PI / 180;
-export const radToDeg = 180 / Math.PI;
diff --git a/src/cubehelix/convertCubehelixToRgb.js b/src/cubehelix/convertCubehelixToRgb.js
deleted file mode 100644
index 5c05b279..00000000
--- a/src/cubehelix/convertCubehelixToRgb.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import { degToRad, M } from './constants.js';
-
-const convertCubehelixToRgb = ({ h, s, l, alpha }) => {
-	let res = { mode: 'rgb' };
-
-	h = (h === undefined ? 0 : h + 120) * degToRad;
-	if (l === undefined) l = 0;
-
-	let amp = s === undefined ? 0 : s * l * (1 - l);
-
-	let cosh = Math.cos(h);
-	let sinh = Math.sin(h);
-
-	res.r = l + amp * (M[0] * cosh + M[1] * sinh);
-	res.g = l + amp * (M[2] * cosh + M[3] * sinh);
-	res.b = l + amp * (M[4] * cosh + M[5] * sinh);
-
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertCubehelixToRgb;
diff --git a/src/cubehelix/convertRgbToCubehelix.js b/src/cubehelix/convertRgbToCubehelix.js
deleted file mode 100644
index 80d50076..00000000
--- a/src/cubehelix/convertRgbToCubehelix.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-	Convert a RGB color to the Cubehelix HSL color space.
-
-	This computation is not present in Green's paper:
-	https://arxiv.org/pdf/1108.5083.pdf
-
-	...but can be derived from the inverse, HSL to RGB conversion.
-
-	It matches the math in Mike Bostock's D3 implementation:
-
-	https://github.com/d3/d3-color/blob/master/src/cubehelix.js
- */
-
-import { radToDeg, M } from './constants.js';
-
-let DE = M[3] * M[4];
-let BE = M[1] * M[4];
-let BCAD = M[1] * M[2] - M[0] * M[3];
-
-const convertRgbToCubehelix = ({ r, g, b, alpha }) => {
-	if (r === undefined) r = 0;
-	if (g === undefined) g = 0;
-	if (b === undefined) b = 0;
-	let l = (BCAD * b + r * DE - g * BE) / (BCAD + DE - BE);
-	let x = b - l;
-	let y = (M[4] * (g - l) - M[2] * x) / M[3];
-
-	let res = {
-		mode: 'cubehelix',
-		l: l,
-		s:
-			l === 0 || l === 1
-				? undefined
-				: Math.sqrt(x * x + y * y) / (M[4] * l * (1 - l))
-	};
-
-	if (res.s) res.h = Math.atan2(y, x) * radToDeg - 120;
-	if (alpha !== undefined) res.alpha = alpha;
-
-	return res;
-};
-
-export default convertRgbToCubehelix;
diff --git a/src/cubehelix/definition.js b/src/cubehelix/definition.js
deleted file mode 100644
index 81be15d1..00000000
--- a/src/cubehelix/definition.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/* 
-	Dave Green's Cubehelix
-	----------------------
-
-	Green, D. A., 2011, "A colour scheme for the display of astronomical intensity images", 
-	Bulletin of the Astronomical Society of India, 39, 289. (2011BASI...39..289G at ADS.) 
-
-	https://www.mrao.cam.ac.uk/%7Edag/CUBEHELIX/
-	https://arxiv.org/pdf/1108.5083.pdf
-
-	Although Cubehelix was defined to be a method to obtain a colour scheme,
-	it actually contains a definition of a colour space, as identified by 
-	Mike Bostock and implemented in D3.js.
-
-	Green's paper introduces the following terminology:
-
-	* 	a `lightness` dimension in the interval [0, 1] 
-		on which we interpolate to obtain the colour scheme
-	*	a `start` colour that is analogous to a Hue in HSL space
-	*	a number of `rotations` around the Hue cylinder.
-	*	a `hue` parameter which should more appropriately be called `saturation`
-	
-	As such, the original definition of the Cubehelix scheme is actually an
-	interpolation between two colors in the Cubehelix space:
-
-	H: start 				H: start + 360 * rotations
-	S: hue 			->		S: hue
-	L: 0					L: 1
-
-	We can therefore extend the interpolation to any two colors in this space,
-	with a variable Saturation and a Lightness interval other than the fixed 0 -> 1.
-*/
-
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import convertRgbToCubehelix from './convertRgbToCubehelix.js';
-import convertCubehelixToRgb from './convertCubehelixToRgb.js';
-import { differenceHueSaturation } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'cubehelix',
-	channels: ['h', 's', 'l', 'alpha'],
-	parse: ['--cubehelix'],
-	serialize: '--cubehelix',
-
-	ranges: {
-		h: [0, 360],
-		s: [0, 4.614],
-		l: [0, 1]
-	},
-
-	fromMode: {
-		rgb: convertRgbToCubehelix
-	},
-
-	toMode: {
-		rgb: convertCubehelixToRgb
-	},
-
-	interpolate: {
-		h: {
-			use: interpolatorLinear,
-			fixup: fixupHueShorter
-		},
-		s: interpolatorLinear,
-		l: interpolatorLinear,
-		alpha: {
-			use: interpolatorLinear,
-			fixup: fixupAlpha
-		}
-	},
-
-	difference: {
-		h: differenceHueSaturation
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/deficiency.js b/src/deficiency.js
deleted file mode 100644
index be66bd09..00000000
--- a/src/deficiency.js
+++ /dev/null
@@ -1,190 +0,0 @@
-import converter from './converter.js';
-import prepare from './_prepare.js';
-import { lerp } from './interpolate/lerp.js';
-
-let rgb = converter('rgb');
-
-/*
-	Color vision deficiency (CVD) simulation based on:
-
-		G. M. Machado, M. M. Oliveira and L. A. F. Fernandes, 
-		"A Physiologically-based Model for Simulation of Color Vision Deficiency" 
-		in IEEE Transactions on Visualization and Computer Graphics, 
-		vol. 15, no. 6, pp. 1291-1298, Nov.-Dec. 2009, 
-		doi: 10.1109/TVCG.2009.113.
-
-	Functions use precomputed matrices from:
-
-		https://www.inf.ufrgs.br/~oliveira/pubs_files/CVD_Simulation/CVD_Simulation.html
-
-	Via the `colorspace` R package documentation:
-
-		http://colorspace.r-forge.r-project.org/reference/simulate_cvd.html
- */
-
-const PROT = [
-	[1.0, 0.0, -0.0, 0.0, 1.0, 0.0, -0.0, -0.0, 1.0],
-	[
-		0.856167, 0.182038, -0.038205, 0.029342, 0.955115, 0.015544, -0.00288,
-		-0.001563, 1.004443
-	],
-	[
-		0.734766, 0.334872, -0.069637, 0.05184, 0.919198, 0.028963, -0.004928,
-		-0.004209, 1.009137
-	],
-	[
-		0.630323, 0.465641, -0.095964, 0.069181, 0.890046, 0.040773, -0.006308,
-		-0.007724, 1.014032
-	],
-	[
-		0.539009, 0.579343, -0.118352, 0.082546, 0.866121, 0.051332, -0.007136,
-		-0.011959, 1.019095
-	],
-	[
-		0.458064, 0.679578, -0.137642, 0.092785, 0.846313, 0.060902, -0.007494,
-		-0.016807, 1.024301
-	],
-	[
-		0.38545, 0.769005, -0.154455, 0.100526, 0.829802, 0.069673, -0.007442,
-		-0.02219, 1.029632
-	],
-	[
-		0.319627, 0.849633, -0.169261, 0.106241, 0.815969, 0.07779, -0.007025,
-		-0.028051, 1.035076
-	],
-	[
-		0.259411, 0.923008, -0.18242, 0.110296, 0.80434, 0.085364, -0.006276,
-		-0.034346, 1.040622
-	],
-	[
-		0.203876, 0.990338, -0.194214, 0.112975, 0.794542, 0.092483, -0.005222,
-		-0.041043, 1.046265
-	],
-	[
-		0.152286, 1.052583, -0.204868, 0.114503, 0.786281, 0.099216, -0.003882,
-		-0.048116, 1.051998
-	]
-];
-
-const DEUTER = [
-	[1.0, 0.0, -0.0, 0.0, 1.0, 0.0, -0.0, -0.0, 1.0],
-	[
-		0.866435, 0.177704, -0.044139, 0.049567, 0.939063, 0.01137, -0.003453,
-		0.007233, 0.99622
-	],
-	[
-		0.760729, 0.319078, -0.079807, 0.090568, 0.889315, 0.020117, -0.006027,
-		0.013325, 0.992702
-	],
-	[
-		0.675425, 0.43385, -0.109275, 0.125303, 0.847755, 0.026942, -0.00795,
-		0.018572, 0.989378
-	],
-	[
-		0.605511, 0.52856, -0.134071, 0.155318, 0.812366, 0.032316, -0.009376,
-		0.023176, 0.9862
-	],
-	[
-		0.547494, 0.607765, -0.155259, 0.181692, 0.781742, 0.036566, -0.01041,
-		0.027275, 0.983136
-	],
-	[
-		0.498864, 0.674741, -0.173604, 0.205199, 0.754872, 0.039929, -0.011131,
-		0.030969, 0.980162
-	],
-	[
-		0.457771, 0.731899, -0.18967, 0.226409, 0.731012, 0.042579, -0.011595,
-		0.034333, 0.977261
-	],
-	[
-		0.422823, 0.781057, -0.203881, 0.245752, 0.709602, 0.044646, -0.011843,
-		0.037423, 0.974421
-	],
-	[
-		0.392952, 0.82361, -0.216562, 0.263559, 0.69021, 0.046232, -0.01191,
-		0.040281, 0.97163
-	],
-	[
-		0.367322, 0.860646, -0.227968, 0.280085, 0.672501, 0.047413, -0.01182,
-		0.04294, 0.968881
-	]
-];
-
-const TRIT = [
-	[1.0, 0.0, -0.0, 0.0, 1.0, 0.0, -0.0, -0.0, 1.0],
-	[
-		0.92667, 0.092514, -0.019184, 0.021191, 0.964503, 0.014306, 0.008437,
-		0.054813, 0.93675
-	],
-	[
-		0.89572, 0.13333, -0.02905, 0.029997, 0.9454, 0.024603, 0.013027,
-		0.104707, 0.882266
-	],
-	[
-		0.905871, 0.127791, -0.033662, 0.026856, 0.941251, 0.031893, 0.01341,
-		0.148296, 0.838294
-	],
-	[
-		0.948035, 0.08949, -0.037526, 0.014364, 0.946792, 0.038844, 0.010853,
-		0.193991, 0.795156
-	],
-	[
-		1.017277, 0.027029, -0.044306, -0.006113, 0.958479, 0.047634, 0.006379,
-		0.248708, 0.744913
-	],
-	[
-		1.104996, -0.046633, -0.058363, -0.032137, 0.971635, 0.060503, 0.001336,
-		0.317922, 0.680742
-	],
-	[
-		1.193214, -0.109812, -0.083402, -0.058496, 0.97941, 0.079086, -0.002346,
-		0.403492, 0.598854
-	],
-	[
-		1.257728, -0.139648, -0.118081, -0.078003, 0.975409, 0.102594,
-		-0.003316, 0.501214, 0.502102
-	],
-	[
-		1.278864, -0.125333, -0.153531, -0.084748, 0.957674, 0.127074,
-		-0.000989, 0.601151, 0.399838
-	],
-	[
-		1.255528, -0.076749, -0.178779, -0.078411, 0.930809, 0.147602, 0.004733,
-		0.691367, 0.3039
-	]
-];
-
-const deficiency = (lut, t) => {
-	let tt = Math.max(0, Math.min(1, t));
-	let i = Math.round(tt / 0.1);
-	let w = Math.round(tt % 0.1);
-	let arr = lut[i];
-	if (w > 0 && i < lut.length - 1) {
-		let arr_2 = lut[i + 1];
-		arr = arr.map((v, idx) => lerp(arr[idx], arr_2[idx], w));
-	}
-	return color => {
-		let c = prepare(color);
-		if (c === undefined) {
-			return undefined;
-		}
-		let { r, g, b } = rgb(c);
-		let ret = {
-			mode: 'rgb',
-			r: arr[0] * r + arr[1] * g + arr[2] * b,
-			g: arr[3] * r + arr[4] * g + arr[5] * b,
-			b: arr[6] * r + arr[7] * g + arr[8] * b
-		};
-		if (c.alpha !== undefined) {
-			ret.alpha = c.alpha;
-		}
-		return converter(c.mode)(ret);
-	};
-};
-
-export const filterDeficiencyProt = (severity = 1) =>
-	deficiency(PROT, severity);
-export const filterDeficiencyDeuter = (severity = 1) =>
-	deficiency(DEUTER, severity);
-export const filterDeficiencyTrit = (severity = 1) =>
-	deficiency(TRIT, severity);
diff --git a/src/difference.js b/src/difference.js
deleted file mode 100644
index 8f383d53..00000000
--- a/src/difference.js
+++ /dev/null
@@ -1,315 +0,0 @@
-import { getMode } from './modes.js';
-import converter from './converter.js';
-import normalizeHue from './util/normalizeHue.js';
-
-const differenceHueSaturation = (std, smp) => {
-	if (std.h === undefined || smp.h === undefined || !std.s || !smp.s) {
-		return 0;
-	}
-	let std_h = normalizeHue(std.h);
-	let smp_h = normalizeHue(smp.h);
-	let dH = Math.sin((((smp_h - std_h + 360) / 2) * Math.PI) / 180);
-	return 2 * Math.sqrt(std.s * smp.s) * dH;
-};
-
-const differenceHueNaive = (std, smp) => {
-	if (std.h === undefined || smp.h === undefined) {
-		return 0;
-	}
-	let std_h = normalizeHue(std.h);
-	let smp_h = normalizeHue(smp.h);
-	if (Math.abs(smp_h - std_h) > 180) {
-		// todo should this be normalized once again?
-		return std_h - (smp_h - 360 * Math.sign(smp_h - std_h));
-	}
-	return smp_h - std_h;
-};
-
-const differenceHueChroma = (std, smp) => {
-	if (std.h === undefined || smp.h === undefined || !std.c || !smp.c) {
-		return 0;
-	}
-	let std_h = normalizeHue(std.h);
-	let smp_h = normalizeHue(smp.h);
-	let dH = Math.sin((((smp_h - std_h + 360) / 2) * Math.PI) / 180);
-	return 2 * Math.sqrt(std.c * smp.c) * dH;
-};
-
-const differenceEuclidean = (mode = 'rgb', weights = [1, 1, 1, 0]) => {
-	let def = getMode(mode);
-	let channels = def.channels;
-	let diffs = def.difference;
-	let conv = converter(mode);
-	return (std, smp) => {
-		let ConvStd = conv(std);
-		let ConvSmp = conv(smp);
-		return Math.sqrt(
-			channels.reduce((sum, k, idx) => {
-				let delta = diffs[k]
-					? diffs[k](ConvStd, ConvSmp)
-					: ConvStd[k] - ConvSmp[k];
-				return (
-					sum +
-					(weights[idx] || 0) * Math.pow(isNaN(delta) ? 0 : delta, 2)
-				);
-			}, 0)
-		);
-	};
-};
-
-const differenceCie76 = () => differenceEuclidean('lab65');
-
-const differenceCie94 = (kL = 1, K1 = 0.045, K2 = 0.015) => {
-	let lab = converter('lab65');
-
-	return (std, smp) => {
-		let LabStd = lab(std);
-		let LabSmp = lab(smp);
-
-		// Extract Lab values, and compute Chroma
-		let lStd = LabStd.l;
-		let aStd = LabStd.a;
-		let bStd = LabStd.b;
-		let cStd = Math.sqrt(aStd * aStd + bStd * bStd);
-
-		let lSmp = LabSmp.l;
-		let aSmp = LabSmp.a;
-		let bSmp = LabSmp.b;
-		let cSmp = Math.sqrt(aSmp * aSmp + bSmp * bSmp);
-
-		let dL2 = Math.pow(lStd - lSmp, 2);
-		let dC2 = Math.pow(cStd - cSmp, 2);
-		let dH2 = Math.pow(aStd - aSmp, 2) + Math.pow(bStd - bSmp, 2) - dC2;
-
-		return Math.sqrt(
-			dL2 / Math.pow(kL, 2) +
-				dC2 / Math.pow(1 + K1 * cStd, 2) +
-				dH2 / Math.pow(1 + K2 * cStd, 2)
-		);
-	};
-};
-
-/*
-	CIEDE2000 color difference, original Matlab implementation by Gaurav Sharma
-	Based on "The CIEDE2000 Color-Difference Formula: Implementation Notes, Supplementary Test Data, and Mathematical Observations" 
-	by Gaurav Sharma, Wencheng Wu, Edul N. Dalal in Color Research and Application, vol. 30. No. 1, pp. 21-30, February 2005.
-	http://www2.ece.rochester.edu/~gsharma/ciede2000/
- */
-
-const differenceCiede2000 = (Kl = 1, Kc = 1, Kh = 1) => {
-	let lab = converter('lab65');
-	return (std, smp) => {
-		let LabStd = lab(std);
-		let LabSmp = lab(smp);
-
-		let lStd = LabStd.l;
-		let aStd = LabStd.a;
-		let bStd = LabStd.b;
-		let cStd = Math.sqrt(aStd * aStd + bStd * bStd);
-
-		let lSmp = LabSmp.l;
-		let aSmp = LabSmp.a;
-		let bSmp = LabSmp.b;
-		let cSmp = Math.sqrt(aSmp * aSmp + bSmp * bSmp);
-
-		let cAvg = (cStd + cSmp) / 2;
-
-		let G =
-			0.5 *
-			(1 -
-				Math.sqrt(
-					Math.pow(cAvg, 7) / (Math.pow(cAvg, 7) + Math.pow(25, 7))
-				));
-
-		let apStd = aStd * (1 + G);
-		let apSmp = aSmp * (1 + G);
-
-		let cpStd = Math.sqrt(apStd * apStd + bStd * bStd);
-		let cpSmp = Math.sqrt(apSmp * apSmp + bSmp * bSmp);
-
-		let hpStd =
-			Math.abs(apStd) + Math.abs(bStd) === 0
-				? 0
-				: Math.atan2(bStd, apStd);
-		hpStd += (hpStd < 0) * 2 * Math.PI;
-
-		let hpSmp =
-			Math.abs(apSmp) + Math.abs(bSmp) === 0
-				? 0
-				: Math.atan2(bSmp, apSmp);
-		hpSmp += (hpSmp < 0) * 2 * Math.PI;
-
-		let dL = lSmp - lStd;
-		let dC = cpSmp - cpStd;
-
-		let dhp = cpStd * cpSmp === 0 ? 0 : hpSmp - hpStd;
-		dhp -= (dhp > Math.PI) * 2 * Math.PI;
-		dhp += (dhp < -Math.PI) * 2 * Math.PI;
-
-		let dH = 2 * Math.sqrt(cpStd * cpSmp) * Math.sin(dhp / 2);
-
-		let Lp = (lStd + lSmp) / 2;
-		let Cp = (cpStd + cpSmp) / 2;
-
-		let hp;
-		if (cpStd * cpSmp === 0) {
-			hp = hpStd + hpSmp;
-		} else {
-			hp = (hpStd + hpSmp) / 2;
-			hp -= (Math.abs(hpStd - hpSmp) > Math.PI) * Math.PI;
-			hp += (hp < 0) * 2 * Math.PI;
-		}
-
-		let Lpm50 = Math.pow(Lp - 50, 2);
-		let T =
-			1 -
-			0.17 * Math.cos(hp - Math.PI / 6) +
-			0.24 * Math.cos(2 * hp) +
-			0.32 * Math.cos(3 * hp + Math.PI / 30) -
-			0.2 * Math.cos(4 * hp - (63 * Math.PI) / 180);
-
-		let Sl = 1 + (0.015 * Lpm50) / Math.sqrt(20 + Lpm50);
-		let Sc = 1 + 0.045 * Cp;
-		let Sh = 1 + 0.015 * Cp * T;
-
-		let deltaTheta =
-			((30 * Math.PI) / 180) *
-			Math.exp(-1 * Math.pow(((180 / Math.PI) * hp - 275) / 25, 2));
-		let Rc =
-			2 *
-			Math.sqrt(Math.pow(Cp, 7) / (Math.pow(Cp, 7) + Math.pow(25, 7)));
-
-		let Rt = -1 * Math.sin(2 * deltaTheta) * Rc;
-
-		return Math.sqrt(
-			Math.pow(dL / (Kl * Sl), 2) +
-				Math.pow(dC / (Kc * Sc), 2) +
-				Math.pow(dH / (Kh * Sh), 2) +
-				(((Rt * dC) / (Kc * Sc)) * dH) / (Kh * Sh)
-		);
-	};
-};
-
-/*
-	CMC (l:c) difference formula
-
-	References:
-		https://en.wikipedia.org/wiki/Color_difference#CMC_l:c_(1984)
-		http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CMC.html
- */
-const differenceCmc = (l = 1, c = 1) => {
-	let lab = converter('lab65');
-
-	/*
-		Comparte two colors:
-		std - standard (first) color
-		smp - sample (second) color
-	 */
-	return (std, smp) => {
-		// convert standard color to Lab
-		let LabStd = lab(std);
-		let lStd = LabStd.l;
-		let aStd = LabStd.a;
-		let bStd = LabStd.b;
-
-		// Obtain hue/chroma
-		let cStd = Math.sqrt(aStd * aStd + bStd * bStd);
-		let hStd = Math.atan2(bStd, aStd);
-		hStd = hStd + 2 * Math.PI * (hStd < 0);
-
-		// convert sample color to Lab, obtain LCh
-		let LabSmp = lab(smp);
-		let lSmp = LabSmp.l;
-		let aSmp = LabSmp.a;
-		let bSmp = LabSmp.b;
-
-		// Obtain chroma
-		let cSmp = Math.sqrt(aSmp * aSmp + bSmp * bSmp);
-
-		// lightness delta squared
-		let dL2 = Math.pow(lStd - lSmp, 2);
-
-		// chroma delta squared
-		let dC2 = Math.pow(cStd - cSmp, 2);
-
-		// hue delta squared
-		let dH2 = Math.pow(aStd - aSmp, 2) + Math.pow(bStd - bSmp, 2) - dC2;
-
-		let F = Math.sqrt(Math.pow(cStd, 4) / (Math.pow(cStd, 4) + 1900));
-		let T =
-			hStd >= (164 / 180) * Math.PI && hStd <= (345 / 180) * Math.PI
-				? 0.56 + Math.abs(0.2 * Math.cos(hStd + (168 / 180) * Math.PI))
-				: 0.36 + Math.abs(0.4 * Math.cos(hStd + (35 / 180) * Math.PI));
-
-		let Sl = lStd < 16 ? 0.511 : (0.040975 * lStd) / (1 + 0.01765 * lStd);
-		let Sc = (0.0638 * cStd) / (1 + 0.0131 * cStd) + 0.638;
-		let Sh = Sc * (F * T + 1 - F);
-
-		return Math.sqrt(
-			dL2 / Math.pow(l * Sl, 2) +
-				dC2 / Math.pow(c * Sc, 2) +
-				dH2 / Math.pow(Sh, 2)
-		);
-	};
-};
-
-/*
-
-	HyAB color difference formula, introduced in:
-
-		Abasi S, Amani Tehran M, Fairchild MD. 
-		"Distance metrics for very large color differences."
-		Color Res Appl. 2019; 1–16. 
-		https://doi.org/10.1002/col.22451
-
-	PDF available at:
-	
-		http://markfairchild.org/PDFs/PAP40.pdf
- */
-const differenceHyab = () => {
-	let lab = converter('lab65');
-	return (std, smp) => {
-		let LabStd = lab(std);
-		let LabSmp = lab(smp);
-		let dL = LabStd.l - LabSmp.l;
-		let dA = LabStd.a - LabSmp.a;
-		let dB = LabStd.b - LabSmp.b;
-		return Math.abs(dL) + Math.sqrt(dA * dA + dB * dB);
-	};
-};
-
-/*
-	"Measuring perceived color difference using YIQ NTSC
-	transmission color space in mobile applications"
-		
-		by Yuriy Kotsarenko, Fernando Ramos in:
-		Programación Matemática y Software (2010) 
-
-	Available at:
-		
-		http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf
- */
-const differenceKotsarenkoRamos = () =>
-	differenceEuclidean('yiq', [0.5053, 0.299, 0.1957]);
-
-/*
-	ΔE_ITP, as defined in Rec. ITU-R BT.2124:
-
-	https://www.itu.int/rec/R-REC-BT.2124/en
-*/
-const differenceItp = () =>
-	differenceEuclidean('itp', [518400, 129600, 518400]);
-
-export {
-	differenceHueChroma,
-	differenceHueSaturation,
-	differenceHueNaive,
-	differenceEuclidean,
-	differenceCie76,
-	differenceCie94,
-	differenceCiede2000,
-	differenceCmc,
-	differenceHyab,
-	differenceKotsarenkoRamos,
-	differenceItp
-};
diff --git a/src/dlab/definition.js b/src/dlab/definition.js
deleted file mode 100644
index ed2c8e28..00000000
--- a/src/dlab/definition.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import convertLabToLch from '../lch/convertLabToLch.js';
-import convertLchToLab from '../lch/convertLchToLab.js';
-import convertLab65ToRgb from '../lab65/convertLab65ToRgb.js';
-import convertRgbToLab65 from '../lab65/convertRgbToLab65.js';
-import convertDlchToLab65 from '../dlch/convertDlchToLab65.js';
-import convertLab65ToDlch from '../dlch/convertLab65ToDlch.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-const convertDlabToLab65 = c => convertDlchToLab65(convertLabToLch(c, 'dlch'));
-const convertLab65ToDlab = c => convertLchToLab(convertLab65ToDlch(c), 'dlab');
-
-const definition = {
-	mode: 'dlab',
-
-	parse: ['--din99o-lab'],
-	serialize: '--din99o-lab',
-
-	toMode: {
-		lab65: convertDlabToLab65,
-		rgb: c => convertLab65ToRgb(convertDlabToLab65(c))
-	},
-
-	fromMode: {
-		lab65: convertLab65ToDlab,
-		rgb: c => convertLab65ToDlab(convertRgbToLab65(c))
-	},
-
-	channels: ['l', 'a', 'b', 'alpha'],
-
-	ranges: {
-		l: [0, 100],
-		a: [-40.09, 45.501],
-		b: [-40.469, 44.344]
-	},
-
-	interpolate: {
-		l: interpolatorLinear,
-		a: interpolatorLinear,
-		b: interpolatorLinear,
-		alpha: {
-			use: interpolatorLinear,
-			fixup: fixupAlpha
-		}
-	}
-};
-
-export default definition;
diff --git a/src/dlch/constants.js b/src/dlch/constants.js
deleted file mode 100644
index 61ce019a..00000000
--- a/src/dlch/constants.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export const kE = 1;
-export const kCH = 1;
-export const θ = (26 / 180) * Math.PI;
-export const cosθ = Math.cos(θ);
-export const sinθ = Math.sin(θ);
-export const factor = 100 / Math.log(139 / 100); // ~ 303.67
diff --git a/src/dlch/convertDlchToLab65.js b/src/dlch/convertDlchToLab65.js
deleted file mode 100644
index ed4f7941..00000000
--- a/src/dlch/convertDlchToLab65.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import { kCH, kE, sinθ, cosθ, θ, factor } from './constants.js';
-
-/*
-	Convert DIN99o LCh to CIELab D65
-	--------------------------------
- */
-
-const convertDlchToLab65 = ({ l, c, h, alpha }) => {
-	if (l === undefined) l = 0;
-	if (c === undefined) c = 0;
-	if (h === undefined) h = 0;
-	let res = {
-		mode: 'lab65',
-		l: (Math.exp((l * kE) / factor) - 1) / 0.0039
-	};
-
-	let G = (Math.exp(0.0435 * c * kCH * kE) - 1) / 0.075;
-	let e = G * Math.cos((h / 180) * Math.PI - θ);
-	let f = G * Math.sin((h / 180) * Math.PI - θ);
-	res.a = e * cosθ - (f / 0.83) * sinθ;
-	res.b = e * sinθ + (f / 0.83) * cosθ;
-
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertDlchToLab65;
diff --git a/src/dlch/convertLab65ToDlch.js b/src/dlch/convertLab65ToDlch.js
deleted file mode 100644
index 29790a2c..00000000
--- a/src/dlch/convertLab65ToDlch.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { kCH, kE, sinθ, cosθ, θ, factor } from './constants.js';
-import normalizeHue from '../util/normalizeHue.js';
-
-/*
-	Convert CIELab D65 to DIN99o LCh
-	================================
- */
-
-const convertLab65ToDlch = ({ l, a, b, alpha }) => {
-	if (l === undefined) l = 0;
-	if (a === undefined) a = 0;
-	if (b === undefined) b = 0;
-	let e = a * cosθ + b * sinθ;
-	let f = 0.83 * (b * cosθ - a * sinθ);
-	let G = Math.sqrt(e * e + f * f);
-	let res = {
-		mode: 'dlch',
-		l: (factor / kE) * Math.log(1 + 0.0039 * l),
-		c: Math.log(1 + 0.075 * G) / (0.0435 * kCH * kE)
-	};
-
-	if (res.c) {
-		res.h = normalizeHue(((Math.atan2(f, e) + θ) / Math.PI) * 180);
-	}
-
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertLab65ToDlch;
diff --git a/src/dlch/definition.js b/src/dlch/definition.js
deleted file mode 100644
index 6e7be6b1..00000000
--- a/src/dlch/definition.js
+++ /dev/null
@@ -1,62 +0,0 @@
-import convertLabToLch from '../lch/convertLabToLch.js';
-import convertLchToLab from '../lch/convertLchToLab.js';
-import convertDlchToLab65 from './convertDlchToLab65.js';
-import convertLab65ToDlch from './convertLab65ToDlch.js';
-import convertLab65ToRgb from '../lab65/convertLab65ToRgb.js';
-import convertRgbToLab65 from '../lab65/convertRgbToLab65.js';
-
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueChroma } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'dlch',
-
-	parse: ['--din99o-lch'],
-	serialize: '--din99o-lch',
-
-	toMode: {
-		lab65: convertDlchToLab65,
-		dlab: c => convertLchToLab(c, 'dlab'),
-		rgb: c => convertLab65ToRgb(convertDlchToLab65(c))
-	},
-
-	fromMode: {
-		lab65: convertLab65ToDlch,
-		dlab: c => convertLabToLch(c, 'dlch'),
-		rgb: c => convertLab65ToDlch(convertRgbToLab65(c))
-	},
-
-	channels: ['l', 'c', 'h', 'alpha'],
-
-	ranges: {
-		l: [0, 100],
-		c: [0, 51.484],
-		h: [0, 360]
-	},
-
-	interpolate: {
-		l: interpolatorLinear,
-		c: interpolatorLinear,
-		h: {
-			use: interpolatorLinear,
-			fixup: fixupHueShorter
-		},
-		alpha: {
-			use: interpolatorLinear,
-			fixup: fixupAlpha
-		}
-	},
-
-	difference: {
-		h: differenceHueChroma
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/easing/gamma.js b/src/easing/gamma.js
deleted file mode 100644
index 47320513..00000000
--- a/src/easing/gamma.js
+++ /dev/null
@@ -1,3 +0,0 @@
-const gamma = (γ = 1) => (γ === 1 ? t => t : t => Math.pow(t, γ));
-
-export default gamma;
diff --git a/src/easing/inOutSine.js b/src/easing/inOutSine.js
deleted file mode 100644
index 9b4ed7ba..00000000
--- a/src/easing/inOutSine.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/* 
-	Sinusoidal (cosine) in-out easing
-*/
-const inOutSine = t => (1 - Math.cos(t * Math.PI)) / 2;
-
-export default inOutSine;
diff --git a/src/easing/midpoint.js b/src/easing/midpoint.js
deleted file mode 100644
index 28ce7810..00000000
--- a/src/easing/midpoint.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Color interpolation hint exponential function
-const midpoint = (H = 0.5) => t =>
-	H <= 0 ? 1 : H >= 1 ? 0 : Math.pow(t, Math.log(0.5) / Math.log(H));
-
-export default midpoint;
diff --git a/src/easing/smootherstep.js b/src/easing/smootherstep.js
deleted file mode 100644
index bebdc7b3..00000000
--- a/src/easing/smootherstep.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*
-	Smootherstep easing function proposed by K. Perlin
-	Reference: https://en.wikipedia.org/wiki/Smoothstep
- */
-const smootherstep = t => t * t * t * (t * (t * 6 - 15) + 10);
-
-export default smootherstep;
diff --git a/src/easing/smoothstep.js b/src/easing/smoothstep.js
deleted file mode 100644
index 246fe0c4..00000000
--- a/src/easing/smoothstep.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/*
-	Smoothstep easing function and its inverse
-	Reference: https://en.wikipedia.org/wiki/Smoothstep
- */
-const easingSmoothstep = t => t * t * (3 - 2 * t);
-const easingSmoothstepInverse = t => 0.5 - Math.sin(Math.asin(1 - 2 * t) / 3);
-
-export { easingSmoothstep, easingSmoothstepInverse };
diff --git a/src/filter.js b/src/filter.js
deleted file mode 100644
index 59199491..00000000
--- a/src/filter.js
+++ /dev/null
@@ -1,162 +0,0 @@
-import { mapper, mapTransferLinear } from './map.js';
-import converter from './converter.js';
-import prepare from './_prepare.js';
-import { getMode } from './modes.js';
-
-const minzero = v => Math.max(v, 0);
-const clamp = v => Math.max(Math.min(v, 1), 0);
-const lerp = (a, b, t) =>
-	a === undefined || b === undefined ? undefined : a + t * (b - a);
-
-const matrixSepia = amount => {
-	let a = 1 - clamp(amount);
-	return [
-		0.393 + 0.607 * a,
-		0.769 - 0.769 * a,
-		0.189 - 0.189 * a,
-		0,
-		0.349 - 0.349 * a,
-		0.686 + 0.314 * a,
-		0.168 - 0.168 * a,
-		0,
-		0.272 - 0.272 * a,
-		0.534 - 0.534 * a,
-		0.131 + 0.869 * a,
-		0,
-		0,
-		0,
-		0,
-		1
-	];
-};
-
-const matrixSaturate = sat => {
-	let s = minzero(sat);
-	return [
-		0.213 + 0.787 * s,
-		0.715 - 0.715 * s,
-		0.072 - 0.072 * s,
-		0,
-		0.213 - 0.213 * s,
-		0.715 + 0.285 * s,
-		0.072 - 0.072 * s,
-		0,
-		0.213 - 0.213 * s,
-		0.715 - 0.715 * s,
-		0.072 + 0.928 * s,
-		0,
-		0,
-		0,
-		0,
-		1
-	];
-};
-
-const matrixGrayscale = amount => {
-	let a = 1 - clamp(amount);
-	return [
-		0.2126 + 0.7874 * a,
-		0.7152 - 0.7152 * a,
-		0.0722 - 0.0722 * a,
-		0,
-		0.2126 - 0.2126 * a,
-		0.7152 + 0.2848 * a,
-		0.0722 - 0.0722 * a,
-		0,
-		0.2126 - 0.2126 * a,
-		0.7152 - 0.7152 * a,
-		0.0722 + 0.9278 * a,
-		0,
-		0,
-		0,
-		0,
-		1
-	];
-};
-
-const matrixHueRotate = degrees => {
-	let rad = (Math.PI * degrees) / 180;
-	let c = Math.cos(rad);
-	let s = Math.sin(rad);
-	return [
-		0.213 + c * 0.787 - s * 0.213,
-		0.715 - c * 0.715 - s * 0.715,
-		0.072 - c * 0.072 + s * 0.928,
-		0,
-		0.213 - c * 0.213 + s * 0.143,
-		0.715 + c * 0.285 + s * 0.14,
-		0.072 - c * 0.072 - s * 0.283,
-		0,
-		0.213 - c * 0.213 - s * 0.787,
-		0.715 - c * 0.715 + s * 0.715,
-		0.072 + c * 0.928 + s * 0.072,
-		0,
-		0,
-		0,
-		0,
-		1
-	];
-};
-
-const matrix = (values, mode, preserve_mode = false) => {
-	let conv = converter(mode);
-	let channels = getMode(mode).channels;
-	return color => {
-		let c = conv(color);
-		if (!c) {
-			return undefined;
-		}
-		let res = { mode };
-		let ch;
-		let count = channels.length;
-		for (let i = 0; i < values.length; i++) {
-			ch = channels[Math.floor(i / count)];
-			if (c[ch] === undefined) {
-				continue;
-			}
-			res[ch] =
-				(res[ch] || 0) + values[i] * (c[channels[i % count]] || 0);
-		}
-		if (!preserve_mode) {
-			return res;
-		}
-		let prep = prepare(color);
-		return prep && res.mode !== prep.mode ? converter(prep.mode)(res) : res;
-	};
-};
-
-const filterBrightness = (amt = 1, mode = 'rgb') => {
-	let a = minzero(amt);
-	return mapper(mapTransferLinear(a), mode, true);
-};
-
-const filterContrast = (amt = 1, mode = 'rgb') => {
-	let a = minzero(amt);
-	return mapper(mapTransferLinear(a, (1 - a) / 2), mode, true);
-};
-const filterSepia = (amt = 1, mode = 'rgb') =>
-	matrix(matrixSepia(amt), mode, true);
-const filterSaturate = (amt = 1, mode = 'rgb') =>
-	matrix(matrixSaturate(amt), mode, true);
-const filterGrayscale = (amt = 1, mode = 'rgb') =>
-	matrix(matrixGrayscale(amt), mode, true);
-const filterInvert = (amt = 1, mode = 'rgb') => {
-	let a = clamp(amt);
-	return mapper(
-		(v, ch) => (ch === 'alpha' ? v : lerp(a, 1 - a, v)),
-		mode,
-		true
-	);
-};
-const filterHueRotate = (deg = 0, mode = 'rgb') =>
-	matrix(matrixHueRotate(deg), mode, true);
-
-export {
-	filterBrightness,
-	filterContrast,
-	filterSepia,
-	filterSaturate,
-	filterGrayscale,
-	filterInvert,
-	filterHueRotate
-};
diff --git a/src/fixup/alpha.js b/src/fixup/alpha.js
deleted file mode 100644
index ca3c1522..00000000
--- a/src/fixup/alpha.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const fixupAlpha = arr => {
-	let some_defined = false;
-	let res = arr.map(v => {
-		if (v !== undefined) {
-			some_defined = true;
-			return v;
-		}
-		return 1;
-	});
-	return some_defined ? res : arr;
-};
-
-export { fixupAlpha };
diff --git a/src/fixup/hue.js b/src/fixup/hue.js
deleted file mode 100644
index 788b0a49..00000000
--- a/src/fixup/hue.js
+++ /dev/null
@@ -1,41 +0,0 @@
-import normalizeHue from '../util/normalizeHue.js';
-
-const hue = (hues, fn) => {
-	return hues
-		.map((hue, idx, arr) => {
-			if (hue === undefined) {
-				return hue;
-			}
-			let normalized = normalizeHue(hue);
-			if (idx === 0 || hues[idx - 1] === undefined) {
-				return normalized;
-			}
-			return fn(normalized - normalizeHue(arr[idx - 1]));
-		})
-		.reduce((acc, curr) => {
-			if (
-				!acc.length ||
-				curr === undefined ||
-				acc[acc.length - 1] === undefined
-			) {
-				acc.push(curr);
-				return acc;
-			}
-			acc.push(curr + acc[acc.length - 1]);
-			return acc;
-		}, []);
-};
-
-const fixupHueShorter = arr =>
-	hue(arr, d => (Math.abs(d) <= 180 ? d : d - 360 * Math.sign(d)));
-const fixupHueLonger = arr =>
-	hue(arr, d => (Math.abs(d) >= 180 || d === 0 ? d : d - 360 * Math.sign(d)));
-const fixupHueIncreasing = arr => hue(arr, d => (d >= 0 ? d : d + 360));
-const fixupHueDecreasing = arr => hue(arr, d => (d <= 0 ? d : d - 360));
-
-export {
-	fixupHueShorter,
-	fixupHueLonger,
-	fixupHueIncreasing,
-	fixupHueDecreasing
-};
diff --git a/src/formatter.js b/src/formatter.js
deleted file mode 100644
index eee8b103..00000000
--- a/src/formatter.js
+++ /dev/null
@@ -1,100 +0,0 @@
-import converter from './converter.js';
-import round from './round.js';
-import prepare from './_prepare.js';
-import { getMode } from './modes.js';
-
-let twoDecimals = round(2);
-
-const clamp = value => Math.max(0, Math.min(1, value || 0));
-const fixup = value => Math.round(clamp(value) * 255);
-
-const rgb = converter('rgb');
-const hsl = converter('hsl');
-
-export const serializeHex = color => {
-	if (color === undefined) {
-		return undefined;
-	}
-
-	let r = fixup(color.r);
-	let g = fixup(color.g);
-	let b = fixup(color.b);
-
-	return '#' + ((1 << 24) | (r << 16) | (g << 8) | b).toString(16).slice(1);
-};
-
-export const serializeHex8 = color => {
-	if (color === undefined) {
-		return undefined;
-	}
-
-	let a = fixup(color.alpha !== undefined ? color.alpha : 1);
-	return serializeHex(color) + ((1 << 8) | a).toString(16).slice(1);
-};
-
-export const serializeRgb = color => {
-	if (color === undefined) {
-		return undefined;
-	}
-
-	let r = fixup(color.r);
-	let g = fixup(color.g);
-	let b = fixup(color.b);
-
-	if (color.alpha === undefined || color.alpha === 1) {
-		// opaque color
-		return `rgb(${r}, ${g}, ${b})`;
-	} else {
-		// transparent color
-		return `rgba(${r}, ${g}, ${b}, ${twoDecimals(clamp(color.alpha))})`;
-	}
-};
-
-export const serializeHsl = color => {
-	if (color === undefined) {
-		return undefined;
-	}
-
-	const h = twoDecimals(color.h || 0);
-	const s = twoDecimals(clamp(color.s) * 100) + '%';
-	const l = twoDecimals(clamp(color.l) * 100) + '%';
-
-	if (color.alpha === undefined || color.alpha === 1) {
-		// opaque color
-		return `hsl(${h}, ${s}, ${l})`;
-	} else {
-		// transparent color
-		return `hsla(${h}, ${s}, ${l}, ${twoDecimals(clamp(color.alpha))})`;
-	}
-};
-
-export const formatCss = c => {
-	const color = prepare(c);
-	if (!color) {
-		return undefined;
-	}
-	const def = getMode(color.mode);
-	if (!def.serialize || typeof def.serialize === 'string') {
-		let res = `color(${def.serialize || `--${color.mode}`} `;
-		def.channels.forEach((ch, i) => {
-			if (ch !== 'alpha') {
-				res +=
-					(i ? ' ' : '') +
-					(color[ch] !== undefined ? color[ch] : 'none');
-			}
-		});
-		if (color.alpha !== undefined && color.alpha < 1) {
-			res += ` / ${color.alpha}`;
-		}
-		return res + ')';
-	}
-	if (typeof def.serialize === 'function') {
-		return def.serialize(color);
-	}
-	return undefined;
-};
-
-export const formatHex = c => serializeHex(rgb(c));
-export const formatHex8 = c => serializeHex8(rgb(c));
-export const formatRgb = c => serializeRgb(rgb(c));
-export const formatHsl = c => serializeHsl(hsl(c));
diff --git a/src/hdr/constants.js b/src/hdr/constants.js
deleted file mode 100644
index 1bde4460..00000000
--- a/src/hdr/constants.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/*
-	Relative XYZ has Y=1 for media white,
-	BT.2048 says media white Y=203 (at PQ 58).
-	See: https://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BT.2408-3-2019-PDF-E.pdf
-*/
-export const YW = 203;
diff --git a/src/hdr/transfer.js b/src/hdr/transfer.js
deleted file mode 100644
index 5b3e39de..00000000
--- a/src/hdr/transfer.js
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
-	https://en.wikipedia.org/wiki/Transfer_functions_in_imaging
-*/
-
-export const M1 = 0.1593017578125;
-export const M2 = 78.84375;
-export const C1 = 0.8359375;
-export const C2 = 18.8515625;
-export const C3 = 18.6875;
-
-/*
-	Perceptual Quantizer, as defined in Rec. BT 2100-2 (2018)
-
-	* https://www.itu.int/rec/R-REC-BT.2100-2-201807-I/en
-	* https://en.wikipedia.org/wiki/Perceptual_quantizer
-*/
-
-/* PQ EOTF, defined for `v` in [0,1]. */
-export function transferPqDecode(v) {
-	if (v < 0) return 0;
-	const c = Math.pow(v, 1 / M2);
-	return 1e4 * Math.pow(Math.max(0, c - C1) / (C2 - C3 * c), 1 / M1);
-}
-
-/* PQ EOTF^-1, defined for `v` in [0, 1e4]. */
-export function transferPqEncode(v) {
-	if (v < 0) return 0;
-	const c = Math.pow(v / 1e4, M1);
-	return Math.pow((C1 + C2 * c) / (1 + C3 * c), M2);
-}
diff --git a/src/hsi/convertHsiToRgb.js b/src/hsi/convertHsiToRgb.js
deleted file mode 100644
index 1fae2ff2..00000000
--- a/src/hsi/convertHsiToRgb.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import normalizeHue from '../util/normalizeHue.js';
-
-// Based on: https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
-
-export default function convertHsiToRgb({ h, s, i, alpha }) {
-	h = normalizeHue(h !== undefined ? h : 0);
-	if (s === undefined) s = 0;
-	if (i === undefined) i = 0;
-	let f = Math.abs(((h / 60) % 2) - 1);
-	let res;
-	switch (Math.floor(h / 60)) {
-		case 0:
-			res = {
-				r: i * (1 + s * (3 / (2 - f) - 1)),
-				g: i * (1 + s * ((3 * (1 - f)) / (2 - f) - 1)),
-				b: i * (1 - s)
-			};
-			break;
-		case 1:
-			res = {
-				r: i * (1 + s * ((3 * (1 - f)) / (2 - f) - 1)),
-				g: i * (1 + s * (3 / (2 - f) - 1)),
-				b: i * (1 - s)
-			};
-			break;
-		case 2:
-			res = {
-				r: i * (1 - s),
-				g: i * (1 + s * (3 / (2 - f) - 1)),
-				b: i * (1 + s * ((3 * (1 - f)) / (2 - f) - 1))
-			};
-			break;
-		case 3:
-			res = {
-				r: i * (1 - s),
-				g: i * (1 + s * ((3 * (1 - f)) / (2 - f) - 1)),
-				b: i * (1 + s * (3 / (2 - f) - 1))
-			};
-			break;
-		case 4:
-			res = {
-				r: i * (1 + s * ((3 * (1 - f)) / (2 - f) - 1)),
-				g: i * (1 - s),
-				b: i * (1 + s * (3 / (2 - f) - 1))
-			};
-			break;
-		case 5:
-			res = {
-				r: i * (1 + s * (3 / (2 - f) - 1)),
-				g: i * (1 - s),
-				b: i * (1 + s * ((3 * (1 - f)) / (2 - f) - 1))
-			};
-			break;
-		default:
-			res = { r: i * (1 - s), g: i * (1 - s), b: i * (1 - s) };
-	}
-
-	res.mode = 'rgb';
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-}
diff --git a/src/hsi/convertRgbToHsi.js b/src/hsi/convertRgbToHsi.js
deleted file mode 100644
index ef3945be..00000000
--- a/src/hsi/convertRgbToHsi.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Based on: https://en.wikipedia.org/wiki/HSL_and_HSV#Formal_derivation
-
-export default function convertRgbToHsi({ r, g, b, alpha }) {
-	if (r === undefined) r = 0;
-	if (g === undefined) g = 0;
-	if (b === undefined) b = 0;
-	let M = Math.max(r, g, b),
-		m = Math.min(r, g, b);
-	let res = {
-		mode: 'hsi',
-		s: r + g + b === 0 ? 0 : 1 - (3 * m) / (r + g + b),
-		i: (r + g + b) / 3
-	};
-	if (M - m !== 0)
-		res.h =
-			(M === r
-				? (g - b) / (M - m) + (g < b) * 6
-				: M === g
-				? (b - r) / (M - m) + 2
-				: (r - g) / (M - m) + 4) * 60;
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-}
diff --git a/src/hsi/definition.js b/src/hsi/definition.js
deleted file mode 100644
index a797ff94..00000000
--- a/src/hsi/definition.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import convertHsiToRgb from './convertHsiToRgb.js';
-import convertRgbToHsi from './convertRgbToHsi.js';
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueSaturation } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'hsi',
-
-	toMode: {
-		rgb: convertHsiToRgb
-	},
-
-	parse: ['--hsi'],
-	serialize: '--hsi',
-
-	fromMode: {
-		rgb: convertRgbToHsi
-	},
-
-	channels: ['h', 's', 'i', 'alpha'],
-
-	ranges: {
-		h: [0, 360]
-	},
-
-	gamut: 'rgb',
-
-	interpolate: {
-		h: { use: interpolatorLinear, fixup: fixupHueShorter },
-		s: interpolatorLinear,
-		i: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-
-	difference: {
-		h: differenceHueSaturation
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/hsl/convertHslToRgb.js b/src/hsl/convertHslToRgb.js
deleted file mode 100644
index 9de963ac..00000000
--- a/src/hsl/convertHslToRgb.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import normalizeHue from '../util/normalizeHue.js';
-// Based on: https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
-
-export default function convertHslToRgb({ h, s, l, alpha }) {
-	h = normalizeHue(h !== undefined ? h : 0);
-	if (s === undefined) s = 0;
-	if (l === undefined) l = 0;
-	let m1 = l + s * (l < 0.5 ? l : 1 - l);
-	let m2 = m1 - (m1 - l) * 2 * Math.abs(((h / 60) % 2) - 1);
-	let res;
-	switch (Math.floor(h / 60)) {
-		case 0:
-			res = { r: m1, g: m2, b: 2 * l - m1 };
-			break;
-		case 1:
-			res = { r: m2, g: m1, b: 2 * l - m1 };
-			break;
-		case 2:
-			res = { r: 2 * l - m1, g: m1, b: m2 };
-			break;
-		case 3:
-			res = { r: 2 * l - m1, g: m2, b: m1 };
-			break;
-		case 4:
-			res = { r: m2, g: 2 * l - m1, b: m1 };
-			break;
-		case 5:
-			res = { r: m1, g: 2 * l - m1, b: m2 };
-			break;
-		default:
-			res = { r: 2 * l - m1, g: 2 * l - m1, b: 2 * l - m1 };
-	}
-	res.mode = 'rgb';
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-}
diff --git a/src/hsl/convertRgbToHsl.js b/src/hsl/convertRgbToHsl.js
deleted file mode 100644
index e616ed2d..00000000
--- a/src/hsl/convertRgbToHsl.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Based on: https://en.wikipedia.org/wiki/HSL_and_HSV#Formal_derivation
-
-export default function convertRgbToHsl({ r, g, b, alpha }) {
-	if (r === undefined) r = 0;
-	if (g === undefined) g = 0;
-	if (b === undefined) b = 0;
-	let M = Math.max(r, g, b),
-		m = Math.min(r, g, b);
-	let res = {
-		mode: 'hsl',
-		s: M === m ? 0 : (M - m) / (1 - Math.abs(M + m - 1)),
-		l: 0.5 * (M + m)
-	};
-	if (M - m !== 0)
-		res.h =
-			(M === r
-				? (g - b) / (M - m) + (g < b) * 6
-				: M === g
-				? (b - r) / (M - m) + 2
-				: (r - g) / (M - m) + 4) * 60;
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-}
diff --git a/src/hsl/definition.js b/src/hsl/definition.js
deleted file mode 100644
index 3a05f97c..00000000
--- a/src/hsl/definition.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import convertHslToRgb from './convertHslToRgb.js';
-import convertRgbToHsl from './convertRgbToHsl.js';
-import parseHslLegacy from './parseHslLegacy.js';
-import parseHsl from './parseHsl.js';
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueSaturation } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'hsl',
-
-	toMode: {
-		rgb: convertHslToRgb
-	},
-
-	fromMode: {
-		rgb: convertRgbToHsl
-	},
-
-	channels: ['h', 's', 'l', 'alpha'],
-
-	ranges: {
-		h: [0, 360]
-	},
-
-	gamut: 'rgb',
-
-	parse: [parseHsl, parseHslLegacy],
-	serialize: c =>
-		`hsl(${c.h !== undefined ? c.h : 'none'} ${
-			c.s !== undefined ? c.s * 100 + '%' : 'none'
-		} ${c.l !== undefined ? c.l * 100 + '%' : 'none'}${
-			c.alpha < 1 ? ` / ${c.alpha}` : ''
-		})`,
-
-	interpolate: {
-		h: { use: interpolatorLinear, fixup: fixupHueShorter },
-		s: interpolatorLinear,
-		l: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-
-	difference: {
-		h: differenceHueSaturation
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/hsl/parseHsl.js b/src/hsl/parseHsl.js
deleted file mode 100644
index 254c0608..00000000
--- a/src/hsl/parseHsl.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Tok } from '../parse.js';
-
-function parseHsl(color, parsed) {
-	if (!parsed || (parsed[0] !== 'hsl' && parsed[0] !== 'hsla')) {
-		return undefined;
-	}
-	const res = { mode: 'hsl' };
-	const [, h, s, l, alpha] = parsed;
-
-	if (h.type !== Tok.None) {
-		if (h.type === Tok.Percentage) {
-			return undefined;
-		}
-		res.h = h.value;
-	}
-
-	if (s.type !== Tok.None) {
-		if (s.type === Tok.Hue) {
-			return undefined;
-		}
-		res.s = s.value / 100;
-	}
-
-	if (l.type !== Tok.None) {
-		if (l.type === Tok.Hue) {
-			return undefined;
-		}
-		res.l = l.value / 100;
-	}
-
-	if (alpha.type !== Tok.None) {
-		res.alpha = Math.min(
-			1,
-			Math.max(
-				0,
-				alpha.type === Tok.Number ? alpha.value : alpha.value / 100
-			)
-		);
-	}
-
-	return res;
-}
-
-export default parseHsl;
diff --git a/src/hsl/parseHslLegacy.js b/src/hsl/parseHslLegacy.js
deleted file mode 100644
index e0b2c13d..00000000
--- a/src/hsl/parseHslLegacy.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import hueToDeg from '../util/hue.js';
-import { hue, per, num_per, c } from '../util/regex.js';
-
-/*
-	hsl() regular expressions for legacy format
-	Reference: https://drafts.csswg.org/css-color/#the-hsl-notation
- */
-const hsl_old = new RegExp(
-	`^hsla?\\(\\s*${hue}${c}${per}${c}${per}\\s*(?:,\\s*${num_per}\\s*)?\\)$`
-);
-
-const parseHslLegacy = color => {
-	let match = color.match(hsl_old);
-	if (!match) return;
-	let res = { mode: 'hsl' };
-
-	if (match[3] !== undefined) {
-		res.h = +match[3];
-	} else if (match[1] !== undefined && match[2] !== undefined) {
-		res.h = hueToDeg(match[1], match[2]);
-	}
-
-	if (match[4] !== undefined) {
-		res.s = Math.min(Math.max(0, match[4] / 100), 1);
-	}
-
-	if (match[5] !== undefined) {
-		res.l = Math.min(Math.max(0, match[5] / 100), 1);
-	}
-
-	if (match[6] !== undefined) {
-		res.alpha = Math.max(0, Math.min(1, match[6] / 100));
-	} else if (match[7] !== undefined) {
-		res.alpha = Math.max(0, Math.min(1, +match[7]));
-	}
-	return res;
-};
-
-export default parseHslLegacy;
diff --git a/src/hsv/convertHsvToRgb.js b/src/hsv/convertHsvToRgb.js
deleted file mode 100644
index 00791455..00000000
--- a/src/hsv/convertHsvToRgb.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import normalizeHue from '../util/normalizeHue.js';
-
-// Based on: https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
-
-export default function convertHsvToRgb({ h, s, v, alpha }) {
-	h = normalizeHue(h !== undefined ? h : 0);
-	if (s === undefined) s = 0;
-	if (v === undefined) v = 0;
-	let f = Math.abs(((h / 60) % 2) - 1);
-	let res;
-	switch (Math.floor(h / 60)) {
-		case 0:
-			res = { r: v, g: v * (1 - s * f), b: v * (1 - s) };
-			break;
-		case 1:
-			res = { r: v * (1 - s * f), g: v, b: v * (1 - s) };
-			break;
-		case 2:
-			res = { r: v * (1 - s), g: v, b: v * (1 - s * f) };
-			break;
-		case 3:
-			res = { r: v * (1 - s), g: v * (1 - s * f), b: v };
-			break;
-		case 4:
-			res = { r: v * (1 - s * f), g: v * (1 - s), b: v };
-			break;
-		case 5:
-			res = { r: v, g: v * (1 - s), b: v * (1 - s * f) };
-			break;
-		default:
-			res = { r: v * (1 - s), g: v * (1 - s), b: v * (1 - s) };
-	}
-	res.mode = 'rgb';
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-}
diff --git a/src/hsv/convertRgbToHsv.js b/src/hsv/convertRgbToHsv.js
deleted file mode 100644
index baebae33..00000000
--- a/src/hsv/convertRgbToHsv.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// Based on: https://en.wikipedia.org/wiki/HSL_and_HSV#Formal_derivation
-
-export default function convertRgbToHsv({ r, g, b, alpha }) {
-	if (r === undefined) r = 0;
-	if (g === undefined) g = 0;
-	if (b === undefined) b = 0;
-	let M = Math.max(r, g, b),
-		m = Math.min(r, g, b);
-	let res = {
-		mode: 'hsv',
-		s: M === 0 ? 0 : 1 - m / M,
-		v: M
-	};
-	if (M - m !== 0)
-		res.h =
-			(M === r
-				? (g - b) / (M - m) + (g < b) * 6
-				: M === g
-				? (b - r) / (M - m) + 2
-				: (r - g) / (M - m) + 4) * 60;
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-}
diff --git a/src/hsv/definition.js b/src/hsv/definition.js
deleted file mode 100644
index c4909bac..00000000
--- a/src/hsv/definition.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import convertHsvToRgb from './convertHsvToRgb.js';
-import convertRgbToHsv from './convertRgbToHsv.js';
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueSaturation } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'hsv',
-
-	toMode: {
-		rgb: convertHsvToRgb
-	},
-
-	parse: ['--hsv'],
-	serialize: '--hsv',
-
-	fromMode: {
-		rgb: convertRgbToHsv
-	},
-
-	channels: ['h', 's', 'v', 'alpha'],
-
-	ranges: {
-		h: [0, 360]
-	},
-
-	gamut: 'rgb',
-
-	interpolate: {
-		h: { use: interpolatorLinear, fixup: fixupHueShorter },
-		s: interpolatorLinear,
-		v: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-
-	difference: {
-		h: differenceHueSaturation
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/hwb/convertHwbToRgb.js b/src/hwb/convertHwbToRgb.js
deleted file mode 100644
index 56e85f00..00000000
--- a/src/hwb/convertHwbToRgb.js
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
-	HWB to RGB converter
-	--------------------
-
-	References:
-		* https://drafts.csswg.org/css-color/#hwb-to-rgb
-		* https://en.wikipedia.org/wiki/HWB_color_model
-		* http://alvyray.com/Papers/CG/HWB_JGTv208.pdf
- */
-
-import convertHsvToRgb from '../hsv/convertHsvToRgb.js';
-
-export default function convertHwbToRgb({ h, w, b, alpha }) {
-	if (w === undefined) w = 0;
-	if (b === undefined) b = 0;
-	// normalize w + b to 1
-	if (w + b > 1) {
-		let s = w + b;
-		w /= s;
-		b /= s;
-	}
-	return convertHsvToRgb({
-		h: h,
-		s: b === 1 ? 1 : 1 - w / (1 - b),
-		v: 1 - b,
-		alpha: alpha
-	});
-}
diff --git a/src/hwb/convertRgbToHwb.js b/src/hwb/convertRgbToHwb.js
deleted file mode 100644
index 55c6daff..00000000
--- a/src/hwb/convertRgbToHwb.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-	RGB to HWB converter
-	--------------------
-
-	References:
-		* https://drafts.csswg.org/css-color/#hwb-to-rgb
-		* https://en.wikipedia.org/wiki/HWB_color_model
-		* http://alvyray.com/Papers/CG/HWB_JGTv208.pdf
- */
-
-import convertRgbToHsv from '../hsv/convertRgbToHsv.js';
-
-export default function convertRgbToHwb(rgba) {
-	let hsv = convertRgbToHsv(rgba);
-	if (hsv === undefined) return undefined;
-	let s = hsv.s !== undefined ? hsv.s : 0;
-	let v = hsv.v !== undefined ? hsv.v : 0;
-	let res = {
-		mode: 'hwb',
-		w: (1 - s) * v,
-		b: 1 - v
-	};
-	if (hsv.h !== undefined) res.h = hsv.h;
-	if (hsv.alpha !== undefined) res.alpha = hsv.alpha;
-	return res;
-}
diff --git a/src/hwb/definition.js b/src/hwb/definition.js
deleted file mode 100644
index 537811b2..00000000
--- a/src/hwb/definition.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import convertHwbToRgb from './convertHwbToRgb.js';
-import convertRgbToHwb from './convertRgbToHwb.js';
-import parseHwb from './parseHwb.js';
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueNaive } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'hwb',
-
-	toMode: {
-		rgb: convertHwbToRgb
-	},
-
-	fromMode: {
-		rgb: convertRgbToHwb
-	},
-
-	channels: ['h', 'w', 'b', 'alpha'],
-
-	ranges: {
-		h: [0, 360]
-	},
-
-	gamut: 'rgb',
-
-	parse: [parseHwb],
-	serialize: c =>
-		`hwb(${c.h !== undefined ? c.h : 'none'} ${
-			c.w !== undefined ? c.w * 100 + '%' : 'none'
-		} ${c.b !== undefined ? c.b * 100 + '%' : 'none'}${
-			c.alpha < 1 ? ` / ${c.alpha}` : ''
-		})`,
-
-	interpolate: {
-		h: { use: interpolatorLinear, fixup: fixupHueShorter },
-		w: interpolatorLinear,
-		b: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-
-	difference: {
-		h: differenceHueNaive
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/hwb/parseHwb.js b/src/hwb/parseHwb.js
deleted file mode 100644
index d0bd8662..00000000
--- a/src/hwb/parseHwb.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { Tok } from '../parse.js';
-
-function ParseHwb(color, parsed) {
-	if (!parsed || parsed[0] !== 'hwb') {
-		return undefined;
-	}
-	const res = { mode: 'hwb' };
-	const [, h, w, b, alpha] = parsed;
-
-	if (h.type !== Tok.None) {
-		if (h.type === Tok.Percentage) {
-			return undefined;
-		}
-		res.h = h.value;
-	}
-
-	if (w.type !== Tok.None) {
-		if (w.type === Tok.Hue) {
-			return undefined;
-		}
-		res.w = w.value / 100;
-	}
-
-	if (b.type !== Tok.None) {
-		if (b.type === Tok.Hue) {
-			return undefined;
-		}
-		res.b = b.value / 100;
-	}
-
-	if (alpha.type !== Tok.None) {
-		res.alpha = Math.min(
-			1,
-			Math.max(
-				0,
-				alpha.type === Tok.Number ? alpha.value : alpha.value / 100
-			)
-		);
-	}
-
-	return res;
-}
-
-export default ParseHwb;
diff --git a/src/index-fn.js b/src/index-fn.js
deleted file mode 100644
index b906846a..00000000
--- a/src/index-fn.js
+++ /dev/null
@@ -1,230 +0,0 @@
-// Color space definitions
-export { default as modeA98 } from './a98/definition.js';
-export { default as modeCubehelix } from './cubehelix/definition.js';
-export { default as modeDlab } from './dlab/definition.js';
-export { default as modeDlch } from './dlch/definition.js';
-export { default as modeHsi } from './hsi/definition.js';
-export { default as modeHsl } from './hsl/definition.js';
-export { default as modeHsv } from './hsv/definition.js';
-export { default as modeHwb } from './hwb/definition.js';
-export { default as modeItp } from './itp/definition.js';
-export { default as modeJab } from './jab/definition.js';
-export { default as modeJch } from './jch/definition.js';
-export { default as modeLab } from './lab/definition.js';
-export { default as modeLab65 } from './lab65/definition.js';
-export { default as modeLch } from './lch/definition.js';
-export { default as modeLch65 } from './lch65/definition.js';
-export { default as modeLchuv } from './lchuv/definition.js';
-export { default as modeLrgb } from './lrgb/definition.js';
-export { default as modeLuv } from './luv/definition.js';
-export { default as modeOkhsl } from './okhsl/modeOkhsl.js';
-export { default as modeOkhsv } from './okhsv/modeOkhsv.js';
-export { default as modeOklab } from './oklab/definition.js';
-export { default as modeOklch } from './oklch/definition.js';
-export { default as modeP3 } from './p3/definition.js';
-export { default as modeProphoto } from './prophoto/definition.js';
-export { default as modeRec2020 } from './rec2020/definition.js';
-export { default as modeRgb } from './rgb/definition.js';
-export { default as modeXyb } from './xyb/definition.js';
-export { default as modeXyz50 } from './xyz50/definition.js';
-export { default as modeXyz65 } from './xyz65/definition.js';
-export { default as modeYiq } from './yiq/definition.js';
-
-export { default as converter } from './converter.js';
-
-export {
-	serializeHex,
-	serializeHex8,
-	serializeRgb,
-	serializeHsl,
-	formatHex,
-	formatHex8,
-	formatRgb,
-	formatHsl,
-	formatCss
-} from './formatter.js';
-
-export { default as colorsNamed } from './colors/named.js';
-export { default as blend } from './blend.js';
-export { default as random } from './random.js';
-
-export {
-	fixupHueShorter,
-	fixupHueLonger,
-	fixupHueIncreasing,
-	fixupHueDecreasing
-} from './fixup/hue.js';
-
-export { fixupAlpha } from './fixup/alpha.js';
-
-export {
-	mapper,
-	mapAlphaMultiply,
-	mapAlphaDivide,
-	mapTransferLinear,
-	mapTransferGamma
-} from './map.js';
-
-export { average, averageAngle, averageNumber } from './average.js';
-
-export { default as round } from './round.js';
-export {
-	interpolate,
-	interpolateWith,
-	interpolateWithPremultipliedAlpha
-} from './interpolate/interpolate.js';
-
-export { interpolatorLinear } from './interpolate/linear.js';
-
-export { interpolatorPiecewise } from './interpolate/piecewise.js';
-
-export {
-	interpolatorSplineBasis,
-	interpolatorSplineBasisClosed
-} from './interpolate/splineBasis.js';
-
-export {
-	interpolatorSplineNatural,
-	interpolatorSplineNaturalClosed
-} from './interpolate/splineNatural.js';
-
-export {
-	interpolatorSplineMonotone,
-	interpolatorSplineMonotone2,
-	interpolatorSplineMonotoneClosed
-} from './interpolate/splineMonotone.js';
-
-export { lerp, unlerp, blerp, trilerp } from './interpolate/lerp.js';
-export { default as samples } from './samples.js';
-export {
-	displayable,
-	inGamut,
-	clampRgb,
-	clampChroma,
-	clampGamut,
-	toGamut
-} from './clamp.js';
-export { default as nearest } from './nearest.js';
-export { useMode, getMode, useParser, removeParser } from './modes.js';
-export { default as parse } from './parse.js';
-
-export {
-	differenceEuclidean,
-	differenceCie76,
-	differenceCie94,
-	differenceCiede2000,
-	differenceCmc,
-	differenceHyab,
-	differenceHueSaturation,
-	differenceHueChroma,
-	differenceHueNaive,
-	differenceKotsarenkoRamos,
-	differenceItp
-} from './difference.js';
-
-export {
-	filterBrightness,
-	filterContrast,
-	filterSepia,
-	filterInvert,
-	filterSaturate,
-	filterGrayscale,
-	filterHueRotate
-} from './filter.js';
-
-export {
-	filterDeficiencyProt,
-	filterDeficiencyDeuter,
-	filterDeficiencyTrit
-} from './deficiency.js';
-
-// Easings
-export { default as easingMidpoint } from './easing/midpoint.js';
-export {
-	easingSmoothstep,
-	easingSmoothstepInverse
-} from './easing/smoothstep.js';
-export { default as easingSmootherstep } from './easing/smootherstep.js';
-export { default as easingInOutSine } from './easing/inOutSine.js';
-export { default as easingGamma } from './easing/gamma.js';
-
-export {
-	luminance as wcagLuminance,
-	contrast as wcagContrast
-} from './wcag.js';
-
-export { default as parseHsl } from './hsl/parseHsl.js';
-export { default as parseHwb } from './hwb/parseHwb.js';
-export { default as parseLab } from './lab/parseLab.js';
-export { default as parseLch } from './lch/parseLch.js';
-export { default as parseNamed } from './rgb/parseNamed.js';
-export { default as parseTransparent } from './rgb/parseTransparent.js';
-export { default as parseHex } from './rgb/parseHex.js';
-export { default as parseRgb } from './rgb/parseRgb.js';
-export { default as parseHslLegacy } from './hsl/parseHslLegacy.js';
-export { default as parseRgbLegacy } from './rgb/parseRgbLegacy.js';
-export { default as parseOklab } from './oklab/parseOklab.js';
-export { default as parseOklch } from './oklch/parseOklch.js';
-
-export { default as convertA98ToXyz65 } from './a98/convertA98ToXyz65.js';
-export { default as convertCubehelixToRgb } from './cubehelix/convertCubehelixToRgb.js';
-export { default as convertDlchToLab65 } from './dlch/convertDlchToLab65.js';
-export { default as convertHsiToRgb } from './hsi/convertHsiToRgb.js';
-export { default as convertHslToRgb } from './hsl/convertHslToRgb.js';
-export { default as convertHsvToRgb } from './hsv/convertHsvToRgb.js';
-export { default as convertHwbToRgb } from './hwb/convertHwbToRgb.js';
-export { default as convertItpToXyz65 } from './itp/convertItpToXyz65.js';
-export { default as convertJabToJch } from './jch/convertJabToJch.js';
-export { default as convertJabToRgb } from './jab/convertJabToRgb.js';
-export { default as convertJabToXyz65 } from './jab/convertJabToXyz65.js';
-export { default as convertJchToJab } from './jch/convertJchToJab.js';
-export { default as convertLab65ToDlch } from './dlch/convertLab65ToDlch.js';
-export { default as convertLab65ToRgb } from './lab65/convertLab65ToRgb.js';
-export { default as convertLab65ToXyz65 } from './lab65/convertLab65ToXyz65.js';
-export { default as convertLabToLch } from './lch/convertLabToLch.js';
-export { default as convertLabToRgb } from './lab/convertLabToRgb.js';
-export { default as convertLabToXyz50 } from './lab/convertLabToXyz50.js';
-export { default as convertLchToLab } from './lch/convertLchToLab.js';
-export { default as convertLchuvToLuv } from './lchuv/convertLchuvToLuv.js';
-export { default as convertLrgbToOklab } from './oklab/convertLrgbToOklab.js';
-export { default as convertLrgbToRgb } from './lrgb/convertLrgbToRgb.js';
-export { default as convertLuvToLchuv } from './lchuv/convertLuvToLchuv.js';
-export { default as convertLuvToXyz50 } from './luv/convertLuvToXyz50.js';
-export { default as convertOkhslToOklab } from './okhsl/convertOkhslToOklab.js';
-export { default as convertOkhsvToOklab } from './okhsv/convertOkhsvToOklab.js';
-export { default as convertOklabToLrgb } from './oklab/convertOklabToLrgb.js';
-export { default as convertOklabToOkhsl } from './okhsl/convertOklabToOkhsl.js';
-export { default as convertOklabToOkhsv } from './okhsv/convertOklabToOkhsv.js';
-export { default as convertOklabToRgb } from './oklab/convertOklabToRgb.js';
-export { default as convertP3ToXyz65 } from './p3/convertP3ToXyz65.js';
-export { default as convertProphotoToXyz50 } from './prophoto/convertProphotoToXyz50.js';
-export { default as convertRec2020ToXyz65 } from './rec2020/convertRec2020ToXyz65.js';
-export { default as convertRgbToCubehelix } from './cubehelix/convertRgbToCubehelix.js';
-export { default as convertRgbToHsi } from './hsi/convertRgbToHsi.js';
-export { default as convertRgbToHsl } from './hsl/convertRgbToHsl.js';
-export { default as convertRgbToHsv } from './hsv/convertRgbToHsv.js';
-export { default as convertRgbToHwb } from './hwb/convertRgbToHwb.js';
-export { default as convertRgbToJab } from './jab/convertRgbToJab.js';
-export { default as convertRgbToLab } from './lab/convertRgbToLab.js';
-export { default as convertRgbToLab65 } from './lab65/convertRgbToLab65.js';
-export { default as convertRgbToLrgb } from './lrgb/convertRgbToLrgb.js';
-export { default as convertRgbToOklab } from './oklab/convertRgbToOklab.js';
-export { default as convertRgbToXyz50 } from './xyz50/convertRgbToXyz50.js';
-export { default as convertRgbToXyz65 } from './xyz65/convertRgbToXyz65.js';
-export { default as convertRgbToYiq } from './yiq/convertRgbToYiq.js';
-export { default as convertRgbToXyb } from './xyb/convertRgbToXyb.js';
-export { default as convertXybToRgb } from './xyb/convertXybToRgb.js';
-export { default as convertXyz65ToA98 } from './a98/convertXyz65ToA98.js';
-export { default as convertXyz65ToItp } from './itp/convertXyz65ToItp.js';
-export { default as convertXyz65ToJab } from './jab/convertXyz65ToJab.js';
-export { default as convertXyz65ToLab65 } from './lab65/convertXyz65ToLab65.js';
-export { default as convertXyz65ToP3 } from './p3/convertXyz65ToP3.js';
-export { default as convertXyz65ToRec2020 } from './rec2020/convertXyz65ToRec2020.js';
-export { default as convertXyz65ToRgb } from './xyz65/convertXyz65ToRgb.js';
-export { default as convertXyz65ToXyz50 } from './xyz65/convertXyz65ToXyz50.js';
-export { default as convertXyz50ToLab } from './lab/convertXyz50ToLab.js';
-export { default as convertXyz50ToLuv } from './luv/convertXyz50ToLuv.js';
-export { default as convertXyz50ToProphoto } from './prophoto/convertXyz50ToProphoto.js';
-export { default as convertXyz50ToRgb } from './xyz50/convertXyz50ToRgb.js';
-export { default as convertXyz50ToXyz65 } from './xyz65/convertXyz50ToXyz65.js';
-export { default as convertYiqToRgb } from './yiq/convertYiqToRgb.js';
diff --git a/src/index.js b/src/index.js
deleted file mode 100644
index 3e7b6042..00000000
--- a/src/index.js
+++ /dev/null
@@ -1,295 +0,0 @@
-// Color space definitions
-import modeA98 from './a98/definition.js';
-import modeCubehelix from './cubehelix/definition.js';
-import modeDlab from './dlab/definition.js';
-import modeDlch from './dlch/definition.js';
-import modeHsi from './hsi/definition.js';
-import modeHsl from './hsl/definition.js';
-import modeHsv from './hsv/definition.js';
-import modeHwb from './hwb/definition.js';
-import modeItp from './itp/definition.js';
-import modeJab from './jab/definition.js';
-import modeJch from './jch/definition.js';
-import modeLab from './lab/definition.js';
-import modeLab65 from './lab65/definition.js';
-import modeLch from './lch/definition.js';
-import modeLch65 from './lch65/definition.js';
-import modeLchuv from './lchuv/definition.js';
-import modeLrgb from './lrgb/definition.js';
-import modeLuv from './luv/definition.js';
-import modeOkhsl from './okhsl/modeOkhsl.js';
-import modeOkhsv from './okhsv/modeOkhsv.js';
-import modeOklab from './oklab/definition.js';
-import modeOklch from './oklch/definition.js';
-import modeP3 from './p3/definition.js';
-import modeProphoto from './prophoto/definition.js';
-import modeRec2020 from './rec2020/definition.js';
-import modeRgb from './rgb/definition.js';
-import modeXyb from './xyb/definition.js';
-import modeXyz50 from './xyz50/definition.js';
-import modeXyz65 from './xyz65/definition.js';
-import modeYiq from './yiq/definition.js';
-import { useMode } from './modes.js';
-
-export { default as converter } from './converter.js';
-
-export {
-	serializeHex,
-	serializeHex8,
-	serializeRgb,
-	serializeHsl,
-	formatHex,
-	formatHex8,
-	formatRgb,
-	formatHsl,
-	formatCss
-} from './formatter.js';
-
-export { default as colorsNamed } from './colors/named.js';
-export { default as blend } from './blend.js';
-export { default as random } from './random.js';
-
-export {
-	fixupHueShorter,
-	fixupHueLonger,
-	fixupHueIncreasing,
-	fixupHueDecreasing
-} from './fixup/hue.js';
-
-export { fixupAlpha } from './fixup/alpha.js';
-
-export {
-	mapper,
-	mapAlphaMultiply,
-	mapAlphaDivide,
-	mapTransferLinear,
-	mapTransferGamma
-} from './map.js';
-
-export { average, averageAngle, averageNumber } from './average.js';
-
-export { default as round } from './round.js';
-export {
-	interpolate,
-	interpolateWith,
-	interpolateWithPremultipliedAlpha
-} from './interpolate/interpolate.js';
-
-export { interpolatorLinear } from './interpolate/linear.js';
-
-export { interpolatorPiecewise } from './interpolate/piecewise.js';
-
-export {
-	interpolatorSplineBasis,
-	interpolatorSplineBasisClosed
-} from './interpolate/splineBasis.js';
-
-export {
-	interpolatorSplineNatural,
-	interpolatorSplineNaturalClosed
-} from './interpolate/splineNatural.js';
-
-export {
-	interpolatorSplineMonotone,
-	interpolatorSplineMonotone2,
-	interpolatorSplineMonotoneClosed
-} from './interpolate/splineMonotone.js';
-
-export { lerp, unlerp, blerp, trilerp } from './interpolate/lerp.js';
-export { default as samples } from './samples.js';
-export {
-	displayable,
-	inGamut,
-	clampRgb,
-	clampChroma,
-	clampGamut,
-	toGamut
-} from './clamp.js';
-export { default as nearest } from './nearest.js';
-export { useMode, getMode, useParser, removeParser } from './modes.js';
-export { default as parse } from './parse.js';
-
-export {
-	differenceEuclidean,
-	differenceCie76,
-	differenceCie94,
-	differenceCiede2000,
-	differenceCmc,
-	differenceHyab,
-	differenceHueSaturation,
-	differenceHueChroma,
-	differenceHueNaive,
-	differenceKotsarenkoRamos,
-	differenceItp
-} from './difference.js';
-
-export {
-	filterBrightness,
-	filterContrast,
-	filterSepia,
-	filterInvert,
-	filterSaturate,
-	filterGrayscale,
-	filterHueRotate
-} from './filter.js';
-
-export {
-	filterDeficiencyProt,
-	filterDeficiencyDeuter,
-	filterDeficiencyTrit
-} from './deficiency.js';
-
-// Easings
-export { default as easingMidpoint } from './easing/midpoint.js';
-export {
-	easingSmoothstep,
-	easingSmoothstepInverse
-} from './easing/smoothstep.js';
-export { default as easingSmootherstep } from './easing/smootherstep.js';
-export { default as easingInOutSine } from './easing/inOutSine.js';
-export { default as easingGamma } from './easing/gamma.js';
-
-export {
-	luminance as wcagLuminance,
-	contrast as wcagContrast
-} from './wcag.js';
-
-export { default as parseHsl } from './hsl/parseHsl.js';
-export { default as parseHwb } from './hwb/parseHwb.js';
-export { default as parseLab } from './lab/parseLab.js';
-export { default as parseLch } from './lch/parseLch.js';
-export { default as parseNamed } from './rgb/parseNamed.js';
-export { default as parseTransparent } from './rgb/parseTransparent.js';
-export { default as parseHex } from './rgb/parseHex.js';
-export { default as parseRgb } from './rgb/parseRgb.js';
-export { default as parseHslLegacy } from './hsl/parseHslLegacy.js';
-export { default as parseRgbLegacy } from './rgb/parseRgbLegacy.js';
-export { default as parseOklab } from './oklab/parseOklab.js';
-export { default as parseOklch } from './oklch/parseOklch.js';
-
-export { default as convertA98ToXyz65 } from './a98/convertA98ToXyz65.js';
-export { default as convertCubehelixToRgb } from './cubehelix/convertCubehelixToRgb.js';
-export { default as convertDlchToLab65 } from './dlch/convertDlchToLab65.js';
-export { default as convertHsiToRgb } from './hsi/convertHsiToRgb.js';
-export { default as convertHslToRgb } from './hsl/convertHslToRgb.js';
-export { default as convertHsvToRgb } from './hsv/convertHsvToRgb.js';
-export { default as convertHwbToRgb } from './hwb/convertHwbToRgb.js';
-export { default as convertItpToXyz65 } from './itp/convertItpToXyz65.js';
-export { default as convertJabToJch } from './jch/convertJabToJch.js';
-export { default as convertJabToRgb } from './jab/convertJabToRgb.js';
-export { default as convertJabToXyz65 } from './jab/convertJabToXyz65.js';
-export { default as convertJchToJab } from './jch/convertJchToJab.js';
-export { default as convertLab65ToDlch } from './dlch/convertLab65ToDlch.js';
-export { default as convertLab65ToRgb } from './lab65/convertLab65ToRgb.js';
-export { default as convertLab65ToXyz65 } from './lab65/convertLab65ToXyz65.js';
-export { default as convertLabToLch } from './lch/convertLabToLch.js';
-export { default as convertLabToRgb } from './lab/convertLabToRgb.js';
-export { default as convertLabToXyz50 } from './lab/convertLabToXyz50.js';
-export { default as convertLchToLab } from './lch/convertLchToLab.js';
-export { default as convertLchuvToLuv } from './lchuv/convertLchuvToLuv.js';
-export { default as convertLrgbToOklab } from './oklab/convertLrgbToOklab.js';
-export { default as convertLrgbToRgb } from './lrgb/convertLrgbToRgb.js';
-export { default as convertLuvToLchuv } from './lchuv/convertLuvToLchuv.js';
-export { default as convertLuvToXyz50 } from './luv/convertLuvToXyz50.js';
-export { default as convertOkhslToOklab } from './okhsl/convertOkhslToOklab.js';
-export { default as convertOkhsvToOklab } from './okhsv/convertOkhsvToOklab.js';
-export { default as convertOklabToLrgb } from './oklab/convertOklabToLrgb.js';
-export { default as convertOklabToOkhsl } from './okhsl/convertOklabToOkhsl.js';
-export { default as convertOklabToOkhsv } from './okhsv/convertOklabToOkhsv.js';
-export { default as convertOklabToRgb } from './oklab/convertOklabToRgb.js';
-export { default as convertP3ToXyz65 } from './p3/convertP3ToXyz65.js';
-export { default as convertProphotoToXyz50 } from './prophoto/convertProphotoToXyz50.js';
-export { default as convertRec2020ToXyz65 } from './rec2020/convertRec2020ToXyz65.js';
-export { default as convertRgbToCubehelix } from './cubehelix/convertRgbToCubehelix.js';
-export { default as convertRgbToHsi } from './hsi/convertRgbToHsi.js';
-export { default as convertRgbToHsl } from './hsl/convertRgbToHsl.js';
-export { default as convertRgbToHsv } from './hsv/convertRgbToHsv.js';
-export { default as convertRgbToHwb } from './hwb/convertRgbToHwb.js';
-export { default as convertRgbToJab } from './jab/convertRgbToJab.js';
-export { default as convertRgbToLab } from './lab/convertRgbToLab.js';
-export { default as convertRgbToLab65 } from './lab65/convertRgbToLab65.js';
-export { default as convertRgbToLrgb } from './lrgb/convertRgbToLrgb.js';
-export { default as convertRgbToOklab } from './oklab/convertRgbToOklab.js';
-export { default as convertRgbToXyb } from './xyb/convertRgbToXyb.js';
-export { default as convertRgbToXyz50 } from './xyz50/convertRgbToXyz50.js';
-export { default as convertRgbToXyz65 } from './xyz65/convertRgbToXyz65.js';
-export { default as convertRgbToYiq } from './yiq/convertRgbToYiq.js';
-export { default as convertXybToRgb } from './xyb/convertXybToRgb.js';
-export { default as convertXyz50ToLab } from './lab/convertXyz50ToLab.js';
-export { default as convertXyz50ToLuv } from './luv/convertXyz50ToLuv.js';
-export { default as convertXyz50ToProphoto } from './prophoto/convertXyz50ToProphoto.js';
-export { default as convertXyz50ToRgb } from './xyz50/convertXyz50ToRgb.js';
-export { default as convertXyz50ToXyz65 } from './xyz65/convertXyz50ToXyz65.js';
-export { default as convertXyz65ToA98 } from './a98/convertXyz65ToA98.js';
-export { default as convertXyz65ToItp } from './itp/convertXyz65ToItp.js';
-export { default as convertXyz65ToJab } from './jab/convertXyz65ToJab.js';
-export { default as convertXyz65ToLab65 } from './lab65/convertXyz65ToLab65.js';
-export { default as convertXyz65ToP3 } from './p3/convertXyz65ToP3.js';
-export { default as convertXyz65ToRec2020 } from './rec2020/convertXyz65ToRec2020.js';
-export { default as convertXyz65ToRgb } from './xyz65/convertXyz65ToRgb.js';
-export { default as convertXyz65ToXyz50 } from './xyz65/convertXyz65ToXyz50.js';
-export { default as convertYiqToRgb } from './yiq/convertYiqToRgb.js';
-
-export {
-	modeA98,
-	modeCubehelix,
-	modeDlab,
-	modeDlch,
-	modeHsi,
-	modeHsl,
-	modeHsv,
-	modeHwb,
-	modeItp,
-	modeJab,
-	modeJch,
-	modeLab,
-	modeLab65,
-	modeLch,
-	modeLch65,
-	modeLchuv,
-	modeLrgb,
-	modeLuv,
-	modeOkhsl,
-	modeOkhsv,
-	modeOklab,
-	modeOklch,
-	modeP3,
-	modeProphoto,
-	modeRec2020,
-	modeRgb,
-	modeXyb,
-	modeXyz50,
-	modeXyz65,
-	modeYiq
-};
-
-export const a98 = useMode(modeA98);
-export const cubehelix = useMode(modeCubehelix);
-export const dlab = useMode(modeDlab);
-export const dlch = useMode(modeDlch);
-export const hsi = useMode(modeHsi);
-export const hsl = useMode(modeHsl);
-export const hsv = useMode(modeHsv);
-export const hwb = useMode(modeHwb);
-export const itp = useMode(modeItp);
-export const jab = useMode(modeJab);
-export const jch = useMode(modeJch);
-export const lab = useMode(modeLab);
-export const lab65 = useMode(modeLab65);
-export const lch = useMode(modeLch);
-export const lch65 = useMode(modeLch65);
-export const lchuv = useMode(modeLchuv);
-export const lrgb = useMode(modeLrgb);
-export const luv = useMode(modeLuv);
-export const okhsl = useMode(modeOkhsl);
-export const okhsv = useMode(modeOkhsv);
-export const oklab = useMode(modeOklab);
-export const oklch = useMode(modeOklch);
-export const p3 = useMode(modeP3);
-export const prophoto = useMode(modeProphoto);
-export const rec2020 = useMode(modeRec2020);
-export const rgb = useMode(modeRgb);
-export const xyb = useMode(modeXyb);
-export const xyz50 = useMode(modeXyz50);
-export const xyz65 = useMode(modeXyz65);
-export const yiq = useMode(modeYiq);
diff --git a/src/interpolate/interpolate.js b/src/interpolate/interpolate.js
deleted file mode 100644
index 51b8c150..00000000
--- a/src/interpolate/interpolate.js
+++ /dev/null
@@ -1,155 +0,0 @@
-import converter from '../converter.js';
-import { getMode } from '../modes.js';
-import normalizePositions from '../util/normalizePositions.js';
-import easingMidpoint from '../easing/midpoint.js';
-import { mapper, mapAlphaMultiply, mapAlphaDivide } from '../map.js';
-
-const isfn = o => typeof o === 'function';
-const isobj = o => o && typeof o === 'object';
-const isnum = o => typeof o === 'number';
-
-const interpolate_fn = (colors, mode = 'rgb', overrides, premap) => {
-	let def = getMode(mode);
-	let conv = converter(mode);
-
-	let conv_colors = [];
-	let positions = [];
-	let fns = {};
-
-	colors.forEach(val => {
-		if (Array.isArray(val)) {
-			conv_colors.push(conv(val[0]));
-			positions.push(val[1]);
-		} else if (isnum(val) || isfn(val)) {
-			// Color interpolation hint or easing function
-			fns[positions.length] = val;
-		} else {
-			conv_colors.push(conv(val));
-			positions.push(undefined);
-		}
-	});
-
-	normalizePositions(positions);
-
-	// override the default interpolators
-	// from the color space definition with any custom ones
-	let fixed = def.channels.reduce((res, ch) => {
-		let ffn;
-		if (isobj(overrides) && isobj(overrides[ch]) && overrides[ch].fixup) {
-			ffn = overrides[ch].fixup;
-		} else if (isobj(def.interpolate[ch]) && def.interpolate[ch].fixup) {
-			ffn = def.interpolate[ch].fixup;
-		} else {
-			ffn = v => v;
-		}
-		res[ch] = ffn(conv_colors.map(color => color[ch]));
-		return res;
-	}, {});
-
-	if (premap) {
-		let ccolors = conv_colors.map((color, idx) => {
-			return def.channels.reduce(
-				(c, ch) => {
-					c[ch] = fixed[ch][idx];
-					return c;
-				},
-				{ mode }
-			);
-		});
-		fixed = def.channels.reduce((res, ch) => {
-			res[ch] = ccolors.map(c => {
-				let v = premap(c[ch], ch, c, mode);
-				return isNaN(v) ? undefined : v;
-			});
-			return res;
-		}, {});
-	}
-
-	let interpolators = def.channels.reduce((res, ch) => {
-		let ifn;
-		if (isfn(overrides)) {
-			ifn = overrides;
-		} else if (isobj(overrides) && isfn(overrides[ch])) {
-			ifn = overrides[ch];
-		} else if (
-			isobj(overrides) &&
-			isobj(overrides[ch]) &&
-			overrides[ch].use
-		) {
-			ifn = overrides[ch].use;
-		} else if (isfn(def.interpolate[ch])) {
-			ifn = def.interpolate[ch];
-		} else if (isobj(def.interpolate[ch])) {
-			ifn = def.interpolate[ch].use;
-		}
-
-		res[ch] = ifn(fixed[ch]);
-		return res;
-	}, {});
-
-	let n = conv_colors.length - 1;
-
-	return t => {
-		// clamp t to the [0, 1] interval
-		t = Math.min(Math.max(0, t), 1);
-
-		if (t <= positions[0]) {
-			return conv_colors[0];
-		}
-
-		if (t > positions[n]) {
-			return conv_colors[n];
-		}
-
-		// Convert `t` from [0, 1] to `t0` between the appropriate two colors.
-		// First, look for the two colors between which `t` is located.
-		// Note: this can be optimized by searching for the index
-		// through bisection instead of start-to-end.
-		let idx = 0;
-		while (positions[idx] < t) idx++;
-		let start = positions[idx - 1];
-		let delta = positions[idx] - start;
-
-		let P = (t - start) / delta;
-
-		// use either the local easing, or the global easing, if any
-		let fn = fns[idx] || fns[0];
-		if (fn !== undefined) {
-			if (isnum(fn)) {
-				fn = easingMidpoint((fn - start) / delta);
-			}
-			P = fn(P);
-		}
-
-		let t0 = (idx - 1 + P) / n;
-
-		return def.channels.reduce(
-			(res, channel) => {
-				let val = interpolators[channel](t0);
-				if (val !== undefined) {
-					res[channel] = val;
-				}
-				return res;
-			},
-			{ mode }
-		);
-	};
-};
-
-const interpolate = (colors, mode = 'rgb', overrides) =>
-	interpolate_fn(colors, mode, overrides);
-
-const interpolateWith =
-	(premap, postmap) =>
-	(colors, mode = 'rgb', overrides) => {
-		let post = postmap ? mapper(postmap, mode) : undefined;
-		let it = interpolate_fn(colors, mode, overrides, premap);
-		return post ? t => post(it(t)) : it;
-	};
-
-const interpolateWithPremultipliedAlpha = interpolateWith(
-	mapAlphaMultiply,
-	mapAlphaDivide
-);
-
-export { interpolate, interpolateWith, interpolateWithPremultipliedAlpha };
diff --git a/src/interpolate/lerp.js b/src/interpolate/lerp.js
deleted file mode 100644
index 9176f77a..00000000
--- a/src/interpolate/lerp.js
+++ /dev/null
@@ -1,28 +0,0 @@
-const lerp = (a, b, t) => a + t * (b - a);
-const unlerp = (a, b, v) => (v - a) / (b - a);
-
-const blerp = (a00, a01, a10, a11, tx, ty) => {
-	return lerp(lerp(a00, a01, tx), lerp(a10, a11, tx), ty);
-};
-
-const trilerp = (
-	a000,
-	a010,
-	a100,
-	a110,
-	a001,
-	a011,
-	a101,
-	a111,
-	tx,
-	ty,
-	tz
-) => {
-	return lerp(
-		blerp(a000, a010, a100, a110, tx, ty),
-		blerp(a001, a011, a101, a111, tx, ty),
-		tz
-	);
-};
-
-export { lerp, blerp, trilerp, unlerp };
diff --git a/src/interpolate/linear.js b/src/interpolate/linear.js
deleted file mode 100644
index aa25b208..00000000
--- a/src/interpolate/linear.js
+++ /dev/null
@@ -1,4 +0,0 @@
-import { lerp } from './lerp.js';
-import { interpolatorPiecewise } from './piecewise.js';
-
-export const interpolatorLinear = interpolatorPiecewise(lerp);
diff --git a/src/interpolate/piecewise.js b/src/interpolate/piecewise.js
deleted file mode 100644
index 08e78e1c..00000000
--- a/src/interpolate/piecewise.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const get_classes = arr => {
-	let classes = [];
-	for (let i = 0; i < arr.length - 1; i++) {
-		let a = arr[i];
-		let b = arr[i + 1];
-		if (a === undefined && b === undefined) {
-			classes.push(undefined);
-		} else if (a !== undefined && b !== undefined) {
-			classes.push([a, b]);
-		} else {
-			classes.push(a !== undefined ? [a, a] : [b, b]);
-		}
-	}
-	return classes;
-};
-
-const interpolatorPiecewise = interpolator => arr => {
-	let classes = get_classes(arr);
-	return t => {
-		let cls = t * classes.length;
-		let idx = t >= 1 ? classes.length - 1 : Math.max(Math.floor(cls), 0);
-		let pair = classes[idx];
-		return pair === undefined
-			? undefined
-			: interpolator(pair[0], pair[1], cls - idx);
-	};
-};
-
-export { interpolatorPiecewise };
diff --git a/src/interpolate/splineBasis.js b/src/interpolate/splineBasis.js
deleted file mode 100644
index fc887c8b..00000000
--- a/src/interpolate/splineBasis.js
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
-	Basis spline
-	------------
-
-	Given control points V0...Vn (our values)
-
-		S0 = V0
-		...
-		Si = 1/6 * Vi-1 + 2/3 * Vi + 1/6 * Vi+1
-		...
-		Sn = Vn
-
-	The Bézier curve has control points:
-
-		Bi = Si-1, 2/3 * Vi-1 + 1/3 * Vi, 1/3 * Vi-1 + 2/3 * Vi, Si
-
-	Which we can then factor into the Bezier's explicit form:
-	
-		B(t) = (1-t)^3 * P0 + 3 * (1-t)^2 * t * P1 + (1-t) * t^2 * P2 + t^3 * P3 
-
- */
-const mod = (v, l) => (v + l) % l;
-
-const bspline = (Vim2, Vim1, Vi, Vip1, t) => {
-	let t2 = t * t;
-	let t3 = t2 * t;
-	return (
-		((1 - 3 * t + 3 * t2 - t3) * Vim2 +
-			(4 - 6 * t2 + 3 * t3) * Vim1 +
-			(1 + 3 * t + 3 * t2 - 3 * t3) * Vi +
-			t3 * Vip1) /
-		6
-	);
-};
-
-export const interpolatorSplineBasis = arr => t => {
-	let classes = arr.length - 1;
-	let i = t >= 1 ? classes - 1 : Math.max(0, Math.floor(t * classes));
-	return bspline(
-		i > 0 ? arr[i - 1] : 2 * arr[i] - arr[i + 1],
-		arr[i],
-		arr[i + 1],
-		i < classes - 1 ? arr[i + 2] : 2 * arr[i + 1] - arr[i],
-		(t - i / classes) * classes
-	);
-};
-
-export const interpolatorSplineBasisClosed = arr => t => {
-	const classes = arr.length - 1;
-	const i = Math.floor(t * classes);
-	return bspline(
-		arr[mod(i - 1, arr.length)],
-		arr[mod(i, arr.length)],
-		arr[mod(i + 1, arr.length)],
-		arr[mod(i + 2, arr.length)],
-		(t - i / classes) * classes
-	);
-};
diff --git a/src/interpolate/splineMonotone.js b/src/interpolate/splineMonotone.js
deleted file mode 100644
index 4704b210..00000000
--- a/src/interpolate/splineMonotone.js
+++ /dev/null
@@ -1,128 +0,0 @@
-import { interpolatorLinear } from './linear.js';
-
-/* 
-	Monotone spline
-	---------------
-
-	Based on:
-
-		Steffen, M.
-		"A simple method for monotonic interpolation in one dimension."
-		in Astronomy and Astrophysics, Vol. 239, p. 443-450 (Nov. 1990),
-      	Provided by the SAO/NASA Astrophysics Data System.
-
-		https://ui.adsabs.harvard.edu/abs/1990A&A...239..443S
-
-	(Reference thanks to `d3/d3-shape`)
-*/
-
-const sgn = Math.sign;
-const min = Math.min;
-const abs = Math.abs;
-
-const mono = arr => {
-	let n = arr.length - 1;
-	let s = [];
-	let p = [];
-	let yp = [];
-	for (let i = 0; i < n; i++) {
-		s.push((arr[i + 1] - arr[i]) * n);
-		p.push(i > 0 ? 0.5 * (arr[i + 1] - arr[i - 1]) * n : undefined);
-		yp.push(
-			i > 0
-				? (sgn(s[i - 1]) + sgn(s[i])) *
-						min(abs(s[i - 1]), abs(s[i]), 0.5 * abs(p[i]))
-				: undefined
-		);
-	}
-	return [s, p, yp];
-};
-
-const interpolator = (arr, yp, s) => {
-	let n = arr.length - 1;
-	let n2 = n * n;
-	return t => {
-		let i;
-		if (t >= 1) {
-			i = n - 1;
-		} else {
-			i = Math.max(0, Math.floor(t * n));
-		}
-		let t1 = t - i / n;
-		let t2 = t1 * t1;
-		let t3 = t2 * t1;
-		return (
-			(yp[i] + yp[i + 1] - 2 * s[i]) * n2 * t3 +
-			(3 * s[i] - 2 * yp[i] - yp[i + 1]) * n * t2 +
-			yp[i] * t1 +
-			arr[i]
-		);
-	};
-};
-
-/*
-	A monotone spline which uses one-sided finite differences
-	at the boundaries.
- */
-export const interpolatorSplineMonotone = arr => {
-	if (arr.length < 3) {
-		return interpolatorLinear(arr);
-	}
-	let n = arr.length - 1;
-	let [s, , yp] = mono(arr);
-	yp[0] = s[0];
-	yp[n] = s[n - 1];
-	return interpolator(arr, yp, s);
-};
-
-/*
-	The clamped monotone spline derives the values of y' 
-	at the boundary points by tracing a parabola 
-	through the first/last three points.
-
-	For arrays of fewer than three values, we fall back to 
-	linear interpolation.
- */
-
-export const interpolatorSplineMonotone2 = arr => {
-	if (arr.length < 3) {
-		return interpolatorLinear(arr);
-	}
-	let n = arr.length - 1;
-	let [s, p, yp] = mono(arr);
-	p[0] = (arr[1] * 2 - arr[0] * 1.5 - arr[2] * 0.5) * n;
-	p[n] = (arr[n] * 1.5 - arr[n - 1] * 2 + arr[n - 2] * 0.5) * n;
-	yp[0] = p[0] * s[0] <= 0 ? 0 : abs(p[0]) > 2 * abs(s[0]) ? 2 * s[0] : p[0];
-	yp[n] =
-		p[n] * s[n - 1] <= 0
-			? 0
-			: abs(p[n]) > 2 * abs(s[n - 1])
-			? 2 * s[n - 1]
-			: p[n];
-	return interpolator(arr, yp, s);
-};
-
-/*
-	The closed monotone spline considers 
-	the array to be periodic:
-
-	arr[-1] = arr[arr.length - 1]
-	arr[arr.length] = arr[0]
-
-	...and so on.
- */
-export const interpolatorSplineMonotoneClosed = arr => {
-	let n = arr.length - 1;
-	let [s, p, yp] = mono(arr);
-	// boundary conditions
-	p[0] = 0.5 * (arr[1] - arr[n]) * n;
-	p[n] = 0.5 * (arr[0] - arr[n - 1]) * n;
-	let s_m1 = (arr[0] - arr[n]) * n;
-	let s_n = s_m1;
-	yp[0] =
-		(sgn(s_m1) + sgn(s[0])) * min(abs(s_m1), abs(s[0]), 0.5 * abs(p[0]));
-	yp[n] =
-		(sgn(s[n - 1]) + sgn(s_n)) *
-		min(abs(s[n - 1]), abs(s_n), 0.5 * abs(p[n]));
-	return interpolator(arr, yp, s);
-};
diff --git a/src/interpolate/splineNatural.js b/src/interpolate/splineNatural.js
deleted file mode 100644
index 17a3f934..00000000
--- a/src/interpolate/splineNatural.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import {
-	interpolatorSplineBasisClosed,
-	interpolatorSplineBasis
-} from './splineBasis.js';
-
-const solve = v => {
-	let i;
-	let n = v.length - 1;
-	let c = new Array(n);
-	let _v = new Array(n);
-	let sol = new Array(n);
-
-	c[1] = 1 / 4;
-	_v[1] = (6 * v[1] - v[0]) / 4;
-
-	for (i = 2; i < n; ++i) {
-		c[i] = 1 / (4 - c[i - 1]);
-		_v[i] = (6 * v[i] - (i == n - 1 ? v[n] : 0) - _v[i - 1]) * c[i];
-	}
-
-	sol[0] = v[0];
-	sol[n] = v[n];
-	if (n - 1 > 0) {
-		sol[n - 1] = _v[n - 1];
-	}
-
-	for (i = n - 2; i > 0; --i) {
-		sol[i] = _v[i] - c[i] * sol[i + 1];
-	}
-
-	return sol;
-};
-
-export const interpolatorSplineNatural = arr =>
-	interpolatorSplineBasis(solve(arr));
-export const interpolatorSplineNaturalClosed = arr =>
-	interpolatorSplineBasisClosed(solve(arr));
diff --git a/src/itp/convertItpToXyz65.js b/src/itp/convertItpToXyz65.js
deleted file mode 100644
index 2796dcb7..00000000
--- a/src/itp/convertItpToXyz65.js
+++ /dev/null
@@ -1,47 +0,0 @@
-import { YW } from '../hdr/constants.js';
-import { transferPqDecode } from '../hdr/transfer.js';
-
-const toRel = c => Math.max(c / YW, 0);
-
-const convertItpToXyz65 = ({ i, t, p, alpha }) => {
-	if (i === undefined) i = 0;
-	if (t === undefined) t = 0;
-	if (p === undefined) p = 0;
-
-	const l = transferPqDecode(
-		i + 0.008609037037932761 * t + 0.11102962500302593 * p
-	);
-	const m = transferPqDecode(
-		i - 0.00860903703793275 * t - 0.11102962500302599 * p
-	);
-	const s = transferPqDecode(
-		i + 0.5600313357106791 * t - 0.32062717498731885 * p
-	);
-
-	const res = {
-		mode: 'xyz65',
-		x: toRel(
-			2.0701522183894219 * l -
-				1.3263473389671556 * m +
-				0.2066510476294051 * s
-		),
-		y: toRel(
-			0.3647385209748074 * l +
-				0.680566024947227 * m -
-				0.0453045459220346 * s
-		),
-		z: toRel(
-			-0.049747207535812 * l -
-				0.0492609666966138 * m +
-				1.1880659249923042 * s
-		)
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertItpToXyz65;
diff --git a/src/itp/convertXyz65ToItp.js b/src/itp/convertXyz65ToItp.js
deleted file mode 100644
index 8c1040db..00000000
--- a/src/itp/convertXyz65ToItp.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import { YW } from '../hdr/constants.js';
-import { transferPqEncode } from '../hdr/transfer.js';
-
-const toAbs = (c = 0) => Math.max(c * YW, 0);
-
-const convertXyz65ToItp = ({ x, y, z, alpha }) => {
-	const absX = toAbs(x);
-	const absY = toAbs(y);
-	const absZ = toAbs(z);
-	const l = transferPqEncode(
-		0.3592832590121217 * absX +
-			0.6976051147779502 * absY -
-			0.0358915932320289 * absZ
-	);
-	const m = transferPqEncode(
-		-0.1920808463704995 * absX +
-			1.1004767970374323 * absY +
-			0.0753748658519118 * absZ
-	);
-	const s = transferPqEncode(
-		0.0070797844607477 * absX +
-			0.0748396662186366 * absY +
-			0.8433265453898765 * absZ
-	);
-
-	const i = 0.5 * l + 0.5 * m;
-	const t = 1.61376953125 * l - 3.323486328125 * m + 1.709716796875 * s;
-	const p = 4.378173828125 * l - 4.24560546875 * m - 0.132568359375 * s;
-
-	const res = { mode: 'itp', i, t, p };
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertXyz65ToItp;
diff --git a/src/itp/definition.js b/src/itp/definition.js
deleted file mode 100644
index 928f20df..00000000
--- a/src/itp/definition.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import convertItpToXyz65 from './convertItpToXyz65.js';
-import convertXyz65ToItp from './convertXyz65ToItp.js';
-import convertRgbToXyz65 from '../xyz65/convertRgbToXyz65.js';
-import convertXyz65ToRgb from '../xyz65/convertXyz65ToRgb.js';
-
-/*
-  ICtCp (or ITP) color space, as defined in ITU-R Recommendation BT.2100.
-
-  ICtCp is drafted to be supported in CSS within
-  [CSS Color HDR Module Level 1](https://drafts.csswg.org/css-color-hdr/#ICtCp) spec.
-*/
-
-const definition = {
-	mode: 'itp',
-	channels: ['i', 't', 'p', 'alpha'],
-	parse: ['--ictcp'],
-	serialize: '--ictcp',
-
-	toMode: {
-		xyz65: convertItpToXyz65,
-		rgb: color => convertXyz65ToRgb(convertItpToXyz65(color))
-	},
-
-	fromMode: {
-		xyz65: convertXyz65ToItp,
-		rgb: color => convertXyz65ToItp(convertRgbToXyz65(color))
-	},
-
-	ranges: {
-		i: [0, 0.581],
-		t: [-0.369, 0.272],
-		p: [-0.164, 0.331]
-	},
-
-	interpolate: {
-		i: interpolatorLinear,
-		t: interpolatorLinear,
-		p: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/src/jab/convertJabToRgb.js b/src/jab/convertJabToRgb.js
deleted file mode 100644
index a041274b..00000000
--- a/src/jab/convertJabToRgb.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import convertXyz65ToRgb from '../xyz65/convertXyz65ToRgb.js';
-import convertJabToXyz65 from './convertJabToXyz65.js';
-
-const convertJabToRgb = color => convertXyz65ToRgb(convertJabToXyz65(color));
-
-export default convertJabToRgb;
diff --git a/src/jab/convertJabToXyz65.js b/src/jab/convertJabToXyz65.js
deleted file mode 100644
index 95b415dc..00000000
--- a/src/jab/convertJabToXyz65.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import { M1 as n, C1, C2, C3 } from '../hdr/transfer.js';
-const p = 134.03437499999998; // = 1.7 * 2523 / Math.pow(2, 5);
-const d0 = 1.6295499532821566e-11;
-
-/* 
-	The encoding function is derived from Perceptual Quantizer.
-*/
-const jabPqDecode = v => {
-	if (v < 0) return 0;
-	let vp = Math.pow(v, 1 / p);
-	return 10000 * Math.pow((C1 - vp) / (C3 * vp - C2), 1 / n);
-};
-
-const rel = v => v / 203;
-
-const convertJabToXyz65 = ({ j, a, b, alpha }) => {
-	if (j === undefined) j = 0;
-	if (a === undefined) a = 0;
-	if (b === undefined) b = 0;
-	let i = (j + d0) / (0.44 + 0.56 * (j + d0));
-
-	let l = jabPqDecode(i + 0.13860504 * a + 0.058047316 * b);
-	let m = jabPqDecode(i - 0.13860504 * a - 0.058047316 * b);
-	let s = jabPqDecode(i - 0.096019242 * a - 0.8118919 * b);
-
-	let res = {
-		mode: 'xyz65',
-		x: rel(
-			1.661373024652174 * l -
-				0.914523081304348 * m +
-				0.23136208173913045 * s
-		),
-		y: rel(
-			-0.3250758611844533 * l +
-				1.571847026732543 * m -
-				0.21825383453227928 * s
-		),
-		z: rel(-0.090982811 * l - 0.31272829 * m + 1.5227666 * s)
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertJabToXyz65;
diff --git a/src/jab/convertRgbToJab.js b/src/jab/convertRgbToJab.js
deleted file mode 100644
index 1ef6f4b5..00000000
--- a/src/jab/convertRgbToJab.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-	Convert sRGB to JzAzBz.
-
-	For achromatic sRGB colors, adjust the equivalent JzAzBz color
-	to be achromatic as well, insteading of having a very slight chroma.
- */
-
-import convertXyz65ToJab from './convertXyz65ToJab.js';
-import convertRgbToXyz65 from '../xyz65/convertRgbToXyz65.js';
-
-const convertRgbToJab = rgb => {
-	let res = convertXyz65ToJab(convertRgbToXyz65(rgb));
-	if (rgb.r === rgb.b && rgb.b === rgb.g) {
-		res.a = res.b = 0;
-	}
-	return res;
-};
-
-export default convertRgbToJab;
diff --git a/src/jab/convertXyz65ToJab.js b/src/jab/convertXyz65ToJab.js
deleted file mode 100644
index d45d45df..00000000
--- a/src/jab/convertXyz65ToJab.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import { M1 as n, C1, C2, C3 } from '../hdr/transfer.js';
-const p = 134.03437499999998; // = 1.7 * 2523 / Math.pow(2, 5);
-const d0 = 1.6295499532821566e-11;
-
-/* 
-	The encoding function is derived from Perceptual Quantizer.
-*/
-const jabPqEncode = v => {
-	if (v < 0) return 0;
-	let vn = Math.pow(v / 10000, n);
-	return Math.pow((C1 + C2 * vn) / (1 + C3 * vn), p);
-};
-
-// Convert to Absolute XYZ
-const abs = (v = 0) => Math.max(v * 203, 0);
-
-const convertXyz65ToJab = ({ x, y, z, alpha }) => {
-	x = abs(x);
-	y = abs(y);
-	z = abs(z);
-
-	let xp = 1.15 * x - 0.15 * z;
-	let yp = 0.66 * y + 0.34 * x;
-
-	let l = jabPqEncode(0.41478972 * xp + 0.579999 * yp + 0.014648 * z);
-	let m = jabPqEncode(-0.20151 * xp + 1.120649 * yp + 0.0531008 * z);
-	let s = jabPqEncode(-0.0166008 * xp + 0.2648 * yp + 0.6684799 * z);
-
-	let i = (l + m) / 2;
-
-	let res = {
-		mode: 'jab',
-		j: (0.44 * i) / (1 - 0.56 * i) - d0,
-		a: 3.524 * l - 4.066708 * m + 0.542708 * s,
-		b: 0.199076 * l + 1.096799 * m - 1.295875 * s
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertXyz65ToJab;
diff --git a/src/jab/definition.js b/src/jab/definition.js
deleted file mode 100644
index 26945c92..00000000
--- a/src/jab/definition.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-	The JzAzBz color space.
-
-	Based on:
-
-	Muhammad Safdar, Guihua Cui, Youn Jin Kim, and Ming Ronnier Luo, 
-	"Perceptually uniform color space for image signals 
-	including high dynamic range and wide gamut," 
-	Opt. Express 25, 15131-15151 (2017) 
-
-	https://doi.org/10.1364/OE.25.015131
- */
-
-import convertXyz65ToJab from './convertXyz65ToJab.js';
-import convertJabToXyz65 from './convertJabToXyz65.js';
-import convertRgbToJab from './convertRgbToJab.js';
-import convertJabToRgb from './convertJabToRgb.js';
-
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-const definition = {
-	mode: 'jab',
-	channels: ['j', 'a', 'b', 'alpha'],
-
-	parse: ['--jzazbz'],
-	serialize: '--jzazbz',
-
-	fromMode: {
-		rgb: convertRgbToJab,
-		xyz65: convertXyz65ToJab
-	},
-
-	toMode: {
-		rgb: convertJabToRgb,
-		xyz65: convertJabToXyz65
-	},
-
-	ranges: {
-		j: [0, 0.222],
-		a: [-0.109, 0.129],
-		b: [-0.185, 0.134]
-	},
-
-	interpolate: {
-		j: interpolatorLinear,
-		a: interpolatorLinear,
-		b: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/src/jch/convertJabToJch.js b/src/jch/convertJabToJch.js
deleted file mode 100644
index ecf1e89e..00000000
--- a/src/jch/convertJabToJch.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import normalizeHue from '../util/normalizeHue.js';
-
-const convertJabToJch = ({ j, a, b, alpha }) => {
-	if (a === undefined) a = 0;
-	if (b === undefined) b = 0;
-	let c = Math.sqrt(a * a + b * b);
-	let res = {
-		mode: 'jch',
-		j,
-		c
-	};
-	if (c) {
-		res.h = normalizeHue((Math.atan2(b, a) * 180) / Math.PI);
-	}
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertJabToJch;
diff --git a/src/jch/convertJchToJab.js b/src/jch/convertJchToJab.js
deleted file mode 100644
index 809d6624..00000000
--- a/src/jch/convertJchToJab.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const convertJchToJab = ({ j, c, h, alpha }) => {
-	if (h === undefined) h = 0;
-	let res = {
-		mode: 'jab',
-		j,
-		a: c ? c * Math.cos((h / 180) * Math.PI) : 0,
-		b: c ? c * Math.sin((h / 180) * Math.PI) : 0
-	};
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertJchToJab;
diff --git a/src/jch/definition.js b/src/jch/definition.js
deleted file mode 100644
index dbf1c3da..00000000
--- a/src/jch/definition.js
+++ /dev/null
@@ -1,52 +0,0 @@
-import convertJabToJch from './convertJabToJch.js';
-import convertJchToJab from './convertJchToJab.js';
-import convertJabToRgb from '../jab/convertJabToRgb.js';
-import convertRgbToJab from '../jab/convertRgbToJab.js';
-
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueChroma } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'jch',
-
-	parse: ['--jzczhz'],
-	serialize: '--jzczhz',
-
-	toMode: {
-		jab: convertJchToJab,
-		rgb: c => convertJabToRgb(convertJchToJab(c))
-	},
-
-	fromMode: {
-		rgb: c => convertJabToJch(convertRgbToJab(c)),
-		jab: convertJabToJch
-	},
-
-	channels: ['j', 'c', 'h', 'alpha'],
-
-	ranges: {
-		j: [0, 0.221],
-		c: [0, 0.19],
-		h: [0, 360]
-	},
-
-	interpolate: {
-		h: { use: interpolatorLinear, fixup: fixupHueShorter },
-		c: interpolatorLinear,
-		j: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-
-	difference: {
-		h: differenceHueChroma
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/lab/convertLabToRgb.js b/src/lab/convertLabToRgb.js
deleted file mode 100644
index 757f5c49..00000000
--- a/src/lab/convertLabToRgb.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import convertLabToXyz50 from './convertLabToXyz50.js';
-import convertXyz50ToRgb from '../xyz50/convertXyz50ToRgb.js';
-
-const convertLabToRgb = lab => convertXyz50ToRgb(convertLabToXyz50(lab));
-
-export default convertLabToRgb;
diff --git a/src/lab/convertLabToXyz50.js b/src/lab/convertLabToXyz50.js
deleted file mode 100644
index 79695e16..00000000
--- a/src/lab/convertLabToXyz50.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { k, e } from '../xyz50/constants.js';
-import { D50 } from '../constants.js';
-
-let fn = v => (Math.pow(v, 3) > e ? Math.pow(v, 3) : (116 * v - 16) / k);
-
-const convertLabToXyz50 = ({ l, a, b, alpha }) => {
-	if (l === undefined) l = 0;
-	if (a === undefined) a = 0;
-	if (b === undefined) b = 0;
-	let fy = (l + 16) / 116;
-	let fx = a / 500 + fy;
-	let fz = fy - b / 200;
-
-	let res = {
-		mode: 'xyz50',
-		x: fn(fx) * D50.X,
-		y: fn(fy) * D50.Y,
-		z: fn(fz) * D50.Z
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertLabToXyz50;
diff --git a/src/lab/convertRgbToLab.js b/src/lab/convertRgbToLab.js
deleted file mode 100644
index 7e34d695..00000000
--- a/src/lab/convertRgbToLab.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import convertRgbToXyz50 from '../xyz50/convertRgbToXyz50.js';
-import convertXyz50ToLab from './convertXyz50ToLab.js';
-
-const convertRgbToLab = rgb => {
-	let res = convertXyz50ToLab(convertRgbToXyz50(rgb));
-
-	// Fixes achromatic RGB colors having a _slight_ chroma due to floating-point errors
-	// and approximated computations in sRGB <-> CIELab.
-	// See: https://github.com/d3/d3-color/pull/46
-	if (rgb.r === rgb.b && rgb.b === rgb.g) {
-		res.a = res.b = 0;
-	}
-	return res;
-};
-
-export default convertRgbToLab;
diff --git a/src/lab/convertXyz50ToLab.js b/src/lab/convertXyz50ToLab.js
deleted file mode 100644
index 2ab779ae..00000000
--- a/src/lab/convertXyz50ToLab.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { k, e } from '../xyz50/constants.js';
-import { D50 } from '../constants.js';
-
-const f = value => (value > e ? Math.cbrt(value) : (k * value + 16) / 116);
-
-const convertXyz50ToLab = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let f0 = f(x / D50.X);
-	let f1 = f(y / D50.Y);
-	let f2 = f(z / D50.Z);
-
-	let res = {
-		mode: 'lab',
-		l: 116 * f1 - 16,
-		a: 500 * (f0 - f1),
-		b: 200 * (f1 - f2)
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertXyz50ToLab;
diff --git a/src/lab/definition.js b/src/lab/definition.js
deleted file mode 100644
index 4cbf7028..00000000
--- a/src/lab/definition.js
+++ /dev/null
@@ -1,46 +0,0 @@
-import convertLabToRgb from './convertLabToRgb.js';
-import convertLabToXyz50 from './convertLabToXyz50.js';
-import convertRgbToLab from './convertRgbToLab.js';
-import convertXyz50ToLab from './convertXyz50ToLab.js';
-import parseLab from './parseLab.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-const definition = {
-	mode: 'lab',
-
-	toMode: {
-		xyz50: convertLabToXyz50,
-		rgb: convertLabToRgb
-	},
-
-	fromMode: {
-		xyz50: convertXyz50ToLab,
-		rgb: convertRgbToLab
-	},
-
-	channels: ['l', 'a', 'b', 'alpha'],
-
-	ranges: {
-		l: [0, 100],
-		a: [-125, 125],
-		b: [-125, 125]
-	},
-
-	parse: [parseLab],
-	serialize: c =>
-		`lab(${c.l !== undefined ? c.l : 'none'} ${
-			c.a !== undefined ? c.a : 'none'
-		} ${c.b !== undefined ? c.b : 'none'}${
-			c.alpha < 1 ? ` / ${c.alpha}` : ''
-		})`,
-
-	interpolate: {
-		l: interpolatorLinear,
-		a: interpolatorLinear,
-		b: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/src/lab/parseLab.js b/src/lab/parseLab.js
deleted file mode 100644
index 94d559e6..00000000
--- a/src/lab/parseLab.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Tok } from '../parse.js';
-
-function parseLab(color, parsed) {
-	if (!parsed || parsed[0] !== 'lab') {
-		return undefined;
-	}
-	const res = { mode: 'lab' };
-	const [, l, a, b, alpha] = parsed;
-	if (l.type === Tok.Hue || a.type === Tok.Hue || b.type === Tok.Hue) {
-		return undefined;
-	}
-	if (l.type !== Tok.None) {
-		res.l = Math.min(Math.max(0, l.value), 100);
-	}
-	if (a.type !== Tok.None) {
-		res.a = a.type === Tok.Number ? a.value : (a.value * 125) / 100;
-	}
-	if (b.type !== Tok.None) {
-		res.b = b.type === Tok.Number ? b.value : (b.value * 125) / 100;
-	}
-	if (alpha.type !== Tok.None) {
-		res.alpha = Math.min(
-			1,
-			Math.max(
-				0,
-				alpha.type === Tok.Number ? alpha.value : alpha.value / 100
-			)
-		);
-	}
-
-	return res;
-}
-
-export default parseLab;
diff --git a/src/lab65/convertLab65ToRgb.js b/src/lab65/convertLab65ToRgb.js
deleted file mode 100644
index 2a835b6a..00000000
--- a/src/lab65/convertLab65ToRgb.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import convertLab65ToXyz65 from './convertLab65ToXyz65.js';
-import convertXyz65ToRgb from '../xyz65/convertXyz65ToRgb.js';
-
-const convertLab65ToRgb = lab => convertXyz65ToRgb(convertLab65ToXyz65(lab));
-
-export default convertLab65ToRgb;
diff --git a/src/lab65/convertLab65ToXyz65.js b/src/lab65/convertLab65ToXyz65.js
deleted file mode 100644
index 354a5b16..00000000
--- a/src/lab65/convertLab65ToXyz65.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import { k, e } from '../xyz65/constants.js';
-import { D65 } from '../constants.js';
-
-let fn = v => (Math.pow(v, 3) > e ? Math.pow(v, 3) : (116 * v - 16) / k);
-
-const convertLab65ToXyz65 = ({ l, a, b, alpha }) => {
-	if (l === undefined) l = 0;
-	if (a === undefined) a = 0;
-	if (b === undefined) b = 0;
-
-	let fy = (l + 16) / 116;
-	let fx = a / 500 + fy;
-	let fz = fy - b / 200;
-
-	let res = {
-		mode: 'xyz65',
-		x: fn(fx) * D65.X,
-		y: fn(fy) * D65.Y,
-		z: fn(fz) * D65.Z
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertLab65ToXyz65;
diff --git a/src/lab65/convertRgbToLab65.js b/src/lab65/convertRgbToLab65.js
deleted file mode 100644
index 0a882551..00000000
--- a/src/lab65/convertRgbToLab65.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import convertRgbToXyz65 from '../xyz65/convertRgbToXyz65.js';
-import convertXyz65ToLab65 from './convertXyz65ToLab65.js';
-
-const convertRgbToLab65 = rgb => {
-	let res = convertXyz65ToLab65(convertRgbToXyz65(rgb));
-
-	// Fixes achromatic RGB colors having a _slight_ chroma due to floating-point errors
-	// and approximated computations in sRGB <-> CIELab.
-	// See: https://github.com/d3/d3-color/pull/46
-	if (rgb.r === rgb.b && rgb.b === rgb.g) {
-		res.a = res.b = 0;
-	}
-	return res;
-};
-
-export default convertRgbToLab65;
diff --git a/src/lab65/convertXyz65ToLab65.js b/src/lab65/convertXyz65ToLab65.js
deleted file mode 100644
index 5df19221..00000000
--- a/src/lab65/convertXyz65ToLab65.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import { k, e } from '../xyz65/constants.js';
-import { D65 } from '../constants.js';
-
-const f = value => (value > e ? Math.cbrt(value) : (k * value + 16) / 116);
-
-const convertXyz65ToLab65 = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let f0 = f(x / D65.X);
-	let f1 = f(y / D65.Y);
-	let f2 = f(z / D65.Z);
-
-	let res = {
-		mode: 'lab65',
-		l: 116 * f1 - 16,
-		a: 500 * (f0 - f1),
-		b: 200 * (f1 - f2)
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertXyz65ToLab65;
diff --git a/src/lab65/definition.js b/src/lab65/definition.js
deleted file mode 100644
index 36caa6d9..00000000
--- a/src/lab65/definition.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import convertLab65ToRgb from './convertLab65ToRgb.js';
-import convertLab65ToXyz65 from './convertLab65ToXyz65.js';
-import convertRgbToLab65 from './convertRgbToLab65.js';
-import convertXyz65ToLab65 from './convertXyz65ToLab65.js';
-import lab from '../lab/definition.js';
-
-const definition = {
-	...lab,
-	mode: 'lab65',
-
-	parse: ['--lab-d65'],
-	serialize: '--lab-d65',
-
-	toMode: {
-		xyz65: convertLab65ToXyz65,
-		rgb: convertLab65ToRgb
-	},
-
-	fromMode: {
-		xyz65: convertXyz65ToLab65,
-		rgb: convertRgbToLab65
-	},
-
-	ranges: {
-		l: [0, 100],
-		a: [-125, 125],
-		b: [-125, 125]
-	}
-};
-
-export default definition;
diff --git a/src/lch/convertLabToLch.js b/src/lch/convertLabToLch.js
deleted file mode 100644
index 79e66d94..00000000
--- a/src/lch/convertLabToLch.js
+++ /dev/null
@@ -1,18 +0,0 @@
-import normalizeHue from '../util/normalizeHue.js';
-
-/* 
-	References: 
-		* https://drafts.csswg.org/css-color/#lab-to-lch
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-*/
-const convertLabToLch = ({ l, a, b, alpha }, mode = 'lch') => {
-	if (a === undefined) a = 0;
-	if (b === undefined) b = 0;
-	let c = Math.sqrt(a * a + b * b);
-	let res = { mode, l, c };
-	if (c) res.h = normalizeHue((Math.atan2(b, a) * 180) / Math.PI);
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertLabToLch;
diff --git a/src/lch/convertLchToLab.js b/src/lch/convertLchToLab.js
deleted file mode 100644
index 3c12bc3d..00000000
--- a/src/lch/convertLchToLab.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/* 
-	References: 
-		* https://drafts.csswg.org/css-color/#lch-to-lab
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-*/
-const convertLchToLab = ({ l, c, h, alpha }, mode = 'lab') => {
-	if (h === undefined) h = 0;
-	let res = {
-		mode,
-		l,
-		a: c ? c * Math.cos((h / 180) * Math.PI) : 0,
-		b: c ? c * Math.sin((h / 180) * Math.PI) : 0
-	};
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertLchToLab;
diff --git a/src/lch/definition.js b/src/lch/definition.js
deleted file mode 100644
index 403d6428..00000000
--- a/src/lch/definition.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import convertLabToLch from './convertLabToLch.js';
-import convertLchToLab from './convertLchToLab.js';
-import convertLabToRgb from '../lab/convertLabToRgb.js';
-import convertRgbToLab from '../lab/convertRgbToLab.js';
-import parseLch from './parseLch.js';
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueChroma } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const definition = {
-	mode: 'lch',
-
-	toMode: {
-		lab: convertLchToLab,
-		rgb: c => convertLabToRgb(convertLchToLab(c))
-	},
-
-	fromMode: {
-		rgb: c => convertLabToLch(convertRgbToLab(c)),
-		lab: convertLabToLch
-	},
-
-	channels: ['l', 'c', 'h', 'alpha'],
-
-	ranges: {
-		l: [0, 100],
-		c: [0, 150],
-		h: [0, 360]
-	},
-
-	parse: [parseLch],
-	serialize: c =>
-		`lch(${c.l !== undefined ? c.l : 'none'} ${
-			c.c !== undefined ? c.c : 'none'
-		} ${c.h !== undefined ? c.h : 'none'}${
-			c.alpha < 1 ? ` / ${c.alpha}` : ''
-		})`,
-
-	interpolate: {
-		h: { use: interpolatorLinear, fixup: fixupHueShorter },
-		c: interpolatorLinear,
-		l: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-
-	difference: {
-		h: differenceHueChroma
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/lch/parseLch.js b/src/lch/parseLch.js
deleted file mode 100644
index 22fb235e..00000000
--- a/src/lch/parseLch.js
+++ /dev/null
@@ -1,40 +0,0 @@
-import { Tok } from '../parse.js';
-
-function parseLch(color, parsed) {
-	if (!parsed || parsed[0] !== 'lch') {
-		return undefined;
-	}
-	const res = { mode: 'lch' };
-	const [, l, c, h, alpha] = parsed;
-	if (l.type !== Tok.None) {
-		if (l.type === Tok.Hue) {
-			return undefined;
-		}
-		res.l = Math.min(Math.max(0, l.value), 100);
-	}
-	if (c.type !== Tok.None) {
-		res.c = Math.max(
-			0,
-			c.type === Tok.Number ? c.value : (c.value * 150) / 100
-		);
-	}
-	if (h.type !== Tok.None) {
-		if (h.type === Tok.Percentage) {
-			return undefined;
-		}
-		res.h = h.value;
-	}
-	if (alpha.type !== Tok.None) {
-		res.alpha = Math.min(
-			1,
-			Math.max(
-				0,
-				alpha.type === Tok.Number ? alpha.value : alpha.value / 100
-			)
-		);
-	}
-
-	return res;
-}
-
-export default parseLch;
diff --git a/src/lch65/definition.js b/src/lch65/definition.js
deleted file mode 100644
index f8e43025..00000000
--- a/src/lch65/definition.js
+++ /dev/null
@@ -1,31 +0,0 @@
-import convertLabToLch from '../lch/convertLabToLch.js';
-import convertLchToLab from '../lch/convertLchToLab.js';
-import convertLab65ToRgb from '../lab65/convertLab65ToRgb.js';
-import convertRgbToLab65 from '../lab65/convertRgbToLab65.js';
-import lch from '../lch/definition.js';
-
-const definition = {
-	...lch,
-	mode: 'lch65',
-
-	parse: ['--lch-d65'],
-	serialize: '--lch-d65',
-
-	toMode: {
-		lab65: c => convertLchToLab(c, 'lab65'),
-		rgb: c => convertLab65ToRgb(convertLchToLab(c, 'lab65'))
-	},
-
-	fromMode: {
-		rgb: c => convertLabToLch(convertRgbToLab65(c), 'lch65'),
-		lab65: c => convertLabToLch(c, 'lch65')
-	},
-
-	ranges: {
-		l: [0, 100],
-		c: [0, 150],
-		h: [0, 360]
-	}
-};
-
-export default definition;
diff --git a/src/lchuv/convertLchuvToLuv.js b/src/lchuv/convertLchuvToLuv.js
deleted file mode 100644
index 44ec9319..00000000
--- a/src/lchuv/convertLchuvToLuv.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const convertLchuvToLuv = ({ l, c, h, alpha }) => {
-	if (h === undefined) h = 0;
-	let res = {
-		mode: 'luv',
-		l: l,
-		u: c ? c * Math.cos((h / 180) * Math.PI) : 0,
-		v: c ? c * Math.sin((h / 180) * Math.PI) : 0
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertLchuvToLuv;
diff --git a/src/lchuv/convertLuvToLchuv.js b/src/lchuv/convertLuvToLchuv.js
deleted file mode 100644
index f795fee6..00000000
--- a/src/lchuv/convertLuvToLchuv.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import normalizeHue from '../util/normalizeHue.js';
-
-const convertLuvToLchuv = ({ l, u, v, alpha }) => {
-	if (u === undefined) u = 0;
-	if (v === undefined) v = 0;
-	let c = Math.sqrt(u * u + v * v);
-	let res = {
-		mode: 'lchuv',
-		l: l,
-		c: c
-	};
-	if (c) {
-		res.h = normalizeHue((Math.atan2(v, u) * 180) / Math.PI);
-	}
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertLuvToLchuv;
diff --git a/src/lchuv/definition.js b/src/lchuv/definition.js
deleted file mode 100644
index cd807915..00000000
--- a/src/lchuv/definition.js
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
-	CIELChuv color space
-	--------------------
-
-	Reference: 
-
-		https://en.wikipedia.org/wiki/CIELUV
- */
-
-import convertLuvToLchuv from './convertLuvToLchuv.js';
-import convertLchuvToLuv from './convertLchuvToLuv.js';
-import convertXyz50ToLuv from '../luv/convertXyz50ToLuv.js';
-import convertLuvToXyz50 from '../luv/convertLuvToXyz50.js';
-import convertXyz50ToRgb from '../xyz50/convertXyz50ToRgb.js';
-import convertRgbToXyz50 from '../xyz50/convertRgbToXyz50.js';
-
-import { fixupHueShorter } from '../fixup/hue.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { differenceHueChroma } from '../difference.js';
-import { averageAngle } from '../average.js';
-
-const convertRgbToLchuv = rgb =>
-	convertLuvToLchuv(convertXyz50ToLuv(convertRgbToXyz50(rgb)));
-const convertLchuvToRgb = lchuv =>
-	convertXyz50ToRgb(convertLuvToXyz50(convertLchuvToLuv(lchuv)));
-
-const definition = {
-	mode: 'lchuv',
-
-	toMode: {
-		luv: convertLchuvToLuv,
-		rgb: convertLchuvToRgb
-	},
-
-	fromMode: {
-		rgb: convertRgbToLchuv,
-		luv: convertLuvToLchuv
-	},
-
-	channels: ['l', 'c', 'h', 'alpha'],
-
-	parse: ['--lchuv'],
-	serialize: '--lchuv',
-
-	ranges: {
-		l: [0, 100],
-		c: [0, 176.956],
-		h: [0, 360]
-	},
-
-	interpolate: {
-		h: { use: interpolatorLinear, fixup: fixupHueShorter },
-		c: interpolatorLinear,
-		l: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-
-	difference: {
-		h: differenceHueChroma
-	},
-
-	average: {
-		h: averageAngle
-	}
-};
-
-export default definition;
diff --git a/src/lrgb/convertLrgbToRgb.js b/src/lrgb/convertLrgbToRgb.js
deleted file mode 100644
index 93cdcb74..00000000
--- a/src/lrgb/convertLrgbToRgb.js
+++ /dev/null
@@ -1,20 +0,0 @@
-const fn = (c = 0) => {
-	const abs = Math.abs(c);
-	if (abs > 0.0031308) {
-		return (Math.sign(c) || 1) * (1.055 * Math.pow(abs, 1 / 2.4) - 0.055);
-	}
-	return c * 12.92;
-};
-
-const convertLrgbToRgb = ({ r, g, b, alpha }, mode = 'rgb') => {
-	let res = {
-		mode,
-		r: fn(r),
-		g: fn(g),
-		b: fn(b)
-	};
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertLrgbToRgb;
diff --git a/src/lrgb/convertRgbToLrgb.js b/src/lrgb/convertRgbToLrgb.js
deleted file mode 100644
index c1fa88de..00000000
--- a/src/lrgb/convertRgbToLrgb.js
+++ /dev/null
@@ -1,20 +0,0 @@
-const fn = (c = 0) => {
-	const abs = Math.abs(c);
-	if (abs <= 0.04045) {
-		return c / 12.92;
-	}
-	return (Math.sign(c) || 1) * Math.pow((abs + 0.055) / 1.055, 2.4);
-};
-
-const convertRgbToLrgb = ({ r, g, b, alpha }) => {
-	let res = {
-		mode: 'lrgb',
-		r: fn(r),
-		g: fn(g),
-		b: fn(b)
-	};
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertRgbToLrgb;
diff --git a/src/lrgb/definition.js b/src/lrgb/definition.js
deleted file mode 100644
index 127b8123..00000000
--- a/src/lrgb/definition.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import rgb from '../rgb/definition.js';
-import convertRgbToLrgb from './convertRgbToLrgb.js';
-import convertLrgbToRgb from './convertLrgbToRgb.js';
-
-const definition = {
-	...rgb,
-	mode: 'lrgb',
-
-	toMode: {
-		rgb: convertLrgbToRgb
-	},
-
-	fromMode: {
-		rgb: convertRgbToLrgb
-	},
-
-	parse: ['srgb-linear'],
-	serialize: 'srgb-linear'
-};
-
-export default definition;
diff --git a/src/luv/convertLuvToXyz50.js b/src/luv/convertLuvToXyz50.js
deleted file mode 100644
index 27921b36..00000000
--- a/src/luv/convertLuvToXyz50.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import { k } from '../xyz50/constants.js';
-import { D50 } from '../constants.js';
-
-export const u_fn = (x, y, z) => (4 * x) / (x + 15 * y + 3 * z);
-export const v_fn = (x, y, z) => (9 * y) / (x + 15 * y + 3 * z);
-
-export const un = u_fn(D50.X, D50.Y, D50.Z);
-export const vn = v_fn(D50.X, D50.Y, D50.Z);
-
-const convertLuvToXyz50 = ({ l, u, v, alpha }) => {
-	if (l === undefined) l = 0;
-	if (l === 0) {
-		return { mode: 'xyz50', x: 0, y: 0, z: 0 };
-	}
-
-	if (u === undefined) u = 0;
-	if (v === undefined) v = 0;
-
-	let up = u / (13 * l) + un;
-	let vp = v / (13 * l) + vn;
-	let y = D50.Y * (l <= 8 ? l / k : Math.pow((l + 16) / 116, 3));
-	let x = (y * (9 * up)) / (4 * vp);
-	let z = (y * (12 - 3 * up - 20 * vp)) / (4 * vp);
-
-	let res = { mode: 'xyz50', x, y, z };
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertLuvToXyz50;
diff --git a/src/luv/convertXyz50ToLuv.js b/src/luv/convertXyz50ToLuv.js
deleted file mode 100644
index 44040037..00000000
--- a/src/luv/convertXyz50ToLuv.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import { k, e } from '../xyz50/constants.js';
-import { D50 } from '../constants.js';
-
-export const u_fn = (x, y, z) => (4 * x) / (x + 15 * y + 3 * z);
-export const v_fn = (x, y, z) => (9 * y) / (x + 15 * y + 3 * z);
-
-export const un = u_fn(D50.X, D50.Y, D50.Z);
-export const vn = v_fn(D50.X, D50.Y, D50.Z);
-
-const l_fn = value => (value <= e ? k * value : 116 * Math.cbrt(value) - 16);
-
-const convertXyz50ToLuv = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let l = l_fn(y / D50.Y);
-	let u = u_fn(x, y, z);
-	let v = v_fn(x, y, z);
-
-	// guard against NaNs produced by `xyz(0 0 0)` black
-	if (!isFinite(u) || !isFinite(v)) {
-		l = u = v = 0;
-	} else {
-		u = 13 * l * (u - un);
-		v = 13 * l * (v - vn);
-	}
-
-	let res = {
-		mode: 'luv',
-		l,
-		u,
-		v
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertXyz50ToLuv;
diff --git a/src/luv/definition.js b/src/luv/definition.js
deleted file mode 100644
index 308638db..00000000
--- a/src/luv/definition.js
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
-	CIELUV color space
-	------------------
-
-	Reference: 
-
-		https://en.wikipedia.org/wiki/CIELUV
- */
-
-import convertXyz50ToLuv from './convertXyz50ToLuv.js';
-import convertLuvToXyz50 from './convertLuvToXyz50.js';
-import convertXyz50ToRgb from '../xyz50/convertXyz50ToRgb.js';
-import convertRgbToXyz50 from '../xyz50/convertRgbToXyz50.js';
-
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-const definition = {
-	mode: 'luv',
-
-	toMode: {
-		xyz50: convertLuvToXyz50,
-		rgb: luv => convertXyz50ToRgb(convertLuvToXyz50(luv))
-	},
-
-	fromMode: {
-		xyz50: convertXyz50ToLuv,
-		rgb: rgb => convertXyz50ToLuv(convertRgbToXyz50(rgb))
-	},
-
-	channels: ['l', 'u', 'v', 'alpha'],
-
-	parse: ['--luv'],
-	serialize: '--luv',
-
-	ranges: {
-		l: [0, 100],
-		u: [-84.936, 175.042],
-		v: [-125.882, 87.243]
-	},
-
-	interpolate: {
-		l: interpolatorLinear,
-		u: interpolatorLinear,
-		v: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/src/map.js b/src/map.js
deleted file mode 100644
index 33ec7c10..00000000
--- a/src/map.js
+++ /dev/null
@@ -1,72 +0,0 @@
-import converter from './converter.js';
-import prepare from './_prepare.js';
-import { getMode } from './modes.js';
-
-const mapper = (fn, mode = 'rgb', preserve_mode = false) => {
-	let channels = mode ? getMode(mode).channels : null;
-	let conv = mode ? converter(mode) : prepare;
-	return color => {
-		let conv_color = conv(color);
-		if (!conv_color) {
-			return undefined;
-		}
-		let res = (channels || getMode(conv_color.mode).channels).reduce(
-			(res, ch) => {
-				let v = fn(conv_color[ch], ch, conv_color, mode);
-				if (v !== undefined && !isNaN(v)) {
-					res[ch] = v;
-				}
-				return res;
-			},
-			{ mode: conv_color.mode }
-		);
-		if (!preserve_mode) {
-			return res;
-		}
-		let prep = prepare(color);
-		if (prep && prep.mode !== res.mode) {
-			return converter(prep.mode)(res);
-		}
-		return res;
-	};
-};
-
-const mapAlphaMultiply = (v, ch, c) => {
-	if (ch !== 'alpha') {
-		return (v || 0) * (c.alpha !== undefined ? c.alpha : 1);
-	}
-	return v;
-};
-
-const mapAlphaDivide = (v, ch, c) => {
-	if (ch !== 'alpha' && c.alpha !== 0) {
-		return (v || 0) / (c.alpha !== undefined ? c.alpha : 1);
-	}
-	return v;
-};
-
-const mapTransferLinear =
-	(slope = 1, intercept = 0) =>
-	(v, ch) => {
-		if (ch !== 'alpha') {
-			return v * slope + intercept;
-		}
-		return v;
-	};
-
-const mapTransferGamma =
-	(amplitude = 1, exponent = 1, offset = 0) =>
-	(v, ch) => {
-		if (ch !== 'alpha') {
-			return amplitude * Math.pow(v, exponent) + offset;
-		}
-		return v;
-	};
-
-export {
-	mapper,
-	mapAlphaMultiply,
-	mapAlphaDivide,
-	mapTransferLinear,
-	mapTransferGamma
-};
diff --git a/src/modes.js b/src/modes.js
deleted file mode 100644
index 52f60dce..00000000
--- a/src/modes.js
+++ /dev/null
@@ -1,96 +0,0 @@
-import converter from './converter.js';
-
-const converters = {};
-const modes = {};
-
-const parsers = [];
-const colorProfiles = {};
-
-const identity = v => v;
-
-const useMode = definition => {
-	converters[definition.mode] = {
-		...converters[definition.mode],
-		...definition.toMode
-	};
-
-	Object.keys(definition.fromMode || {}).forEach(k => {
-		if (!converters[k]) {
-			converters[k] = {};
-		}
-		converters[k][definition.mode] = definition.fromMode[k];
-	});
-
-	// Color space channel ranges
-	if (!definition.ranges) {
-		definition.ranges = {};
-	}
-
-	if (!definition.difference) {
-		definition.difference = {};
-	}
-
-	definition.channels.forEach(channel => {
-		// undefined channel ranges default to the [0, 1] interval
-		if (definition.ranges[channel] === undefined) {
-			definition.ranges[channel] = [0, 1];
-		}
-
-		if (!definition.interpolate[channel]) {
-			throw new Error(`Missing interpolator for: ${channel}`);
-		}
-
-		if (typeof definition.interpolate[channel] === 'function') {
-			definition.interpolate[channel] = {
-				use: definition.interpolate[channel]
-			};
-		}
-
-		if (!definition.interpolate[channel].fixup) {
-			definition.interpolate[channel].fixup = identity;
-		}
-	});
-
-	modes[definition.mode] = definition;
-	(definition.parse || []).forEach(parser => {
-		useParser(parser, definition.mode);
-	});
-
-	return converter(definition.mode);
-};
-
-const getMode = mode => modes[mode];
-
-const useParser = (parser, mode) => {
-	if (typeof parser === 'string') {
-		if (!mode) {
-			throw new Error(`'mode' required when 'parser' is a string`);
-		}
-		colorProfiles[parser] = mode;
-	} else if (typeof parser === 'function') {
-		if (parsers.indexOf(parser) < 0) {
-			parsers.push(parser);
-		}
-	}
-};
-
-const removeParser = parser => {
-	if (typeof parser === 'string') {
-		delete colorProfiles[parser];
-	} else if (typeof parser === 'function') {
-		const idx = parsers.indexOf(parser);
-		if (idx > 0) {
-			parsers.splice(idx, 1);
-		}
-	}
-};
-
-export {
-	useMode,
-	getMode,
-	useParser,
-	removeParser,
-	converters,
-	parsers,
-	colorProfiles
-};
diff --git a/src/nearest.js b/src/nearest.js
deleted file mode 100644
index 76874fcd..00000000
--- a/src/nearest.js
+++ /dev/null
@@ -1,30 +0,0 @@
-import { differenceEuclidean } from './difference.js';
-
-/*
-	This works linearly right now, but we might get better performance
-	with a V-P Tree (Vantage Point Tree). 
-
-	Reference:
-	* http://pnylab.com/papers/vptree/main.html
- */
-
-const nearest = (colors, metric = differenceEuclidean(), accessor = d => d) => {
-	let arr = colors.map((c, idx) => ({ color: accessor(c), i: idx }));
-	return (color, n = 1, τ = Infinity) => {
-		if (isFinite(n)) {
-			n = Math.max(1, Math.min(n, arr.length - 1));
-		}
-
-		arr.forEach(c => {
-			c.d = metric(color, c.color);
-		});
-
-		return arr
-			.sort((a, b) => a.d - b.d)
-			.slice(0, n)
-			.filter(c => c.d < τ)
-			.map(c => colors[c.i]);
-	};
-};
-
-export default nearest;
diff --git a/src/okhsl/LICENSE b/src/okhsl/LICENSE
deleted file mode 100644
index f7755bb8..00000000
--- a/src/okhsl/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (c) 2021 Björn Ottosson
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
\ No newline at end of file
diff --git a/src/okhsl/convertOkhslToOklab.js b/src/okhsl/convertOkhslToOklab.js
deleted file mode 100644
index 273613d1..00000000
--- a/src/okhsl/convertOkhslToOklab.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-	Adapted from code by Björn Ottosson,
-	released under the MIT license:
-
-	Copyright (c) 2021 Björn Ottosson
-
-	Permission is hereby granted, free of charge, to any person obtaining a copy of
-	this software and associated documentation files (the "Software"), to deal in
-	the Software without restriction, including without limitation the rights to
-	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-	of the Software, and to permit persons to whom the Software is furnished to do
-	so, subject to the following conditions:
-
-	The above copyright notice and this permission notice shall be included in all
-	copies or substantial portions of the Software.
-
-	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-	SOFTWARE.
- */
-
-import { toe_inv, get_Cs } from './helpers.js';
-
-export default function convertOkhslToOklab(hsl) {
-	let h = hsl.h !== undefined ? hsl.h : 0;
-	let s = hsl.s !== undefined ? hsl.s : 0;
-	let l = hsl.l !== undefined ? hsl.l : 0;
-
-	const ret = { mode: 'oklab', l: toe_inv(l) };
-
-	if (hsl.alpha !== undefined) {
-		ret.alpha = hsl.alpha;
-	}
-
-	if (!s || l === 1) {
-		ret.a = ret.b = 0;
-		return ret;
-	}
-
-	let a_ = Math.cos((h / 180) * Math.PI);
-	let b_ = Math.sin((h / 180) * Math.PI);
-	let [C_0, C_mid, C_max] = get_Cs(ret.l, a_, b_);
-	let t, k_0, k_1, k_2;
-	if (s < 0.8) {
-		t = 1.25 * s;
-		k_0 = 0;
-		k_1 = 0.8 * C_0;
-		k_2 = 1 - k_1 / C_mid;
-	} else {
-		t = 5 * (s - 0.8);
-		k_0 = C_mid;
-		k_1 = (0.2 * C_mid * C_mid * 1.25 * 1.25) / C_0;
-		k_2 = 1 - k_1 / (C_max - C_mid);
-	}
-	let C = k_0 + (t * k_1) / (1 - k_2 * t);
-	ret.a = C * a_;
-	ret.b = C * b_;
-
-	return ret;
-}
diff --git a/src/okhsl/convertOklabToOkhsl.js b/src/okhsl/convertOklabToOkhsl.js
deleted file mode 100644
index 23c2f5ef..00000000
--- a/src/okhsl/convertOklabToOkhsl.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-	Adapted from code by Björn Ottosson,
-	released under the MIT license:
-
-	Copyright (c) 2021 Björn Ottosson
-
-	Permission is hereby granted, free of charge, to any person obtaining a copy of
-	this software and associated documentation files (the "Software"), to deal in
-	the Software without restriction, including without limitation the rights to
-	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-	of the Software, and to permit persons to whom the Software is furnished to do
-	so, subject to the following conditions:
-
-	The above copyright notice and this permission notice shall be included in all
-	copies or substantial portions of the Software.
-
-	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-	SOFTWARE.
- */
-
-import normalizeHue from '../util/normalizeHue.js';
-import { get_Cs, toe } from './helpers.js';
-
-export default function convertOklabToOkhsl(lab) {
-	const l = lab.l !== undefined ? lab.l : 0;
-	const a = lab.a !== undefined ? lab.a : 0;
-	const b = lab.b !== undefined ? lab.b : 0;
-
-	const ret = { mode: 'okhsl', l: toe(l) };
-
-	if (lab.alpha !== undefined) {
-		ret.alpha = lab.alpha;
-	}
-	let c = Math.sqrt(a * a + b * b);
-	if (!c) {
-		ret.s = 0;
-		return ret;
-	}
-	let [C_0, C_mid, C_max] = get_Cs(l, a / c, b / c);
-	let s;
-	if (c < C_mid) {
-		let k_0 = 0;
-		let k_1 = 0.8 * C_0;
-		let k_2 = 1 - k_1 / C_mid;
-		let t = (c - k_0) / (k_1 + k_2 * (c - k_0));
-		s = t * 0.8;
-	} else {
-		let k_0 = C_mid;
-		let k_1 = (0.2 * C_mid * C_mid * 1.25 * 1.25) / C_0;
-		let k_2 = 1 - k_1 / (C_max - C_mid);
-		let t = (c - k_0) / (k_1 + k_2 * (c - k_0));
-		s = 0.8 + 0.2 * t;
-	}
-	if (s) {
-		ret.s = s;
-		ret.h = normalizeHue((Math.atan2(b, a) * 180) / Math.PI);
-	}
-	return ret;
-}
diff --git a/src/okhsl/helpers.js b/src/okhsl/helpers.js
deleted file mode 100644
index 50db5593..00000000
--- a/src/okhsl/helpers.js
+++ /dev/null
@@ -1,348 +0,0 @@
-/*
-	Adapted from code by Björn Ottosson,
-	released under the MIT license:
-
-	Copyright (c) 2021 Björn Ottosson
-
-	Permission is hereby granted, free of charge, to any person obtaining a copy of
-	this software and associated documentation files (the "Software"), to deal in
-	the Software without restriction, including without limitation the rights to
-	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-	of the Software, and to permit persons to whom the Software is furnished to do
-	so, subject to the following conditions:
-
-	The above copyright notice and this permission notice shall be included in all
-	copies or substantial portions of the Software.
-
-	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-	SOFTWARE.
- */
-
-import convertOklabToLrgb from '../oklab/convertOklabToLrgb.js';
-
-export function toe(x) {
-	const k_1 = 0.206;
-	const k_2 = 0.03;
-	const k_3 = (1 + k_1) / (1 + k_2);
-	return (
-		0.5 *
-		(k_3 * x -
-			k_1 +
-			Math.sqrt((k_3 * x - k_1) * (k_3 * x - k_1) + 4 * k_2 * k_3 * x))
-	);
-}
-
-export function toe_inv(x) {
-	const k_1 = 0.206;
-	const k_2 = 0.03;
-	const k_3 = (1 + k_1) / (1 + k_2);
-	return (x * x + k_1 * x) / (k_3 * (x + k_2));
-}
-
-// Finds the maximum saturation possible for a given hue that fits in sRGB
-// Saturation here is defined as S = C/L
-// a and b must be normalized so a^2 + b^2 == 1
-function compute_max_saturation(a, b) {
-	// Max saturation will be when one of r, g or b goes below zero.
-
-	// Select different coefficients depending on which component goes below zero first
-	let k0, k1, k2, k3, k4, wl, wm, ws;
-
-	if (-1.88170328 * a - 0.80936493 * b > 1) {
-		// Red component
-		k0 = +1.19086277;
-		k1 = +1.76576728;
-		k2 = +0.59662641;
-		k3 = +0.75515197;
-		k4 = +0.56771245;
-		wl = +4.0767416621;
-		wm = -3.3077115913;
-		ws = +0.2309699292;
-	} else if (1.81444104 * a - 1.19445276 * b > 1) {
-		// Green component
-		k0 = +0.73956515;
-		k1 = -0.45954404;
-		k2 = +0.08285427;
-		k3 = +0.1254107;
-		k4 = +0.14503204;
-		wl = -1.2684380046;
-		wm = +2.6097574011;
-		ws = -0.3413193965;
-	} else {
-		// Blue component
-		k0 = +1.35733652;
-		k1 = -0.00915799;
-		k2 = -1.1513021;
-		k3 = -0.50559606;
-		k4 = +0.00692167;
-		wl = -0.0041960863;
-		wm = -0.7034186147;
-		ws = +1.707614701;
-	}
-
-	// Approximate max saturation using a polynomial:
-	let S = k0 + k1 * a + k2 * b + k3 * a * a + k4 * a * b;
-
-	// Do one step Halley's method to get closer
-	// this gives an error less than 10e6, except for some blue hues where the dS/dh is close to infinite
-	// this should be sufficient for most applications, otherwise do two/three steps
-
-	let k_l = +0.3963377774 * a + 0.2158037573 * b;
-	let k_m = -0.1055613458 * a - 0.0638541728 * b;
-	let k_s = -0.0894841775 * a - 1.291485548 * b;
-
-	{
-		let l_ = 1 + S * k_l;
-		let m_ = 1 + S * k_m;
-		let s_ = 1 + S * k_s;
-
-		let l = l_ * l_ * l_;
-		let m = m_ * m_ * m_;
-		let s = s_ * s_ * s_;
-
-		let l_dS = 3 * k_l * l_ * l_;
-		let m_dS = 3 * k_m * m_ * m_;
-		let s_dS = 3 * k_s * s_ * s_;
-
-		let l_dS2 = 6 * k_l * k_l * l_;
-		let m_dS2 = 6 * k_m * k_m * m_;
-		let s_dS2 = 6 * k_s * k_s * s_;
-
-		let f = wl * l + wm * m + ws * s;
-		let f1 = wl * l_dS + wm * m_dS + ws * s_dS;
-		let f2 = wl * l_dS2 + wm * m_dS2 + ws * s_dS2;
-
-		S = S - (f * f1) / (f1 * f1 - 0.5 * f * f2);
-	}
-
-	return S;
-}
-
-export function find_cusp(a, b) {
-	// First, find the maximum saturation (saturation S = C/L)
-	let S_cusp = compute_max_saturation(a, b);
-
-	// Convert to linear sRGB to find the first point where at least one of r,g or b >= 1:
-	let rgb = convertOklabToLrgb({ l: 1, a: S_cusp * a, b: S_cusp * b });
-	let L_cusp = Math.cbrt(1 / Math.max(rgb.r, rgb.g, rgb.b));
-	let C_cusp = L_cusp * S_cusp;
-
-	return [L_cusp, C_cusp];
-}
-
-// Finds intersection of the line defined by
-// L = L0 * (1 - t) + t * L1;
-// C = t * C1;
-// a and b must be normalized so a^2 + b^2 == 1
-function find_gamut_intersection(a, b, L1, C1, L0, cusp = null) {
-	if (!cusp) {
-		// Find the cusp of the gamut triangle
-		cusp = find_cusp(a, b);
-	}
-
-	// Find the intersection for upper and lower half seprately
-	let t;
-	if ((L1 - L0) * cusp[1] - (cusp[0] - L0) * C1 <= 0) {
-		// Lower half
-
-		t = (cusp[1] * L0) / (C1 * cusp[0] + cusp[1] * (L0 - L1));
-	} else {
-		// Upper half
-
-		// First intersect with triangle
-		t = (cusp[1] * (L0 - 1)) / (C1 * (cusp[0] - 1) + cusp[1] * (L0 - L1));
-
-		// Then one step Halley's method
-		{
-			let dL = L1 - L0;
-			let dC = C1;
-
-			let k_l = +0.3963377774 * a + 0.2158037573 * b;
-			let k_m = -0.1055613458 * a - 0.0638541728 * b;
-			let k_s = -0.0894841775 * a - 1.291485548 * b;
-
-			let l_dt = dL + dC * k_l;
-			let m_dt = dL + dC * k_m;
-			let s_dt = dL + dC * k_s;
-
-			// If higher accuracy is required, 2 or 3 iterations of the following block can be used:
-			{
-				let L = L0 * (1 - t) + t * L1;
-				let C = t * C1;
-
-				let l_ = L + C * k_l;
-				let m_ = L + C * k_m;
-				let s_ = L + C * k_s;
-
-				let l = l_ * l_ * l_;
-				let m = m_ * m_ * m_;
-				let s = s_ * s_ * s_;
-
-				let ldt = 3 * l_dt * l_ * l_;
-				let mdt = 3 * m_dt * m_ * m_;
-				let sdt = 3 * s_dt * s_ * s_;
-
-				let ldt2 = 6 * l_dt * l_dt * l_;
-				let mdt2 = 6 * m_dt * m_dt * m_;
-				let sdt2 = 6 * s_dt * s_dt * s_;
-
-				let r =
-					4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s - 1;
-				let r1 =
-					4.0767416621 * ldt -
-					3.3077115913 * mdt +
-					0.2309699292 * sdt;
-				let r2 =
-					4.0767416621 * ldt2 -
-					3.3077115913 * mdt2 +
-					0.2309699292 * sdt2;
-
-				let u_r = r1 / (r1 * r1 - 0.5 * r * r2);
-				let t_r = -r * u_r;
-
-				let g =
-					-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s - 1;
-				let g1 =
-					-1.2684380046 * ldt +
-					2.6097574011 * mdt -
-					0.3413193965 * sdt;
-				let g2 =
-					-1.2684380046 * ldt2 +
-					2.6097574011 * mdt2 -
-					0.3413193965 * sdt2;
-
-				let u_g = g1 / (g1 * g1 - 0.5 * g * g2);
-				let t_g = -g * u_g;
-
-				let b =
-					-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s - 1;
-				let b1 =
-					-0.0041960863 * ldt -
-					0.7034186147 * mdt +
-					1.707614701 * sdt;
-				let b2 =
-					-0.0041960863 * ldt2 -
-					0.7034186147 * mdt2 +
-					1.707614701 * sdt2;
-
-				let u_b = b1 / (b1 * b1 - 0.5 * b * b2);
-				let t_b = -b * u_b;
-
-				t_r = u_r >= 0 ? t_r : 10e5;
-				t_g = u_g >= 0 ? t_g : 10e5;
-				t_b = u_b >= 0 ? t_b : 10e5;
-
-				t += Math.min(t_r, Math.min(t_g, t_b));
-			}
-		}
-	}
-
-	return t;
-}
-
-export function get_ST_max(a_, b_, cusp = null) {
-	if (!cusp) {
-		cusp = find_cusp(a_, b_);
-	}
-	let L = cusp[0];
-	let C = cusp[1];
-	return [C / L, C / (1 - L)];
-}
-
-export function get_ST_mid(a_, b_) {
-	let S =
-		0.11516993 +
-		1 /
-			(+7.4477897 +
-				4.1590124 * b_ +
-				a_ *
-					(-2.19557347 +
-						1.75198401 * b_ +
-						a_ *
-							(-2.13704948 -
-								10.02301043 * b_ +
-								a_ *
-									(-4.24894561 +
-										5.38770819 * b_ +
-										4.69891013 * a_))));
-
-	let T =
-		0.11239642 +
-		1 /
-			(+1.6132032 -
-				0.68124379 * b_ +
-				a_ *
-					(+0.40370612 +
-						0.90148123 * b_ +
-						a_ *
-							(-0.27087943 +
-								0.6122399 * b_ +
-								a_ *
-									(+0.00299215 -
-										0.45399568 * b_ -
-										0.14661872 * a_))));
-
-	return [S, T];
-}
-
-export function get_Cs(L, a_, b_) {
-	let cusp = find_cusp(a_, b_);
-
-	let C_max = find_gamut_intersection(a_, b_, L, 1, L, cusp);
-	let ST_max = get_ST_max(a_, b_, cusp);
-
-	let S_mid =
-		0.11516993 +
-		1 /
-			(+7.4477897 +
-				4.1590124 * b_ +
-				a_ *
-					(-2.19557347 +
-						1.75198401 * b_ +
-						a_ *
-							(-2.13704948 -
-								10.02301043 * b_ +
-								a_ *
-									(-4.24894561 +
-										5.38770819 * b_ +
-										4.69891013 * a_))));
-
-	let T_mid =
-		0.11239642 +
-		1 /
-			(+1.6132032 -
-				0.68124379 * b_ +
-				a_ *
-					(+0.40370612 +
-						0.90148123 * b_ +
-						a_ *
-							(-0.27087943 +
-								0.6122399 * b_ +
-								a_ *
-									(+0.00299215 -
-										0.45399568 * b_ -
-										0.14661872 * a_))));
-
-	let k = C_max / Math.min(L * ST_max[0], (1 - L) * ST_max[1]);
-
-	let C_a = L * S_mid;
-	let C_b = (1 - L) * T_mid;
-	let C_mid =
-		0.9 *
-		k *
-		Math.sqrt(
-			Math.sqrt(
-				1 / (1 / (C_a * C_a * C_a * C_a) + 1 / (C_b * C_b * C_b * C_b))
-			)
-		);
-
-	C_a = L * 0.4;
-	C_b = (1 - L) * 0.8;
-	let C_0 = Math.sqrt(1 / (1 / (C_a * C_a) + 1 / (C_b * C_b)));
-	return [C_0, C_mid, C_max];
-}
diff --git a/src/okhsl/modeOkhsl.js b/src/okhsl/modeOkhsl.js
deleted file mode 100644
index e2f55b7e..00000000
--- a/src/okhsl/modeOkhsl.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import convertRgbToOklab from '../oklab/convertRgbToOklab.js';
-import convertOklabToRgb from '../oklab/convertOklabToRgb.js';
-import convertOklabToOkhsl from './convertOklabToOkhsl.js';
-import convertOkhslToOklab from './convertOkhslToOklab.js';
-
-import modeHsl from '../hsl/definition.js';
-
-const modeOkhsl = {
-	...modeHsl,
-	mode: 'okhsl',
-	channels: ['h', 's', 'l', 'alpha'],
-	parse: ['--okhsl'],
-	serialize: '--okhsl',
-	fromMode: {
-		oklab: convertOklabToOkhsl,
-		rgb: c => convertOklabToOkhsl(convertRgbToOklab(c))
-	},
-	toMode: {
-		oklab: convertOkhslToOklab,
-		rgb: c => convertOklabToRgb(convertOkhslToOklab(c))
-	}
-};
-
-export default modeOkhsl;
diff --git a/src/okhsv/convertOkhsvToOklab.js b/src/okhsv/convertOkhsvToOklab.js
deleted file mode 100644
index 5261e7d7..00000000
--- a/src/okhsv/convertOkhsvToOklab.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
-	Copyright (c) 2021 Björn Ottosson
-
-	Permission is hereby granted, free of charge, to any person obtaining a copy of
-	this software and associated documentation files (the "Software"), to deal in
-	the Software without restriction, including without limitation the rights to
-	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-	of the Software, and to permit persons to whom the Software is furnished to do
-	so, subject to the following conditions:
-
-	The above copyright notice and this permission notice shall be included in all
-	copies or substantial portions of the Software.
-
-	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-	SOFTWARE.
- */
-
-import convertOklabToLrgb from '../oklab/convertOklabToLrgb.js';
-import { get_ST_max, toe_inv } from '../okhsl/helpers.js';
-
-export default function convertOkhsvToOklab(hsv) {
-	const ret = { mode: 'oklab' };
-	if (hsv.alpha !== undefined) {
-		ret.alpha = hsv.alpha;
-	}
-
-	const h = hsv.h !== undefined ? hsv.h : 0;
-	const s = hsv.s !== undefined ? hsv.s : 0;
-	const v = hsv.v !== undefined ? hsv.v : 0;
-
-	const a_ = Math.cos((h / 180) * Math.PI);
-	const b_ = Math.sin((h / 180) * Math.PI);
-
-	const [S_max, T] = get_ST_max(a_, b_);
-	const S_0 = 0.5;
-	const k = 1 - S_0 / S_max;
-	const L_v = 1 - (s * S_0) / (S_0 + T - T * k * s);
-	const C_v = (s * T * S_0) / (S_0 + T - T * k * s);
-
-	const L_vt = toe_inv(L_v);
-	const C_vt = (C_v * L_vt) / L_v;
-	const rgb_scale = convertOklabToLrgb({
-		l: L_vt,
-		a: a_ * C_vt,
-		b: b_ * C_vt
-	});
-	const scale_L = Math.cbrt(
-		1 / Math.max(rgb_scale.r, rgb_scale.g, rgb_scale.b, 0)
-	);
-
-	const L_new = toe_inv(v * L_v);
-	const C = (C_v * L_new) / L_v;
-
-	ret.l = L_new * scale_L;
-	ret.a = C * a_ * scale_L;
-	ret.b = C * b_ * scale_L;
-
-	return ret;
-}
diff --git a/src/okhsv/convertOklabToOkhsv.js b/src/okhsv/convertOklabToOkhsv.js
deleted file mode 100644
index 308173da..00000000
--- a/src/okhsv/convertOklabToOkhsv.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-	Adapted from code by Björn Ottosson,
-	released under the MIT license:
-
-	Copyright (c) 2021 Björn Ottosson
-
-	Permission is hereby granted, free of charge, to any person obtaining a copy of
-	this software and associated documentation files (the "Software"), to deal in
-	the Software without restriction, including without limitation the rights to
-	use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-	of the Software, and to permit persons to whom the Software is furnished to do
-	so, subject to the following conditions:
-
-	The above copyright notice and this permission notice shall be included in all
-	copies or substantial portions of the Software.
-
-	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-	SOFTWARE.
- */
-
-import normalizeHue from '../util/normalizeHue.js';
-import convertOklabToLrgb from '../oklab/convertOklabToLrgb.js';
-import { get_ST_max, toe_inv, toe } from '../okhsl/helpers.js';
-
-export default function convertOklabToOkhsv(lab) {
-	let l = lab.l !== undefined ? lab.l : 0;
-	let a = lab.a !== undefined ? lab.a : 0;
-	let b = lab.b !== undefined ? lab.b : 0;
-
-	let c = Math.sqrt(a * a + b * b);
-
-	// TODO: c = 0
-	let a_ = c ? a / c : 1;
-	let b_ = c ? b / c : 1;
-
-	let [S_max, T] = get_ST_max(a_, b_);
-	let S_0 = 0.5;
-	let k = 1 - S_0 / S_max;
-
-	let t = T / (c + l * T);
-	let L_v = t * l;
-	let C_v = t * c;
-
-	let L_vt = toe_inv(L_v);
-	let C_vt = (C_v * L_vt) / L_v;
-
-	let rgb_scale = convertOklabToLrgb({ l: L_vt, a: a_ * C_vt, b: b_ * C_vt });
-	let scale_L = Math.cbrt(
-		1 / Math.max(rgb_scale.r, rgb_scale.g, rgb_scale.b, 0)
-	);
-
-	l = l / scale_L;
-	c = ((c / scale_L) * toe(l)) / l;
-	l = toe(l);
-
-	const ret = {
-		mode: 'okhsv',
-		s: c ? ((S_0 + T) * C_v) / (T * S_0 + T * k * C_v) : 0,
-		v: l ? l / L_v : 0
-	};
-	if (ret.s) {
-		ret.h = normalizeHue((Math.atan2(b, a) * 180) / Math.PI);
-	}
-	if (lab.alpha !== undefined) {
-		ret.alpha = lab.alpha;
-	}
-	return ret;
-}
diff --git a/src/okhsv/modeOkhsv.js b/src/okhsv/modeOkhsv.js
deleted file mode 100644
index c9636221..00000000
--- a/src/okhsv/modeOkhsv.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import convertRgbToOklab from '../oklab/convertRgbToOklab.js';
-import convertOklabToRgb from '../oklab/convertOklabToRgb.js';
-import convertOklabToOkhsv from './convertOklabToOkhsv.js';
-import convertOkhsvToOklab from './convertOkhsvToOklab.js';
-
-import modeHsv from '../hsv/definition.js';
-
-const modeOkhsv = {
-	...modeHsv,
-	mode: 'okhsv',
-	channels: ['h', 's', 'v', 'alpha'],
-	parse: ['--okhsv'],
-	serialize: '--okhsv',
-	fromMode: {
-		oklab: convertOklabToOkhsv,
-		rgb: c => convertOklabToOkhsv(convertRgbToOklab(c))
-	},
-	toMode: {
-		oklab: convertOkhsvToOklab,
-		rgb: c => convertOklabToRgb(convertOkhsvToOklab(c))
-	}
-};
-
-export default modeOkhsv;
diff --git a/src/oklab/convertLrgbToOklab.js b/src/oklab/convertLrgbToOklab.js
deleted file mode 100644
index 21e9feb6..00000000
--- a/src/oklab/convertLrgbToOklab.js
+++ /dev/null
@@ -1,39 +0,0 @@
-const convertLrgbToOklab = ({ r, g, b, alpha }) => {
-	if (r === undefined) r = 0;
-	if (g === undefined) g = 0;
-	if (b === undefined) b = 0;
-
-	let L = Math.cbrt(
-		0.412221469470763 * r + 0.5363325372617348 * g + 0.0514459932675022 * b
-	);
-	let M = Math.cbrt(
-		0.2119034958178252 * r + 0.6806995506452344 * g + 0.1073969535369406 * b
-	);
-	let S = Math.cbrt(
-		0.0883024591900564 * r + 0.2817188391361215 * g + 0.6299787016738222 * b
-	);
-
-	let res = {
-		mode: 'oklab',
-		l:
-			0.210454268309314 * L +
-			0.7936177747023054 * M -
-			0.0040720430116193 * S,
-		a:
-			1.9779985324311684 * L -
-			2.4285922420485799 * M +
-			0.450593709617411 * S,
-		b:
-			0.0259040424655478 * L +
-			0.7827717124575296 * M -
-			0.8086757549230774 * S
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertLrgbToOklab;
diff --git a/src/oklab/convertOklabToLrgb.js b/src/oklab/convertOklabToLrgb.js
deleted file mode 100644
index 9d3b35b1..00000000
--- a/src/oklab/convertOklabToLrgb.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const convertOklabToLrgb = ({ l, a, b, alpha }) => {
-	if (l === undefined) l = 0;
-	if (a === undefined) a = 0;
-	if (b === undefined) b = 0;
-
-	let L = Math.pow(l + 0.3963377773761749 * a + 0.2158037573099136 * b, 3);
-	let M = Math.pow(l - 0.1055613458156586 * a - 0.0638541728258133 * b, 3);
-	let S = Math.pow(l - 0.0894841775298119 * a - 1.2914855480194092 * b, 3);
-
-	let res = {
-		mode: 'lrgb',
-		r:
-			4.0767416360759574 * L -
-			3.3077115392580616 * M +
-			0.2309699031821044 * S,
-		g:
-			-1.2684379732850317 * L +
-			2.6097573492876887 * M -
-			0.3413193760026573 * S,
-		b:
-			-0.0041960761386756 * L -
-			0.7034186179359362 * M +
-			1.7076146940746117 * S
-	};
-
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-
-	return res;
-};
-
-export default convertOklabToLrgb;
diff --git a/src/oklab/convertOklabToRgb.js b/src/oklab/convertOklabToRgb.js
deleted file mode 100644
index 900490bd..00000000
--- a/src/oklab/convertOklabToRgb.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import convertLrgbToRgb from '../lrgb/convertLrgbToRgb.js';
-import convertOklabToLrgb from './convertOklabToLrgb.js';
-
-const convertOklabToRgb = c => convertLrgbToRgb(convertOklabToLrgb(c));
-
-export default convertOklabToRgb;
diff --git a/src/oklab/convertRgbToOklab.js b/src/oklab/convertRgbToOklab.js
deleted file mode 100644
index 05328458..00000000
--- a/src/oklab/convertRgbToOklab.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import convertRgbToLrgb from '../lrgb/convertRgbToLrgb.js';
-import convertLrgbToOklab from './convertLrgbToOklab.js';
-
-const convertRgbToOklab = rgb => {
-	let res = convertLrgbToOklab(convertRgbToLrgb(rgb));
-	if (rgb.r === rgb.b && rgb.b === rgb.g) {
-		res.a = res.b = 0;
-	}
-	return res;
-};
-
-export default convertRgbToOklab;
diff --git a/src/oklab/definition.js b/src/oklab/definition.js
deleted file mode 100644
index e08a43b5..00000000
--- a/src/oklab/definition.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import convertOklabToLrgb from './convertOklabToLrgb.js';
-import convertLrgbToOklab from './convertLrgbToOklab.js';
-import convertRgbToOklab from './convertRgbToOklab.js';
-import convertOklabToRgb from './convertOklabToRgb.js';
-import parseOklab from './parseOklab.js';
-
-import lab from '../lab/definition.js';
-
-/*
-	Oklab, a perceptual color space for image processing by Björn Ottosson
-	Reference: https://bottosson.github.io/posts/oklab/
- */
-
-const definition = {
-	...lab,
-	mode: 'oklab',
-
-	toMode: {
-		lrgb: convertOklabToLrgb,
-		rgb: convertOklabToRgb
-	},
-
-	fromMode: {
-		lrgb: convertLrgbToOklab,
-		rgb: convertRgbToOklab
-	},
-
-	ranges: {
-		l: [0, 1],
-		a: [-0.4, 0.4],
-		b: [-0.4, 0.4]
-	},
-
-	parse: [parseOklab],
-	serialize: c =>
-		`oklab(${c.l !== undefined ? c.l : 'none'} ${
-			c.a !== undefined ? c.a : 'none'
-		} ${c.b !== undefined ? c.b : 'none'}${
-			c.alpha < 1 ? ` / ${c.alpha}` : ''
-		})`
-};
-
-export default definition;
diff --git a/src/oklab/parseOklab.js b/src/oklab/parseOklab.js
deleted file mode 100644
index aaf4f075..00000000
--- a/src/oklab/parseOklab.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import { Tok } from '../parse.js';
-
-function parseOklab(color, parsed) {
-	if (!parsed || parsed[0] !== 'oklab') {
-		return undefined;
-	}
-	const res = { mode: 'oklab' };
-	const [, l, a, b, alpha] = parsed;
-	if (l.type === Tok.Hue || a.type === Tok.Hue || b.type === Tok.Hue) {
-		return undefined;
-	}
-	if (l.type !== Tok.None) {
-		res.l = Math.min(
-			Math.max(0, l.type === Tok.Number ? l.value : l.value / 100),
-			1
-		);
-	}
-	if (a.type !== Tok.None) {
-		res.a = a.type === Tok.Number ? a.value : (a.value * 0.4) / 100;
-	}
-	if (b.type !== Tok.None) {
-		res.b = b.type === Tok.Number ? b.value : (b.value * 0.4) / 100;
-	}
-	if (alpha.type !== Tok.None) {
-		res.alpha = Math.min(
-			1,
-			Math.max(
-				0,
-				alpha.type === Tok.Number ? alpha.value : alpha.value / 100
-			)
-		);
-	}
-
-	return res;
-}
-
-export default parseOklab;
diff --git a/src/oklch/definition.js b/src/oklch/definition.js
deleted file mode 100644
index 3d56e325..00000000
--- a/src/oklch/definition.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import lch from '../lch/definition.js';
-import convertLabToLch from '../lch/convertLabToLch.js';
-import convertLchToLab from '../lch/convertLchToLab.js';
-import convertOklabToRgb from '../oklab/convertOklabToRgb.js';
-import convertRgbToOklab from '../oklab/convertRgbToOklab.js';
-import parseOklch from './parseOklch.js';
-
-const definition = {
-	...lch,
-	mode: 'oklch',
-
-	toMode: {
-		oklab: c => convertLchToLab(c, 'oklab'),
-		rgb: c => convertOklabToRgb(convertLchToLab(c, 'oklab'))
-	},
-
-	fromMode: {
-		rgb: c => convertLabToLch(convertRgbToOklab(c), 'oklch'),
-		oklab: c => convertLabToLch(c, 'oklch')
-	},
-
-	parse: [parseOklch],
-	serialize: c =>
-		`oklch(${c.l !== undefined ? c.l : 'none'} ${
-			c.c !== undefined ? c.c : 'none'
-		} ${c.h !== undefined ? c.h : 'none'}${
-			c.alpha < 1 ? ` / ${c.alpha}` : ''
-		})`,
-
-	ranges: {
-		l: [0, 1],
-		c: [0, 0.4],
-		h: [0, 360]
-	}
-};
-
-export default definition;
diff --git a/src/oklch/parseOklch.js b/src/oklch/parseOklch.js
deleted file mode 100644
index fcd03d30..00000000
--- a/src/oklch/parseOklch.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import { Tok } from '../parse.js';
-
-function parseOklch(color, parsed) {
-	if (!parsed || parsed[0] !== 'oklch') {
-		return undefined;
-	}
-	const res = { mode: 'oklch' };
-	const [, l, c, h, alpha] = parsed;
-	if (l.type !== Tok.None) {
-		if (l.type === Tok.Hue) {
-			return undefined;
-		}
-		res.l = Math.min(
-			Math.max(0, l.type === Tok.Number ? l.value : l.value / 100),
-			1
-		);
-	}
-	if (c.type !== Tok.None) {
-		res.c = Math.max(
-			0,
-			c.type === Tok.Number ? c.value : (c.value * 0.4) / 100
-		);
-	}
-	if (h.type !== Tok.None) {
-		if (h.type === Tok.Percentage) {
-			return undefined;
-		}
-		res.h = h.value;
-	}
-	if (alpha.type !== Tok.None) {
-		res.alpha = Math.min(
-			1,
-			Math.max(
-				0,
-				alpha.type === Tok.Number ? alpha.value : alpha.value / 100
-			)
-		);
-	}
-
-	return res;
-}
-
-export default parseOklch;
diff --git a/src/p3/convertP3ToXyz65.js b/src/p3/convertP3ToXyz65.js
deleted file mode 100644
index 42a844ea..00000000
--- a/src/p3/convertP3ToXyz65.js
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
-	Convert Display P3 values to CIE XYZ D65
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-*/
-
-import convertRgbToLrgb from '../lrgb/convertRgbToLrgb.js';
-
-const convertP3ToXyz65 = rgb => {
-	let { r, g, b, alpha } = convertRgbToLrgb(rgb);
-	let res = {
-		mode: 'xyz65',
-		x:
-			0.486570948648216 * r +
-			0.265667693169093 * g +
-			0.1982172852343625 * b,
-		y:
-			0.2289745640697487 * r +
-			0.6917385218365062 * g +
-			0.079286914093745 * b,
-		z: 0.0 * r + 0.0451133818589026 * g + 1.043944368900976 * b
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertP3ToXyz65;
diff --git a/src/p3/convertXyz65ToP3.js b/src/p3/convertXyz65ToP3.js
deleted file mode 100644
index b9fd4e58..00000000
--- a/src/p3/convertXyz65ToP3.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
-	CIE XYZ D65 values to Display P3.
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-*/
-
-import convertLrgbToRgb from '../lrgb/convertLrgbToRgb.js';
-
-const convertXyz65ToP3 = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = convertLrgbToRgb(
-		{
-			r:
-				x * 2.4934969119414263 -
-				y * 0.9313836179191242 -
-				0.402710784450717 * z,
-			g:
-				x * -0.8294889695615749 +
-				y * 1.7626640603183465 +
-				0.0236246858419436 * z,
-			b:
-				x * 0.0358458302437845 -
-				y * 0.0761723892680418 +
-				0.9568845240076871 * z
-		},
-		'p3'
-	);
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz65ToP3;
diff --git a/src/p3/definition.js b/src/p3/definition.js
deleted file mode 100644
index 6b7e3c7a..00000000
--- a/src/p3/definition.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import rgb from '../rgb/definition.js';
-import convertP3ToXyz65 from './convertP3ToXyz65.js';
-import convertXyz65ToP3 from './convertXyz65ToP3.js';
-import convertRgbToXyz65 from '../xyz65/convertRgbToXyz65.js';
-import convertXyz65ToRgb from '../xyz65/convertXyz65ToRgb.js';
-
-const definition = {
-	...rgb,
-	mode: 'p3',
-	parse: ['display-p3'],
-	serialize: 'display-p3',
-
-	fromMode: {
-		rgb: color => convertXyz65ToP3(convertRgbToXyz65(color)),
-		xyz65: convertXyz65ToP3
-	},
-
-	toMode: {
-		rgb: color => convertXyz65ToRgb(convertP3ToXyz65(color)),
-		xyz65: convertP3ToXyz65
-	}
-};
-
-export default definition;
diff --git a/src/parse.js b/src/parse.js
deleted file mode 100644
index 140c7a07..00000000
--- a/src/parse.js
+++ /dev/null
@@ -1,362 +0,0 @@
-import { parsers, colorProfiles, getMode } from './modes.js';
-
-/* eslint-disable-next-line no-control-regex */
-const IdentStartCodePoint = /[^\x00-\x7F]|[a-zA-Z_]/;
-
-/* eslint-disable-next-line no-control-regex */
-const IdentCodePoint = /[^\x00-\x7F]|[-\w]/;
-
-export const Tok = {
-	Function: 'function',
-	Ident: 'ident',
-	Number: 'number',
-	Percentage: 'percentage',
-	ParenClose: ')',
-	None: 'none',
-	Hue: 'hue',
-	Alpha: 'alpha'
-};
-
-let _i = 0;
-
-/*
-	4.3.10. Check if three code points would start a number
-	https://drafts.csswg.org/css-syntax/#starts-with-a-number
- */
-function is_num(chars) {
-	let ch = chars[_i];
-	let ch1 = chars[_i + 1];
-	if (ch === '-' || ch === '+') {
-		return /\d/.test(ch1) || (ch1 === '.' && /\d/.test(chars[_i + 2]));
-	}
-	if (ch === '.') {
-		return /\d/.test(ch1);
-	}
-	return /\d/.test(ch);
-}
-
-/*
-	Check if the stream starts with an identifier.
- */
-
-function is_ident(chars) {
-	if (_i >= chars.length) {
-		return false;
-	}
-	let ch = chars[_i];
-	if (IdentStartCodePoint.test(ch)) {
-		return true;
-	}
-	if (ch === '-') {
-		if (chars.length - _i < 2) {
-			return false;
-		}
-		let ch1 = chars[_i + 1];
-		if (ch1 === '-' || IdentStartCodePoint.test(ch1)) {
-			return true;
-		}
-		return false;
-	}
-	return false;
-}
-
-/*
-	4.3.3. Consume a numeric token
-	https://drafts.csswg.org/css-syntax/#consume-numeric-token
- */
-
-const huenits = {
-	deg: 1,
-	rad: 180 / Math.PI,
-	grad: 9 / 10,
-	turn: 360
-};
-
-function num(chars) {
-	let value = '';
-	if (chars[_i] === '-' || chars[_i] === '+') {
-		value += chars[_i++];
-	}
-	value += digits(chars);
-	if (chars[_i] === '.' && /\d/.test(chars[_i + 1])) {
-		value += chars[_i++] + digits(chars);
-	}
-	if (chars[_i] === 'e' || chars[_i] === 'E') {
-		if (
-			(chars[_i + 1] === '-' || chars[_i + 1] === '+') &&
-			/\d/.test(chars[_i + 2])
-		) {
-			value += chars[_i++] + chars[_i++] + digits(chars);
-		} else if (/\d/.test(chars[_i + 1])) {
-			value += chars[_i++] + digits(chars);
-		}
-	}
-	if (is_ident(chars)) {
-		let id = ident(chars);
-		if (id === 'deg' || id === 'rad' || id === 'turn' || id === 'grad') {
-			return { type: Tok.Hue, value: value * huenits[id] };
-		}
-		return undefined;
-	}
-	if (chars[_i] === '%') {
-		_i++;
-		return { type: Tok.Percentage, value: +value };
-	}
-	return { type: Tok.Number, value: +value };
-}
-
-/*
-	Consume digits.
- */
-function digits(chars) {
-	let v = '';
-	while (/\d/.test(chars[_i])) {
-		v += chars[_i++];
-	}
-	return v;
-}
-
-/*
-	Consume an identifier.
- */
-function ident(chars) {
-	let v = '';
-	while (_i < chars.length && IdentCodePoint.test(chars[_i])) {
-		v += chars[_i++];
-	}
-	return v;
-}
-
-/*
-	Consume an ident-like token.
- */
-function identlike(chars) {
-	let v = ident(chars);
-	if (chars[_i] === '(') {
-		_i++;
-		return { type: Tok.Function, value: v };
-	}
-	if (v === 'none') {
-		return { type: Tok.None, value: undefined };
-	}
-	return { type: Tok.Ident, value: v };
-}
-
-export function tokenize(str = '') {
-	let chars = str.trim();
-	let tokens = [];
-	let ch;
-
-	/* reset counter */
-	_i = 0;
-
-	while (_i < chars.length) {
-		ch = chars[_i++];
-
-		/*
-			Consume whitespace without emitting it
-		 */
-		if (ch === '\n' || ch === '\t' || ch === ' ') {
-			while (
-				_i < chars.length &&
-				(chars[_i] === '\n' || chars[_i] === '\t' || chars[_i] === ' ')
-			) {
-				_i++;
-			}
-			continue;
-		}
-
-		if (ch === ',') {
-			return undefined;
-		}
-
-		if (ch === ')') {
-			tokens.push({ type: Tok.ParenClose });
-			continue;
-		}
-
-		if (ch === '+') {
-			_i--;
-			if (is_num(chars)) {
-				tokens.push(num(chars));
-				continue;
-			}
-			return undefined;
-		}
-
-		if (ch === '-') {
-			_i--;
-			if (is_num(chars)) {
-				tokens.push(num(chars));
-				continue;
-			}
-			if (is_ident(chars)) {
-				tokens.push({ type: Tok.Ident, value: ident(chars) });
-				continue;
-			}
-			return undefined;
-		}
-
-		if (ch === '.') {
-			_i--;
-			if (is_num(chars)) {
-				tokens.push(num(chars));
-				continue;
-			}
-			return undefined;
-		}
-
-		if (ch === '/') {
-			while (
-				_i < chars.length &&
-				(chars[_i] === '\n' || chars[_i] === '\t' || chars[_i] === ' ')
-			) {
-				_i++;
-			}
-			let alpha;
-			if (is_num(chars)) {
-				alpha = num(chars);
-				if (alpha.type !== Tok.Hue) {
-					tokens.push({ type: Tok.Alpha, value: alpha });
-					continue;
-				}
-			}
-			if (is_ident(chars)) {
-				if (ident(chars) === 'none') {
-					tokens.push({
-						type: Tok.Alpha,
-						value: { type: Tok.None, value: undefined }
-					});
-					continue;
-				}
-			}
-			return undefined;
-		}
-
-		if (/\d/.test(ch)) {
-			_i--;
-			tokens.push(num(chars));
-			continue;
-		}
-
-		if (IdentStartCodePoint.test(ch)) {
-			_i--;
-			tokens.push(identlike(chars));
-			continue;
-		}
-
-		/*
-			Treat everything not already handled as an error.
-		 */
-		return undefined;
-	}
-
-	return tokens;
-}
-
-export function parseColorSyntax(tokens) {
-	tokens._i = 0;
-	let token = tokens[tokens._i++];
-	if (!token || token.type !== Tok.Function || token.value !== 'color') {
-		return undefined;
-	}
-	token = tokens[tokens._i++];
-	if (token.type !== Tok.Ident) {
-		return undefined;
-	}
-	const mode = colorProfiles[token.value];
-	if (!mode) {
-		return undefined;
-	}
-	const res = { mode };
-	const coords = consumeCoords(tokens, false);
-	if (!coords) {
-		return undefined;
-	}
-	const channels = getMode(mode).channels;
-	for (let ii = 0, c, ch; ii < channels.length; ii++) {
-		c = coords[ii];
-		ch = channels[ii];
-		if (c.type !== Tok.None) {
-			res[ch] = c.type === Tok.Number ? c.value : c.value / 100;
-			if (ch === 'alpha') {
-				res[ch] = Math.max(0, Math.min(1, res[ch]));
-			}
-		}
-	}
-	return res;
-}
-
-function consumeCoords(tokens, includeHue) {
-	const coords = [];
-	let token;
-	while (tokens._i < tokens.length) {
-		token = tokens[tokens._i++];
-		if (
-			token.type === Tok.None ||
-			token.type === Tok.Number ||
-			token.type === Tok.Alpha ||
-			token.type === Tok.Percentage ||
-			(includeHue && token.type === Tok.Hue)
-		) {
-			coords.push(token);
-			continue;
-		}
-		if (token.type === Tok.ParenClose) {
-			if (tokens._i < tokens.length) {
-				return undefined;
-			}
-			continue;
-		}
-		return undefined;
-	}
-
-	if (coords.length < 3 || coords.length > 4) {
-		return undefined;
-	}
-
-	if (coords.length === 4) {
-		if (coords[3].type !== Tok.Alpha) {
-			return undefined;
-		}
-		coords[3] = coords[3].value;
-	}
-	if (coords.length === 3) {
-		coords.push({ type: Tok.None, value: undefined });
-	}
-
-	return coords.every(c => c.type !== Tok.Alpha) ? coords : undefined;
-}
-
-export function parseModernSyntax(tokens, includeHue) {
-	tokens._i = 0;
-	let token = tokens[tokens._i++];
-	if (!token || token.type !== Tok.Function) {
-		return undefined;
-	}
-	let coords = consumeCoords(tokens, includeHue);
-	if (!coords) {
-		return undefined;
-	}
-	coords.unshift(token.value);
-	return coords;
-}
-
-const parse = color => {
-	if (typeof color !== 'string') {
-		return undefined;
-	}
-	const tokens = tokenize(color);
-	const parsed = tokens ? parseModernSyntax(tokens, true) : undefined;
-	let result = undefined;
-	let i = 0;
-	let len = parsers.length;
-	while (i < len) {
-		if ((result = parsers[i++](color, parsed)) !== undefined) {
-			return result;
-		}
-	}
-	return tokens ? parseColorSyntax(tokens) : undefined;
-};
-
-export default parse;
diff --git a/src/prophoto/convertProphotoToXyz50.js b/src/prophoto/convertProphotoToXyz50.js
deleted file mode 100644
index b8c674b2..00000000
--- a/src/prophoto/convertProphotoToXyz50.js
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-	Convert ProPhoto RGB values to CIE XYZ D50
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-*/
-
-const linearize = (v = 0) => {
-	let abs = Math.abs(v);
-	if (abs >= 16 / 512) {
-		return Math.sign(v) * Math.pow(abs, 1.8);
-	}
-	return v / 16;
-};
-
-const convertProphotoToXyz50 = prophoto => {
-	let r = linearize(prophoto.r);
-	let g = linearize(prophoto.g);
-	let b = linearize(prophoto.b);
-	let res = {
-		mode: 'xyz50',
-		x:
-			0.7977666449006423 * r +
-			0.1351812974005331 * g +
-			0.0313477341283922 * b,
-		y:
-			0.2880748288194013 * r +
-			0.7118352342418731 * g +
-			0.0000899369387256 * b,
-		z: 0 * r + 0 * g + 0.8251046025104602 * b
-	};
-	if (prophoto.alpha !== undefined) {
-		res.alpha = prophoto.alpha;
-	}
-	return res;
-};
-
-export default convertProphotoToXyz50;
diff --git a/src/prophoto/convertXyz50ToProphoto.js b/src/prophoto/convertXyz50ToProphoto.js
deleted file mode 100644
index 2651f797..00000000
--- a/src/prophoto/convertXyz50ToProphoto.js
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
-	Convert CIE XYZ D50 values to ProPhoto RGB
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-*/
-
-const gamma = v => {
-	let abs = Math.abs(v);
-	if (abs >= 1 / 512) {
-		return Math.sign(v) * Math.pow(abs, 1 / 1.8);
-	}
-	return 16 * v;
-};
-
-const convertXyz50ToProphoto = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = {
-		mode: 'prophoto',
-		r: gamma(
-			x * 1.3457868816471585 -
-				y * 0.2555720873797946 -
-				0.0511018649755453 * z
-		),
-		g: gamma(
-			x * -0.5446307051249019 +
-				y * 1.5082477428451466 +
-				0.0205274474364214 * z
-		),
-		b: gamma(x * 0.0 + y * 0.0 + 1.2119675456389452 * z)
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz50ToProphoto;
diff --git a/src/prophoto/definition.js b/src/prophoto/definition.js
deleted file mode 100644
index 4fd2c561..00000000
--- a/src/prophoto/definition.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import rgb from '../rgb/definition.js';
-
-import convertXyz50ToProphoto from './convertXyz50ToProphoto.js';
-import convertProphotoToXyz50 from './convertProphotoToXyz50.js';
-
-import convertXyz50ToRgb from '../xyz50/convertXyz50ToRgb.js';
-import convertRgbToXyz50 from '../xyz50/convertRgbToXyz50.js';
-
-/*
-	ProPhoto RGB Color space
-
-	References:
-		* https://en.wikipedia.org/wiki/ProPhoto_RGB_color_space
- */
-
-const definition = {
-	...rgb,
-	mode: 'prophoto',
-	parse: ['prophoto-rgb'],
-	serialize: 'prophoto-rgb',
-
-	fromMode: {
-		xyz50: convertXyz50ToProphoto,
-		rgb: color => convertXyz50ToProphoto(convertRgbToXyz50(color))
-	},
-
-	toMode: {
-		xyz50: convertProphotoToXyz50,
-		rgb: color => convertXyz50ToRgb(convertProphotoToXyz50(color))
-	}
-};
-
-export default definition;
diff --git a/src/random.js b/src/random.js
deleted file mode 100644
index 212997cc..00000000
--- a/src/random.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { getMode } from './modes.js';
-
-/*
-	Generate a random number between `min` and `max`
- */
-const rand = ([min, max]) => min + Math.random() * (max - min);
-
-/*
-	Convert a constraints object to intervals.
- */
-const to_intervals = constraints =>
-	Object.keys(constraints).reduce((o, k) => {
-		let v = constraints[k];
-		o[k] = Array.isArray(v) ? v : [v, v];
-		return o;
-	}, {});
-
-/*
-	Generate a random color.
- */
-const random = (mode = 'rgb', constraints = {}) => {
-	let def = getMode(mode);
-	let limits = to_intervals(constraints);
-	return def.channels.reduce(
-		(res, ch) => {
-			// ignore alpha if not present in constraints
-			if (limits.alpha || ch !== 'alpha') {
-				res[ch] = rand(limits[ch] || def.ranges[ch]);
-			}
-			return res;
-		},
-		{ mode }
-	);
-};
-
-export default random;
diff --git a/src/rec2020/convertRec2020ToXyz65.js b/src/rec2020/convertRec2020ToXyz65.js
deleted file mode 100644
index b65f24b6..00000000
--- a/src/rec2020/convertRec2020ToXyz65.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
-	Convert Rec. 2020 values to CIE XYZ D65
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-		* https://www.itu.int/rec/R-REC-BT.2020/en
-*/
-
-const α = 1.09929682680944;
-const β = 0.018053968510807;
-
-const linearize = (v = 0) => {
-	let abs = Math.abs(v);
-	if (abs < β * 4.5) {
-		return v / 4.5;
-	}
-	return (Math.sign(v) || 1) * Math.pow((abs + α - 1) / α, 1 / 0.45);
-};
-
-const convertRec2020ToXyz65 = rec2020 => {
-	let r = linearize(rec2020.r);
-	let g = linearize(rec2020.g);
-	let b = linearize(rec2020.b);
-	let res = {
-		mode: 'xyz65',
-		x:
-			0.6369580483012911 * r +
-			0.1446169035862083 * g +
-			0.1688809751641721 * b,
-		y:
-			0.262700212011267 * r +
-			0.6779980715188708 * g +
-			0.059301716469862 * b,
-		z: 0 * r + 0.0280726930490874 * g + 1.0609850577107909 * b
-	};
-	if (rec2020.alpha !== undefined) {
-		res.alpha = rec2020.alpha;
-	}
-	return res;
-};
-
-export default convertRec2020ToXyz65;
diff --git a/src/rec2020/convertXyz65ToRec2020.js b/src/rec2020/convertXyz65ToRec2020.js
deleted file mode 100644
index dfd56755..00000000
--- a/src/rec2020/convertXyz65ToRec2020.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
-	Convert CIE XYZ D65 values to Rec. 2020
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-		* https://www.itu.int/rec/R-REC-BT.2020/en
-*/
-
-const α = 1.09929682680944;
-const β = 0.018053968510807;
-const gamma = v => {
-	const abs = Math.abs(v);
-	if (abs > β) {
-		return (Math.sign(v) || 1) * (α * Math.pow(abs, 0.45) - (α - 1));
-	}
-	return 4.5 * v;
-};
-
-const convertXyz65ToRec2020 = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = {
-		mode: 'rec2020',
-		r: gamma(
-			x * 1.7166511879712683 -
-				y * 0.3556707837763925 -
-				0.2533662813736599 * z
-		),
-		g: gamma(
-			x * -0.6666843518324893 +
-				y * 1.6164812366349395 +
-				0.0157685458139111 * z
-		),
-		b: gamma(
-			x * 0.0176398574453108 -
-				y * 0.0427706132578085 +
-				0.9421031212354739 * z
-		)
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz65ToRec2020;
diff --git a/src/rec2020/definition.js b/src/rec2020/definition.js
deleted file mode 100644
index 13a5f8bd..00000000
--- a/src/rec2020/definition.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import rgb from '../rgb/definition.js';
-
-import convertXyz65ToRec2020 from './convertXyz65ToRec2020.js';
-import convertRec2020ToXyz65 from './convertRec2020ToXyz65.js';
-
-import convertRgbToXyz65 from '../xyz65/convertRgbToXyz65.js';
-import convertXyz65ToRgb from '../xyz65/convertXyz65ToRgb.js';
-
-const definition = {
-	...rgb,
-	mode: 'rec2020',
-
-	fromMode: {
-		xyz65: convertXyz65ToRec2020,
-		rgb: color => convertXyz65ToRec2020(convertRgbToXyz65(color))
-	},
-
-	toMode: {
-		xyz65: convertRec2020ToXyz65,
-		rgb: color => convertXyz65ToRgb(convertRec2020ToXyz65(color))
-	},
-
-	parse: ['rec2020'],
-	serialize: 'rec2020'
-};
-
-export default definition;
diff --git a/src/rgb/definition.js b/src/rgb/definition.js
deleted file mode 100644
index dc3b36e8..00000000
--- a/src/rgb/definition.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import parseNamed from './parseNamed.js';
-import parseHex from './parseHex.js';
-import parseRgbLegacy from './parseRgbLegacy.js';
-import parseRgb from './parseRgb.js';
-import parseTransparent from './parseTransparent.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-/*
-	sRGB color space
- */
-
-const definition = {
-	mode: 'rgb',
-	channels: ['r', 'g', 'b', 'alpha'],
-	parse: [
-		parseRgb,
-		parseHex,
-		parseRgbLegacy,
-		parseNamed,
-		parseTransparent,
-		'srgb'
-	],
-	serialize: 'srgb',
-	interpolate: {
-		r: interpolatorLinear,
-		g: interpolatorLinear,
-		b: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	},
-	gamut: true,
-	white: { r: 1, g: 1, b: 1 },
-	black: { r: 0, g: 0, b: 0 }
-};
-
-export default definition;
diff --git a/src/rgb/parseHex.js b/src/rgb/parseHex.js
deleted file mode 100644
index bb361965..00000000
--- a/src/rgb/parseHex.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import parseNumber from './parseNumber.js';
-
-const hex = /^#?([0-9a-f]{8}|[0-9a-f]{6}|[0-9a-f]{4}|[0-9a-f]{3})$/i;
-
-const parseHex = color => {
-	let match;
-	// eslint-disable-next-line no-cond-assign
-	return (match = color.match(hex))
-		? parseNumber(parseInt(match[1], 16), match[1].length)
-		: undefined;
-};
-
-export default parseHex;
diff --git a/src/rgb/parseNamed.js b/src/rgb/parseNamed.js
deleted file mode 100644
index f739d61d..00000000
--- a/src/rgb/parseNamed.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import parseNumber from './parseNumber.js';
-import named from '../colors/named.js';
-
-// Also supports the `transparent` color as defined in:
-// https://drafts.csswg.org/css-color/#transparent-black
-const parseNamed = color => {
-	return parseNumber(named[color.toLowerCase()], 6);
-};
-
-export default parseNamed;
diff --git a/src/rgb/parseNumber.js b/src/rgb/parseNumber.js
deleted file mode 100644
index 98510036..00000000
--- a/src/rgb/parseNumber.js
+++ /dev/null
@@ -1,47 +0,0 @@
-const parseNumber = (color, len) => {
-	if (typeof color !== 'number') return;
-
-	// hex3: #c93 -> #cc9933
-	if (len === 3) {
-		return {
-			mode: 'rgb',
-			r: (((color >> 8) & 0xf) | ((color >> 4) & 0xf0)) / 255,
-			g: (((color >> 4) & 0xf) | (color & 0xf0)) / 255,
-			b: ((color & 0xf) | ((color << 4) & 0xf0)) / 255
-		};
-	}
-
-	// hex4: #c931 -> #cc993311
-	if (len === 4) {
-		return {
-			mode: 'rgb',
-			r: (((color >> 12) & 0xf) | ((color >> 8) & 0xf0)) / 255,
-			g: (((color >> 8) & 0xf) | ((color >> 4) & 0xf0)) / 255,
-			b: (((color >> 4) & 0xf) | (color & 0xf0)) / 255,
-			alpha: ((color & 0xf) | ((color << 4) & 0xf0)) / 255
-		};
-	}
-
-	// hex6: #f0f1f2
-	if (len === 6) {
-		return {
-			mode: 'rgb',
-			r: ((color >> 16) & 0xff) / 255,
-			g: ((color >> 8) & 0xff) / 255,
-			b: (color & 0xff) / 255
-		};
-	}
-
-	// hex8: #f0f1f2ff
-	if (len === 8) {
-		return {
-			mode: 'rgb',
-			r: ((color >> 24) & 0xff) / 255,
-			g: ((color >> 16) & 0xff) / 255,
-			b: ((color >> 8) & 0xff) / 255,
-			alpha: (color & 0xff) / 255
-		};
-	}
-};
-
-export default parseNumber;
diff --git a/src/rgb/parseRgb.js b/src/rgb/parseRgb.js
deleted file mode 100644
index da17a252..00000000
--- a/src/rgb/parseRgb.js
+++ /dev/null
@@ -1,34 +0,0 @@
-import { Tok } from '../parse.js';
-
-function parseRgb(color, parsed) {
-	if (!parsed || (parsed[0] !== 'rgb' && parsed[0] !== 'rgba')) {
-		return undefined;
-	}
-	const res = { mode: 'rgb' };
-	const [, r, g, b, alpha] = parsed;
-	if (r.type === Tok.Hue || g.type === Tok.Hue || b.type === Tok.Hue) {
-		return undefined;
-	}
-	if (r.type !== Tok.None) {
-		res.r = r.type === Tok.Number ? r.value / 255 : r.value / 100;
-	}
-	if (g.type !== Tok.None) {
-		res.g = g.type === Tok.Number ? g.value / 255 : g.value / 100;
-	}
-	if (b.type !== Tok.None) {
-		res.b = b.type === Tok.Number ? b.value / 255 : b.value / 100;
-	}
-	if (alpha.type !== Tok.None) {
-		res.alpha = Math.min(
-			1,
-			Math.max(
-				0,
-				alpha.type === Tok.Number ? alpha.value : alpha.value / 100
-			)
-		);
-	}
-
-	return res;
-}
-
-export default parseRgb;
diff --git a/src/rgb/parseRgbLegacy.js b/src/rgb/parseRgbLegacy.js
deleted file mode 100644
index 12823d2a..00000000
--- a/src/rgb/parseRgbLegacy.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import { num, per, num_per, c } from '../util/regex.js';
-
-/*
-	rgb() regular expressions for legacy format
-	Reference: https://drafts.csswg.org/css-color/#rgb-functions
- */
-const rgb_num_old = new RegExp(
-	`^rgba?\\(\\s*${num}${c}${num}${c}${num}\\s*(?:,\\s*${num_per}\\s*)?\\)$`
-);
-
-const rgb_per_old = new RegExp(
-	`^rgba?\\(\\s*${per}${c}${per}${c}${per}\\s*(?:,\\s*${num_per}\\s*)?\\)$`
-);
-
-const parseRgbLegacy = color => {
-	let res = { mode: 'rgb' };
-	let match;
-	if ((match = color.match(rgb_num_old))) {
-		if (match[1] !== undefined) {
-			res.r = match[1] / 255;
-		}
-		if (match[2] !== undefined) {
-			res.g = match[2] / 255;
-		}
-		if (match[3] !== undefined) {
-			res.b = match[3] / 255;
-		}
-	} else if ((match = color.match(rgb_per_old))) {
-		if (match[1] !== undefined) {
-			res.r = match[1] / 100;
-		}
-		if (match[2] !== undefined) {
-			res.g = match[2] / 100;
-		}
-		if (match[3] !== undefined) {
-			res.b = match[3] / 100;
-		}
-	} else {
-		return undefined;
-	}
-
-	if (match[4] !== undefined) {
-		res.alpha = Math.max(0, Math.min(1, match[4] / 100));
-	} else if (match[5] !== undefined) {
-		res.alpha = Math.max(0, Math.min(1, +match[5]));
-	}
-
-	return res;
-};
-
-export default parseRgbLegacy;
diff --git a/src/rgb/parseTransparent.js b/src/rgb/parseTransparent.js
deleted file mode 100644
index 6a2279e7..00000000
--- a/src/rgb/parseTransparent.js
+++ /dev/null
@@ -1,6 +0,0 @@
-const parseTransparent = c =>
-	c === 'transparent'
-		? { mode: 'rgb', r: 0, g: 0, b: 0, alpha: 0 }
-		: undefined;
-
-export default parseTransparent;
diff --git a/src/round.js b/src/round.js
deleted file mode 100644
index c4a2c1ff..00000000
--- a/src/round.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// From: https://github.com/d3/d3-format/issues/32
-
-const r = (value, precision) =>
-	Math.round(value * (precision = Math.pow(10, precision))) / precision;
-
-const round =
-	(precision = 4) =>
-	value =>
-		typeof value === 'number' ? r(value, precision) : value;
-
-export default round;
diff --git a/src/samples.js b/src/samples.js
deleted file mode 100644
index 6d70c47e..00000000
--- a/src/samples.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import gamma from './easing/gamma.js';
-
-const samples = (n = 2, γ = 1) => {
-	let ease = gamma(γ);
-	if (n < 2) {
-		return n < 1 ? [] : [ease(0.5)];
-	}
-	let res = [];
-	for (let i = 0; i < n; i++) {
-		res.push(ease(i / (n - 1)));
-	}
-	return res;
-};
-
-export default samples;
diff --git a/src/util/hue.js b/src/util/hue.js
deleted file mode 100644
index 54a29362..00000000
--- a/src/util/hue.js
+++ /dev/null
@@ -1,14 +0,0 @@
-const hueToDeg = (val, unit) => {
-	switch (unit) {
-		case 'deg':
-			return +val;
-		case 'rad':
-			return (val / Math.PI) * 180;
-		case 'grad':
-			return (val / 10) * 9;
-		case 'turn':
-			return val * 360;
-	}
-};
-
-export default hueToDeg;
diff --git a/src/util/normalizeHue.js b/src/util/normalizeHue.js
deleted file mode 100644
index 8ecc3139..00000000
--- a/src/util/normalizeHue.js
+++ /dev/null
@@ -1,3 +0,0 @@
-const normalizeHue = hue => ((hue = hue % 360) < 0 ? hue + 360 : hue);
-
-export default normalizeHue;
diff --git a/src/util/normalizePositions.js b/src/util/normalizePositions.js
deleted file mode 100644
index 80e59430..00000000
--- a/src/util/normalizePositions.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
-	Normalize an array of color stop positions for a gradient
-	based on the rules defined in the CSS Images Module 4 spec:
-
-	1. make the first position 0 and the last position 1 if missing
-	2. sequences of unpositioned color stops should be spread out evenly
-	3. no position can be smaller than any of the ones preceding it
-	
-	Reference: https://drafts.csswg.org/css-images-4/#color-stop-fixup
-
-	Note: this method does not make a defensive copy of the array
-	it receives as argument. Instead, it adjusts the values in-place.
- */
-const normalizePositions = arr => {
-	// 1. fix up first/last position if missing
-	if (arr[0] === undefined) {
-		arr[0] = 0;
-	}
-	if (arr[arr.length - 1] === undefined) {
-		arr[arr.length - 1] = 1;
-	}
-
-	let i = 1;
-	let j;
-	let from_idx;
-	let from_pos;
-	let inc;
-	while (i < arr.length) {
-		// 2. fill up undefined positions
-		if (arr[i] === undefined) {
-			from_idx = i;
-			from_pos = arr[i - 1];
-			j = i;
-
-			// find end of `undefined` sequence...
-			while (arr[j] === undefined) j++;
-
-			// ...and add evenly-spread positions
-			inc = (arr[j] - from_pos) / (j - i + 1);
-			while (i < j) {
-				arr[i] = from_pos + (i + 1 - from_idx) * inc;
-				i++;
-			}
-		} else if (arr[i] < arr[i - 1]) {
-			// 3. make positions increase
-			arr[i] = arr[i - 1];
-		}
-		i++;
-	}
-	return arr;
-};
-
-export default normalizePositions;
diff --git a/src/util/regex.js b/src/util/regex.js
deleted file mode 100644
index 6a27ff82..00000000
--- a/src/util/regex.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
-	Basic building blocks for color regexes
-	---------------------------------------
-
-	These regexes are expressed as strings
-	to be interpolated in the color regexes.
- */
-
-// <number>
-export const num = '([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)';
-
-// <number> or 'none'
-export const num_none = `(?:${num}|none)`;
-
-// <percentage>
-export const per = `${num}%`;
-
-// <percent> or 'none'
-export const per_none = `(?:${num}%|none)`;
-
-// <number-percentage> (<alpha-value>)
-export const num_per = `(?:${num}%|${num})`;
-
-// <number-percentage> (<alpha-value>) or 'none'
-export const num_per_none = `(?:${num}%|${num}|none)`;
-
-// <hue>
-export const hue = `(?:${num}(deg|grad|rad|turn)|${num})`;
-
-// <hue> or 'none'
-export const hue_none = `(?:${num}(deg|grad|rad|turn)|${num}|none)`;
-
-export const c = `\\s*,\\s*`; // comma
-export const so = '\\s*'; // space, optional
-export const s = `\\s+`; // space
-
-export const rx_num_per_none = new RegExp('^' + num_per_none + '$');
diff --git a/src/wcag.js b/src/wcag.js
deleted file mode 100644
index 271e6cf8..00000000
--- a/src/wcag.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import converter from './converter.js';
-
-/*
-	WCAG luminance
-	References: 
-
-	https://en.wikipedia.org/wiki/Relative_luminance
-	https://github.com/w3c/wcag/issues/236#issuecomment-379526596
- */
-export function luminance(color) {
-	let c = converter('lrgb')(color);
-	return 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b;
-}
-
-/*
-	WCAG contrast
- */
-export function contrast(a, b) {
-	let L1 = luminance(a);
-	let L2 = luminance(b);
-	return (Math.max(L1, L2) + 0.05) / (Math.min(L1, L2) + 0.05);
-}
diff --git a/src/xyb/constants.js b/src/xyb/constants.js
deleted file mode 100644
index c577519a..00000000
--- a/src/xyb/constants.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export const bias = 0.00379307325527544933;
-export const bias_cbrt = Math.cbrt(bias);
diff --git a/src/xyb/convertRgbToXyb.js b/src/xyb/convertRgbToXyb.js
deleted file mode 100644
index dab80558..00000000
--- a/src/xyb/convertRgbToXyb.js
+++ /dev/null
@@ -1,27 +0,0 @@
-import convertRgbToLrgb from '../lrgb/convertRgbToLrgb.js';
-import { bias, bias_cbrt } from './constants.js';
-
-const transfer = v => Math.cbrt(v) - bias_cbrt;
-
-const convertRgbToXyb = color => {
-	const { r, g, b, alpha } = convertRgbToLrgb(color);
-	const l = transfer(0.3 * r + 0.622 * g + 0.078 * b + bias);
-	const m = transfer(0.23 * r + 0.692 * g + 0.078 * b + bias);
-	const s = transfer(
-		0.24342268924547819 * r +
-			0.20476744424496821 * g +
-			0.5518098665095536 * b +
-			bias
-	);
-	const res = {
-		mode: 'xyb',
-		x: (l - m) / 2,
-		y: (l + m) / 2,
-		/* Apply default chroma from luma (subtract Y from B) */
-		b: s - (l + m) / 2
-	};
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertRgbToXyb;
diff --git a/src/xyb/convertXybToRgb.js b/src/xyb/convertXybToRgb.js
deleted file mode 100644
index f65c2a3d..00000000
--- a/src/xyb/convertXybToRgb.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import convertLrgbToRgb from '../lrgb/convertLrgbToRgb.js';
-import { bias, bias_cbrt } from './constants.js';
-
-const transfer = v => Math.pow(v + bias_cbrt, 3);
-
-const convertXybToRgb = ({ x, y, b, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (b === undefined) b = 0;
-	const l = transfer(x + y) - bias;
-	const m = transfer(y - x) - bias;
-	/* Account for chroma from luma: add Y back to B */
-	const s = transfer(b + y) - bias;
-
-	const res = convertLrgbToRgb({
-		r:
-			11.031566904639861 * l -
-			9.866943908131562 * m -
-			0.16462299650829934 * s,
-		g:
-			-3.2541473810744237 * l +
-			4.418770377582723 * m -
-			0.16462299650829934 * s,
-		b:
-			-3.6588512867136815 * l +
-			2.7129230459360922 * m +
-			1.9459282407775895 * s
-	});
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertXybToRgb;
diff --git a/src/xyb/definition.js b/src/xyb/definition.js
deleted file mode 100644
index b7d2489d..00000000
--- a/src/xyb/definition.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-import convertRgbToXyb from './convertRgbToXyb.js';
-import convertXybToRgb from './convertXybToRgb.js';
-
-/*
-	The XYB color space, used in JPEG XL.
-	Reference: https://ds.jpeg.org/whitepapers/jpeg-xl-whitepaper.pdf
-*/
-
-const definition = {
-	mode: 'xyb',
-	channels: ['x', 'y', 'b', 'alpha'],
-	parse: ['--xyb'],
-	serialize: '--xyb',
-
-	toMode: {
-		rgb: convertXybToRgb
-	},
-
-	fromMode: {
-		rgb: convertRgbToXyb
-	},
-
-	ranges: {
-		x: [-0.0154, 0.0281],
-		y: [0, 0.8453],
-		b: [-0.2778, 0.388]
-	},
-
-	interpolate: {
-		x: interpolatorLinear,
-		y: interpolatorLinear,
-		b: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/src/xyz50/constants.js b/src/xyz50/constants.js
deleted file mode 100644
index f08caee1..00000000
--- a/src/xyz50/constants.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export const k = Math.pow(29, 3) / Math.pow(3, 3);
-export const e = Math.pow(6, 3) / Math.pow(29, 3);
diff --git a/src/xyz50/convertRgbToXyz50.js b/src/xyz50/convertRgbToXyz50.js
deleted file mode 100644
index e0faf49c..00000000
--- a/src/xyz50/convertRgbToXyz50.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-	Convert sRGB values to CIE XYZ D50
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-	
-*/
-
-import convertRgbToLrgb from '../lrgb/convertRgbToLrgb.js';
-
-const convertRgbToXyz50 = rgb => {
-	let { r, g, b, alpha } = convertRgbToLrgb(rgb);
-	let res = {
-		mode: 'xyz50',
-		x:
-			0.436065742824811 * r +
-			0.3851514688337912 * g +
-			0.14307845442264197 * b,
-		y:
-			0.22249319175623702 * r +
-			0.7168870538238823 * g +
-			0.06061979053616537 * b,
-		z:
-			0.013923904500943465 * r +
-			0.09708128566574634 * g +
-			0.7140993584005155 * b
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertRgbToXyz50;
diff --git a/src/xyz50/convertXyz50ToRgb.js b/src/xyz50/convertXyz50ToRgb.js
deleted file mode 100644
index 32c35e4d..00000000
--- a/src/xyz50/convertXyz50ToRgb.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-	CIE XYZ D50 values to sRGB.
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-*/
-
-import convertLrgbToRgb from '../lrgb/convertLrgbToRgb.js';
-
-const convertXyz50ToRgb = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = convertLrgbToRgb({
-		r:
-			x * 3.1341359569958707 -
-			y * 1.6173863321612538 -
-			0.4906619460083532 * z,
-		g:
-			x * -0.978795502912089 +
-			y * 1.916254567259524 +
-			0.03344273116131949 * z,
-		b:
-			x * 0.07195537988411677 -
-			y * 0.2289768264158322 +
-			1.405386058324125 * z
-	});
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz50ToRgb;
diff --git a/src/xyz50/definition.js b/src/xyz50/definition.js
deleted file mode 100644
index 7463629a..00000000
--- a/src/xyz50/definition.js
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
-	The XYZ D50 color space
-	-----------------------
- */
-
-import convertXyz50ToRgb from './convertXyz50ToRgb.js';
-import convertXyz50ToLab from '../lab/convertXyz50ToLab.js';
-import convertRgbToXyz50 from './convertRgbToXyz50.js';
-import convertLabToXyz50 from '../lab/convertLabToXyz50.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-const definition = {
-	mode: 'xyz50',
-	parse: ['xyz-d50'],
-	serialize: 'xyz-d50',
-
-	toMode: {
-		rgb: convertXyz50ToRgb,
-		lab: convertXyz50ToLab
-	},
-
-	fromMode: {
-		rgb: convertRgbToXyz50,
-		lab: convertLabToXyz50
-	},
-
-	channels: ['x', 'y', 'z', 'alpha'],
-
-	ranges: {
-		x: [0, 0.964],
-		y: [0, 0.999],
-		z: [0, 0.825]
-	},
-
-	interpolate: {
-		x: interpolatorLinear,
-		y: interpolatorLinear,
-		z: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/src/xyz65/constants.js b/src/xyz65/constants.js
deleted file mode 100644
index f08caee1..00000000
--- a/src/xyz65/constants.js
+++ /dev/null
@@ -1,2 +0,0 @@
-export const k = Math.pow(29, 3) / Math.pow(3, 3);
-export const e = Math.pow(6, 3) / Math.pow(29, 3);
diff --git a/src/xyz65/convertRgbToXyz65.js b/src/xyz65/convertRgbToXyz65.js
deleted file mode 100644
index a067a558..00000000
--- a/src/xyz65/convertRgbToXyz65.js
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-	Convert sRGB values to CIE XYZ D65
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-		* https://observablehq.com/@danburzo/color-matrix-calculator
-*/
-
-import convertRgbToLrgb from '../lrgb/convertRgbToLrgb.js';
-
-const convertRgbToXyz65 = rgb => {
-	let { r, g, b, alpha } = convertRgbToLrgb(rgb);
-	let res = {
-		mode: 'xyz65',
-		x:
-			0.4123907992659593 * r +
-			0.357584339383878 * g +
-			0.1804807884018343 * b,
-		y:
-			0.2126390058715102 * r +
-			0.715168678767756 * g +
-			0.0721923153607337 * b,
-		z:
-			0.0193308187155918 * r +
-			0.119194779794626 * g +
-			0.9505321522496607 * b
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertRgbToXyz65;
diff --git a/src/xyz65/convertXyz50ToXyz65.js b/src/xyz65/convertXyz50ToXyz65.js
deleted file mode 100644
index b04ae656..00000000
--- a/src/xyz65/convertXyz50ToXyz65.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-	Chromatic adaptation of CIE XYZ from D50 to D65 white point
-	using the Bradford method.
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html	
-*/
-
-const convertXyz50ToXyz65 = xyz50 => {
-	let { x, y, z, alpha } = xyz50;
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = {
-		mode: 'xyz65',
-		x:
-			0.9554734527042182 * x -
-			0.0230985368742614 * y +
-			0.0632593086610217 * z,
-		y:
-			-0.0283697069632081 * x +
-			1.0099954580058226 * y +
-			0.021041398966943 * z,
-		z:
-			0.0123140016883199 * x -
-			0.0205076964334779 * y +
-			1.3303659366080753 * z
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz50ToXyz65;
diff --git a/src/xyz65/convertXyz65ToRgb.js b/src/xyz65/convertXyz65ToRgb.js
deleted file mode 100644
index 246752aa..00000000
--- a/src/xyz65/convertXyz65ToRgb.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-	CIE XYZ D65 values to sRGB.
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-		* https://observablehq.com/@danburzo/color-matrix-calculator
-*/
-
-import convertLrgbToRgb from '../lrgb/convertLrgbToRgb.js';
-
-const convertXyz65ToRgb = ({ x, y, z, alpha }) => {
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = convertLrgbToRgb({
-		r:
-			x * 3.2409699419045226 -
-			y * 1.5373831775700939 -
-			0.4986107602930034 * z,
-		g:
-			x * -0.9692436362808796 +
-			y * 1.8759675015077204 +
-			0.0415550574071756 * z,
-		b:
-			x * 0.0556300796969936 -
-			y * 0.2039769588889765 +
-			1.0569715142428784 * z
-	});
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz65ToRgb;
diff --git a/src/xyz65/convertXyz65ToXyz50.js b/src/xyz65/convertXyz65ToXyz50.js
deleted file mode 100644
index 2e170dc6..00000000
--- a/src/xyz65/convertXyz65ToXyz50.js
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
-	Chromatic adaptation of CIE XYZ from D65 to D50 white point
-	using the Bradford method.
-
-	References:
-		* https://drafts.csswg.org/css-color/#color-conversion-code
-		* http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html	
-*/
-
-const convertXyz65ToXyz50 = xyz65 => {
-	let { x, y, z, alpha } = xyz65;
-	if (x === undefined) x = 0;
-	if (y === undefined) y = 0;
-	if (z === undefined) z = 0;
-	let res = {
-		mode: 'xyz50',
-		x:
-			1.0479298208405488 * x +
-			0.0229467933410191 * y -
-			0.0501922295431356 * z,
-		y:
-			0.0296278156881593 * x +
-			0.990434484573249 * y -
-			0.0170738250293851 * z,
-		z:
-			-0.0092430581525912 * x +
-			0.0150551448965779 * y +
-			0.7518742899580008 * z
-	};
-	if (alpha !== undefined) {
-		res.alpha = alpha;
-	}
-	return res;
-};
-
-export default convertXyz65ToXyz50;
diff --git a/src/xyz65/definition.js b/src/xyz65/definition.js
deleted file mode 100644
index 5694d7c5..00000000
--- a/src/xyz65/definition.js
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
-	The XYZ D65 color space
-	-----------------------
- */
-
-import convertXyz65ToRgb from './convertXyz65ToRgb.js';
-import convertRgbToXyz65 from './convertRgbToXyz65.js';
-
-import convertXyz65ToXyz50 from './convertXyz65ToXyz50.js';
-import convertXyz50ToXyz65 from './convertXyz50ToXyz65.js';
-
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-const definition = {
-	mode: 'xyz65',
-
-	toMode: {
-		rgb: convertXyz65ToRgb,
-		xyz50: convertXyz65ToXyz50
-	},
-
-	fromMode: {
-		rgb: convertRgbToXyz65,
-		xyz50: convertXyz50ToXyz65
-	},
-
-	ranges: {
-		x: [0, 0.95],
-		y: [0, 1],
-		z: [0, 1.088]
-	},
-
-	channels: ['x', 'y', 'z', 'alpha'],
-
-	parse: ['xyz', 'xyz-d65'],
-	serialize: 'xyz-d65',
-
-	interpolate: {
-		x: interpolatorLinear,
-		y: interpolatorLinear,
-		z: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/src/yiq/convertRgbToYiq.js b/src/yiq/convertRgbToYiq.js
deleted file mode 100644
index 4218f5ed..00000000
--- a/src/yiq/convertRgbToYiq.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const convertRgbToYiq = ({ r, g, b, alpha }) => {
-	if (r === undefined) r = 0;
-	if (g === undefined) g = 0;
-	if (b === undefined) b = 0;
-	const res = {
-		mode: 'yiq',
-		y: 0.29889531 * r + 0.58662247 * g + 0.11448223 * b,
-		i: 0.59597799 * r - 0.2741761 * g - 0.32180189 * b,
-		q: 0.21147017 * r - 0.52261711 * g + 0.31114694 * b
-	};
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertRgbToYiq;
diff --git a/src/yiq/convertYiqToRgb.js b/src/yiq/convertYiqToRgb.js
deleted file mode 100644
index 0871b512..00000000
--- a/src/yiq/convertYiqToRgb.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const convertYiqToRgb = ({ y, i, q, alpha }) => {
-	if (y === undefined) y = 0;
-	if (i === undefined) i = 0;
-	if (q === undefined) q = 0;
-	const res = {
-		mode: 'rgb',
-		r: y + 0.95608445 * i + 0.6208885 * q,
-		g: y - 0.27137664 * i - 0.6486059 * q,
-		b: y - 1.10561724 * i + 1.70250126 * q
-	};
-	if (alpha !== undefined) res.alpha = alpha;
-	return res;
-};
-
-export default convertYiqToRgb;
diff --git a/src/yiq/definition.js b/src/yiq/definition.js
deleted file mode 100644
index 15ce657b..00000000
--- a/src/yiq/definition.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import convertRgbToYiq from './convertRgbToYiq.js';
-import convertYiqToRgb from './convertYiqToRgb.js';
-import { interpolatorLinear } from '../interpolate/linear.js';
-import { fixupAlpha } from '../fixup/alpha.js';
-
-/*
-	YIQ Color Space
-
-	References
-	----------
-
-	Wikipedia:
-		https://en.wikipedia.org/wiki/YIQ
-
-	"Measuring perceived color difference using YIQ NTSC
-	transmission color space in mobile applications"
-		
-		by Yuriy Kotsarenko, Fernando Ramos in:
-		Programación Matemática y Software (2010) 
-
-	Available at:
-		
-		http://www.progmat.uaem.mx:8080/artVol2Num2/Articulo3Vol2Num2.pdf
- */
-
-const definition = {
-	mode: 'yiq',
-
-	toMode: {
-		rgb: convertYiqToRgb
-	},
-
-	fromMode: {
-		rgb: convertRgbToYiq
-	},
-
-	channels: ['y', 'i', 'q', 'alpha'],
-
-	parse: ['--yiq'],
-	serialize: '--yiq',
-
-	ranges: {
-		i: [-0.595, 0.595],
-		q: [-0.522, 0.522]
-	},
-
-	interpolate: {
-		y: interpolatorLinear,
-		i: interpolatorLinear,
-		q: interpolatorLinear,
-		alpha: { use: interpolatorLinear, fixup: fixupAlpha }
-	}
-};
-
-export default definition;
diff --git a/test/a98.test.js b/test/a98.test.js
deleted file mode 100644
index 20551127..00000000
--- a/test/a98.test.js
+++ /dev/null
@@ -1,56 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { a98, rgb, formatCss } from '../src/index.js';
-
-test('a98', t => {
-	assert.deepEqual(
-		a98('white'),
-		{ mode: 'a98', r: 0.9999999999999999, g: 1, b: 1.0000000000000002 },
-		'white'
-	);
-	assert.deepEqual(a98('black'), { mode: 'a98', r: 0, g: 0, b: 0 }, 'black');
-	assert.deepEqual(
-		a98('red'),
-		{
-			mode: 'a98',
-			r: 0.8585916022954421,
-			g: -5.533624232798453e-8,
-			b: 2.1612063668957067e-8
-		},
-		'red'
-	);
-});
-
-test('color(a98-rgb)', t => {
-	assert.deepEqual(a98('color(a98-rgb 1 0 0 / 0.25)'), {
-		r: 1,
-		g: 0,
-		b: 0,
-		alpha: 0.25,
-		mode: 'a98'
-	});
-	assert.deepEqual(a98('color(a98-rgb 0% 50% 0.5 / 25%)'), {
-		r: 0,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'a98'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(a98-rgb 0% 50% 0.5 / 25%)'),
-		'color(a98-rgb 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(a98-rgb none 0.5 none)'), 'a98 to rgb is ok');
-	assert.deepEqual(
-		rgb('color(a98-rgb none 0.5 none)'),
-		rgb('color(a98-rgb 0 0.5 0')
-	);
-	assert.ok(a98('rgb(none 100 20)'), 'rgb to a98 is ok');
-	assert.deepEqual(a98('rgb(none 100 20)'), a98('rgb(0 100 20)'));
-});
diff --git a/test/api.test.js b/test/api.test.js
deleted file mode 100644
index 6fe51c97..00000000
--- a/test/api.test.js
+++ /dev/null
@@ -1,492 +0,0 @@
-/*
-	Keep an eye on the API surface of the various bundles
- */
-import test from 'node:test';
-import assert from 'node:assert';
-
-import * as full from '../src/index.js';
-import * as css from '../src/bootstrap/css.js';
-import * as all from '../src/bootstrap/all.js';
-import * as fn from '../src/index-fn.js';
-
-const API_FULL = [
-	'a98',
-	'average',
-	'averageAngle',
-	'averageNumber',
-	'blend',
-	'blerp',
-	'clampChroma',
-	'clampGamut',
-	'clampRgb',
-	'colorsNamed',
-	'convertA98ToXyz65',
-	'convertCubehelixToRgb',
-	'convertDlchToLab65',
-	'converter',
-	'convertHsiToRgb',
-	'convertHslToRgb',
-	'convertHsvToRgb',
-	'convertHwbToRgb',
-	'convertItpToXyz65',
-	'convertJabToJch',
-	'convertJabToRgb',
-	'convertJabToXyz65',
-	'convertJchToJab',
-	'convertLab65ToDlch',
-	'convertLab65ToRgb',
-	'convertLab65ToXyz65',
-	'convertLabToLch',
-	'convertLabToRgb',
-	'convertLabToXyz50',
-	'convertLchToLab',
-	'convertLchuvToLuv',
-	'convertLrgbToOklab',
-	'convertLrgbToRgb',
-	'convertLuvToLchuv',
-	'convertLuvToXyz50',
-	'convertOkhslToOklab',
-	'convertOkhsvToOklab',
-	'convertOklabToLrgb',
-	'convertOklabToOkhsl',
-	'convertOklabToOkhsv',
-	'convertOklabToRgb',
-	'convertP3ToXyz65',
-	'convertProphotoToXyz50',
-	'convertRec2020ToXyz65',
-	'convertRgbToCubehelix',
-	'convertRgbToHsi',
-	'convertRgbToHsl',
-	'convertRgbToHsv',
-	'convertRgbToHwb',
-	'convertRgbToJab',
-	'convertRgbToLab',
-	'convertRgbToLab65',
-	'convertRgbToLrgb',
-	'convertRgbToOklab',
-	'convertRgbToXyb',
-	'convertRgbToXyz50',
-	'convertRgbToXyz65',
-	'convertRgbToYiq',
-	'convertXybToRgb',
-	'convertXyz50ToLab',
-	'convertXyz50ToLuv',
-	'convertXyz50ToProphoto',
-	'convertXyz50ToRgb',
-	'convertXyz50ToXyz65',
-	'convertXyz65ToA98',
-	'convertXyz65ToItp',
-	'convertXyz65ToJab',
-	'convertXyz65ToLab65',
-	'convertXyz65ToP3',
-	'convertXyz65ToRec2020',
-	'convertXyz65ToRgb',
-	'convertXyz65ToXyz50',
-	'convertYiqToRgb',
-	'cubehelix',
-	'differenceCie76',
-	'differenceCie94',
-	'differenceCiede2000',
-	'differenceCmc',
-	'differenceEuclidean',
-	'differenceHueChroma',
-	'differenceHueNaive',
-	'differenceHueSaturation',
-	'differenceHyab',
-	'differenceKotsarenkoRamos',
-	'differenceItp',
-	'displayable',
-	'dlab',
-	'dlch',
-	'easingGamma',
-	'easingInOutSine',
-	'easingMidpoint',
-	'easingSmootherstep',
-	'easingSmoothstep',
-	'easingSmoothstepInverse',
-	'filterBrightness',
-	'filterContrast',
-	'filterDeficiencyDeuter',
-	'filterDeficiencyProt',
-	'filterDeficiencyTrit',
-	'filterGrayscale',
-	'filterHueRotate',
-	'filterInvert',
-	'filterSaturate',
-	'filterSepia',
-	'fixupAlpha',
-	'fixupHueDecreasing',
-	'fixupHueIncreasing',
-	'fixupHueLonger',
-	'fixupHueShorter',
-	'formatCss',
-	'formatHex',
-	'formatHex8',
-	'formatHsl',
-	'formatRgb',
-	'getMode',
-	'hsi',
-	'hsl',
-	'hsv',
-	'hwb',
-	'itp',
-	'inGamut',
-	'interpolate',
-	'interpolateWith',
-	'interpolateWithPremultipliedAlpha',
-	'interpolatorLinear',
-	'interpolatorPiecewise',
-	'interpolatorSplineBasis',
-	'interpolatorSplineBasisClosed',
-	'interpolatorSplineMonotone',
-	'interpolatorSplineMonotone2',
-	'interpolatorSplineMonotoneClosed',
-	'interpolatorSplineNatural',
-	'interpolatorSplineNaturalClosed',
-	'jab',
-	'jch',
-	'lab',
-	'lab65',
-	'lch',
-	'lch65',
-	'lchuv',
-	'lerp',
-	'lrgb',
-	'luv',
-	'mapAlphaDivide',
-	'mapAlphaMultiply',
-	'mapper',
-	'mapTransferGamma',
-	'mapTransferLinear',
-	'modeA98',
-	'modeCubehelix',
-	'modeDlab',
-	'modeDlch',
-	'modeHsi',
-	'modeHsl',
-	'modeHsv',
-	'modeHwb',
-	'modeItp',
-	'modeJab',
-	'modeJch',
-	'modeLab',
-	'modeLab65',
-	'modeLch',
-	'modeLch65',
-	'modeLchuv',
-	'modeLrgb',
-	'modeLuv',
-	'modeOkhsl',
-	'modeOkhsv',
-	'modeOklab',
-	'modeOklch',
-	'modeP3',
-	'modeProphoto',
-	'modeRec2020',
-	'modeRgb',
-	'modeXyb',
-	'modeXyz50',
-	'modeXyz65',
-	'modeYiq',
-	'nearest',
-	'okhsl',
-	'okhsv',
-	'oklab',
-	'oklch',
-	'p3',
-	'parse',
-	'parseHex',
-	'parseHsl',
-	'parseHslLegacy',
-	'parseHwb',
-	'parseLab',
-	'parseLch',
-	'parseNamed',
-	'parseOklab',
-	'parseOklch',
-	'parseRgb',
-	'parseRgbLegacy',
-	'parseTransparent',
-	'prophoto',
-	'random',
-	'rec2020',
-	'removeParser',
-	'rgb',
-	'round',
-	'samples',
-	'serializeHex',
-	'serializeHex8',
-	'serializeHsl',
-	'serializeRgb',
-	'toGamut',
-	'trilerp',
-	'unlerp',
-	'useMode',
-	'useParser',
-	'wcagContrast',
-	'wcagLuminance',
-	'xyb',
-	'xyz50',
-	'xyz65',
-	'yiq'
-];
-const API_CSS = [
-	'a98',
-	'hsl',
-	'hsv',
-	'hwb',
-	'lab',
-	'lab65',
-	'lch',
-	'lch65',
-	'lrgb',
-	'oklab',
-	'oklch',
-	'p3',
-	'prophoto',
-	'rec2020',
-	'rgb',
-	'xyz50',
-	'xyz65'
-];
-
-const API_ALL = [
-	'a98',
-	'cubehelix',
-	'dlab',
-	'dlch',
-	'hsi',
-	'hsl',
-	'hsv',
-	'hwb',
-	'itp',
-	'jab',
-	'jch',
-	'lab',
-	'lab65',
-	'lch',
-	'lch65',
-	'lchuv',
-	'lrgb',
-	'luv',
-	'okhsl',
-	'okhsv',
-	'oklab',
-	'oklch',
-	'p3',
-	'prophoto',
-	'rec2020',
-	'rgb',
-	'xyb',
-	'xyz50',
-	'xyz65',
-	'yiq'
-];
-
-const API_FN = [
-	'average',
-	'averageAngle',
-	'averageNumber',
-	'blend',
-	'blerp',
-	'clampChroma',
-	'clampGamut',
-	'clampRgb',
-	'colorsNamed',
-	'convertA98ToXyz65',
-	'convertCubehelixToRgb',
-	'convertDlchToLab65',
-	'converter',
-	'convertHsiToRgb',
-	'convertHslToRgb',
-	'convertHsvToRgb',
-	'convertHwbToRgb',
-	'convertItpToXyz65',
-	'convertJabToJch',
-	'convertJabToRgb',
-	'convertJabToXyz65',
-	'convertJchToJab',
-	'convertLab65ToDlch',
-	'convertLab65ToRgb',
-	'convertLab65ToXyz65',
-	'convertLabToLch',
-	'convertLabToRgb',
-	'convertLabToXyz50',
-	'convertLchToLab',
-	'convertLchuvToLuv',
-	'convertLrgbToOklab',
-	'convertLrgbToRgb',
-	'convertLuvToLchuv',
-	'convertLuvToXyz50',
-	'convertOkhslToOklab',
-	'convertOkhsvToOklab',
-	'convertOklabToLrgb',
-	'convertOklabToOkhsl',
-	'convertOklabToOkhsv',
-	'convertOklabToRgb',
-	'convertP3ToXyz65',
-	'convertProphotoToXyz50',
-	'convertRec2020ToXyz65',
-	'convertRgbToCubehelix',
-	'convertRgbToHsi',
-	'convertRgbToHsl',
-	'convertRgbToHsv',
-	'convertRgbToHwb',
-	'convertRgbToJab',
-	'convertRgbToLab',
-	'convertRgbToLab65',
-	'convertRgbToLrgb',
-	'convertRgbToOklab',
-	'convertRgbToXyb',
-	'convertRgbToXyz50',
-	'convertRgbToXyz65',
-	'convertRgbToYiq',
-	'convertXybToRgb',
-	'convertXyz50ToLab',
-	'convertXyz50ToLuv',
-	'convertXyz50ToProphoto',
-	'convertXyz50ToRgb',
-	'convertXyz50ToXyz65',
-	'convertXyz65ToA98',
-	'convertXyz65ToItp',
-	'convertXyz65ToJab',
-	'convertXyz65ToLab65',
-	'convertXyz65ToP3',
-	'convertXyz65ToRec2020',
-	'convertXyz65ToRgb',
-	'convertXyz65ToXyz50',
-	'convertYiqToRgb',
-	'differenceCie76',
-	'differenceCie94',
-	'differenceCiede2000',
-	'differenceCmc',
-	'differenceEuclidean',
-	'differenceHueChroma',
-	'differenceHueNaive',
-	'differenceHueSaturation',
-	'differenceHyab',
-	'differenceKotsarenkoRamos',
-	'differenceItp',
-	'displayable',
-	'easingGamma',
-	'easingInOutSine',
-	'easingMidpoint',
-	'easingSmootherstep',
-	'easingSmoothstep',
-	'easingSmoothstepInverse',
-	'filterBrightness',
-	'filterContrast',
-	'filterDeficiencyDeuter',
-	'filterDeficiencyProt',
-	'filterDeficiencyTrit',
-	'filterGrayscale',
-	'filterHueRotate',
-	'filterInvert',
-	'filterSaturate',
-	'filterSepia',
-	'fixupAlpha',
-	'fixupHueDecreasing',
-	'fixupHueIncreasing',
-	'fixupHueLonger',
-	'fixupHueShorter',
-	'formatCss',
-	'formatHex',
-	'formatHex8',
-	'formatHsl',
-	'formatRgb',
-	'getMode',
-	'inGamut',
-	'interpolate',
-	'interpolateWith',
-	'interpolateWithPremultipliedAlpha',
-	'interpolatorLinear',
-	'interpolatorPiecewise',
-	'interpolatorSplineBasis',
-	'interpolatorSplineBasisClosed',
-	'interpolatorSplineMonotone',
-	'interpolatorSplineMonotone2',
-	'interpolatorSplineMonotoneClosed',
-	'interpolatorSplineNatural',
-	'interpolatorSplineNaturalClosed',
-	'lerp',
-	'mapAlphaDivide',
-	'mapAlphaMultiply',
-	'mapper',
-	'mapTransferGamma',
-	'mapTransferLinear',
-	'modeA98',
-	'modeCubehelix',
-	'modeDlab',
-	'modeDlch',
-	'modeHsi',
-	'modeHsl',
-	'modeHsv',
-	'modeHwb',
-	'modeItp',
-	'modeJab',
-	'modeJch',
-	'modeLab',
-	'modeLab65',
-	'modeLch',
-	'modeLch65',
-	'modeLchuv',
-	'modeLrgb',
-	'modeLuv',
-	'modeOkhsl',
-	'modeOkhsv',
-	'modeOklab',
-	'modeOklch',
-	'modeP3',
-	'modeProphoto',
-	'modeRec2020',
-	'modeRgb',
-	'modeXyb',
-	'modeXyz50',
-	'modeXyz65',
-	'modeYiq',
-	'nearest',
-	'parse',
-	'parseHex',
-	'parseHsl',
-	'parseHslLegacy',
-	'parseHwb',
-	'parseLab',
-	'parseLch',
-	'parseNamed',
-	'parseOklab',
-	'parseOklch',
-	'parseRgb',
-	'parseRgbLegacy',
-	'parseTransparent',
-	'random',
-	'removeParser',
-	'round',
-	'samples',
-	'serializeHex',
-	'serializeHex8',
-	'serializeHsl',
-	'serializeRgb',
-	'toGamut',
-	'trilerp',
-	'unlerp',
-	'useMode',
-	'useParser',
-	'wcagContrast',
-	'wcagLuminance'
-];
-
-test('culori', t => {
-	assert.deepEqual(Object.keys(full).sort(), API_FULL.sort());
-});
-
-test('culori/css', t => {
-	assert.deepEqual(Object.keys(css).sort(), API_CSS.sort());
-});
-
-test('culori/all', t => {
-	assert.deepEqual(Object.keys(all).sort(), API_ALL.sort());
-});
-
-test('culori/fn', t => {
-	assert.deepEqual(Object.keys(fn).sort(), API_FN.sort());
-});
diff --git a/test/average.test.js b/test/average.test.js
deleted file mode 100644
index 2786ac02..00000000
--- a/test/average.test.js
+++ /dev/null
@@ -1,12 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { average, averageAngle, formatHex } from '../src/index.js';
-
-test('average', t => {
-	assert.equal(formatHex(average(['#ff0000', '#0000ff'])), '#800080');
-	assert.equal(formatHex(average(['#ff0000', '#0000ff'], 'lch')), '#f50086');
-});
-
-test('averageAngle', t => {
-	assert.equal(averageAngle([270, 0]), 315);
-});
diff --git a/test/blend.test.js b/test/blend.test.js
deleted file mode 100644
index 27894c08..00000000
--- a/test/blend.test.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { blend } from '../src/index.js';
-
-test('blendNormal', t => {
-	assert.deepEqual(blend(['white', 'rgba(0, 0, 0, 0.5)']), {
-		mode: 'rgb',
-		r: 0.5,
-		g: 0.5,
-		b: 0.5,
-		alpha: 1
-	});
-
-	assert.deepEqual(
-		blend([
-			{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0.5 },
-			{ mode: 'rgb', r: 0, g: 0, b: 1, alpha: 0.5 }
-		]),
-		{
-			mode: 'rgb',
-			r: 0.3333333333333333,
-			g: 0,
-			b: 0.6666666666666666,
-			alpha: 0.75
-		}
-	);
-
-	// blend with transparent source
-	assert.deepEqual(
-		blend([{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0.5 }, 'transparent']),
-		{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0.5 }
-	);
-
-	// blend with transparent backdrop
-	assert.deepEqual(
-		blend(['transparent', { mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0.5 }]),
-		{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0.5 }
-	);
-});
diff --git a/test/cat.test.js b/test/cat.test.js
deleted file mode 100644
index daaa1de5..00000000
--- a/test/cat.test.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { xyz65, xyz50, rgb } from '../src/index.js';
-
-let colors = ['red', 'green', 'blue', 'white', 'black', 'magenta', 'tomato'];
-let e = 1e-14;
-
-let sameXYZ = (a, b) => {
-	return (
-		a.mode === b.mode &&
-		Math.abs(a.x - b.x) < e &&
-		Math.abs(a.y - b.y) < e &&
-		Math.abs(a.z - b.z) < e
-	);
-};
-
-let sameRGB = (a, b) => {
-	return (
-		a.mode === b.mode &&
-		Math.abs(a.r - b.r) < e &&
-		Math.abs(a.g - b.g) < e &&
-		Math.abs(a.b - b.b) < e
-	);
-};
-
-test('rgb -> xyz50 = rgb -> xyz65 -> xyz50', t => {
-	colors.forEach(c => {
-		assert.ok(sameXYZ(xyz50(rgb(c)), xyz50(xyz65(rgb(c)))), c);
-	});
-});
-
-test('rgb -> xyz50 -> rgb = rgb -> xyz50 -> xyz65 -> rgb', t => {
-	colors.forEach(c => {
-		assert.ok(sameRGB(rgb(xyz50(rgb(c))), rgb(xyz65(xyz50(rgb(c))))), c);
-	});
-});
diff --git a/test/clamp.test.js b/test/clamp.test.js
deleted file mode 100644
index 05665198..00000000
--- a/test/clamp.test.js
+++ /dev/null
@@ -1,266 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	clampChroma,
-	displayable,
-	inGamut,
-	clampRgb,
-	clampGamut,
-	formatCss,
-	toGamut,
-	lch
-} from '../src/index.js';
-
-test('RGB', t => {
-	assert.equal(displayable({ mode: 'rgb', r: 0, g: 0, b: 0 }), true);
-	assert.equal(
-		displayable({ mode: 'rgb', r: 1, g: 1, b: 1, alpha: 0.5 }),
-		true
-	);
-	assert.equal(
-		displayable({ mode: 'rgb', r: 1.1, g: 1, b: 1, alpha: 0.5 }),
-		false
-	);
-});
-
-test('LCh', t => {
-	assert.equal(displayable('lch(50% 0 0)'), true);
-	assert.equal(displayable('lch(50% -100 0)'), true);
-	assert.equal(displayable('lch(120% -100 0)'), false);
-});
-
-test('clampChroma (rgb)', t => {
-	assert.deepEqual(clampChroma('red'), { mode: 'rgb', r: 1, g: 0, b: 0 });
-	assert.deepEqual(clampChroma('rgb(300, 255, 255)'), {
-		mode: 'rgb',
-		r: 1,
-		g: 1,
-		b: 1
-	});
-});
-
-test('clampChroma (lch)', t => {
-	assert.deepEqual(clampChroma('lch(50% 120 5)'), {
-		mode: 'lch',
-		l: 50,
-		c: 77.4609375,
-		h: 5
-	});
-	assert.equal(displayable(clampChroma('lch(50% 120 5)')), true);
-	assert.deepEqual(
-		clampChroma({
-			mode: 'lch',
-			l: 0,
-			c: 100,
-			h: 30
-		}),
-		{
-			mode: 'lch',
-			l: 0,
-			c: 0,
-			h: 30
-		},
-		'for l = 0, only c = 0 is in gamut'
-	);
-});
-
-test('Issue #129', t => {
-	let color = {
-		mode: 'lch',
-		l: 44.01740616147086,
-		c: 58.743630227529145,
-		h: 180.30393476177233
-	};
-	assert.equal(displayable(clampChroma(color)), true);
-	assert.equal(
-		displayable(clampChroma({ mode: 'oklch', l: 0.5, c: 0.161, h: 180 })),
-		true
-	);
-
-	assert.deepEqual(
-		clampChroma({ mode: 'oklch', l: 0.5, c: 0.16, h: 180 }, 'oklch'),
-		{ mode: 'oklch', l: 0.5, c: 0.090703125, h: 180 }
-	);
-
-	assert.equal(
-		formatCss(clampChroma('lch(80% 150 60)', 'lch', 'p3')),
-		'lch(80 60.040283203125 60)',
-		'with p3 gamut'
-	);
-});
-
-test('inGamut()', t => {
-	assert.equal(
-		inGamut('rec2020')('color(rec2020 1 1 0)'),
-		true,
-		'rec2020 in rec2020 gamut'
-	);
-	assert.equal(
-		inGamut('p3')('color(rec2020 1 1 0)'),
-		false,
-		'rec2020 in p3 gamut'
-	);
-	assert.equal(
-		inGamut('rgb')('color(rec2020 1 1 0)'),
-		false,
-		'rec2020 in rgb gamut'
-	);
-
-	assert.equal(
-		inGamut('rec2020')('color(display-p3 1 1 0)'),
-		true,
-		'p3 in rec2020 gamut'
-	);
-	assert.equal(
-		inGamut('p3')('color(display-p3 1 1 0)'),
-		true,
-		'p3 in p3 gamut'
-	);
-	assert.equal(
-		inGamut('rgb')('color(display-p3 1 1 0)'),
-		false,
-		'p3 in rgb gamut'
-	);
-
-	assert.equal(inGamut('hsl')('color(srgb 1 1 0)'), true, 'in hsl gamut');
-	assert.equal(
-		inGamut('hsl')('color(srgb 1 1.1 0)'),
-		false,
-		'out of hsl gamut'
-	);
-});
-
-test('clampGamut()', t => {
-	const p3Color = 'color(display-p3 1 1 0)';
-
-	assert.equal(
-		formatCss(clampGamut('rgb')(p3Color)),
-		'color(display-p3 0.9999999999999999 0.9999999999999997 0.3308973181805899)',
-		'p3 color to rgb'
-	);
-	assert.equal(
-		formatCss(clampGamut('p3')(p3Color)),
-		'color(display-p3 1 1 0)',
-		'p3 color to p3'
-	);
-	assert.equal(
-		formatCss(clampGamut('rec2020')(p3Color)),
-		'color(display-p3 1 1 0)',
-		'p3 color to rec2020'
-	);
-
-	const crimson = 'color(display-p3 0.8 0.1 0.3)';
-	const toRgb = clampGamut('rgb');
-
-	assert.equal(
-		formatCss(toRgb(crimson)),
-		'color(display-p3 0.8015640173988641 0.16985582666875737 0.30217671004779834)',
-		'api docs example'
-	);
-});
-
-test('toGamut()', t => {
-	assert.equal(
-		formatCss(toGamut('rgb')({ mode: 'oklch', l: 1.5, c: 0.2, h: 180 })),
-		'color(srgb 1 1 1)',
-		'white'
-	);
-	assert.equal(
-		formatCss(toGamut('rgb')({ mode: 'oklch', l: -1.5, c: 0.2, h: 180 })),
-		'color(srgb 0 0 0)',
-		'black'
-	);
-	assert.equal(
-		formatCss(toGamut('rgb')('color(--lch-d65 100 0 180)')),
-		'color(srgb 1 1 1)',
-		'chroma = 0'
-	);
-	assert.equal(
-		formatCss(toGamut('p3')('lch(80% 150 60)')),
-		'color(display-p3 0.9999999999999999 0.6969234114981073 0.5084794107705369)',
-		'api docs example'
-	);
-
-	const likeClampChroma = toGamut('rgb', 'lch', null);
-
-	assert.deepEqual(lch(likeClampChroma('lch(50% 120 5)')), {
-		mode: 'lch',
-		l: 50.00519612994975,
-		c: 77.47625128342412,
-		h: 5.006331789592595
-	});
-
-	assert.throws(() => toGamut('rgb', 'lab'));
-});
-
-test('missing components', t => {
-	assert.ok(displayable('rgb(none none none)'), 'displayable');
-
-	assert.ok(inGamut('p3')('color(display-p3 none none none)'), 'inGamut');
-
-	assert.deepEqual(
-		clampRgb('rgb(none 300 none)'),
-		{
-			mode: 'rgb',
-			r: 0,
-			g: 1,
-			b: 0
-		},
-		'clampRgb'
-	);
-
-	assert.deepEqual(
-		clampGamut('p3')('color(display-p3 none 3 none)'),
-		{
-			mode: 'p3',
-			r: 0,
-			g: 1,
-			b: 0
-		},
-		'clampGamut'
-	);
-
-	assert.deepEqual(
-		clampChroma({
-			mode: 'lch',
-			l: 120
-		}),
-		{
-			mode: 'lch',
-			l: 100.00000139649632,
-			c: 0
-		},
-		'clampChroma, lch color (no conversion)'
-	);
-
-	assert.deepEqual(
-		clampChroma('color(srgb 1.1 none none)'),
-		{
-			mode: 'rgb',
-			r: 0.9999762593315072,
-			g: 0.3000275449561938,
-			b: 0.17168509121325368
-		},
-		'clampChroma, rgb color'
-	);
-
-	assert.deepEqual(
-		toGamut()({
-			mode: 'lch',
-			l: 120
-		}),
-		{ r: 1, g: 1, b: 1, mode: 'rgb' },
-		'toGamut(), oklch color (no conversion)'
-	);
-
-	assert.deepEqual(
-		toGamut()('color(srgb 1.1 none none)'),
-		{
-			mode: 'rgb',
-			r: 0.9999999999999997,
-			g: 0.2478080277701502,
-			b: 0.18935505411180673
-		},
-		'toGamut(), rgb color'
-	);
-});
diff --git a/test/color-syntax.test.js b/test/color-syntax.test.js
deleted file mode 100644
index ad19a2e1..00000000
--- a/test/color-syntax.test.js
+++ /dev/null
@@ -1,49 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { parse } from '../src/index.js';
-
-test('fewer values than channels', t => {
-	const tests = [
-		'color(srgb)',
-		'color(srgb )',
-		'color(srgb/)',
-		'color(srgb /0.5)',
-		'color(srgb 0.25)',
-		'color(srgb 0.25 50%)',
-		'color( srgb 25% .5 / 0.2)'
-	];
-	tests.forEach(test => {
-		assert.equal(parse(test), undefined, test);
-	});
-});
-
-test('more values than channels', t => {
-	const tests = [
-		'color(srgb 25% .5 75% 0.33 0.66)',
-		'color(srgb 25% .5 75% 0.33 0.66 / 70% )',
-		'color(srgb 25% .5 75% 0.33 / 0.7)'
-	];
-	tests.forEach(test => {
-		assert.equal(parse(test), undefined, test);
-	});
-});
-
-test('hue components', t => {
-	const tests = ['color(srgb 0.5 0.5 0deg)'];
-	tests.forEach(test => {
-		assert.equal(parse(test), undefined, test);
-	});
-});
-
-test('clamp alpha', t => {
-	assert.deepEqual(
-		parse('color(srgb 1.5 -0.4 0.2 / -0.5)'),
-		{ mode: 'rgb', r: 1.5, g: -0.4, b: 0.2, alpha: 0 },
-		'clamp alpha < 0'
-	);
-	assert.deepEqual(
-		parse('color(srgb 1.5 -0.4 0.2 / 1.5)'),
-		{ mode: 'rgb', r: 1.5, g: -0.4, b: 0.2, alpha: 1 },
-		'clamp alpha > 1'
-	);
-});
diff --git a/test/css.test.js b/test/css.test.js
deleted file mode 100644
index c1358773..00000000
--- a/test/css.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { formatRgb, formatHex, rgb } from '../src/index.js';
-
-test('formatRgb', t => {
-	assert.deepEqual(
-		formatRgb(rgb('rgb(200, 300, 100)')),
-		'rgb(200, 255, 100)',
-		'rgb'
-	);
-
-	assert.deepEqual(
-		formatRgb(rgb('rgba(200, 300, 100, 0.1)')),
-		'rgba(200, 255, 100, 0.1)',
-		'rgb'
-	);
-});
-
-test('formatHex', t => {
-	assert.deepEqual(formatHex(rgb('#c0c2ff')), '#c0c2ff', '#c0c2ff');
-
-	assert.deepEqual(formatHex(rgb('#00c2ff')), '#00c2ff', '#00c2ff');
-});
diff --git a/test/cubehelix.test.js b/test/cubehelix.test.js
deleted file mode 100644
index cbced792..00000000
--- a/test/cubehelix.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { cubehelix, formatCss, rgb } from '../src/index.js';
-
-test('color(--cubehelix)', t => {
-	assert.deepEqual(cubehelix('color(--cubehelix 30 0.5 1 / 0.25)'), {
-		h: 30,
-		s: 0.5,
-		l: 1,
-		alpha: 0.25,
-		mode: 'cubehelix'
-	});
-	assert.deepEqual(cubehelix('color(--cubehelix 0 50% 0.5 / 25%)'), {
-		h: 0,
-		s: 0.5,
-		l: 0.5,
-		alpha: 0.25,
-		mode: 'cubehelix'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--cubehelix 0 50% 0.5 / 25%)'),
-		'color(--cubehelix 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--cubehelix none 0.5 none)'));
-	assert.deepEqual(
-		rgb('color(--cubehelix none 0.5 none)'),
-		rgb('color(--cubehelix 0 0.5 0)')
-	);
-	assert.ok(cubehelix('rgb(none 100 20)'));
-	assert.deepEqual(cubehelix('rgb(none 100 20)'), cubehelix('rgb(0 100 20)'));
-});
diff --git a/test/deficiency.test.js b/test/deficiency.test.js
deleted file mode 100644
index c05d12af..00000000
--- a/test/deficiency.test.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	filterDeficiencyProt,
-	filterDeficiencyDeuter,
-	filterDeficiencyTrit,
-	formatHex
-} from '../src/index.js';
-
-test('0 severity', t => {
-	assert.equal(formatHex(filterDeficiencyProt(0)('red')), '#ff0000');
-	assert.equal(formatHex(filterDeficiencyDeuter(0)('red')), '#ff0000');
-	assert.equal(formatHex(filterDeficiencyTrit(0)('red')), '#ff0000');
-});
-
-test('0.55 severity', t => {
-	assert.equal(formatHex(filterDeficiencyProt(0.55)('blue')), '#0012ff');
-	assert.equal(formatHex(filterDeficiencyDeuter(0.55)('blue')), '#000afa');
-	assert.equal(formatHex(filterDeficiencyTrit(0.55)('blue')), '#000fae');
-});
-
-test('1 severity', t => {
-	assert.equal(formatHex(filterDeficiencyProt(1)('green')), '#876500');
-	assert.equal(formatHex(filterDeficiencyDeuter(1)('green')), '#6e5605');
-	assert.equal(formatHex(filterDeficiencyTrit(1)('green')), '#007758');
-});
diff --git a/test/difference.test.js b/test/difference.test.js
deleted file mode 100644
index e0bbe123..00000000
--- a/test/difference.test.js
+++ /dev/null
@@ -1,179 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	differenceEuclidean,
-	differenceCie76,
-	differenceCie94,
-	differenceCiede2000,
-	differenceCmc,
-	differenceHyab,
-	differenceKotsarenkoRamos,
-	differenceItp,
-	rgb,
-	lab65,
-	round,
-	hsl
-} from '../src/index.js';
-
-test('euclidean distance in RGB', t => {
-	let delta = differenceEuclidean();
-
-	assert.equal(
-		delta(
-			rgb({ r: 1, g: 0, b: 0, alpha: 0.5 }),
-			rgb({ r: 0, g: 1, b: 0, alpha: 0.75 })
-		),
-		1.4142135623730951
-	);
-
-	assert.equal(delta('red', 'red'), 0);
-});
-
-test('euclidean distance in HSL', t => {
-	let delta = differenceEuclidean('hsl');
-
-	assert.equal(
-		delta(hsl({ h: 0, s: 1, l: 1 }), hsl({ h: 180, s: 1, l: 1 })),
-		2
-	);
-
-	assert.equal(
-		delta(hsl({ h: 0, s: 1, l: 1 }), hsl({ h: 360, s: 1, l: 1 })),
-		2.4492935982947064e-16
-	);
-
-	assert.equal(
-		delta(hsl({ h: 60, s: 1, l: 1 }), hsl({ h: -540, s: 1, l: 1 })),
-		1.732050807568877
-	);
-});
-
-test('cie76 difference', t => {
-	assert.equal(
-		differenceCie76()(
-			lab65({ l: 1, a: 0, b: 0, alpha: 0.5 }),
-			lab65({ l: 0, a: 1, b: 0, alpha: 0.75 })
-		),
-		1.4142135623730951
-	);
-});
-
-test('cie94 difference', t => {
-	assert.equal(
-		differenceCie94()(
-			lab65({ l: 1, a: 0, b: 0, alpha: 0.5 }),
-			lab65({ l: 0, a: 1, b: 0, alpha: 0.75 })
-		),
-		1.4142135623730951
-	);
-});
-
-test('ciede2000 difference', t => {
-	let approx = round(4);
-
-	// Test data from: http://www2.ece.rochester.edu/~gsharma/ciede2000/
-	let testdata = `50.0000	2.6772	-79.7751	50.0000	0.0000	-82.7485	2.0425
-		50.0000	3.1571	-77.2803	50.0000	0.0000	-82.7485	2.8615
-		50.0000	2.8361	-74.0200	50.0000	0.0000	-82.7485	3.4412
-		50.0000	-1.3802	-84.2814	50.0000	0.0000	-82.7485	1.0000
-		50.0000	-1.1848	-84.8006	50.0000	0.0000	-82.7485	1.0000
-		50.0000	-0.9009	-85.5211	50.0000	0.0000	-82.7485	1.0000
-		50.0000	0.0000	0.0000	50.0000	-1.0000	2.0000	2.3669
-		50.0000	-1.0000	2.0000	50.0000	0.0000	0.0000	2.3669
-		50.0000	2.4900	-0.0010	50.0000	-2.4900	0.0009	7.1792
-		50.0000	2.4900	-0.0010	50.0000	-2.4900	0.0010	7.1792
-		50.0000	2.4900	-0.0010	50.0000	-2.4900	0.0011	7.2195
-		50.0000	2.4900	-0.0010	50.0000	-2.4900	0.0012	7.2195
-		50.0000	-0.0010	2.4900	50.0000	0.0009	-2.4900	4.8045
-		50.0000	-0.0010	2.4900	50.0000	0.0010	-2.4900	4.8045
-		50.0000	-0.0010	2.4900	50.0000	0.0011	-2.4900	4.7461
-		50.0000	2.5000	0.0000	50.0000	0.0000	-2.5000	4.3065
-		50.0000	2.5000	0.0000	73.0000	25.0000	-18.0000	27.1492
-		50.0000	2.5000	0.0000	61.0000	-5.0000	29.0000	22.8977
-		50.0000	2.5000	0.0000	56.0000	-27.0000	-3.0000	31.9030
-		50.0000	2.5000	0.0000	58.0000	24.0000	15.0000	19.4535
-		50.0000	2.5000	0.0000	50.0000	3.1736	0.5854	1.0000
-		50.0000	2.5000	0.0000	50.0000	3.2972	0.0000	1.0000
-		50.0000	2.5000	0.0000	50.0000	1.8634	0.5757	1.0000
-		50.0000	2.5000	0.0000	50.0000	3.2592	0.3350	1.0000
-		60.2574	-34.0099	36.2677	60.4626	-34.1751	39.4387	1.2644
-		63.0109	-31.0961	-5.8663	62.8187	-29.7946	-4.0864	1.2630
-		61.2901	3.7196	-5.3901	61.4292	2.2480	-4.9620	1.8731
-		35.0831	-44.1164	3.7933	35.0232	-40.0716	1.5901	1.8645
-		22.7233	20.0904	-46.6940	23.0331	14.9730	-42.5619	2.0373
-		36.4612	47.8580	18.3852	36.2715	50.5065	21.2231	1.4146
-		90.8027	-2.0831	1.4410	91.1528	-1.6435	0.0447	1.4441
-		90.9257	-0.5406	-0.9208	88.6381	-0.8985	-0.7239	1.5381
-		6.7747	-0.2908	-2.4247	5.8714	-0.0985	-2.2286	0.6377
-		2.0776	0.0795	-1.1350	0.9033	-0.0636	-0.5514	0.9082`
-		.split('\n')
-		.map(line => line.trim().split(/\s+/));
-
-	for (var i = 0; i < testdata.length; i++) {
-		let line = testdata[i];
-		assert.equal(
-			approx(
-				differenceCiede2000()(
-					lab65({ l: +line[0], a: +line[1], b: +line[2] }),
-					lab65({ l: +line[3], a: +line[4], b: +line[5] })
-				)
-			),
-			+line[6]
-		);
-
-		// also test for symmetry
-		assert.equal(
-			approx(
-				differenceCiede2000()(
-					lab65({ l: +line[3], a: +line[4], b: +line[5] }),
-					lab65({ l: +line[0], a: +line[1], b: +line[2] })
-				)
-			),
-			+line[6]
-		);
-	}
-});
-
-test('differenceCmc', t => {
-	assert.equal(
-		differenceCmc()(
-			lab65({ l: 1, a: 0, b: 0, alpha: 0.5 }),
-			lab65({ l: 0, a: 1, b: 0, alpha: 0.75 })
-		),
-		2.507265255284643
-	);
-
-	assert.equal(
-		differenceCmc()('rgb(55, 60, 48)', 'rgb(55, 65, 53)'),
-		3.590406912120119
-	);
-
-	assert.equal(
-		differenceCmc(2, 1)('rgb(55, 60, 48)', 'rgb(55, 65, 53)'),
-		2.82061249589761
-	);
-
-	assert.equal(
-		differenceCmc()('lab(50% 40 20)', 'lab(60% 20 100)'),
-		53.10947821085943
-	);
-});
-
-test('differenceKotsarenkoRamos', t => {
-	assert.equal(
-		differenceKotsarenkoRamos()('white', 'black'),
-		0.7108445752103619
-	);
-});
-
-test('difference in LCh space', t => {
-	assert.equal(differenceEuclidean('lch')('red', 'green'), 130.3598834181675);
-});
-
-test('differenceHyab', t => {
-	assert.equal(differenceHyab()('red', 'green'), 139.92805737622862);
-});
-
-test('differenceItp', t => {
-	assert.equal(differenceItp()('red', 'green'), 238.28868759957626);
-});
diff --git a/test/dlab.test.js b/test/dlab.test.js
deleted file mode 100644
index a838dbb7..00000000
--- a/test/dlab.test.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { dlab, rgb, formatCss } from '../src/index.js';
-
-test('dlab', t => {
-	assert.deepEqual(
-		dlab('white'),
-		{ mode: 'dlab', l: 100, a: 0, b: 0 },
-		'white'
-	);
-
-	// Tests that achromatic RGB colors get a = b = 0
-	assert.deepEqual(
-		dlab('#111'),
-		{ mode: 'dlab', l: 5.938147621379976, a: 0, b: 0 },
-		'#111'
-	);
-
-	assert.deepEqual(
-		dlab('black'),
-		{ mode: 'dlab', l: 0, a: 0, b: 0 },
-		'black'
-	);
-	assert.deepEqual(
-		dlab('red'),
-		{
-			mode: 'dlab',
-			l: 57.28917941426675,
-			a: 39.49797800074304,
-			b: 30.518440059252875
-		},
-		'red'
-	);
-});
-
-test('color(--din99o-lab)', t => {
-	assert.deepEqual(dlab('color(--din99o-lab 30 0.5 1 / 0.25)'), {
-		l: 30,
-		a: 0.5,
-		b: 1,
-		alpha: 0.25,
-		mode: 'dlab'
-	});
-	assert.deepEqual(dlab('color(--din99o-lab 0 50% 0.5 / 25%)'), {
-		l: 0,
-		a: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'dlab'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--din99o-lab 0 50% 0.5 / 25%)'),
-		'color(--din99o-lab 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--din99o-lab none 0.5 none)'), 'dlab to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--din99o-lab none 0.5 none)'),
-		rgb('color(--din99o-lab 0 0.5 0)')
-	);
-	assert.ok(dlab('rgb(none 100 20)'), 'rgb to dlab is ok');
-	assert.deepEqual(dlab('rgb(none 100 20)'), dlab('rgb(0 100 20)'));
-});
diff --git a/test/dlch.test.js b/test/dlch.test.js
deleted file mode 100644
index 48f92190..00000000
--- a/test/dlch.test.js
+++ /dev/null
@@ -1,57 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { dlch, rgb, formatCss } from '../src/index.js';
-
-test('dlch', t => {
-	assert.deepEqual(dlch('white'), { mode: 'dlch', l: 100, c: 0 }, 'white');
-	assert.deepEqual(
-		dlch('#111'),
-		{ mode: 'dlch', l: 5.938147621379976, c: 0 },
-		'#111'
-	);
-	assert.deepEqual(dlch('black'), { mode: 'dlch', l: 0, c: 0 }, 'black');
-	assert.deepEqual(
-		dlch('red'),
-		{
-			mode: 'dlch',
-			l: 57.28917941426675,
-			c: 49.914581534832,
-			h: 37.691765574369924
-		},
-		'red'
-	);
-});
-
-test('color(--din99o-lch)', t => {
-	assert.deepEqual(dlch('color(--din99o-lch 30 0.5 1 / 0.25)'), {
-		l: 30,
-		c: 0.5,
-		h: 1,
-		alpha: 0.25,
-		mode: 'dlch'
-	});
-	assert.deepEqual(dlch('color(--din99o-lch 0 50% 0.5 / 25%)'), {
-		l: 0,
-		c: 0.5,
-		h: 0.5,
-		alpha: 0.25,
-		mode: 'dlch'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--din99o-lch 0 50% 0.5 / 25%)'),
-		'color(--din99o-lch 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--din99o-lch none 0.5 none)'), 'dlch to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--din99o-lch none 0.5 none)'),
-		rgb('color(--din99o-lch 0% 0.5 0)')
-	);
-	assert.ok(dlch('rgb(none 100 20)'), 'rgb to dlch is ok');
-	assert.deepEqual(dlch('rgb(none 100 20)'), dlch('rgb(0 100 20)'));
-});
diff --git a/test/easing.test.js b/test/easing.test.js
deleted file mode 100644
index 9b62127a..00000000
--- a/test/easing.test.js
+++ /dev/null
@@ -1,45 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-
-import midpoint from '../src/easing/midpoint.js';
-import {
-	easingSmoothstep,
-	easingSmoothstepInverse
-} from '../src/easing/smoothstep.js';
-import smootherstep from '../src/easing/smootherstep.js';
-import samples from '../src/samples.js';
-
-test('easingMidpoint', t => {
-	let noop = midpoint(0.5);
-	let curve = midpoint(0.2);
-
-	assert.equal(noop(0.1), 0.1);
-	assert.equal(noop(0.4), 0.4);
-	assert.equal(noop(0.5), 0.5);
-	assert.equal(noop(0.7), 0.7);
-	assert.equal(noop(1), 1);
-
-	assert.equal(curve(0), 0);
-	assert.equal(curve(1), 1);
-});
-
-test('easingSmoothstep', t => {
-	assert.equal(easingSmoothstep(0), 0);
-	assert.equal(easingSmoothstep(1), 1);
-	assert.equal(easingSmoothstep(0.5), 0.5);
-});
-
-test('easingSmoothstepInverse', t => {
-	samples(5).forEach(x => {
-		assert.ok(
-			Math.abs(easingSmoothstepInverse(easingSmoothstep(x)) - x) < 1e-15,
-			`roundtrip: ${x}`
-		);
-	});
-});
-
-test('easingSmootherstep', t => {
-	assert.equal(smootherstep(0), 0);
-	assert.equal(smootherstep(1), 1);
-	assert.equal(smootherstep(0.5), 0.5);
-});
diff --git a/test/filter.test.js b/test/filter.test.js
deleted file mode 100644
index a2fe8c3b..00000000
--- a/test/filter.test.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	filterBrightness,
-	filterContrast,
-	filterSepia,
-	formatHex,
-	filterSaturate,
-	filterGrayscale,
-	filterInvert,
-	filterHueRotate
-} from '../src/index.js';
-
-test('filterBrightness', t => {
-	assert.deepEqual(
-		filterBrightness(1)('hsl(60 100% 50% / 25%)'),
-		{ mode: 'hsl', h: 60, s: 1, l: 0.5, alpha: 0.25 },
-		'unchanged in the original color space'
-	);
-	assert.equal(
-		formatHex(filterBrightness(2)('#003366')),
-		'#0066cc',
-		'brightens the color'
-	);
-});
-
-test('filterContrast', t => {
-	assert.equal(
-		formatHex(filterContrast(2)('#003366')),
-		'#00004d',
-		'Increases the contrast'
-	);
-});
-
-test('filterSepia', t => {
-	assert.equal(formatHex(filterSepia(0)('red')), '#ff0000', 'unchanged');
-	assert.equal(formatHex(filterSepia(1)('red')), '#645945', 'fully sepia');
-});
-
-test('filterSaturate', t => {
-	assert.equal(
-		formatHex(filterSaturate(0)('#cc0033')),
-		'#2f2f2f',
-		'fully desaturated'
-	);
-	assert.equal(
-		formatHex(filterSaturate(1)('#cc0033')),
-		'#cc0033',
-		'unchanged'
-	);
-	assert.equal(
-		formatHex(filterSaturate(2)('#cc0033')),
-		'#ff0037',
-		'oversaturated'
-	);
-});
-
-test('filterGrayscale', t => {
-	assert.equal(formatHex(filterGrayscale(0)('red')), '#ff0000', 'unchanged');
-	assert.equal(
-		formatHex(filterGrayscale(1)('red')),
-		'#363636',
-		'fully grayscale'
-	);
-});
-
-test('filterInvert', t => {
-	assert.equal(formatHex(filterInvert(0)('red')), '#ff0000', 'unchanged');
-	assert.equal(formatHex(filterInvert(0.5)('red')), '#808080', 'gray');
-	assert.equal(
-		formatHex(filterInvert(1)('red')),
-		'#00ffff',
-		'fully inverted'
-	);
-});
-
-test('filterHueRotate', t => {
-	assert.equal(formatHex(filterHueRotate(60)('red')), '#6c3b00');
-});
diff --git a/test/fixupAlpha.test.js b/test/fixupAlpha.test.js
deleted file mode 100644
index e271acde..00000000
--- a/test/fixupAlpha.test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { fixupAlpha } from '../src/index.js';
-
-test('fixupAlpha: some defined', t => {
-	assert.deepEqual(fixupAlpha([undefined, 0, undefined]), [1, 0, 1]);
-});
-
-test('fixupAlpha: all undefined', t => {
-	assert.deepEqual(fixupAlpha([undefined, undefined, undefined]), [
-		undefined,
-		undefined,
-		undefined
-	]);
-});
diff --git a/test/fixupHue.test.js b/test/fixupHue.test.js
deleted file mode 100644
index ea8fa770..00000000
--- a/test/fixupHue.test.js
+++ /dev/null
@@ -1,39 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	fixupHueShorter,
-	fixupHueLonger,
-	fixupHueIncreasing,
-	fixupHueDecreasing
-} from '../src/index.js';
-
-test('fixupHueShorter', t => {
-	assert.deepEqual(
-		fixupHueShorter([0, 340, 30, 0, 170]),
-		[0, -20, 30, 0, 170]
-	);
-	assert.deepEqual(fixupHueShorter([-250, -8]), [110, -8]);
-});
-
-test('fixupHueLonger', t => {
-	assert.deepEqual(
-		fixupHueLonger([0, 340, 30, 0, 170]),
-		[0, 340, 30, 360, 170]
-	);
-
-	assert.deepEqual(
-		fixupHueLonger([0, 179, 179, 360]),
-		[0, -181, -181, 0],
-		'equal consecutive values'
-	);
-});
-
-test('fixupHueIncreasing', t => {
-	let hues = [0, 340, 30, 0, 170];
-	assert.deepEqual(fixupHueIncreasing(hues), [0, 340, 390, 720, 890]);
-});
-
-test('fixupHueDecreasing', t => {
-	let hues = [0, 340, 30, 0, 170];
-	assert.deepEqual(fixupHueDecreasing(hues), [0, -20, -330, -360, -550]);
-});
diff --git a/test/formatter.test.js b/test/formatter.test.js
deleted file mode 100644
index d73de19f..00000000
--- a/test/formatter.test.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	formatHex,
-	formatHex8,
-	formatRgb,
-	formatHsl,
-	rgb
-} from '../src/index.js';
-
-test('formatHex', t => {
-	assert.equal(formatHex('tomato'), '#ff6347');
-});
-
-test('formatHex8', t => {
-	assert.equal(
-		formatHex8({ mode: 'rgb', r: 1, g: 1, b: 1, alpha: 0 }),
-		'#ffffff00'
-	);
-});
-
-test('formatRgb', t => {
-	assert.equal(formatRgb(rgb('#f0f0f0f0')), 'rgba(240, 240, 240, 0.94)');
-	assert.equal(formatRgb('#f0f0f0f0'), 'rgba(240, 240, 240, 0.94)');
-});
-
-test('formatHsl', t => {
-	assert.equal(formatHsl('red'), 'hsl(0, 100%, 50%)');
-	assert.equal(
-		formatHsl({
-			mode: 'hsl',
-			h: 30.21,
-			s: 0.2361,
-			l: 0.48321,
-			alpha: -0.2
-		}),
-		'hsla(30.21, 23.61%, 48.32%, 0)'
-	);
-	assert.equal(
-		formatHsl({ mode: 'hsl', h: 405, s: 1.2, l: -1 }),
-		'hsl(405, 100%, 0%)'
-	);
-});
diff --git a/test/hsi.test.js b/test/hsi.test.js
deleted file mode 100644
index 8f3daa2f..00000000
--- a/test/hsi.test.js
+++ /dev/null
@@ -1,125 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { hsi, rgb, formatCss } from '../src/index.js';
-
-test('rgb() converts from HSI to RGB', t => {
-	assert.deepEqual(
-		rgb(hsi({ h: 0, s: 0, i: 0 })),
-		{ r: 0, g: 0, b: 0, mode: 'rgb' },
-		'lightness 0 should yield black'
-	);
-
-	assert.deepEqual(
-		rgb(hsi({ h: 60, s: 0.25, i: 0 })),
-		{ r: 0, g: 0, b: 0, mode: 'rgb' },
-		'...regardless of hue and saturation'
-	);
-
-	assert.deepEqual(
-		rgb(hsi({ h: 0, s: 0, i: 0.5 })),
-		{ r: 0.5, g: 0.5, b: 0.5, mode: 'rgb' },
-		'saturation 0 should yield gray'
-	);
-
-	assert.deepEqual(
-		rgb(hsi({ h: 60, s: 0, i: 0.25 })),
-		{ r: 0.25, g: 0.25, b: 0.25, mode: 'rgb' },
-		'...regardless of the hue'
-	);
-
-	assert.deepEqual(
-		rgb(hsi({ h: 100, s: 0, i: 0.5 })),
-		{ r: 0.5, g: 0.5, b: 0.5, mode: 'rgb' },
-		'...or the lightness'
-	);
-});
-
-test('hsi() converts RGB to HSI', t => {
-	assert.deepEqual(
-		hsi(rgb({ r: 0, g: 0, b: 0 })),
-		{ s: 0, i: 0, mode: 'hsi' },
-		'black'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 0.25, g: 0.25, b: 0.25 })),
-		{ s: 0, i: 0.25, mode: 'hsi' },
-		'R = G = B yields undefined hue'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 0.6, g: 0.6, b: 0.6 })),
-		{ s: 0, i: 0.6, mode: 'hsi' },
-		'R = G = B yields zero saturation'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 1, g: 0, b: 0 })),
-		{ h: 0, s: 1, i: 0.3333333333333333, mode: 'hsi' },
-		'red'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 1, g: 1, b: 0 })),
-		{ h: 60, s: 1, i: 0.6666666666666666, mode: 'hsi' },
-		'yellow'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 0, g: 1, b: 0 })),
-		{ h: 120, s: 1, i: 0.3333333333333333, mode: 'hsi' },
-		'green'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 0, g: 1, b: 1 })),
-		{ h: 180, s: 1, i: 0.6666666666666666, mode: 'hsi' },
-		'cyan'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 0, g: 0, b: 1 })),
-		{ h: 240, s: 1, i: 0.3333333333333333, mode: 'hsi' },
-		'blue'
-	);
-
-	assert.deepEqual(
-		hsi(rgb({ r: 1, g: 0, b: 1 })),
-		{ h: 300, s: 1, i: 0.6666666666666666, mode: 'hsi' },
-		'magenta'
-	);
-});
-
-test('color(--hsi)', t => {
-	assert.deepEqual(hsi('color(--hsi 30 0.5 1 / 0.25)'), {
-		h: 30,
-		s: 0.5,
-		i: 1,
-		alpha: 0.25,
-		mode: 'hsi'
-	});
-	assert.deepEqual(hsi('color(--hsi 0 50% 0.5 / 25%)'), {
-		h: 0,
-		s: 0.5,
-		i: 0.5,
-		alpha: 0.25,
-		mode: 'hsi'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--hsi 0 50% 0.5 / 25%)'),
-		'color(--hsi 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--hsi none 0.5 none)'), 'hsi to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--hsi none 0.5 none)'),
-		rgb('color(--hsi 0 0.5 0')
-	);
-	assert.ok(hsi('rgb(none 100 20)'), 'rgb to hsi is ok');
-	assert.deepEqual(hsi('rgb(none 100 20)'), hsi('rgb(0 100 20)'));
-});
diff --git a/test/hsl.test.js b/test/hsl.test.js
deleted file mode 100644
index 3483bdcb..00000000
--- a/test/hsl.test.js
+++ /dev/null
@@ -1,153 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { hsl, rgb, formatCss } from '../src/index.js';
-
-test('rgb() converts from HSL to RGB', t => {
-	assert.deepEqual(
-		rgb(hsl({ h: 0, s: 0, l: 0 })),
-		{ r: 0, g: 0, b: 0, mode: 'rgb' },
-		'lightness 0 should yield black'
-	);
-
-	assert.deepEqual(
-		rgb(hsl({ h: 60, s: 0.25, l: 0 })),
-		{ r: 0, g: 0, b: 0, mode: 'rgb' },
-		'...regardless of hue and saturation'
-	);
-
-	assert.deepEqual(
-		rgb(hsl({ h: 0, s: 0, l: 0.5 })),
-		{ r: 0.5, g: 0.5, b: 0.5, mode: 'rgb' },
-		'saturation 0 should yield gray'
-	);
-
-	assert.deepEqual(
-		rgb(hsl({ h: 60, s: 0, l: 0.25 })),
-		{ r: 0.25, g: 0.25, b: 0.25, mode: 'rgb' },
-		'...regardless of the hue'
-	);
-
-	assert.deepEqual(
-		rgb(hsl({ h: 100, s: 0, l: 0.5 })),
-		{ r: 0.5, g: 0.5, b: 0.5, mode: 'rgb' },
-		'...or the lightness'
-	);
-});
-
-test('hsl() converts RGB to HSL', t => {
-	assert.deepEqual(
-		hsl(rgb({ r: 0, g: 0, b: 0 })),
-		{ s: 0, l: 0, mode: 'hsl' },
-		'black'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 0.25, g: 0.25, b: 0.25 })),
-		{ s: 0, l: 0.25, mode: 'hsl' },
-		'R = G = B yields undefined hue'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 0.6, g: 0.6, b: 0.6 })),
-		{ s: 0, l: 0.6, mode: 'hsl' },
-		'R = G = B yields zero saturation'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 1, g: 0, b: 0 })),
-		{ h: 0, s: 1, l: 0.5, mode: 'hsl' },
-		'red'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 1, g: 1, b: 0 })),
-		{ h: 60, s: 1, l: 0.5, mode: 'hsl' },
-		'yellow'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 0, g: 1, b: 0 })),
-		{ h: 120, s: 1, l: 0.5, mode: 'hsl' },
-		'green'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 0, g: 1, b: 1 })),
-		{ h: 180, s: 1, l: 0.5, mode: 'hsl' },
-		'cyan'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 0, g: 0, b: 1 })),
-		{ h: 240, s: 1, l: 0.5, mode: 'hsl' },
-		'blue'
-	);
-
-	assert.deepEqual(
-		hsl(rgb({ r: 1, g: 0, b: 1 })),
-		{ h: 300, s: 1, l: 0.5, mode: 'hsl' },
-		'magenta'
-	);
-});
-
-test('hsl() parses hsl / hsla CSS strings', t => {
-	assert.deepEqual(
-		hsl('hsl(0, 100%, 0%)'),
-		{ s: 1, l: 0, h: 0, mode: 'hsl' },
-		'black'
-	);
-
-	assert.deepEqual(
-		hsl('hsl(100, 0%, 50%)'),
-		{ s: 0, l: 0.5, h: 100, mode: 'hsl' },
-		'grey'
-	);
-
-	assert.deepEqual(
-		hsl('hsl(0, 100%, 50%)'),
-		{ h: 0, s: 1, l: 0.5, mode: 'hsl' },
-		'red'
-	);
-
-	assert.deepEqual(
-		hsl('hsla(219, 34%, 46%, 1)'),
-		{ mode: 'hsl', h: 219, s: 0.34, l: 0.46, alpha: 1 },
-		'alpha [0-1]'
-	);
-
-	assert.deepEqual(
-		hsl('hsla(219, 34%, 46%, 25%)'),
-		{ mode: 'hsl', h: 219, s: 0.34, l: 0.46, alpha: 0.25 },
-		'alpha percentage'
-	);
-});
-
-test('CSS <number> in `hsl()` syntax', test => {
-	assert.deepEqual(
-		hsl('hsl(3e1, 1e2%, 0.5e2%)'),
-		{ mode: 'hsl', h: 30, s: 1, l: 0.5 },
-		'exponential notation'
-	);
-	assert.deepEqual(
-		hsl('hsl(30.5, 90.6%, 48.3%)'),
-		{ mode: 'hsl', h: 30.5, s: 0.9059999999999999, l: 0.483 },
-		'float values'
-	);
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('hsl(.5turn 40% 20% / 50%)'),
-		'hsl(180 40% 20% / 0.5)'
-	);
-	assert.equal(formatCss('hsl(.5turn 40% 20%)'), 'hsl(180 40% 20%)');
-	assert.equal(formatCss('hsl(.5turn 40% 20% / 100%)'), 'hsl(180 40% 20%)');
-	assert.equal(formatCss(hsl('#ffffff00')), 'hsl(none 0% 100% / 0)');
-});
-
-test('missing components', t => {
-	assert.ok(rgb('hsl(none 50% none)'));
-	assert.deepEqual(rgb('hsl(none 50% none)'), rgb('hsl(0deg 50% 0%)'));
-	assert.ok(hsl('rgb(none 100 20)'));
-	assert.deepEqual(hsl('rgb(none 100 20)'), hsl('rgb(0 100 20)'));
-});
diff --git a/test/hsv.test.js b/test/hsv.test.js
deleted file mode 100644
index ecdc8d16..00000000
--- a/test/hsv.test.js
+++ /dev/null
@@ -1,129 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { hsv, rgb, formatCss } from '../src/index.js';
-
-test('rgb() converts from HSV to RGB', t => {
-	assert.deepEqual(
-		rgb(hsv({ h: 0, s: 0, v: 0 })),
-		{ r: 0, g: 0, b: 0, mode: 'rgb' },
-		'lightness 0 should yield black'
-	);
-
-	assert.deepEqual(
-		rgb(hsv({ h: 60, s: 0.25, v: 0 })),
-		{ r: 0, g: 0, b: 0, mode: 'rgb' },
-		'...regardless of hue and saturation'
-	);
-
-	assert.deepEqual(
-		rgb(hsv({ h: 0, s: 0, v: 0.5 })),
-		{ r: 0.5, g: 0.5, b: 0.5, mode: 'rgb' },
-		'saturation 0 should yield gray'
-	);
-
-	assert.deepEqual(
-		rgb(hsv({ h: 60, s: 0, v: 0.25 })),
-		{ r: 0.25, g: 0.25, b: 0.25, mode: 'rgb' },
-		'...regardless of the hue'
-	);
-
-	assert.deepEqual(
-		rgb(hsv({ h: 100, s: 0, v: 0.5 })),
-		{ r: 0.5, g: 0.5, b: 0.5, mode: 'rgb' },
-		'...or the lightness'
-	);
-});
-
-test('hsv() converts RGB to HSV', t => {
-	assert.deepEqual(
-		hsv(rgb({ r: 0, g: 0, b: 0 })),
-		{ s: 0, v: 0, mode: 'hsv' },
-		'black'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 0.25, g: 0.25, b: 0.25 })),
-		{ s: 0, v: 0.25, mode: 'hsv' },
-		'R = G = B yields undefined hue'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 0.6, g: 0.6, b: 0.6 })),
-		{ s: 0, v: 0.6, mode: 'hsv' },
-		'R = G = B yields zero saturation'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 1, g: 0, b: 0 })),
-		{ h: 0, s: 1, v: 1, mode: 'hsv' },
-		'red'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 1, g: 1, b: 0 })),
-		{ h: 60, s: 1, v: 1, mode: 'hsv' },
-		'yellow'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 0, g: 1, b: 0 })),
-		{ h: 120, s: 1, v: 1, mode: 'hsv' },
-		'green'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 0, g: 1, b: 1 })),
-		{ h: 180, s: 1, v: 1, mode: 'hsv' },
-		'cyan'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 0, g: 0, b: 1 })),
-		{ h: 240, s: 1, v: 1, mode: 'hsv' },
-		'blue'
-	);
-
-	assert.deepEqual(
-		hsv(rgb({ r: 1, g: 0, b: 1 })),
-		{ h: 300, s: 1, v: 1, mode: 'hsv' },
-		'magenta'
-	);
-});
-
-test('hsv(str)', t => {
-	assert.deepEqual(hsv('white'), { mode: 'hsv', s: 0, v: 1 });
-});
-
-test('color(--hsv)', t => {
-	assert.deepEqual(hsv('color(--hsv 30 0.5 1 / 0.25)'), {
-		h: 30,
-		s: 0.5,
-		v: 1,
-		alpha: 0.25,
-		mode: 'hsv'
-	});
-	assert.deepEqual(hsv('color(--hsv 0 50% 0.5 / 25%)'), {
-		h: 0,
-		s: 0.5,
-		v: 0.5,
-		alpha: 0.25,
-		mode: 'hsv'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--hsv 0 50% 0.5 / 25%)'),
-		'color(--hsv 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--hsv none 0.5 none)'), 'hsv to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--hsv none 0.5 none)'),
-		rgb('color(--hsv 0 0.5 0')
-	);
-	assert.ok(hsv('rgb(none 100 20)'), 'rgb to hsv is ok');
-	assert.deepEqual(hsv('rgb(none 100 20)'), hsv('rgb(0 100 20)'));
-});
diff --git a/test/hwb.test.js b/test/hwb.test.js
deleted file mode 100644
index d08875cb..00000000
--- a/test/hwb.test.js
+++ /dev/null
@@ -1,54 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { hwb, rgb, formatCss } from '../src/index.js';
-
-test('hwb() parses hwb CSS strings', t => {
-	assert.deepEqual(
-		hwb('hwb(100 0% 0%)'),
-		{ h: 100, w: 0, b: 0, mode: 'hwb' },
-		'black'
-	);
-
-	assert.deepEqual(
-		hwb('hwb(200 150% 150%)'),
-		{ h: 200, w: 1.5, b: 1.5, mode: 'hwb' },
-		'grey'
-	);
-
-	assert.deepEqual(
-		hwb('hwb(200 150% 50% / 50%)'),
-		{ h: 200, w: 1.5, b: 0.5, mode: 'hwb', alpha: 0.5 },
-		'grey (alpha [0-1])'
-	);
-
-	assert.deepEqual(
-		hwb('hwb(200 150% 50% / .5)'),
-		{ h: 200, w: 1.5, b: 0.5, mode: 'hwb', alpha: 0.5 },
-		'grey (alpha percentage)'
-	);
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('hwb(200 150% 50% / .5)'),
-		'hwb(200 150% 50% / 0.5)'
-	);
-	assert.equal(formatCss('hwb(200 150% 50% / 100%)'), 'hwb(200 150% 50%)');
-	assert.equal(formatCss('hwb(200 150% 50%)'), 'hwb(200 150% 50%)');
-	assert.equal(formatCss(hwb('#ffffff00')), 'hwb(none 100% 0% / 0)');
-});
-
-test('missing components', t => {
-	assert.ok(rgb('hwb(none 50% none)'));
-	assert.deepEqual(rgb('hwb(none 50% none)'), rgb('hwb(0deg 50% 0%'));
-	assert.ok(hwb('rgb(none 100 20)'));
-	assert.deepEqual(hwb('rgb(none 100 20)'), hwb('rgb(0 100 20)'));
-});
-
-test('powerless components', t => {
-	assert.deepEqual(hwb(rgb('hwb(60deg 75% 50%)')), {
-		mode: 'hwb',
-		w: 0.6,
-		b: 0.4
-	});
-});
diff --git a/test/interpolate.test.js b/test/interpolate.test.js
deleted file mode 100644
index 8a3c3178..00000000
--- a/test/interpolate.test.js
+++ /dev/null
@@ -1,244 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	interpolate,
-	interpolateWith,
-	interpolateWithPremultipliedAlpha,
-	formatHex,
-	formatHex8,
-	rgb,
-	samples
-} from '../src/index.js';
-
-test('interpolate between black and white in RGB', t => {
-	let grays = interpolate(['#fff', '#000']);
-	assert.equal(formatHex(grays(0.0)), '#ffffff');
-	assert.equal(formatHex(grays(0.1)), '#e6e6e6');
-	assert.equal(formatHex(grays(0.2)), '#cccccc');
-	assert.equal(formatHex(grays(0.3)), '#b3b3b3');
-	assert.equal(formatHex(grays(0.4)), '#999999');
-	assert.equal(formatHex(grays(0.5)), '#808080');
-	assert.equal(formatHex(grays(0.6)), '#666666');
-	assert.equal(formatHex(grays(0.7)), '#4d4d4d');
-	assert.equal(formatHex(grays(0.8)), '#333333');
-	assert.equal(formatHex(grays(0.9)), '#191919');
-	assert.equal(formatHex(grays(1.0)), '#000000');
-});
-
-test('interpolate between black and white in RGBA', t => {
-	let grays = interpolate(['#ffff', '#0000']);
-	assert.deepEqual(rgb(grays(0.0)), {
-		r: 1,
-		g: 1,
-		b: 1,
-		alpha: 1,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.1)), {
-		r: 0.9,
-		g: 0.9,
-		b: 0.9,
-		alpha: 0.9,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.2)), {
-		r: 0.8,
-		g: 0.8,
-		b: 0.8,
-		alpha: 0.8,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.3)), {
-		r: 0.7,
-		g: 0.7,
-		b: 0.7,
-		alpha: 0.7,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.4)), {
-		r: 0.6,
-		g: 0.6,
-		b: 0.6,
-		alpha: 0.6,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.5)), {
-		r: 0.5,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.5,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.6)), {
-		r: 0.4,
-		g: 0.4,
-		b: 0.4,
-		alpha: 0.4,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.7)), {
-		r: 0.30000000000000004,
-		g: 0.30000000000000004,
-		b: 0.30000000000000004,
-		alpha: 0.30000000000000004,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.8)), {
-		r: 0.19999999999999996,
-		g: 0.19999999999999996,
-		b: 0.19999999999999996,
-		alpha: 0.19999999999999996,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.9)), {
-		r: 0.09999999999999998,
-		g: 0.09999999999999998,
-		b: 0.09999999999999998,
-		alpha: 0.09999999999999998,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(1.0)), {
-		r: 0,
-		g: 0,
-		b: 0,
-		alpha: 0,
-		mode: 'rgb'
-	});
-});
-
-test('interpolate between black and white in RGB/RGBA', t => {
-	let grays = interpolate(['#fff', '#0000']);
-	assert.deepEqual(rgb(grays(0.0)), {
-		r: 1,
-		g: 1,
-		b: 1,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.1)), {
-		r: 0.9,
-		g: 0.9,
-		b: 0.9,
-		alpha: 0.9,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.2)), {
-		r: 0.8,
-		g: 0.8,
-		b: 0.8,
-		alpha: 0.8,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.3)), {
-		r: 0.7,
-		g: 0.7,
-		b: 0.7,
-		alpha: 0.7,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.4)), {
-		r: 0.6,
-		g: 0.6,
-		b: 0.6,
-		alpha: 0.6,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.5)), {
-		r: 0.5,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.5,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.6)), {
-		r: 0.4,
-		g: 0.4,
-		b: 0.4,
-		alpha: 0.4,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.7)), {
-		r: 0.30000000000000004,
-		g: 0.30000000000000004,
-		b: 0.30000000000000004,
-		alpha: 0.30000000000000004,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.8)), {
-		r: 0.19999999999999996,
-		g: 0.19999999999999996,
-		b: 0.19999999999999996,
-		alpha: 0.19999999999999996,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(0.9)), {
-		r: 0.09999999999999998,
-		g: 0.09999999999999998,
-		b: 0.09999999999999998,
-		alpha: 0.09999999999999998,
-		mode: 'rgb'
-	});
-	assert.deepEqual(rgb(grays(1.0)), {
-		r: 0,
-		g: 0,
-		b: 0,
-		alpha: 0,
-		mode: 'rgb'
-	});
-});
-
-test('bug checking', t => {
-	assert.deepEqual(
-		samples(4)
-			.map(interpolate(['blue', 'white'], 'hsv'))
-			.map(formatHex),
-		['#0000ff', '#5555ff', '#aaaaff', '#ffffff']
-	);
-});
-
-test('color interpolation hints', t => {
-	[0, 0.1, 0.2, 0.5, 0.8, 1].forEach(t0 => {
-		assert.deepEqual(
-			interpolate(['red', 0.5, 'green'])(t0),
-			interpolate(['red', 'green'])(t0)
-		);
-	});
-
-	assert.deepEqual(interpolate(['red', 0.2, 'green'])(0.5), {
-		mode: 'rgb',
-		r: 0.25808621995139025,
-		g: 0.372411622926361,
-		b: 0
-	});
-});
-
-test('interpolateWith()', t => {
-	let colors = ['red', ['transparent', 0.33], 'blue'];
-	let it2 = interpolateWith(v => v / 2)(colors);
-
-	assert.equal(formatHex8(it2(0.25)), '#1f00001f', 'w premultiplication');
-	assert.equal(formatHex8(it2(0.75)), '#00005050', 'w premultiplication');
-});
-
-test('interpolateWithPremultipliedAlpha()', t => {
-	let colors = ['red', 'transparent', 'blue'];
-	let it = interpolate(colors);
-	let it2 = interpolateWithPremultipliedAlpha(colors);
-
-	assert.equal(formatHex8(it(0.25)), '#80000080', 'w/o premultiplication');
-	assert.equal(formatHex8(it(0.75)), '#00008080', 'w/o premultiplication');
-	assert.equal(formatHex8(it2(0.25)), '#ff000080', 'w premultiplication');
-	assert.equal(formatHex8(it2(0.75)), '#0000ff80', 'w premultiplication');
-});
-
-test('Easing fn returning outside [0,1], issue #140', t => {
-	// From: https://github.com/mattdesl/eases/blob/master/back-in-out.js
-	function backInOut(t) {
-		var s = 1.70158 * 1.525;
-		return (t *= 2) < 1
-			? 0.5 * (t * t * ((s + 1) * t - s))
-			: 0.5 * ((t -= 2) * t * ((s + 1) * t + s) + 2);
-	}
-	const it = interpolate([backInOut, '#ff0000', '#cc8833', '#3344cc']);
-	assert.equal(isNaN(it(0.05).r), false);
-	assert.equal(isNaN(it(0.95).r), false);
-});
diff --git a/test/interpolatorLinear.test.js b/test/interpolatorLinear.test.js
deleted file mode 100644
index 229ffd07..00000000
--- a/test/interpolatorLinear.test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { samples, interpolatorLinear } from '../src/index.js';
-
-test('interpolatorLinear', t => {
-	let data = [3, 2.8, 2.5, 1, 0.95, 0.8, 0.5, 0.1, 0.05];
-	assert.deepEqual(
-		samples(10).map(interpolatorLinear(data)),
-		[
-			3, 2.822222222222222, 2.5666666666666664, 1.5000000000000002,
-			0.9722222222222222, 0.8833333333333333, 0.7000000000000002,
-			0.4111111111111111, 0.09444444444444447, 0.05
-		]
-	);
-});
-
-test('outside [0, 1] range', t => {
-	let it = interpolatorLinear([3, 10, 1]);
-	assert.equal(it(-0.5), -4);
-	assert.equal(it(-1), -11);
-	assert.equal(it(1.5), -8);
-	assert.equal(it(2), -17);
-});
diff --git a/test/interpolatorSplineBasis.test.js b/test/interpolatorSplineBasis.test.js
deleted file mode 100644
index d47c8f5c..00000000
--- a/test/interpolatorSplineBasis.test.js
+++ /dev/null
@@ -1,50 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	samples,
-	interpolatorSplineBasis,
-	interpolatorSplineBasisClosed
-} from '../src/index.js';
-
-test('interpolatorSplineBasis', t => {
-	let data = [3, 2.8, 2.5, 1, 0.95, 0.8, 0.5, 0.1, 0.05];
-	assert.deepEqual(
-		samples(10).map(interpolatorSplineBasis(data)),
-		[
-			3, 2.810516689529035, 2.472382258802012, 1.5641975308641978,
-			0.9905807041609512, 0.8782807498856883, 0.6919753086419754,
-			0.4039094650205761, 0.13541380887059906, 0.05000000000000001
-		]
-	);
-});
-
-test('interpolatorSplineBasisClosed', t => {
-	let data = [3, 2.8, 2.5, 1, 0.95, 0.8, 0.5, 0.1, 0.05];
-	assert.deepEqual(
-		samples(10).map(interpolatorSplineBasisClosed(data)),
-		[
-			2.475, 2.8097965249199817, 2.472382258802012, 1.5641975308641978,
-			0.9905807041609512, 0.8782807498856883, 0.6919753086419754,
-			0.4039094650205761, 0.1360996799268405, 0.5499999999999999
-		]
-	);
-});
-
-test('interpolatorSplineBasis: outside [0, 1] range', t => {
-	let it = interpolatorSplineBasis([3, 10, 1]);
-	assert.deepEqual(
-		[-0.5, 1, 1.5, 2].map(it),
-		[-1.3333333333333333, 1, -5.333333333333333, 4.333333333333333]
-	);
-});
-
-test('interpolatorSplineBasisClosed: outside [0, 1] range', t => {
-	let it = interpolatorSplineBasisClosed([3, 10, 1]);
-	assert.deepEqual(
-		[-0.5, 1, 1.5, 2].map(it),
-		[
-			2.8333333333333335, 2.8333333333333335, 3.8333333333333335,
-			7.333333333333333
-		]
-	);
-});
diff --git a/test/interpolatorSplineMonotone.test.js b/test/interpolatorSplineMonotone.test.js
deleted file mode 100644
index eadc83fb..00000000
--- a/test/interpolatorSplineMonotone.test.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	samples,
-	interpolatorSplineMonotone,
-	interpolatorSplineMonotone2,
-	interpolatorSplineMonotoneClosed
-} from '../src/index.js';
-
-test('interpolatorSplineMonotone', t => {
-	let data = [3, 2.8, 2.5, 1, 0.95, 0.8, 0.5, 0.1, 0.05];
-	assert.deepEqual(
-		samples(10).map(interpolatorSplineMonotone(data)),
-		[
-			3, 2.826611796982167, 2.6089163237311386, 1.3592592592592596,
-			0.973593964334705, 0.8984224965706447, 0.7148148148148149,
-			0.40631001371742104, 0.09005486968449936, 0.049999999999999975
-		]
-	);
-});
-
-test('interpolatorSplineMonotone2', t => {
-	let data = [3, 2.8, 2.5, 1, 0.95, 0.8, 0.5, 0.1, 0.05];
-	assert.deepEqual(
-		samples(10).map(interpolatorSplineMonotone2(data)),
-		[
-			3, 2.82716049382716, 2.6089163237311386, 1.3592592592592596,
-			0.973593964334705, 0.8984224965706447, 0.7148148148148149,
-			0.40631001371742104, 0.08950617283950621, 0.04999999999999999
-		]
-	);
-});
-
-test('interpolatorSplineMonotoneClosed', t => {
-	let data = [3, 2.8, 2.5, 1, 0.95, 0.8, 0.5, 0.1, 0.05];
-	assert.deepEqual(
-		samples(10).map(interpolatorSplineMonotoneClosed(data)),
-		[
-			3, 2.8288065843621397, 2.6089163237311386, 1.3592592592592596,
-			0.973593964334705, 0.8984224965706447, 0.7148148148148149,
-			0.40631001371742104, 0.08950617283950621, 0.04999999999999999
-		]
-	);
-});
-
-test('interpolatorSplineMonotone: outside [0, 1] range', t => {
-	let it = interpolatorSplineMonotone([3, 10, 1]);
-	assert.deepEqual([-0.5, 1, 1.5, 2].map(it), [10, 1, 10, 91]);
-});
-
-test('interpolatorSplineMonotone2: outside [0, 1] range', t => {
-	let it = interpolatorSplineMonotone2([3, 10, 1]);
-	assert.deepEqual([-0.5, 1, 1.5, 2].map(it), [-18, 1, -22, -53]);
-});
-
-test('interpolatorSplineMonotoneClosed: outside [0, 1] range', t => {
-	let it = interpolatorSplineMonotoneClosed([3, 10, 1]);
-	assert.deepEqual([-0.5, 1, 1.5, 2].map(it), [22, 1, 46, 253]);
-});
diff --git a/test/interpolatorSplineNatural.test.js b/test/interpolatorSplineNatural.test.js
deleted file mode 100644
index bd500b17..00000000
--- a/test/interpolatorSplineNatural.test.js
+++ /dev/null
@@ -1,38 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	samples,
-	interpolatorSplineNatural,
-	interpolatorSplineNaturalClosed
-} from '../src/index.js';
-
-test('interpolatorSplineNatural', t => {
-	let arr = [10, 20, 0, 40, 70];
-	let it = interpolatorSplineNatural(arr);
-	assert.deepEqual(samples(5).map(it), arr);
-});
-
-test('interpolatorSplineNaturalClosed', t => {
-	let arr = [10, 20, 0, 40, 70];
-	let it = interpolatorSplineNaturalClosed(arr);
-	assert.deepEqual(samples(5).map(it), [23.75, 20, 0, 40, 56.25]);
-});
-
-test('interpolatorSplineNatural: outside [0, 1] range', t => {
-	let it = interpolatorSplineNatural([3, 10, 1]);
-	assert.deepEqual(
-		[-0.5, 1, 1.5, 2].map(it),
-		[-4.166666666666667, 1, -8.166666666666666, 7.166666666666667]
-	);
-});
-
-test('interpolatorSplineNaturalClosed: outside [0, 1] range', t => {
-	let it = interpolatorSplineNaturalClosed([3, 10, 1]);
-	assert.deepEqual(
-		[-0.5, 1, 1.5, 2].map(it),
-		[
-			3.5416666666666665, 3.5416666666666665, 4.541666666666667,
-			10.166666666666666
-		]
-	);
-});
diff --git a/test/itp.test.js b/test/itp.test.js
deleted file mode 100644
index 50875f09..00000000
--- a/test/itp.test.js
+++ /dev/null
@@ -1,73 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { formatCss, formatHex, itp } from '../src/index.js';
-
-test('itp', t => {
-	assert.deepEqual(
-		itp('white'),
-		{
-			mode: 'itp',
-			i: 0.5806888810416109,
-			t: 1.1102230246251565e-16,
-			p: 2.914335439641036e-16
-		},
-		'white'
-	);
-	assert.deepEqual(
-		itp('black'),
-		{
-			mode: 'itp',
-			i: 7.309559025783966e-7,
-			t: -2.117582368135751e-22,
-			p: 1.3234889800848443e-23
-		},
-		'black'
-	);
-	assert.deepEqual(
-		itp('red'),
-		{
-			mode: 'itp',
-			i: 0.4278802843622844,
-			t: -0.11570435976969046,
-			p: 0.27872894737532694
-		},
-		'red'
-	);
-});
-
-test('color(--ictcp)', t => {
-	assert.deepEqual(itp('color(--ictcp 1 0 0 / 0.25)'), {
-		mode: 'itp',
-		i: 1,
-		t: 0,
-		p: 0,
-		alpha: 0.25
-	});
-	assert.deepEqual(itp('color(--ictcp 0% 50% 0.5 / 25%)'), {
-		mode: 'itp',
-		i: 0,
-		t: 0.5,
-		p: 0.5,
-		alpha: 0.25
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--ictcp 0% 50% 0.5 / 25%)'),
-		'color(--ictcp 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatHex({
-			mode: 'itp',
-			i: 0.4278802843622844,
-			t: -0.11570435976969046,
-			p: 0.27872894737532694
-		}),
-		'#ff0000',
-		'red'
-	);
-});
diff --git a/test/jab.test.js b/test/jab.test.js
deleted file mode 100644
index af7e2642..00000000
--- a/test/jab.test.js
+++ /dev/null
@@ -1,59 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { jab, rgb, formatHex, formatCss } from '../src/index.js';
-
-test('jab', t => {
-	assert.deepEqual(
-		jab('white'),
-		{ mode: 'jab', j: 0.222065249535743, a: 0, b: 0 },
-		'white'
-	);
-
-	assert.deepEqual(
-		jab('black'),
-		{ mode: 'jab', j: 3.2311742677852644e-27, a: 0, b: 0 },
-		'black'
-	);
-
-	assert.deepEqual(
-		jab('red'),
-		{
-			mode: 'jab',
-			j: 0.13438473104350068,
-			a: 0.11788526260797229,
-			b: 0.11187810901317238
-		},
-		'red'
-	);
-});
-
-test('rgb -> jab -> rgb', t => {
-	assert.equal(formatHex(jab('#cc3302')), '#cc3302', '#cc3302');
-});
-
-test('color(--jzazbz)', t => {
-	assert.deepEqual(jab('color(--jzazbz 30 -10 +15 / 0.25)'), {
-		j: 30,
-		a: -10,
-		b: +15,
-		alpha: 0.25,
-		mode: 'jab'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--jzazbz 30 -1e1 +15 / 0.25)'),
-		'color(--jzazbz 30 -10 15 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--jzazbz none 0.5 none)'), 'jab to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--jzazbz none 0.5 none)'),
-		rgb('color(--jzazbz 0 0.5 0)')
-	);
-	assert.ok(jab('rgb(none 100 20)'), 'rgb to jab is ok');
-	assert.deepEqual(jab('rgb(none 100 20)'), jab('rgb(0 100 20)'));
-});
diff --git a/test/jch.test.js b/test/jch.test.js
deleted file mode 100644
index f1a14bf7..00000000
--- a/test/jch.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { formatRgb, formatCss, jch, rgb } from '../src/index.js';
-
-test('PQ_inv negative value', t => {
-	assert.equal(
-		formatRgb({ mode: 'jch', j: 0.01768, c: 0.095, h: 77 }),
-		'rgb(42, 0, 0)'
-	);
-});
-
-test('color(--jzczhz)', t => {
-	assert.deepEqual(jch('color(--jzczhz 30 10e1 -15 / 0.25)'), {
-		j: 30,
-		c: 100,
-		h: -15,
-		alpha: 0.25,
-		mode: 'jch'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--jzczhz 30 1e1 +15 / 0.25)'),
-		'color(--jzczhz 30 10 15 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--jzczhz none 0.5 none)'), 'jch to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--jzczhz none 0.5 none)'),
-		rgb('color(--jzczhz 0% 0.5 0)')
-	);
-	assert.ok(jch('rgb(none 100 20)'), 'rgb to jch is ok');
-	assert.deepEqual(jch('rgb(none 100 20)'), jch('rgb(0 100 20)'));
-});
diff --git a/test/lab.test.js b/test/lab.test.js
deleted file mode 100644
index 9c7536de..00000000
--- a/test/lab.test.js
+++ /dev/null
@@ -1,51 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { lab, rgb, formatCss } from '../src/index.js';
-
-test('lab', t => {
-	assert.deepEqual(
-		lab('white'),
-		{ mode: 'lab', l: 100.00000139649632, a: 0, b: 0 },
-		'white'
-	);
-
-	// Tests that achromatic RGB colors get a = b = 0 in CIELab
-	assert.deepEqual(
-		lab('#111'),
-		{ mode: 'lab', l: 5.063329676301251, a: 0, b: 0 },
-		'#111'
-	);
-
-	assert.deepEqual(lab('black'), { mode: 'lab', l: 0, a: 0, b: 0 }, 'black');
-	assert.deepEqual(
-		lab('red'),
-		{
-			mode: 'lab',
-			l: 54.29054294696968,
-			a: 80.80492033462417,
-			b: 69.89098825896278
-		},
-		'red'
-	);
-
-	assert.deepEqual(lab('lab(50% -10% 200% / 10%)'), {
-		mode: 'lab',
-		l: 50,
-		a: -12.5,
-		b: 250,
-		alpha: 0.1
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(formatCss('lab(40% 10 30 / 50%)'), 'lab(40 10 30 / 0.5)');
-	assert.equal(formatCss('lab(40% 10 30 / 100%)'), 'lab(40 10 30)');
-	assert.equal(formatCss('lab(40% 10 30)'), 'lab(40 10 30)');
-});
-
-test('missing components', t => {
-	assert.ok(rgb('lab(none 0.5 none)'), 'lab to rgb is ok');
-	assert.deepEqual(rgb('lab(none 0.5 none)'), rgb('lab(0% 0.5 0%)'));
-	assert.ok(lab('rgb(none 100 20)'), 'rgb to lab is ok');
-	assert.deepEqual(lab('rgb(none 100 20)'), lab('rgb(0 100 20)'));
-});
diff --git a/test/lab65.test.js b/test/lab65.test.js
deleted file mode 100644
index d259e435..00000000
--- a/test/lab65.test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { lab65, rgb, formatCss } from '../src/index.js';
-
-test('lab65', t => {
-	assert.deepEqual(
-		lab65('white'),
-		{ mode: 'lab65', l: 100, a: 0, b: 0 },
-		'white'
-	);
-
-	// Tests that achromatic RGB colors get a = b = 0 in CIELab D65
-	assert.deepEqual(
-		lab65('#111'),
-		{ mode: 'lab65', l: 5.063329493432597, a: 0, b: 0 },
-		'#111'
-	);
-
-	assert.deepEqual(
-		lab65('black'),
-		{ mode: 'lab65', l: 0, a: 0, b: 0 },
-		'black'
-	);
-	assert.deepEqual(
-		lab65('red'),
-		{
-			mode: 'lab65',
-			l: 53.237115595429344,
-			a: 80.09011352310385,
-			b: 67.20326351172214
-		},
-		'red'
-	);
-});
-
-test('color(--lab-d65)', t => {
-	assert.deepEqual(lab65('color(--lab-d65 30 0.5 1 / 0.25)'), {
-		l: 30,
-		a: 0.5,
-		b: 1,
-		alpha: 0.25,
-		mode: 'lab65'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--lab-d65 30 0.5 1 / 0.25)'),
-		'color(--lab-d65 30 0.5 1 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--lab-d65 none 0.5 none)'), 'lab65 to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--lab-d65 none 0.5 none)'),
-		rgb('color(--lab-d65 0 0.5 0)')
-	);
-	assert.ok(lab65('rgb(none 100 20)'), 'rgb to lab65 is ok');
-	assert.deepEqual(lab65('rgb(none 100 20)'), lab65('rgb(0 100 20)'));
-});
diff --git a/test/lch.test.js b/test/lch.test.js
deleted file mode 100644
index ebe869d8..00000000
--- a/test/lch.test.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { lch, rgb, formatCss } from '../src/index.js';
-
-test('lch', t => {
-	assert.deepEqual(
-		lch('white'),
-		{ mode: 'lch', l: 100.00000139649632, c: 0 },
-		'white'
-	);
-	assert.deepEqual(
-		lch('#111'),
-		{ mode: 'lch', l: 5.063329676301251, c: 0 },
-		'#111'
-	);
-	assert.deepEqual(lch('black'), { mode: 'lch', l: 0, c: 0 }, 'black');
-	assert.deepEqual(
-		lch('red'),
-		{
-			mode: 'lch',
-			l: 54.29054294696968,
-			c: 106.83719104365966,
-			h: 40.85766878213079
-		},
-		'red'
-	);
-	assert.deepEqual(lch('lch(20% 30% .5turn / 10%)'), {
-		mode: 'lch',
-		l: 20,
-		c: 45,
-		h: 180,
-		alpha: 0.1
-	});
-	assert.deepEqual(lch('lch(20% -30% .5turn / 10%)'), {
-		mode: 'lch',
-		l: 20,
-		c: 0,
-		h: 180,
-		alpha: 0.1
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(formatCss('lch(40% 10 30 / 50%)'), 'lch(40 10 30 / 0.5)');
-	assert.equal(formatCss('lch(40% 10 30 / 100%)'), 'lch(40 10 30)');
-	assert.equal(formatCss('lch(40% 10 30)'), 'lch(40 10 30)');
-	assert.equal(
-		formatCss(lch('#ffffff00')),
-		'lch(100.00000139649632 0 none / 0)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('lch(none 0.5 none)'), 'lch to rgb is ok');
-	assert.deepEqual(rgb('lch(none 0.5 none)'), rgb('lch(0% 0.5 0)'));
-	assert.ok(lch('rgb(none 100 20)'), 'rgb to lch is ok');
-	assert.deepEqual(lch('rgb(none 100 20)'), lch('rgb(0 100 20)'));
-});
diff --git a/test/lch65.test.js b/test/lch65.test.js
deleted file mode 100644
index 64870fd8..00000000
--- a/test/lch65.test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { lch65, lab65, formatCss } from '../src/index.js';
-
-test('lch65', t => {
-	assert.deepEqual(lch65('white'), { mode: 'lch65', l: 100, c: 0 }, 'white');
-	assert.deepEqual(
-		lch65('#111'),
-		{ mode: 'lch65', l: 5.063329493432597, c: 0 },
-		'#111'
-	);
-	assert.deepEqual(lch65('black'), { mode: 'lch65', l: 0, c: 0 }, 'black');
-	assert.deepEqual(
-		lch65('red'),
-		{
-			mode: 'lch65',
-			l: 53.237115595429344,
-			c: 104.55001152926587,
-			h: 39.99986515439813
-		},
-		'red'
-	);
-});
-
-test('lab65 <-> lch65', t => {
-	assert.deepEqual(lch65(lab65({ l: 100, a: 0.2, b: 0.2 })), {
-		mode: 'lch65',
-		l: 100,
-		c: 0.28284271247461906,
-		h: 45
-	});
-
-	assert.deepEqual(
-		lab65(
-			lch65({
-				mode: 'lch65',
-				l: 100,
-				c: 0.28284271247461906,
-				h: 45
-			})
-		),
-		{ mode: 'lab65', l: 100, a: 0.20000000000000004, b: 0.2 }
-	);
-});
-
-test('color(--lch-d65)', t => {
-	assert.deepEqual(lch65('color(--lch-d65 30 0.5 1 / 0.25)'), {
-		l: 30,
-		c: 0.5,
-		h: 1,
-		alpha: 0.25,
-		mode: 'lch65'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--lch-d65 30 0.5 1 / 0.25)'),
-		'color(--lch-d65 30 0.5 1 / 0.25)'
-	);
-});
diff --git a/test/lchuv.test.js b/test/lchuv.test.js
deleted file mode 100644
index 69a27732..00000000
--- a/test/lchuv.test.js
+++ /dev/null
@@ -1,65 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { lchuv, rgb, formatCss } from '../src/index.js';
-
-test('lchuv', t => {
-	assert.deepEqual(
-		lchuv('white'),
-		{
-			mode: 'lchuv',
-			l: 100.00000139649632,
-			c: 0.000013192899605235416,
-			h: 129.3684297210339
-		},
-		'white'
-	);
-	assert.deepEqual(lchuv('black'), { mode: 'lchuv', l: 0, c: 0 }, 'black');
-	assert.deepEqual(
-		lchuv('red'),
-		{
-			mode: 'lchuv',
-			l: 54.29054294696968,
-			c: 176.94953872495253,
-			h: 8.434231142939021
-		},
-		'red'
-	);
-	assert.deepEqual(
-		lchuv('#00cc0080'),
-		{
-			mode: 'lchuv',
-			l: 71.74973747305378,
-			c: 99.4709666171262,
-			h: 134.23124010020916,
-			alpha: 0.5019607843137255
-		},
-		'#00cc0080'
-	);
-});
-
-test('color(--lchuv)', t => {
-	assert.deepEqual(lchuv('color(--lchuv 30 0.5 1 / 0.25)'), {
-		l: 30,
-		c: 0.5,
-		h: 1,
-		alpha: 0.25,
-		mode: 'lchuv'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--lchuv 30 0.5 1 / 0.25)'),
-		'color(--lchuv 30 0.5 1 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--lchuv none 0.5 none)'), 'lchuv to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--lchuv none 0.5 none)'),
-		rgb('color(--lchuv 0 0.5 0)')
-	);
-	assert.ok(lchuv('rgb(none 100 20)'), 'rgb to lchuv is ok');
-	assert.deepEqual(lchuv('rgb(none 100 20)'), lchuv('rgb(0 100 20)'));
-});
diff --git a/test/lerp.test.js b/test/lerp.test.js
deleted file mode 100644
index 25543d5b..00000000
--- a/test/lerp.test.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { lerp, unlerp, trilerp } from '../src/index.js';
-
-test('lerp()', t => {
-	assert.equal(lerp(10, 2, 0.5), 6);
-});
-
-test('unlerp()', t => {
-	assert.equal(unlerp(5, 10, 2.5), -0.5);
-});
-
-const RYB_CUBE = [
-	{ mode: 'rgb', r: 1, g: 1, b: 1 }, // white
-	{ mode: 'rgb', r: 1, g: 0, b: 0 }, // red
-	{ mode: 'rgb', r: 1, g: 1, b: 0 }, // yellow
-	{ mode: 'rgb', r: 1, g: 0.5, b: 0 }, // orange
-	{ mode: 'rgb', r: 0.163, g: 0.373, b: 0.6 }, // blue
-	{ mode: 'rgb', r: 0.5, g: 0, b: 0.5 }, // violet
-	{ mode: 'rgb', r: 0, g: 0.66, b: 0.2 }, // green
-	{ mode: 'rgb', r: 0.2, g: 0.094, b: 0 } // black
-];
-
-test('trilerp()', t => {
-	const RYB_COLOR = [1, 0.5, 0.25];
-	const EXPECTED_LINEAR = {
-		mode: 'rgb',
-		r: 0.8375,
-		g: 0.19924999999999998,
-		b: 0.0625
-	};
-	const EXPECTED_BIASED = {
-		mode: 'rgb',
-		r: 0.8984375,
-		g: 0.21828124999999998,
-		b: 0.0390625
-	};
-
-	function ryb2rgb(coords, bias = true) {
-		const biased_coords = bias
-			? coords.map(t => t * t * (3 - 2 * t))
-			: coords;
-		return {
-			mode: 'rgb',
-			r: trilerp(...RYB_CUBE.map(it => it.r), ...biased_coords),
-			g: trilerp(...RYB_CUBE.map(it => it.g), ...biased_coords),
-			b: trilerp(...RYB_CUBE.map(it => it.b), ...biased_coords)
-		};
-	}
-
-	assert.deepEqual(ryb2rgb(RYB_COLOR, false), EXPECTED_LINEAR, 'ryb: linear');
-	assert.deepEqual(ryb2rgb(RYB_COLOR), EXPECTED_BIASED, 'ryb: biased');
-});
diff --git a/test/lrgb.test.js b/test/lrgb.test.js
deleted file mode 100644
index cd6e4de9..00000000
--- a/test/lrgb.test.js
+++ /dev/null
@@ -1,75 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { rgb, lrgb, formatCss } from '../src/index.js';
-
-test('round-trip', t => {
-	let in_gamut = {
-		mode: 'rgb',
-		r: 0.1,
-		g: 0.25,
-		b: 0.7
-	};
-	assert.deepEqual(
-		lrgb(in_gamut),
-		{
-			mode: 'lrgb',
-			r: 0.010022825574869039,
-			g: 0.05087608817155679,
-			b: 0.44798841244188325
-		},
-		'in gamut'
-	);
-	assert.deepEqual(rgb(lrgb(in_gamut)), in_gamut, 'in gamut');
-
-	let out_of_gamut = {
-		mode: 'rgb',
-		r: -0.2,
-		g: 0.25,
-		b: 2.7
-	};
-	assert.deepEqual(
-		lrgb(out_of_gamut),
-		{
-			mode: 'lrgb',
-			r: -0.033104766570885055,
-			g: 0.05087608817155679,
-			b: 10.011195548645787
-		},
-		'out of gamut'
-	);
-	assert.deepEqual(rgb(lrgb(out_of_gamut)), out_of_gamut, 'out of gamut');
-});
-
-test('color(srgb-linear)', t => {
-	assert.deepEqual(lrgb('color(srgb-linear 1 0 0 / 0.25)'), {
-		r: 1,
-		g: 0,
-		b: 0,
-		alpha: 0.25,
-		mode: 'lrgb'
-	});
-	assert.deepEqual(lrgb('color(srgb-linear 0% 50% 0.5 / 25%)'), {
-		r: 0,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'lrgb'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(srgb-linear 0% 50% 0.5 / 25%)'),
-		'color(srgb-linear 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(srgb-linear none 0.5 none)'), 'lrgb to rgb is ok');
-	assert.deepEqual(
-		rgb('color(srgb-linear none 0.5 none)'),
-		rgb('color(srgb-linear 0 0.5 0')
-	);
-	assert.ok(lrgb('rgb(none 100 20)'), 'rgb to lrgb is ok');
-	assert.deepEqual(lrgb('rgb(none 100 20)'), lrgb('rgb(0 100 20)'));
-});
diff --git a/test/luv.test.js b/test/luv.test.js
deleted file mode 100644
index 1b7a6e01..00000000
--- a/test/luv.test.js
+++ /dev/null
@@ -1,58 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { luv, rgb } from '../src/index.js';
-
-test('luv', t => {
-	assert.deepEqual(
-		luv('white'),
-		{
-			mode: 'luv',
-			l: 100.00000139649632,
-			u: -0.00000836831738933014,
-			v: 0.0000101992089921354
-		},
-		'white'
-	);
-	assert.deepEqual(luv('black'), { mode: 'luv', l: 0, u: 0, v: 0 }, 'black');
-	assert.deepEqual(
-		luv('red'),
-		{
-			mode: 'luv',
-			l: 54.29054294696968,
-			u: 175.03580817106865,
-			v: 25.95390361533953
-		},
-		'red'
-	);
-	assert.deepEqual(
-		luv('#00cc0080'),
-		{
-			mode: 'luv',
-			l: 71.74973747305378,
-			u: -69.38655858949816,
-			v: 71.27396920932334,
-			alpha: 0.5019607843137255
-		},
-		'#00cc0080'
-	);
-});
-
-test('color(--luv)', t => {
-	assert.deepEqual(luv('color(--luv 30 0.5 1 / 0.25)'), {
-		l: 30,
-		u: 0.5,
-		v: 1,
-		alpha: 0.25,
-		mode: 'luv'
-	});
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--luv none 0.5 none)'), 'luv to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--luv none 0.5 none)'),
-		rgb('color(--luv 0 0.5 0)')
-	);
-	assert.ok(luv('rgb(none 100 20)'), 'rgb to luv is ok');
-	assert.deepEqual(luv('rgb(none 100 20)'), luv('rgb(0 100 20)'));
-});
diff --git a/test/map.test.js b/test/map.test.js
deleted file mode 100644
index 924fc35e..00000000
--- a/test/map.test.js
+++ /dev/null
@@ -1,90 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	mapper,
-	mapAlphaMultiply,
-	mapAlphaDivide,
-	mapTransferLinear,
-	mapTransferGamma,
-	formatHex,
-	formatHex8
-} from '../src/index.js';
-
-test('mapping alpha', t => {
-	let multiply = mapper(mapAlphaMultiply);
-	let divide = mapper(mapAlphaDivide);
-
-	assert.equal(formatHex8(multiply('#ff00cc80')), '#80006680');
-	assert.equal(formatHex8(divide(multiply('#ff00cc80'))), '#ff00cc80');
-});
-
-test('linear transfer function', t => {
-	let brighten = mapper(mapTransferLinear(2));
-	assert.equal(formatHex(brighten('#cc0033')), '#ff0066');
-});
-
-test('gamma transfer function', t => {
-	let brighten = mapper(mapTransferGamma(2.2));
-	assert.equal(formatHex(brighten('#cc0033')), '#ff0070');
-});
-
-test('mode = null', t => {
-	let increaser = mapper(v => v + 0.1, null);
-	assert.equal(
-		formatHex(increaser('#cc0033')),
-		'#e61a4d',
-		'color is rgb string'
-	);
-	assert.equal(
-		increaser({ mode: 'rgb', r: 0.8, g: 0, b: 0.2 }).mode,
-		'rgb',
-		'color is rgb'
-	);
-});
-
-test('preserve_mode', t => {
-	const rgbColor = { mode: 'rgb', r: 0.8, g: 0, b: 0.2 };
-	const fn = v => v + 0.1;
-	assert.equal(
-		formatHex(mapper(fn, null, true)(rgbColor)),
-		'#e61a4d',
-		'mode = null, preserve_mode = true'
-	);
-	assert.equal(
-		mapper(fn, undefined, true)('#cc0033').mode,
-		'rgb',
-		'mode = undefined, preserve_mode = true'
-	);
-	assert.equal(
-		mapper(fn, 'hsl', true)('#cc0033').mode,
-		'rgb',
-		'mode = hsl, preserve_mode = true'
-	);
-	assert.equal(
-		mapper(fn, 'hsl', false)('#cc0033').mode,
-		'hsl',
-		'mode = hsl, preserve_mode = false'
-	);
-	assert.equal(
-		mapper(fn, 'oklch', false)('#cc0033').mode,
-		'oklch',
-		'mode = oklch, preserve_mode = false'
-	);
-	const oklchColor = {
-		mode: 'oklch',
-		alpha: 0.25,
-		l: 30,
-		c: 0.5,
-		h: 1
-	};
-	assert.equal(
-		mapper(fn, 'hsl', false)(oklchColor).mode,
-		'hsl',
-		'oklch color, mode = hsl, preserve_mode = false'
-	);
-	assert.equal(
-		mapper(fn, 'hsl', true)(oklchColor).mode,
-		'oklch',
-		'oklch color, mode = hsl, preserve_mode = true'
-	);
-});
diff --git a/test/nearest.test.js b/test/nearest.test.js
deleted file mode 100644
index cd061bda..00000000
--- a/test/nearest.test.js
+++ /dev/null
@@ -1,42 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { nearest, colorsNamed } from '../src/index.js';
-
-let nearestNamedColor = nearest(Object.keys(colorsNamed));
-
-test('check against named colors', test => {
-	assert.deepEqual(
-		nearestNamedColor('red'),
-		['red'],
-		'Closest named color to red'
-	);
-
-	assert.deepEqual(
-		nearestNamedColor('red', Infinity, 0.5),
-		[
-			'red',
-			'orangered',
-			'crimson',
-			'firebrick',
-			'brown',
-			'darkred',
-			'chocolate',
-			'tomato',
-			'maroon'
-		],
-		'Close named colors to red, d <= 0.5'
-	);
-});
-
-test('nearest() with accessor', t => {
-	let palette = {
-		Burgundy: '#914e72',
-		Blue: '#0078bf',
-		Green: '#00a95c',
-		'Medium Blue': '#3255a4',
-		'Bright Red': '#f15060'
-	};
-	let names = Object.keys(palette);
-	let nearestColors = nearest(names, undefined, name => palette[name]);
-	assert.deepEqual(nearestColors('red', 1), ['Bright Red']);
-});
diff --git a/test/none.test.js b/test/none.test.js
deleted file mode 100644
index cb5c828c..00000000
--- a/test/none.test.js
+++ /dev/null
@@ -1,116 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	parse,
-	formatHex,
-	formatHex8,
-	formatRgb,
-	formatHsl,
-	formatCss
-} from '../src/index.js';
-
-test('parse "none" keyword', t => {
-	assert.deepEqual(
-		parse('rgb(none, 255, 127.5)'),
-		undefined,
-		'rgb() <number> (legacy)'
-	);
-	assert.deepEqual(
-		parse('rgb(none 255 127.5 / none)'),
-		{ mode: 'rgb', g: 1, b: 0.5 },
-		'rgb() <number>'
-	);
-	assert.deepEqual(
-		parse('rgb(none, 100%, 50%)'),
-		undefined,
-		'rgb() <percentage> (legacy)'
-	);
-	assert.deepEqual(
-		parse('rgba(none 100% 50% / none)'),
-		{ mode: 'rgb', g: 1, b: 0.5 },
-		'rgb() <percentage>'
-	);
-	assert.deepEqual(
-		parse('hsl(none, 50%, 100%)'),
-		undefined,
-		'hsl() (legacy)'
-	);
-	assert.deepEqual(
-		parse('hsla(none 50% none)'),
-		{ mode: 'hsl', s: 0.5 },
-		'hsl()'
-	);
-
-	assert.deepEqual(
-		parse('hwb(none none 50% / none)'),
-		{ mode: 'hwb', b: 0.5 },
-		'hwb()'
-	);
-
-	assert.deepEqual(
-		parse('lab(none 12 none)'),
-		{ mode: 'lab', a: 12 },
-		'lab()'
-	);
-
-	assert.deepEqual(
-		parse('lch(5% none 1turn)'),
-		{ mode: 'lch', l: 5, h: 360 },
-		'lch()'
-	);
-
-	assert.deepEqual(
-		parse('color(display-p3 none none none / 0.1)'),
-		{ mode: 'p3', alpha: 0.1 },
-		'color()'
-	);
-});
-
-test('serialize "none" keyword', t => {
-	assert.equal(
-		formatRgb('rgb(none none none / none)'),
-		'rgb(0, 0, 0)',
-		'formatRgb'
-	);
-	assert.equal(
-		formatHex('rgb(none none none / none)'),
-		'#000000',
-		'formatHex'
-	);
-	assert.equal(
-		formatHex8('rgb(none none none / none)'),
-		'#000000ff',
-		'formatHex8'
-	);
-	assert.equal(
-		formatHsl('hsl(none none none / none)'),
-		'hsl(0, 0%, 0%)',
-		'formatHsl'
-	);
-	assert.equal(
-		formatCss('hsl(none none none)'),
-		'hsl(none none none)',
-		'formatCss(hsl)'
-	);
-	assert.equal(
-		formatCss('lab(none none none / none)'),
-		'lab(none none none)',
-		'formatCss(lab)'
-	);
-	assert.equal(
-		formatCss('lch(none none none / none)'),
-		'lch(none none none)',
-		'formatCss(lch)'
-	);
-
-	assert.equal(
-		formatCss('oklab(none none none / none)'),
-		'oklab(none none none)',
-		'formatCss(oklab)'
-	);
-	assert.equal(
-		formatCss('oklch(none none none / none)'),
-		'oklch(none none none)',
-		'formatCss(oklch)'
-	);
-});
diff --git a/test/normalizePositions.test.js b/test/normalizePositions.test.js
deleted file mode 100644
index dc1f3082..00000000
--- a/test/normalizePositions.test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import normalize from '../src/util/normalizePositions.js';
-
-test('util: normalizePositions', t => {
-	assert.deepEqual(
-		normalize([undefined, undefined, undefined, undefined, undefined]),
-		[0, 0.25, 0.5, 0.75, 1]
-	);
-
-	assert.deepEqual(
-		normalize([0.2, undefined, undefined, 0.8]),
-		[0.2, 0.4, 0.6000000000000001, 0.8]
-	);
-});
diff --git a/test/okhsl.test.js b/test/okhsl.test.js
deleted file mode 100644
index 21a29bda..00000000
--- a/test/okhsl.test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { okhsl, rgb, formatHex, formatCss } from '../src/index.js';
-
-test('rgb → okhsl', t => {
-	assert.equal(
-		formatCss(okhsl('red')),
-		'color(--okhsl 29.233880279627854 1.0000000007111225 0.5680846563197034)',
-		'red'
-	);
-	assert.equal(
-		formatCss(okhsl('white')),
-		'color(--okhsl none 0 1.0000000000000002)',
-		'white'
-	);
-	assert.equal(formatCss(okhsl('black')), 'color(--okhsl none 0 0)', 'black');
-	assert.equal(
-		formatCss(okhsl('#3333')),
-		'color(--okhsl none 0 0.2209950737733088 / 0.2)',
-		'#333'
-	);
-});
-
-test('okhsl → rgb', t => {
-	assert.equal(
-		formatHex(
-			'color(--okhsl 29.233885192342633 1.0000000001433997 0.5680846525040862)'
-		),
-		'#ff0000',
-		'red'
-	);
-	assert.equal(
-		formatHex('color(--okhsl 0 0 0.9999999923961898)'),
-		'#ffffff',
-		'white'
-	);
-	assert.equal(formatHex('color(--okhsl 0 0 0)'), '#000000', 'black');
-	assert.equal(
-		formatHex('color(--okhsl 0 0 0.2209950715093747 / 0.2)'),
-		'#333333',
-		'#333'
-	);
-	assert.deepEqual(
-		formatHex('color(--okhsl 0 1 1)'),
-		'#ffffff',
-		'color(--okhsl 0 1 1)'
-	);
-	assert.equal(
-		formatHex('color(--okhsl 0 1 0)'),
-		'#000000',
-		'color(--okhsl 0 1 0)'
-	);
-});
-
-test('rgb → okhsl → rgb', t => {
-	assert.equal(formatHex(okhsl('red')), '#ff0000', 'red');
-	assert.equal(formatHex(okhsl('white')), '#ffffff', 'white');
-	assert.equal(formatHex(okhsl('black')), '#000000', 'black');
-	assert.equal(formatHex(okhsl('#3333')), '#333333', '#333');
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--okhsl none 0.5 none)'));
-	assert.deepEqual(
-		rgb('color(--okhsl none 0.5 none)'),
-		rgb('color(--okhsl 0 0.5 0)')
-	);
-	assert.ok(okhsl('rgb(none 100 20)'));
-	assert.deepEqual(okhsl('rgb(none 100 20)'), okhsl('rgb(0 100 20)'));
-});
diff --git a/test/okhsv.test.js b/test/okhsv.test.js
deleted file mode 100644
index e27b87bb..00000000
--- a/test/okhsv.test.js
+++ /dev/null
@@ -1,70 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { okhsv, rgb, formatHex, formatCss } from '../src/index.js';
-
-test('rgb → okhsv', t => {
-	assert.equal(
-		formatCss(okhsv('red')),
-		'color(--okhsv 29.233880279627854 0.9995219665357181 0.9999999999999998)',
-		'red'
-	);
-	assert.equal(
-		formatCss(okhsv('white')),
-		'color(--okhsv none 0 1.0000000000000004)',
-		'white'
-	);
-	assert.equal(formatCss(okhsv('black')), 'color(--okhsv none 0 0)', 'black');
-	assert.equal(
-		formatCss(okhsv('#3333')),
-		'color(--okhsv none 0 0.22099507377330885 / 0.2)',
-		'#333'
-	);
-});
-
-test('okhsv → rgb', t => {
-	assert.equal(
-		formatHex(
-			'color(--okhsv 29.233885192342633 0.9995219692256989 1.0000000001685625)'
-		),
-		'#ff0000',
-		'red'
-	);
-	assert.equal(
-		formatHex('color(--okhsv 0 0 0.9999999923961898)'),
-		'#ffffff',
-		'white'
-	);
-	assert.equal(formatHex('color(--okhsv 0 0 0)'), '#000000', 'black');
-	assert.equal(
-		formatHex('color(--okhsv 0 0 0.2209950715093747 / 0.2)'),
-		'#333333',
-		'#333'
-	);
-	assert.equal(
-		formatHex('color(--okhsv 0 1 1)'),
-		'#ff0088',
-		'color(--okhsv 0 1 1)'
-	);
-	assert.equal(
-		formatHex('color(--okhsv 0 1 0)'),
-		'#000000',
-		'color(--okhsv 0 1 0)'
-	);
-});
-
-test('rgb → okhsv → rgb', t => {
-	assert.equal(formatHex(okhsv('red')), '#ff0000', 'red');
-	assert.equal(formatHex(okhsv('white')), '#ffffff', 'white');
-	assert.equal(formatHex(okhsv('black')), '#000000', 'black');
-	assert.equal(formatHex(okhsv('#3333')), '#333333', '#333');
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--okhsv none 0.5 none)'));
-	assert.deepEqual(
-		rgb('color(--okhsv none 0.5 none)'),
-		rgb('color(--okhsv 0 0.5 0)')
-	);
-	assert.ok(okhsv('rgb(none 100 20)'));
-	assert.deepEqual(okhsv('rgb(none 100 20)'), okhsv('rgb(0 100 20)'));
-});
diff --git a/test/oklab.test.js b/test/oklab.test.js
deleted file mode 100644
index 7a0003db..00000000
--- a/test/oklab.test.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	oklab,
-	rgb,
-	formatCss,
-	useParser,
-	removeParser
-} from '../src/index.js';
-
-test('rgb → oklab', t => {
-	assert.deepEqual(
-		oklab('white'),
-		{ mode: 'oklab', l: 1.0000000000000002, a: 0, b: 0 },
-		'white'
-	);
-
-	// Tests that achromatic RGB colors get a = b = 0 in OKLab
-	assert.deepEqual(
-		oklab('#111'),
-		{ mode: 'oklab', l: 0.17763777307657064, a: 0, b: 0 },
-		'#111'
-	);
-
-	assert.deepEqual(
-		oklab('black'),
-		{ mode: 'oklab', l: 0, a: 0, b: 0 },
-		'black'
-	);
-	assert.deepEqual(
-		oklab('red'),
-		{
-			mode: 'oklab',
-			l: 0.6279553639214311,
-			a: 0.22486306842627443,
-			b: 0.12584627733058495
-		},
-		'red'
-	);
-});
-
-test('color(--oklab) with custom ident registration', t => {
-	const c = 'color(--oklab 30 0.5 1 / 0.25)';
-	const cc = {
-		l: 30,
-		a: 0.5,
-		b: 1,
-		alpha: 0.25,
-		mode: 'oklab'
-	};
-	assert.equal(oklab(c), undefined);
-	useParser('--oklab', 'oklab');
-	assert.deepEqual(oklab(c), cc);
-	removeParser('--oklab');
-	assert.equal(oklab(c), undefined);
-});
-
-test('oklab()', t => {
-	assert.deepEqual(oklab('oklab(0.4 0.5 1 / 0.25)'), {
-		l: 0.4,
-		a: 0.5,
-		b: 1,
-		alpha: 0.25,
-		mode: 'oklab'
-	});
-	assert.deepEqual(oklab('oklab(25% -20% 125% / 15%)'), {
-		mode: 'oklab',
-		l: 0.25,
-		a: -0.08,
-		b: 0.5,
-		alpha: 0.15
-	});
-	assert.deepEqual(
-		oklab('oklab(-0.5 1 0)'),
-		{ l: 0, a: 1, b: 0, mode: 'oklab' },
-		'clamp L to 0'
-	);
-	assert.deepEqual(
-		oklab('oklab(2 1 0)'),
-		{ l: 1, a: 1, b: 0, mode: 'oklab' },
-		'clamp L to 1'
-	);
-
-	assert.deepEqual(
-		oklab('oklab(0.4 -1 1 / -0.5)'),
-		{ mode: 'oklab', l: 0.4, a: -1, b: 1, alpha: 0 },
-		'clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		oklab('oklab(0.4 -1 1 / 1.5)'),
-		{ mode: 'oklab', l: 0.4, a: -1, b: 1, alpha: 1 },
-		'clamp alpha > 1'
-	);
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('oklab(30% 0.5 1 / 0.25)'),
-		'oklab(0.3 0.5 1 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('oklab(none 0.5 none)'), 'oklab to rgb is ok');
-	assert.deepEqual(rgb('oklab(none 0.5 none)'), rgb('oklab(0% 0.5 0%)'));
-	assert.ok(oklab('rgb(none 100 20)'), 'rgb to oklab is ok');
-	assert.deepEqual(oklab('rgb(none 100 20)'), oklab('rgb(0 100 20)'));
-});
diff --git a/test/oklch.test.js b/test/oklch.test.js
deleted file mode 100644
index 93c10a1b..00000000
--- a/test/oklch.test.js
+++ /dev/null
@@ -1,127 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import {
-	rgb,
-	oklch,
-	formatCss,
-	useParser,
-	removeParser,
-	displayable,
-	inGamut
-} from '../src/index.js';
-
-test('oklch', t => {
-	assert.deepEqual(
-		oklch('white'),
-		{ mode: 'oklch', l: 1.0000000000000002, c: 0 },
-		'white'
-	);
-	assert.deepEqual(
-		oklch('#111'),
-		{ mode: 'oklch', l: 0.17763777307657064, c: 0 },
-		'#111'
-	);
-	assert.deepEqual(oklch('black'), { mode: 'oklch', l: 0, c: 0 }, 'black');
-	assert.deepEqual(
-		oklch('red'),
-		{
-			mode: 'oklch',
-			l: 0.6279553639214311,
-			c: 0.2576833038053608,
-			h: 29.233880279627854
-		},
-		'red'
-	);
-});
-
-test('oklch()', t => {
-	assert.deepEqual(oklch('oklch(0.3 0.5 1 / 0.25)'), {
-		l: 0.3,
-		c: 0.5,
-		h: 1,
-		alpha: 0.25,
-		mode: 'oklch'
-	});
-	assert.deepEqual(oklch('oklch(40% 50% .5turn / 15%)'), {
-		mode: 'oklch',
-		l: 0.4,
-		c: 0.2,
-		h: 180,
-		alpha: 0.15
-	});
-	assert.deepEqual(
-		oklch('oklch(-1 0.5 0.5turn / 0.42)'),
-		{
-			mode: 'oklch',
-			l: 0,
-			c: 0.5,
-			h: 180,
-			alpha: 0.42
-		},
-		'clamp L to 0'
-	);
-	assert.deepEqual(
-		oklch('oklch(2 0.5 40deg / 0.42)'),
-		{
-			mode: 'oklch',
-			l: 1,
-			c: 0.5,
-			h: 40,
-			alpha: 0.42
-		},
-		'clamp L to 1'
-	);
-	assert.deepEqual(
-		oklch('oklch(0.4 0.5 10 / -0.5)'),
-		{ mode: 'oklch', l: 0.4, c: 0.5, h: 10, alpha: 0 },
-		'clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		oklch('oklch(0.4 0.5 10 / 1.5)'),
-		{ mode: 'oklch', l: 0.4, c: 0.5, h: 10, alpha: 1 },
-		'clamp alpha > 1'
-	);
-});
-
-test('color(--oklch) with custom ident', t => {
-	const color_str = 'color(--oklch 30 0.5 1 / 0.25)';
-	const color = {
-		l: 30,
-		c: 0.5,
-		h: 1,
-		alpha: 0.25,
-		mode: 'oklch'
-	};
-	assert.equal(oklch(color_str), undefined);
-	useParser('--oklch', 'oklch');
-	assert.deepEqual(oklch(color_str), color);
-	removeParser('--oklch');
-	assert.equal(oklch(color_str), undefined);
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('oklch(30% 0.5 1 / 0.25)'),
-		'oklch(0.3 0.5 1 / 0.25)'
-	);
-	assert.equal(
-		formatCss(oklch('#ffffff00')),
-		'oklch(1.0000000000000002 0 none / 0)'
-	);
-});
-
-test('Issue #255', t => {
-	assert.deepEqual(rgb(oklch('tomato')), {
-		mode: 'rgb',
-		r: 0.9999999999999997,
-		g: 0.38823529411764784,
-		b: 0.2784313725490196
-	});
-	assert.ok(displayable(oklch('tomato')));
-});
-
-test('Issue #249', t => {
-	assert.ok(displayable('oklch(100% 0 0)'));
-	assert.ok(inGamut('rgb')('oklch(100% 0 0)'));
-});
diff --git a/test/p3.test.js b/test/p3.test.js
deleted file mode 100644
index a9efaf53..00000000
--- a/test/p3.test.js
+++ /dev/null
@@ -1,61 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { p3, rgb, formatCss } from '../src/index.js';
-
-test('p3', t => {
-	assert.deepEqual(
-		p3('white'),
-		{
-			mode: 'p3',
-			r: 0.9999999999999999,
-			g: 0.9999999999999997,
-			b: 0.9999999999999997
-		},
-		'white'
-	);
-	assert.deepEqual(p3('black'), { mode: 'p3', r: 0, g: 0, b: 0 }, 'black');
-	assert.deepEqual(
-		p3('red'),
-		{
-			mode: 'p3',
-			r: 0.9174875573251657,
-			g: 0.20028680774084662,
-			b: 0.1385605912111141
-		},
-		'red'
-	);
-});
-
-test('color(display-p3)', t => {
-	assert.deepEqual(p3('color(display-p3 1 0 0 / 0.25)'), {
-		r: 1,
-		g: 0,
-		b: 0,
-		alpha: 0.25,
-		mode: 'p3'
-	});
-	assert.deepEqual(p3('color(display-p3 0% 50% 0.5 / 25%)'), {
-		r: 0,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'p3'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(display-p3 0% 50% 0.5 / 25%)'),
-		'color(display-p3 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(display-p3 none 0.5 none)'), 'p3 to rgb is ok');
-	assert.deepEqual(
-		rgb('color(display-p3 none 0.5 none)'),
-		rgb('color(display-p3 0 0.5 0')
-	);
-	assert.ok(p3('rgb(none 100 20)'), 'rgb to p3 is ok');
-	assert.deepEqual(p3('rgb(none 100 20)'), p3('rgb(0 100 20)'));
-});
diff --git a/test/parse.test.js b/test/parse.test.js
deleted file mode 100644
index 6f1fd072..00000000
--- a/test/parse.test.js
+++ /dev/null
@@ -1,410 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { parse } from '../src/index.js';
-
-test('named colors', t => {
-	assert.deepEqual(
-		parse('tomato'),
-		{ mode: 'rgb', r: 1, g: 0.38823529411764707, b: 0.2784313725490196 },
-		'tomato'
-	);
-
-	assert.deepEqual(
-		parse('RoyalBlue'),
-		{
-			mode: 'rgb',
-			r: 0.2549019607843137,
-			g: 0.4117647058823529,
-			b: 0.8823529411764706
-		},
-		'RoyalBlue (CamelCase)'
-	);
-});
-
-test('hex colors', t => {
-	assert.deepEqual(
-		parse('#369'),
-		{ mode: 'rgb', r: 0.2, g: 0.4, b: 0.6 },
-		'#369'
-	);
-
-	assert.deepEqual(
-		parse('369'),
-		{ mode: 'rgb', r: 0.2, g: 0.4, b: 0.6 },
-		'369'
-	);
-
-	assert.deepEqual(
-		parse('#3690'),
-		{ mode: 'rgb', r: 0.2, g: 0.4, b: 0.6, alpha: 0 },
-		'#3690'
-	);
-
-	assert.deepEqual(
-		parse('3690'),
-		{ mode: 'rgb', r: 0.2, g: 0.4, b: 0.6, alpha: 0 },
-		'3690'
-	);
-
-	assert.deepEqual(
-		parse('#163264'),
-		{
-			mode: 'rgb',
-			r: 0.08627450980392157,
-			g: 0.19607843137254902,
-			b: 0.39215686274509803
-		},
-		'#163264'
-	);
-
-	assert.deepEqual(
-		parse('163264'),
-		{
-			mode: 'rgb',
-			r: 0.08627450980392157,
-			g: 0.19607843137254902,
-			b: 0.39215686274509803
-		},
-		'163264'
-	);
-
-	assert.deepEqual(
-		parse('#163264ff'),
-		{
-			mode: 'rgb',
-			r: 0.08627450980392157,
-			g: 0.19607843137254902,
-			b: 0.39215686274509803,
-			alpha: 1
-		},
-		'#163264ff'
-	);
-
-	assert.deepEqual(
-		parse('163264FF'),
-		{
-			mode: 'rgb',
-			r: 0.08627450980392157,
-			g: 0.19607843137254902,
-			b: 0.39215686274509803,
-			alpha: 1
-		},
-		'163264FF'
-	);
-});
-
-test('rgb', t => {
-	assert.deepEqual(
-		parse('rgb(255, 0, 0)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgb legacy'
-	);
-
-	assert.deepEqual(
-		parse('rgb(100%, 0%, 0%)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgb legacy (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('rgba(255, 0, 0, 0.5)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb', alpha: 0.5 },
-		'rgba legacy'
-	);
-
-	assert.deepEqual(
-		parse('rgba(100%, 0%, 0%, 50%)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb', alpha: 0.5 },
-		'rgba legacy (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('rgb(255  0  0)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgb current'
-	);
-
-	assert.deepEqual(
-		parse('rgb(100% 0%   0%)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgb current (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('rgb(255 0  0 / 0.5)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb', alpha: 0.5 },
-		'rgba current'
-	);
-
-	assert.deepEqual(
-		parse('rgb(100% 0% 0% / 50%)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb', alpha: 0.5 },
-		'rgba current (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('rgba(255, 0, 0, 150%)'),
-		{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 1 },
-		'rgb legacy, clamp alpha > 1'
-	);
-
-	assert.deepEqual(
-		parse('rgba(255, 0, 0, -50%)'),
-		{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0 },
-		'rgb legacy, clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		parse('rgb(255 0 0 / 150%)'),
-		{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 1 },
-		'rgb modern, clamp alpha > 1'
-	);
-
-	assert.deepEqual(
-		parse('rgb(255 0 0 / -50%)'),
-		{ mode: 'rgb', r: 1, g: 0, b: 0, alpha: 0 },
-		'rgb modern, clamp alpha < 0'
-	);
-});
-
-test('hsl', t => {
-	assert.deepEqual(
-		parse('hsl(0, 1, 0.5)'),
-		undefined,
-		'hsl legacy (no percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(120, 100%, 50%)'),
-		{ h: 120, s: 1, l: 0.5, mode: 'hsl' },
-		'hsl legacy (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(120deg, 100%, 50%)'),
-		{ h: 120, s: 1, l: 0.5, mode: 'hsl' },
-		'hsl legacy (deg)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(0.5turn, 100%, 50%)'),
-		{ h: 180, s: 1, l: 0.5, mode: 'hsl' },
-		'hsl legacy (turn)'
-	);
-
-	assert.deepEqual(
-		parse(`hsl(${Math.PI}rad, 100%, 50%)`),
-		{ h: 180, s: 1, l: 0.5, mode: 'hsl' },
-		'hsl legacy (rad)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(40grad, 100%, 50%)'),
-		{ h: 36, s: 1, l: 0.5, mode: 'hsl' },
-		'hsl legacy (grad)'
-	);
-
-	assert.deepEqual(
-		parse('hsla(0, 1, 0.5, 0.5)'),
-		undefined,
-		'hsla legacy (no percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsla(240, 100%, 50%, 50%)'),
-		{ h: 240, s: 1, l: 0.5, mode: 'hsl', alpha: 0.5 },
-		'hsla legacy (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(0 100 50)'),
-		{ h: 0, s: 1, l: 0.5, mode: 'hsl' },
-		'hsl current (no percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(180 100% 50%)'),
-		{ h: 180, s: 1, l: 0.5, mode: 'hsl' },
-		'hsl current (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(0 100 50 / 0.5)'),
-		{ h: 0, s: 1, l: 0.5, mode: 'hsl', alpha: 0.5 },
-		'hsla current (no percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsl(0 100% 50% / 50%)'),
-		{ h: 0, s: 1, l: 0.5, mode: 'hsl', alpha: 0.5 },
-		'hsla current (percentage)'
-	);
-
-	assert.deepEqual(
-		parse('hsla(240, 100%, 50%, -50%)'),
-		{ mode: 'hsl', h: 240, s: 1, l: 0.5, alpha: 0 },
-		'hsl legacy, clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		parse('hsla(240, 100%, 50%, 150%)'),
-		{ mode: 'hsl', h: 240, s: 1, l: 0.5, alpha: 1 },
-		'hsl legacy, clamp alpha > 1'
-	);
-
-	assert.deepEqual(
-		parse('hsl(240 100% 50% / -50%)'),
-		{ mode: 'hsl', h: 240, s: 1, l: 0.5, alpha: 0 },
-		'hsl modern, clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		parse('hsla(240 100% 50% / 150%)'),
-		{ mode: 'hsl', h: 240, s: 1, l: 0.5, alpha: 1 },
-		'hsl modern, clamp alpha > 1'
-	);
-});
-
-test('hwb', t => {
-	assert.deepEqual(
-		parse('hwb(100 0% 0%)'),
-		{ h: 100, w: 0, b: 0, mode: 'hwb' },
-		'black'
-	);
-
-	assert.deepEqual(
-		parse('hwb(200 150% 150%)'),
-		{ h: 200, w: 1.5, b: 1.5, mode: 'hwb' },
-		'grey'
-	);
-
-	assert.deepEqual(
-		parse('hwb(200 10% 30% / 50%)'),
-		{ h: 200, w: 0.1, b: 0.3, alpha: 0.5, mode: 'hwb' },
-		'hwba'
-	);
-
-	assert.deepEqual(
-		parse('hwb(60deg 25 100 / 0.5)'),
-		{
-			h: 60,
-			w: 0.25,
-			b: 1,
-			alpha: 0.5,
-			mode: 'hwb'
-		},
-		'<number>'
-	);
-
-	assert.deepEqual(
-		parse('hwb(50deg 25 100 / -0.5)'),
-		{ mode: 'hwb', h: 50, w: 0.25, b: 1, alpha: 0 },
-		'clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		parse('hwb(50deg 25 100 / 150%)'),
-		{ mode: 'hwb', h: 50, w: 0.25, b: 1, alpha: 1 },
-		'clamp alpha > 1'
-	);
-});
-
-test('transparent', t => {
-	assert.deepEqual(parse('transparent'), {
-		r: 0,
-		g: 0,
-		b: 0,
-		alpha: 0,
-		mode: 'rgb'
-	});
-});
-
-test('lab()', t => {
-	assert.deepEqual(
-		parse('lab(50% -5 10 / 50%)'),
-		{ l: 50, a: -5, b: 10, alpha: 0.5, mode: 'lab' },
-		'lab + alpha'
-	);
-
-	assert.deepEqual(
-		parse('lab(50% -5 10)'),
-		{ l: 50, a: -5, b: 10, mode: 'lab' },
-		'lab with percentage'
-	);
-
-	assert.deepEqual(
-		parse('lab(130 -45 +1000)'),
-		{ l: 100, a: -45, b: 1000, mode: 'lab' },
-		'clamp L to 100'
-	);
-
-	assert.deepEqual(
-		parse('lab(-1 -45 +1000)'),
-		{ l: 0, a: -45, b: 1000, mode: 'lab' },
-		'clamp L to 0'
-	);
-
-	assert.deepEqual(
-		parse('lab(40 -10 10 / -0.5)'),
-		{ mode: 'lab', l: 40, a: -10, b: 10, alpha: 0 },
-		'clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		parse('lab(40 -10 10 / 1.5)'),
-		{ mode: 'lab', l: 40, a: -10, b: 10, alpha: 1 },
-		'clamp alpha > 1'
-	);
-});
-
-test('lch()', t => {
-	assert.deepEqual(
-		parse('lch(50% 3 240 / 50%)'),
-		{ l: 50, c: 3, h: 240, alpha: 0.5, mode: 'lch' },
-		'lch + alpha'
-	);
-
-	assert.deepEqual(
-		parse('lch(50% -3 240deg / 50%)'),
-		{ l: 50, c: 0, h: 240, alpha: 0.5, mode: 'lch' },
-		'lch negative c'
-	);
-
-	assert.deepEqual(
-		parse('lch(50% 3 240)'),
-		{ l: 50, c: 3, h: 240, mode: 'lch' },
-		'lch with percentage'
-	);
-
-	assert.deepEqual(
-		parse('lch(130 -45 480deg)'),
-		{ l: 100, c: 0, h: 480, mode: 'lch' },
-		'clamp L to 100, C to 0'
-	);
-
-	assert.deepEqual(
-		parse('lch(-1 -45 -480deg)'),
-		{ l: 0, c: 0, h: -480, mode: 'lch' },
-		'clamp L to 0, C to 0'
-	);
-
-	assert.deepEqual(
-		parse('lch(40 5 10 / -0.5)'),
-		{ mode: 'lch', l: 40, c: 5, h: 10, alpha: 0 },
-		'clamp alpha < 0'
-	);
-
-	assert.deepEqual(
-		parse('lch(40 5 10 / 1.5)'),
-		{ mode: 'lch', l: 40, c: 5, h: 10, alpha: 1 },
-		'clamp alpha > 1'
-	);
-});
-
-test('undefined', t => {
-	assert.equal(parse(undefined), undefined);
-});
-
-test('Issue #204', t => {
-	assert.equal(parse('oklch(70% 0..1 156)'), undefined);
-});
diff --git a/test/prophoto.test.js b/test/prophoto.test.js
deleted file mode 100644
index 5267862c..00000000
--- a/test/prophoto.test.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { prophoto, rgb, formatCss } from '../src/index.js';
-
-test('prophoto', t => {
-	assert.deepEqual(
-		prophoto('white'),
-		{
-			mode: 'prophoto',
-			r: 0.9999999886664714,
-			g: 1.000000032778334,
-			b: 0.9999999636791803
-		},
-		'white'
-	);
-	assert.deepEqual(
-		prophoto('black'),
-		{ mode: 'prophoto', r: 0, g: 0, b: 0 },
-		'black'
-	);
-	assert.deepEqual(
-		prophoto('red'),
-		{
-			mode: 'prophoto',
-			r: 0.7022480690905015,
-			g: 0.2757205683151893,
-			b: 0.10354759457098542
-		},
-		'red'
-	);
-});
-
-test('color(prophoto-rgb)', t => {
-	assert.deepEqual(prophoto('color(prophoto-rgb 1 0 0 / 0.25)'), {
-		r: 1,
-		g: 0,
-		b: 0,
-		alpha: 0.25,
-		mode: 'prophoto'
-	});
-	assert.deepEqual(prophoto('color(prophoto-rgb 0% 50% 0.5 / 25%)'), {
-		r: 0,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'prophoto'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(prophoto-rgb 0% 50% 0.5 / 25%)'),
-		'color(prophoto-rgb 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(
-		rgb('color(prophoto-rgb none 0.5 none)'),
-		'prophoto to rgb is ok'
-	);
-	assert.deepEqual(
-		rgb('color(prophoto-rgb none 0.5 none)'),
-		rgb('color(prophoto-rgb 0 0.5 0')
-	);
-	assert.ok(prophoto('rgb(none 100 20)'), 'rgb to prophoto is ok');
-	assert.deepEqual(prophoto('rgb(none 100 20)'), prophoto('rgb(0 100 20)'));
-});
diff --git a/test/random.test.js b/test/random.test.js
deleted file mode 100644
index 35aead9d..00000000
--- a/test/random.test.js
+++ /dev/null
@@ -1,22 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { random } from '../src/index.js';
-
-test('random (rgb)', test => {
-	let c1 = random();
-	let c2 = random('rgb', { r: 0.1 });
-	let c3 = random('rgb', { r: [0.4, 0.6] });
-
-	assert.equal(c1.mode, 'rgb');
-	assert.ok(c1.r >= 0);
-	assert.ok(c1.r <= 1);
-
-	assert.equal(c2.r, 0.1);
-	assert.ok(c3.r >= 0.4);
-	assert.ok(c3.r <= 0.6);
-});
-
-test('random (lch)', test => {
-	let c = random('lch');
-	assert.equal(c.mode, 'lch');
-});
diff --git a/test/rec2020.test.js b/test/rec2020.test.js
deleted file mode 100644
index 671ba89b..00000000
--- a/test/rec2020.test.js
+++ /dev/null
@@ -1,60 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { rec2020, rgb, formatCss } from '../src/index.js';
-
-test('rec2020', t => {
-	assert.deepEqual(
-		rec2020('white'),
-		{ mode: 'rec2020', r: 1, g: 1, b: 1 },
-		'white'
-	);
-	assert.deepEqual(
-		rec2020('black'),
-		{ mode: 'rec2020', r: 0, g: 0, b: 0 },
-		'black'
-	);
-	assert.deepEqual(
-		rec2020('red'),
-		{
-			mode: 'rec2020',
-			r: 0.7919771358198009,
-			g: 0.23097568481079728,
-			b: 0.07376147493817597
-		},
-		'red'
-	);
-});
-
-test('color(rec2020)', t => {
-	assert.deepEqual(rec2020('color(rec2020 1 0 0 / 0.25)'), {
-		r: 1,
-		g: 0,
-		b: 0,
-		alpha: 0.25,
-		mode: 'rec2020'
-	});
-	assert.deepEqual(rec2020('color(rec2020 0% 50% 0.5 / 25%)'), {
-		r: 0,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'rec2020'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(rec2020 0% 50% 0.5 / 25%)'),
-		'color(rec2020 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(rec2020 none 0.5 none)'), 'rec2020 to rgb is ok');
-	assert.deepEqual(
-		rgb('color(rec2020 none 0.5 none)'),
-		rgb('color(rec2020 0 0.5 0')
-	);
-	assert.ok(rec2020('rgb(none 100 20)'), 'rgb to rec2020 is ok');
-	assert.deepEqual(rec2020('rgb(none 100 20)'), rec2020('rgb(0 100 20)'));
-});
diff --git a/test/rgb.test.js b/test/rgb.test.js
deleted file mode 100644
index 48d24f71..00000000
--- a/test/rgb.test.js
+++ /dev/null
@@ -1,103 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { rgb, formatHex, formatCss } from '../src/index.js';
-
-test('rgb(Specifier)', t => {
-	assert.deepEqual(formatHex(rgb('#ffffff')), '#ffffff');
-
-	assert.deepEqual(
-		rgb('tomato'),
-		{ r: 1, g: 0.38823529411764707, b: 0.2784313725490196, mode: 'rgb' },
-		'named color'
-	);
-
-	assert.deepEqual(
-		rgb('rgb(255, 0, 0)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgb()'
-	);
-
-	assert.deepEqual(
-		rgb('rgba(255, 0, 0)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgba()'
-	);
-
-	assert.deepEqual(
-		rgb('rgb(100%, 0%, 0%)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgb()'
-	);
-
-	assert.deepEqual(
-		rgb('rgba(100%, 0%, 0%)'),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'rgba()'
-	);
-});
-
-test('rgb(Object)', t => {
-	assert.deepEqual(
-		rgb({ r: 1, g: 0, b: 0 }),
-		{ r: 1, g: 0, b: 0, mode: 'rgb' },
-		'red'
-	);
-
-	assert.deepEqual(
-		rgb({ r: 0.1, g: 0.2, b: 0.3, alpha: 0.4 }),
-		{ r: 0.1, g: 0.2, b: 0.3, alpha: 0.4, mode: 'rgb' },
-		'floating point'
-	);
-});
-
-test('color(srgb)', t => {
-	assert.deepEqual(
-		rgb('color(srgb 1 0 0 / 0.25)'),
-		{
-			r: 1,
-			g: 0,
-			b: 0,
-			alpha: 0.25,
-			mode: 'rgb'
-		},
-		'color(srgb 1 0 0 / 0.25)'
-	);
-	assert.deepEqual(rgb('color(srgb 0% 50% 0.5 / 25%)'), {
-		r: 0,
-		g: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'rgb'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss(rgb('color(srgb 1 0 0.5/1)')),
-		'color(srgb 1 0 0.5)',
-		'color(srgb 1 0 0.5/1)'
-	);
-});
-
-/*
-	See: https://emnudge.dev/blog/perfect-rgb-regex/
-*/
-test('exotic species', t => {
-	assert.equal(
-		formatCss(rgb('rgb(1-2-3)')),
-		'color(srgb 0.00392156862745098 -0.00784313725490196 -0.011764705882352941)'
-	);
-	assert.equal(
-		formatCss(rgb('rgb(1-.2.3)')),
-		'color(srgb 0.00392156862745098 -0.0007843137254901962 0.001176470588235294)'
-	);
-	assert.equal(
-		formatCss(rgb('rgb(1 .2.3)')),
-		'color(srgb 0.00392156862745098 0.0007843137254901962 0.001176470588235294)'
-	);
-	assert.equal(
-		formatCss(rgb('rgb(.1.2.3)')),
-		'color(srgb 0.0003921568627450981 0.0007843137254901962 0.001176470588235294)'
-	);
-	assert.equal(formatCss(rgb('rgb(1.2.3)')), undefined);
-});
diff --git a/test/samples.test.js b/test/samples.test.js
deleted file mode 100644
index 7769ad25..00000000
--- a/test/samples.test.js
+++ /dev/null
@@ -1,114 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { interpolate, samples, formatHex } from '../src/index.js';
-
-test('11 swatches between black and white in RGB', t => {
-	assert.deepEqual(
-		samples(11)
-			.map(interpolate(['#fff', '#000']))
-			.map(formatHex),
-		[
-			'#ffffff',
-			'#e6e6e6',
-			'#cccccc',
-			'#b3b3b3',
-			'#999999',
-			'#808080',
-			'#666666',
-			'#4d4d4d',
-			'#333333',
-			'#191919',
-			'#000000'
-		]
-	);
-});
-
-test('11 swatches between black and white in Lab', t => {
-	assert.deepEqual(
-		samples(11)
-			.map(interpolate(['#fff', '#000'], 'lab'))
-			.map(formatHex),
-		[
-			'#ffffff',
-			'#e2e2e2',
-			'#c6c6c6',
-			'#ababab',
-			'#919191',
-			'#777777',
-			'#5e5e5e',
-			'#474747',
-			'#303030',
-			'#1b1b1b',
-			'#000000'
-		]
-	);
-});
-
-test('11 swatches between black and white in Lch', t => {
-	assert.deepEqual(
-		samples(11)
-			.map(interpolate(['#fff', '#000'], 'lch'))
-			.map(formatHex),
-		[
-			'#ffffff',
-			'#e2e2e2',
-			'#c6c6c6',
-			'#ababab',
-			'#919191',
-			'#777777',
-			'#5e5e5e',
-			'#474747',
-			'#303030',
-			'#1b1b1b',
-			'#000000'
-		]
-	);
-});
-
-test('11 swatches between black and white in DIN99o', t => {
-	assert.deepEqual(
-		samples(11)
-			.map(interpolate(['#fff', '#000'], 'dlab'))
-			.map(formatHex),
-		[
-			'#ffffff',
-			'#dedede',
-			'#bfbfbf',
-			'#a2a2a2',
-			'#868686',
-			'#6d6d6d',
-			'#555555',
-			'#3f3f3f',
-			'#2b2b2b',
-			'#191919',
-			'#000000'
-		]
-	);
-
-	// assert.deepEqual(
-	// 	samples(11).map(interpolate(['red', 'white'], 'dlch')).map(formatHex),
-	// 	[]
-	// )
-});
-
-// test('default cubehelix scale', function(test) {
-
-// 	let start = cubehelix({
-// 		h: 300,
-// 		s: 0.5,
-// 		l: 0
-// 	});
-
-// 	let end = cubehelix({
-// 		h: -240,
-// 		s: 0.5,
-// 		l: 1
-// 	})
-
-// 	assert.deepEqual(
-// 		samples(10).map(interpolate([start, end], 'cubehelix')).map(formatHex),
-// 		['#000000', '#1a1935', '#15474e', '#2b6f39', '#767b33', '#c17a6f', '#d490c6', '#c3c0f2', '#ceebef', '#ffffff']
-// 	)
-
-// 	;
-// });
diff --git a/test/tree-shaking/not-tree-shaken.js b/test/tree-shaking/not-tree-shaken.js
deleted file mode 100644
index 6bd60397..00000000
--- a/test/tree-shaking/not-tree-shaken.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import { parseHex, convertRgbToHsl, serializeHsl } from '../../src/index.js';
-
-console.log(serializeHsl(convertRgbToHsl(parseHex('#ffcc00'))));
diff --git a/test/tree-shaking/tree-shaken.js b/test/tree-shaking/tree-shaken.js
deleted file mode 100644
index c744f515..00000000
--- a/test/tree-shaking/tree-shaken.js
+++ /dev/null
@@ -1,3 +0,0 @@
-import { parseHex, convertRgbToHsl, serializeHsl } from '../../src/index-fn.js';
-
-console.log(serializeHsl(convertRgbToHsl(parseHex('#ffcc00'))));
diff --git a/test/visual/gamut-map-newton.js b/test/visual/gamut-map-newton.js
deleted file mode 100644
index b52712ef..00000000
--- a/test/visual/gamut-map-newton.js
+++ /dev/null
@@ -1,89 +0,0 @@
-const OKLAB_TO_LMS = [
-	[0.99999999845051981432, 0.39633779217376785678, 0.21580375806075880339],
-	[1.0000000088817607767, -0.1055613423236563494, -0.063854174771705903402],
-	[1.0000000546724109177, -0.089484182094965759684, -1.2914855378640917399]
-];
-
-const LMS_TO_XYZ_D65 = [
-	[1.2268798733741557, -0.5578149965554813, 0.28139105017721583],
-	[-0.04057576262431372, 1.1122868293970594, -0.07171106666151701],
-	[-0.07637294974672142, -0.4214933239627914, 1.5869240244272418]
-];
-
-const XYZ_D65_TO_LRGB = [
-	[3.2409699419045226, -1.537383177570094, -0.4986107602930034],
-	[-0.9692436362808796, 1.8759675015077202, 0.04155505740717559],
-	[0.05563007969699366, -0.20397695888897652, 1.0569715142428786]
-];
-
-const LMS_TO_LRGB = multiplyMatrices(XYZ_D65_TO_LRGB, LMS_TO_XYZ_D65);
-
-function multiplyMatrices(a, b) {
-	let res = [[], [], []];
-	for (let i = 0; i < 3; i++) {
-		for (let j = 0; j < 3; j++) {
-			res[i][j] =
-				a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];
-		}
-	}
-	return res;
-}
-
-function multiplyMatrixWithVector(m, v) {
-	return [
-		m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2],
-		m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2],
-		m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2]
-	];
-}
-
-function multiplyComponentWise(arr1, arr2) {
-	return arr1.map((it, i) => it * arr2[i]);
-}
-
-function multiplyVectors(arr1, arr2) {
-	return arr1.reduce((acc, curr, i) => {
-		return acc + curr * arr2[i];
-	}, 0);
-}
-
-export function GamutMapNewton(original) {
-	const zero_a_b = [0, original[1], original[2]];
-	let alpha = 1;
-	let res_oklab = original.slice();
-	let res_rgb = multiplyMatrixWithVector(
-		LMS_TO_LRGB,
-		multiplyMatrixWithVector(OKLAB_TO_LMS, res_oklab).map(it => it ** 3)
-	);
-	for (let comp = 0; comp < 3; comp++) {
-		if (res_rgb[comp] >= 0 && res_rgb[comp] <= 1) continue;
-		let target = res_rgb[comp] > 1 ? 1 : 0;
-		for (let iter = 0; iter < 6; iter++) {
-			let residual =
-				multiplyVectors(
-					LMS_TO_LRGB[comp],
-					multiplyMatrixWithVector(OKLAB_TO_LMS, res_oklab).map(
-						it => it ** 3
-					)
-				) - target;
-			if (Math.abs(residual) < 1e-15) break;
-			let gradient = multiplyVectors(
-				LMS_TO_LRGB[comp],
-				multiplyComponentWise(
-					multiplyMatrixWithVector(OKLAB_TO_LMS, res_oklab).map(
-						it => 3 * it ** 2
-					),
-					multiplyMatrixWithVector(OKLAB_TO_LMS, zero_a_b)
-				)
-			);
-			alpha -= residual / gradient;
-			res_oklab[1] = alpha * original[1];
-			res_oklab[2] = alpha * original[2];
-		}
-		res_rgb = multiplyMatrixWithVector(
-			LMS_TO_LRGB,
-			multiplyMatrixWithVector(OKLAB_TO_LMS, res_oklab).map(it => it ** 3)
-		);
-	}
-	return [res_oklab, res_rgb];
-}
diff --git a/test/visual/gamut-mapping-algorithms.js b/test/visual/gamut-mapping-algorithms.js
deleted file mode 100644
index bef3b337..00000000
--- a/test/visual/gamut-mapping-algorithms.js
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
-	Gamut clipping strategies
-	-------------------------
- */
-
-import {
-	clampGamut,
-	converter,
-	differenceEuclidean,
-	getMode,
-	inGamut,
-	oklab
-} from '../../src/index.js';
-
-import { GamutMapNewton } from './gamut-map-newton.js';
-
-export function toGamutCSSColor4(
-	dest = 'rgb',
-	mode = 'oklch',
-	delta = differenceEuclidean('oklch'),
-	jnd = 0.02
-) {
-	const inDestinationGamut = inGamut(dest);
-	const clipToGamut = clampGamut(dest);
-	const destConv = converter(dest);
-
-	const ucs = converter(mode);
-	const { ranges } = getMode(mode);
-
-	const gamutDef = getMode(dest);
-	const White = { mode: dest };
-	const Black = { mode: dest };
-	gamutDef.channels.forEach(ch => {
-		Black[ch] = gamutDef.ranges[ch][0];
-		White[ch] = gamutDef.ranges[ch][1];
-	});
-
-	return color => {
-		if (color === undefined) {
-			return undefined;
-		}
-		const candidate = { ...ucs(color) };
-		if (candidate.l >= ranges.l[1]) {
-			const res = { ...White };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (candidate.l <= ranges.l[0]) {
-			const res = { ...Black };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (inDestinationGamut(candidate)) {
-			return destConv(candidate);
-		}
-
-		let start = 0;
-		let end = candidate.c;
-		let clipped;
-		/* Corresponds to about 10 steps */
-		let epsilon = (ranges.c[1] - ranges.c[0]) / 1000;
-		while (end - start > epsilon) {
-			candidate.c = (start + end) * 0.5;
-			if (inDestinationGamut(candidate)) {
-				start = candidate.c;
-			} else {
-				clipped = clipToGamut(candidate);
-				if (delta(candidate, clipped) <= jnd) {
-					return clipped;
-				}
-				end = candidate.c;
-			}
-		}
-		return destConv(candidate);
-	};
-}
-
-export function toGamutCSSColor4Smooth(
-	dest = 'rgb',
-	mode = 'oklch',
-	delta = differenceEuclidean('oklch'),
-	jnd = 0.02
-) {
-	const inDestinationGamut = inGamut(dest);
-	const clipToGamut = clampGamut(dest);
-	const destConv = converter(dest);
-
-	const ucs = converter(mode);
-	const { ranges } = getMode(mode);
-
-	const gamutDef = getMode(dest);
-	const White = { mode: dest };
-	const Black = { mode: dest };
-	gamutDef.channels.forEach(ch => {
-		Black[ch] = gamutDef.ranges[ch][0];
-		White[ch] = gamutDef.ranges[ch][1];
-	});
-
-	return color => {
-		if (color === undefined) {
-			return undefined;
-		}
-		const candidate = { ...ucs(color) };
-		if (candidate.l >= ranges.l[1]) {
-			const res = { ...White };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (candidate.l <= ranges.l[0]) {
-			const res = { ...Black };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (inDestinationGamut(candidate)) {
-			return destConv(candidate);
-		}
-
-		let start = 0;
-		let end = candidate.c;
-		let epsilon = (ranges.c[1] - ranges.c[0]) / 1000;
-		let lower_bound_in_gamut = true;
-		let clipped = clipToGamut(candidate);
-		let e = delta(clipped, candidate);
-		if (e < jnd) {
-			return clipped;
-		}
-
-		while (end - start > epsilon) {
-			candidate.c = (start + end) * 0.5;
-			if (lower_bound_in_gamut && inDestinationGamut(candidate)) {
-				start = candidate.c;
-			} else {
-				clipped = clipToGamut(candidate);
-				e = delta(candidate, clipped);
-				if (e <= jnd) {
-					if (jnd - e < epsilon) {
-						return clipped;
-					} else {
-						lower_bound_in_gamut = false;
-						start = candidate.c;
-					}
-				} else {
-					end = candidate.c;
-				}
-			}
-		}
-		return destConv(candidate);
-	};
-}
-
-export function toGamutFuzzy(
-	dest = 'rgb',
-	mode = 'oklch',
-	delta = differenceEuclidean('oklch'),
-	jnd = 0.02
-) {
-	const inDestinationGamut = inGamut(dest);
-	const clipToGamut = clampGamut(dest);
-	const destConv = converter(dest);
-
-	const ucs = converter(mode);
-	const { ranges } = getMode(mode);
-
-	const gamutDef = getMode(dest);
-	const White = { mode: dest };
-	const Black = { mode: dest };
-	gamutDef.channels.forEach(ch => {
-		Black[ch] = gamutDef.ranges[ch][0];
-		White[ch] = gamutDef.ranges[ch][1];
-	});
-
-	return color => {
-		if (color === undefined) {
-			return undefined;
-		}
-		const candidate = { ...ucs(color) };
-		if (candidate.l >= ranges.l[1]) {
-			const res = { ...White };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (candidate.l <= ranges.l[0]) {
-			const res = { ...Black };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (inDestinationGamut(candidate)) {
-			return destConv(candidate);
-		}
-		let clipped = clipToGamut(candidate);
-		if (delta(candidate, clipped) <= jnd) {
-			return clipped;
-		}
-
-		let start = 0;
-		let end = candidate.c;
-
-		/* Corresponds to about 10 steps */
-		let epsilon = (ranges.c[1] - ranges.c[0]) / 1000;
-		while (end - start > epsilon) {
-			candidate.c = (start + end) * 0.5;
-			clipped = clipToGamut(candidate);
-			if (
-				inDestinationGamut(candidate) ||
-				delta(candidate, clipped) <= jnd
-			) {
-				start = candidate.c;
-			} else {
-				end = candidate.c;
-			}
-		}
-		return inDestinationGamut(candidate) ? destConv(candidate) : clipped;
-	};
-}
-
-export function toGamutCLReduce(
-	dest = 'rgb',
-	mode = 'oklch',
-	delta = differenceEuclidean('oklch')
-) {
-	const inDestinationGamut = inGamut(dest);
-	const destConv = converter(dest);
-
-	const ucs = converter(mode);
-	const { ranges } = getMode(mode);
-
-	const gamutDef = getMode(dest);
-	const White = { mode: dest };
-	const Black = { mode: dest };
-	gamutDef.channels.forEach(ch => {
-		Black[ch] = gamutDef.ranges[ch][0];
-		White[ch] = gamutDef.ranges[ch][1];
-	});
-
-	return color => {
-		if (color === undefined) {
-			return undefined;
-		}
-		const candidate = { ...ucs(color) };
-		if (candidate.l >= ranges.l[1]) {
-			const res = { ...White };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (candidate.l <= ranges.l[0]) {
-			const res = { ...Black };
-			if (color.alpha !== undefined) {
-				res.alpha = color.alpha;
-			}
-			return res;
-		}
-		if (inDestinationGamut(candidate)) {
-			return destConv(candidate);
-		}
-
-		let startC = 0;
-		let alpha = 0.5;
-		let startL =
-			((ranges.l[1] + ranges.l[0]) / 2) * alpha +
-			candidate.l * (1 - alpha);
-		let endC = candidate.c;
-		let endL = candidate.l;
-		let epsilonC = (ranges.c[1] - ranges.c[0]) / 1000;
-		let epsilonL = (ranges.l[1] - ranges.l[0]) / 1000;
-		while (endC - startC > epsilonC || endL - startL > epsilonL) {
-			candidate.c = (startC + endC) * 0.5;
-			candidate.l = (startL + endL) * 0.5;
-			if (inDestinationGamut(candidate)) {
-				startC = candidate.c;
-				startL = candidate.l;
-			} else {
-				endC = candidate.c;
-				endL = candidate.l;
-			}
-		}
-		return destConv(candidate);
-	};
-}
-
-export function toGamutNewton() {
-	return color => {
-		const color_oklab = oklab(color);
-		const [, res_rgb] = GamutMapNewton([
-			color_oklab.l,
-			color_oklab.a,
-			color_oklab.b
-		]);
-		return {
-			mode: 'lrgb',
-			r: res_rgb[0],
-			g: res_rgb[1],
-			b: res_rgb[2]
-		};
-	};
-}
diff --git a/test/visual/gamut-mapping.html b/test/visual/gamut-mapping.html
deleted file mode 100644
index 428884fd..00000000
--- a/test/visual/gamut-mapping.html
+++ /dev/null
@@ -1,397 +0,0 @@
-<!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="utf-8" />
-		<meta name="viewport" content="width=device-width, initial-scale=1" />
-		<title>Gamut mapping algorithms</title>
-
-		<style>
-			body {
-				padding: 0;
-				margin: 0;
-			}
-
-			.side-by-side {
-				display: flex;
-				flex-wrap: nowrap;
-				justify-content: center;
-				border: 1rem solid #fff;
-				background: #f0f0f0;
-				padding: 0.5rem;
-				gap: 1rem;
-				height: 400px;
-				resize: vertical;
-				overflow: hidden;
-			}
-
-			.spectrum {
-				margin: 0;
-				display: flex;
-				flex-direction: column;
-				aspect-ratio: 1 / 1.1;
-				justify-content: space-between;
-			}
-		</style>
-
-		<script type="module">
-			import {
-				clampChroma,
-				clampGamut,
-				differenceEuclidean,
-				dlch,
-				getMode,
-				inGamut,
-				lch,
-				lch65,
-				oklch,
-				rgb,
-				toGamut
-			} from '../../src/index.js';
-			import {
-				toGamutCSSColor4,
-				toGamutCSSColor4Smooth,
-				toGamutFuzzy,
-				toGamutCLReduce,
-				toGamutNewton
-			} from './gamut-mapping-algorithms.js';
-
-			import {
-				formDataMap,
-				draw,
-				scaleLinear,
-				scalePow
-			} from './utils.js';
-
-			const inRgb = inGamut('rgb');
-			const toRgb = clampGamut('rgb');
-
-			/* DOM Elements */
-			const controlsForm = document.querySelector('#controls');
-			const outputs = [...document.querySelectorAll('output[for]')];
-
-			const canvasLeft = document.querySelector('#canvas-left canvas');
-			const canvasRight = document.querySelector('#canvas-right canvas');
-
-			const CANVAS_SIZE = 200;
-			[canvasLeft, canvasRight].forEach(c => {
-				c.width = CANVAS_SIZE;
-				c.height = CANVAS_SIZE;
-			});
-
-			const METHODS = {
-				clip: () => c => toRgb(c),
-				css4: toGamutCSSColor4,
-				'css4-smooth': toGamutCSSColor4Smooth,
-				fuzzy: toGamutFuzzy,
-				'chroma-reduce': function (gamut, space) {
-					return c => clampChroma(c, space);
-				},
-				'cl-reduce': toGamutCLReduce,
-				culori: toGamut,
-				newton: toGamutNewton
-			};
-
-			const CONVERTERS = {
-				lch,
-				oklch,
-				lch65,
-				dlch
-			};
-
-			const scaleJND = scalePow([0, 100], [0, 100], 4);
-			const widen = (range, inc) => {
-				return [range[0] * (1 + inc), range[1] * (1 + inc)];
-			};
-
-			function redraw(controls) {
-				let ranges = getMode(controls.drawspace).ranges;
-
-				const scaleL = scaleLinear(
-					[CANVAS_SIZE, 0],
-					widen(ranges.l, 0)
-				);
-				const scaleC = scaleLinear(
-					[0, CANVAS_SIZE],
-					widen(ranges.c, 0)
-				);
-
-				function roughlySame(color, ref) {
-					return (
-						differenceEuclidean(controls.space)(color, ref) <=
-						controls.jnd
-					);
-				}
-
-				function color(i, j) {
-					const res = {
-						mode: controls.drawspace,
-						l: scaleL(j),
-						c: scaleC(i),
-						h: controls.hue
-					};
-					if (!controls.showgamut || controls.showgamut === 'none') {
-						return res;
-					}
-
-					const nextColorToRight = {
-						mode: controls.drawspace,
-						l: scaleL(j),
-						c: scaleC(i + 1),
-						h: controls.hue
-					};
-
-					let isGamutLimit = false;
-
-					if (controls.showgamut === 'strict') {
-						isGamutLimit = inRgb(res) && !inRgb(nextColorToRight);
-					} else if (controls.showgamut === 'loose') {
-						isGamutLimit =
-							(inRgb(res) || roughlySame(res, toRgb(res))) &&
-							!(
-								inRgb(nextColorToRight) ||
-								roughlySame(
-									nextColorToRight,
-									toRgb(nextColorToRight)
-								)
-							);
-					}
-					if (isGamutLimit) {
-						return 'white';
-					}
-					return res;
-				}
-
-				const gamutMapLeft = controls.method_left(
-					'rgb',
-					controls.space,
-					differenceEuclidean(controls.space),
-					controls.jnd
-				);
-
-				const gamutMapRight = controls.method_right(
-					'rgb',
-					controls.space,
-					differenceEuclidean(controls.space),
-					controls.jnd
-				);
-
-				let perfNow = performance.now();
-
-				draw(canvasLeft, (i, j) => {
-					const res = rgb(gamutMapLeft(color(i, j)));
-					if (!res) {
-						console.log(color(i, j), 'gamutMapLeft');
-					}
-					return res;
-				});
-
-				console.log('left: ', performance.now() - perfNow);
-
-				const epsilon = 1e-3;
-				function diff(colorA, colorB) {
-					colorA = rgb(colorA);
-					colorB = rgb(colorB);
-					if (Math.abs(colorA.r - colorB.r) > epsilon) {
-						return true;
-					}
-					if (Math.abs(colorA.g - colorB.g) > epsilon) {
-						return true;
-					}
-					if (Math.abs(colorA.b - colorB.b) > epsilon) {
-						return true;
-					}
-					return false;
-				}
-
-				perfNow = performance.now();
-				draw(canvasRight, (i, j) => {
-					const res = gamutMapRight(color(i, j));
-					if (!res) {
-						console.log(color(i, j), 'gamutMapRight');
-					}
-					if (!controls.showdiff || controls.showdiff === 'none') {
-						return rgb(res);
-					}
-					const ref = gamutMapLeft(color(i, j));
-					if (controls.showdiff === 'strict') {
-						return rgb(diff(res, ref) ? 'magenta' : res);
-					}
-					if (controls.showdiff === 'loose') {
-						return rgb(roughlySame(res, ref) ? res : 'magenta');
-					}
-					return rgb(res);
-				});
-				console.log('right: ', performance.now() - perfNow);
-			}
-
-			controlsForm.addEventListener('input', e => {
-				const controls = formDataMap(e.currentTarget, {
-					jnd: v => scaleJND(v),
-					method_left: v => METHODS[v],
-					method_right: v => METHODS[v]
-				});
-				outputs.forEach(el => (el.value = controls[el.htmlFor]));
-				redraw(controls);
-			});
-			controlsForm.dispatchEvent(new Event('input'));
-		</script>
-	</head>
-	<body>
-		<h1>Gamut mapping algorithms</h1>
-
-		<form id="controls">
-			<fieldset>
-				<legend>Show difference</legend>
-				<label
-					><input type="radio" name="showdiff" value="none" checked />
-					None</label
-				>
-				<label
-					><input type="radio" name="showdiff" value="strict" />
-					Strict</label
-				>
-				<label
-					><input type="radio" name="showdiff" value="loose" />
-					Loose</label
-				>
-			</fieldset>
-
-			<div class="side-by-side">
-				<figure class="spectrum" id="canvas-left">
-					<canvas></canvas>
-					<figcaption>
-						<label
-							>Method:
-							<select name="method_left">
-								<option value="clip" selected>clip</option>
-								<option value="chroma-reduce">
-									chroma-reduce
-								</option>
-								<option value="css4">css-color-4</option>
-								<option value="css4-smooth">
-									css-color-4-smooth
-								</option>
-								<option value="fuzzy">fuzzy</option>
-								<option value="culori">culori.toGamut()</option>
-								<option value="cl-reduce">cl-reduce</option>
-								<option value="newton">
-									newton (@ccameron)
-								</option>
-							</select>
-						</label>
-					</figcaption>
-				</figure>
-				<figure class="spectrum" id="canvas-right">
-					<canvas></canvas>
-					<figcaption>
-						<label
-							>Method:
-							<select name="method_right">
-								<option value="clip" selected>clip</option>
-								<option value="chroma-reduce">
-									chroma-reduce
-								</option>
-								<option value="css4">css-color-4</option>
-								<option value="css4-smooth">
-									css-color-4-smooth
-								</option>
-								<option value="fuzzy">fuzzy</option>
-								<option value="culori">culori.toGamut()</option>
-								<option value="cl-reduce">cl-reduce</option>
-								<option value="newton">
-									newton (@ccameron)
-								</option>
-							</select>
-						</label>
-					</figcaption>
-				</figure>
-			</div>
-			<p>
-				<label>
-					Hue:
-					<input
-						id="hue"
-						name="hue"
-						type="range"
-						min="0"
-						max="360"
-						step="0.5"
-					/>
-				</label>
-				<output for="hue"></output>
-
-				<label>
-					JND:
-					<input
-						id="jnd"
-						type="range"
-						min="0"
-						max="100"
-						step="1"
-						name="jnd"
-					/>
-				</label>
-				<output for="jnd"></output>
-			</p>
-			<p>
-				Illustrate space:
-				<label
-					><input type="radio" name="drawspace" value="lch" checked />
-					LCH (D50)</label
-				>
-				<label
-					><input type="radio" name="drawspace" value="lch65" /> LCH
-					(D65)</label
-				>
-				<label
-					><input type="radio" name="drawspace" value="oklch" />
-					OKLCH</label
-				>
-				<label
-					><input type="radio" name="drawspace" value="dlch" /> DIN99o
-					LCH</label
-				>
-			</p>
-			<p>
-				Mapping space:
-				<label
-					><input type="radio" name="space" value="lch" checked /> LCH
-					(D50)</label
-				>
-				<label
-					><input type="radio" name="space" value="lch65" /> LCH
-					(D65)</label
-				>
-				<label
-					><input type="radio" name="space" value="oklch" />
-					OKLCH</label
-				>
-				<label
-					><input type="radio" name="space" value="dlch" /> DIN99o
-					LCH</label
-				>
-			</p>
-
-			<fieldset>
-				<legend>Show gamut</legend>
-				<label
-					><input
-						type="radio"
-						name="showgamut"
-						value="none"
-						checked
-					/>
-					None</label
-				>
-				<label
-					><input type="radio" name="showgamut" value="strict" />
-					Strict</label
-				>
-				<label
-					><input type="radio" name="showgamut" value="loose" />
-					Loose</label
-				>
-			</fieldset>
-		</form>
-	</body>
-</html>
diff --git a/test/visual/utils.js b/test/visual/utils.js
deleted file mode 100644
index 72803433..00000000
--- a/test/visual/utils.js
+++ /dev/null
@@ -1,99 +0,0 @@
-export function formDataMap(form, mappings = {}) {
-	const excludedTags = ['FIELDSET', 'OBJECT', 'OUTPUT'];
-	const excludedTypes = ['button', 'submit', 'reset', 'image'];
-
-	function shouldSubmit(el) {
-		if (!el.name) return false;
-		if (excludedTags.includes(el.tagName)) return false;
-		if (excludedTypes.includes(el.type)) return false;
-		if (el.type === 'radio' && !el.checked) return false;
-		if (el.type === 'checkbox' && !el.checked) return false;
-		if (el.disabled || el.matches(':disabled')) return false;
-		if (el.closest('datalist')) return false;
-		return true;
-	}
-
-	const result = {};
-
-	function append(key, val) {
-		if (Object.hasOwn(mappings, key)) {
-			val = mappings[key](val);
-		}
-		result[key] = Object.hasOwn(result, key)
-			? [].concat(result[key], val)
-			: val;
-	}
-
-	Array.from(form.elements).forEach(el => {
-		if (!shouldSubmit(el)) return;
-		const { name, type } = el;
-		if (type === 'number' || type === 'range') {
-			append(name, +el.value);
-		} else if (type === 'date' || type === 'datetime-local') {
-			append(name, el.valueAsDate());
-		} else if (type === 'file') {
-			append(name, el.files);
-		} else if (type === 'url') {
-			append(name, new URL(el.value));
-		} else if (type === 'select-one' || type === 'select-multiple') {
-			Array.from(el.selectedOptions).forEach(option =>
-				append(name, option.value)
-			);
-		} else {
-			append(name, el.value);
-		}
-	});
-
-	return result;
-}
-
-const to255 = v => Math.round(Math.max(0, Math.min(1, v)) * 255);
-
-export function draw(canvas, fn) {
-	const ctx = canvas.getContext('2d');
-	const w = canvas.width;
-	const h = canvas.height;
-	const imageData = ctx.createImageData(w, h);
-	for (let idx = 0, color; idx < imageData.data.length; ) {
-		color = fn((idx / 4) % w, Math.floor(idx / 4 / w));
-		if (!color) {
-			throw new Error('no color');
-		}
-		imageData.data[idx++] = to255(color.r);
-		imageData.data[idx++] = to255(color.g);
-		imageData.data[idx++] = to255(color.b);
-		imageData.data[idx++] = 255;
-	}
-	ctx.putImageData(imageData, 0, 0);
-}
-
-export function plotFunction(fn, domain, step = 1) {
-	const points = [];
-	const range = [Infinity, -Infinity];
-	let res, i;
-	for (i = domain[0]; i <= domain[1]; i += step) {
-		res = fn(i);
-		if (res < range[0]) {
-			range[0] = res;
-		}
-		if (res > range[1]) {
-			range[1] = res;
-		}
-		points.push([i, res]);
-	}
-	return { points, range };
-}
-
-export function scaleLinear(domain, range) {
-	return v => {
-		const t = (v - domain[0]) / (domain[1] - domain[0]);
-		return (t - 1) * range[0] + t * range[1];
-	};
-}
-
-export function scalePow(domain, range, exponent) {
-	return v => {
-		const t = Math.pow((v - domain[0]) / (domain[1] - domain[0]), exponent);
-		return (t - 1) * range[0] + t * range[1];
-	};
-}
diff --git a/test/wcag.test.js b/test/wcag.test.js
deleted file mode 100644
index eeacfe68..00000000
--- a/test/wcag.test.js
+++ /dev/null
@@ -1,15 +0,0 @@
-import { wcagLuminance, wcagContrast } from '../src/index.js';
-import test from 'node:test';
-import assert from 'node:assert';
-
-test('wcagLuminance', t => {
-	assert.equal(wcagLuminance('white'), 1);
-	assert.equal(wcagLuminance('black'), 0);
-	assert.equal(wcagLuminance('#999'), 0.31854677812509186);
-});
-
-test('wcagContrast', t => {
-	assert.equal(wcagContrast('black', 'white'), 21);
-	assert.equal(wcagContrast('white', 'black'), 21);
-	assert.equal(wcagContrast('red', 'red'), 1);
-});
diff --git a/test/xyb.test.js b/test/xyb.test.js
deleted file mode 100644
index c3130d01..00000000
--- a/test/xyb.test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { xyb, rgb, formatRgb, formatCss } from '../src/index.js';
-
-test('rgb -> xyb', t => {
-	assert.deepEqual(xyb('purple'), {
-		mode: 'xyb',
-		x: 0.013838974535428816,
-		y: 0.27055837298918495,
-		b: 0.1333134464452821
-	});
-});
-
-test('rgb -> xyb -> rgb', t => {
-	assert.deepEqual(
-		formatRgb(xyb('rgb(255, 255, 255)')),
-		'rgb(255, 255, 255)',
-		'white'
-	);
-
-	assert.deepEqual(formatRgb(xyb('rgb(0, 0, 0)')), 'rgb(0, 0, 0)', 'black');
-	assert.deepEqual(formatRgb(xyb('rgb(100, 0, 0)')), 'rgb(100, 0, 0)', 'red');
-	assert.deepEqual(
-		formatRgb(xyb('rgb(0, 120, 0)')),
-		'rgb(0, 120, 0)',
-		'blue'
-	);
-	assert.deepEqual(formatRgb(xyb('rgb(0, 0, 89)')), 'rgb(0, 0, 89)', 'green');
-});
-
-test('color(--xyb)', t => {
-	assert.deepEqual(xyb('color(--xyb 1 0 0 / 0.25)'), {
-		x: 1,
-		y: 0,
-		b: 0,
-		alpha: 0.25,
-		mode: 'xyb'
-	});
-	assert.deepEqual(xyb('color(--xyb 0% 50% 0.5 / 25%)'), {
-		x: 0,
-		y: 0.5,
-		b: 0.5,
-		alpha: 0.25,
-		mode: 'xyb'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--xyb 0% 50% 0.5 / 25%)'),
-		'color(--xyb 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--xyb none 0.5 none)'), 'xyb to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--xyb none 0.5 none)'),
-		rgb('color(--xyb 0 0.5 0')
-	);
-	assert.ok(xyb('rgb(none 100 20)'), 'rgb to xyb is ok');
-	assert.deepEqual(xyb('rgb(none 100 20)'), xyb('rgb(0 100 20)'));
-});
diff --git a/test/xyz50.test.js b/test/xyz50.test.js
deleted file mode 100644
index 9b5cfa74..00000000
--- a/test/xyz50.test.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { xyz50, rgb, formatCss } from '../src/index.js';
-
-test('xyz50', t => {
-	assert.deepEqual(
-		xyz50('white'),
-		{
-			mode: 'xyz50',
-			x: 0.9642956660812442,
-			y: 1.0000000361162846,
-			z: 0.8251045485672053
-		},
-		'white'
-	);
-	assert.deepEqual(xyz50('black'), { mode: 'xyz50', x: 0, y: 0, z: 0 });
-	assert.deepEqual(
-		xyz50('red'),
-		{
-			mode: 'xyz50',
-			x: 0.436065742824811,
-			y: 0.22249319175623702,
-			z: 0.013923904500943465
-		},
-		'red'
-	);
-	assert.deepEqual(
-		xyz50('#00cc0080'),
-		{
-			mode: 'xyz50',
-			x: 0.23256498648213272,
-			y: 0.43287600197031817,
-			z: 0.05862033437620246,
-			alpha: 0.5019607843137255
-		},
-		'#00cc0080'
-	);
-});
-
-test('color(xyz-d50)', t => {
-	assert.deepEqual(xyz50('color(xyz-d50 1 0 0 / 0.25)'), {
-		x: 1,
-		y: 0,
-		z: 0,
-		alpha: 0.25,
-		mode: 'xyz50'
-	});
-	assert.deepEqual(xyz50('color(xyz-d50 0% 50% 0.5 / 25%)'), {
-		x: 0,
-		y: 0.5,
-		z: 0.5,
-		alpha: 0.25,
-		mode: 'xyz50'
-	});
-});
-
-test('color(--xyz-d50)', t => {
-	assert.deepEqual(xyz50('color(--xyz-d50 1 0 0 / 0.25)'), undefined);
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(xyz-d50 0% 50% 0.5 / 25%)'),
-		'color(xyz-d50 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(xyz-d50 none 0.5 none)'), 'xyz50 to rgb is ok');
-	assert.deepEqual(
-		rgb('color(xyz-d50 none 0.5 none)'),
-		rgb('color(xyz-d50 0 0.5 0')
-	);
-	assert.ok(xyz50('rgb(none 100 20)'), 'rgb to xyz50 is ok');
-	assert.deepEqual(xyz50('rgb(none 100 20)'), xyz50('rgb(0 100 20)'));
-});
diff --git a/test/xyz65.test.js b/test/xyz65.test.js
deleted file mode 100644
index 3b1233e4..00000000
--- a/test/xyz65.test.js
+++ /dev/null
@@ -1,98 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { xyz65, rgb, formatCss } from '../src/index.js';
-
-test('xyz65', t => {
-	/*
-		These should theoretically be equal to the Xn, Yn, and Zn values
-		from xyz65/constants.js, but there's a small rounding error for `y`.
-	 */
-	assert.deepEqual(
-		xyz65('white'),
-		{
-			mode: 'xyz65',
-			x: 0.9504559270516715,
-			y: 0.9999999999999999,
-			z: 1.0890577507598784
-		},
-		'white'
-	);
-
-	assert.deepEqual(xyz65('black'), { mode: 'xyz65', x: 0, y: 0, z: 0 });
-	assert.deepEqual(
-		xyz65('red'),
-		{
-			mode: 'xyz65',
-			x: 0.4123907992659593,
-			y: 0.2126390058715102,
-			z: 0.0193308187155918
-		},
-		'red'
-	);
-	assert.deepEqual(
-		xyz65('#00cc0080'),
-		{
-			mode: 'xyz65',
-			x: 0.21591920006651102,
-			y: 0.43183840013302205,
-			z: 0.071973066688837,
-			alpha: 0.5019607843137255
-		},
-		'#00cc0080'
-	);
-});
-
-test('color(xyz)', t => {
-	assert.deepEqual(xyz65('color(xyz 1 0 0 / 0.25)'), {
-		x: 1,
-		y: 0,
-		z: 0,
-		alpha: 0.25,
-		mode: 'xyz65'
-	});
-	assert.deepEqual(xyz65('color(xyz 0% 50% 0.5 / 25%)'), {
-		x: 0,
-		y: 0.5,
-		z: 0.5,
-		alpha: 0.25,
-		mode: 'xyz65'
-	});
-});
-
-test('color(xyz-d65)', t => {
-	assert.deepEqual(xyz65('color(xyz-d65 1 0 0 / 0.25)'), {
-		x: 1,
-		y: 0,
-		z: 0,
-		alpha: 0.25,
-		mode: 'xyz65'
-	});
-	assert.deepEqual(xyz65('color(xyz-d65 0% 50% 0.5 / 25%)'), {
-		x: 0,
-		y: 0.5,
-		z: 0.5,
-		alpha: 0.25,
-		mode: 'xyz65'
-	});
-});
-
-test('color(--xyz-d65)', t => {
-	assert.deepEqual(xyz65('color(--xyz-d65 1 0 0 / 0.25)'), undefined);
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(xyz 0% 50% 0.5 / 25%)'),
-		'color(xyz-d65 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(xyz-d65 none 0.5 none)'), 'xyz65 to rgb is ok');
-	assert.deepEqual(
-		rgb('color(xyz-d65 none 0.5 none)'),
-		rgb('color(xyz-d65 0 0.5 0')
-	);
-	assert.ok(xyz65('rgb(none 100 20)'), 'rgb to xyz65 is ok');
-	assert.deepEqual(xyz65('rgb(none 100 20)'), xyz65('rgb(0 100 20)'));
-});
diff --git a/test/yiq.test.js b/test/yiq.test.js
deleted file mode 100644
index 720e9774..00000000
--- a/test/yiq.test.js
+++ /dev/null
@@ -1,63 +0,0 @@
-import test from 'node:test';
-import assert from 'node:assert';
-import { yiq, rgb, formatRgb, formatCss } from '../src/index.js';
-
-test('rgb -> yiq', t => {
-	assert.deepEqual(yiq('purple'), {
-		mode: 'yiq',
-		y: 0.20749931419607845,
-		i: 0.13762565019607842,
-		q: 0.26233329443137254
-	});
-});
-
-test('rgb -> yiq -> rgb', t => {
-	assert.deepEqual(
-		formatRgb(yiq('rgb(255, 255, 255)')),
-		'rgb(255, 255, 255)',
-		'white'
-	);
-
-	assert.deepEqual(formatRgb(yiq('rgb(0, 0, 0)')), 'rgb(0, 0, 0)', 'black');
-	assert.deepEqual(formatRgb(yiq('rgb(100, 0, 0)')), 'rgb(100, 0, 0)', 'red');
-	assert.deepEqual(
-		formatRgb(yiq('rgb(0, 120, 0)')),
-		'rgb(0, 120, 0)',
-		'blue'
-	);
-	assert.deepEqual(formatRgb(yiq('rgb(0, 0, 89)')), 'rgb(0, 0, 89)', 'green');
-});
-
-test('color(--yiq)', t => {
-	assert.deepEqual(yiq('color(--yiq 1 0 0 / 0.25)'), {
-		y: 1,
-		i: 0,
-		q: 0,
-		alpha: 0.25,
-		mode: 'yiq'
-	});
-	assert.deepEqual(yiq('color(--yiq 0% 50% 0.5 / 25%)'), {
-		y: 0,
-		i: 0.5,
-		q: 0.5,
-		alpha: 0.25,
-		mode: 'yiq'
-	});
-});
-
-test('formatCss', t => {
-	assert.equal(
-		formatCss('color(--yiq 0% 50% 0.5 / 25%)'),
-		'color(--yiq 0 0.5 0.5 / 0.25)'
-	);
-});
-
-test('missing components', t => {
-	assert.ok(rgb('color(--yiq none 0.5 none)'), 'yiq to rgb is ok');
-	assert.deepEqual(
-		rgb('color(--yiq none 0.5 none)'),
-		rgb('color(--yiq 0 0.5 0')
-	);
-	assert.ok(yiq('rgb(none 100 20)'), 'rgb to yiq is ok');
-	assert.deepEqual(yiq('rgb(none 100 20)'), yiq('rgb(0 100 20)'));
-});
diff --git a/tools/math/itp-matrices.py b/tools/math/itp-matrices.py
deleted file mode 100644
index 6a568159..00000000
--- a/tools/math/itp-matrices.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import numpy as np;
-
-np.set_printoptions(precision=16, sign='-', floatmode='fixed');
-
-XYZ_D65_TO_REC2020 = np.array([
-    [1.7166511879712683, -0.3556707837763925, -0.2533662813736599],
-    [-0.6666843518324893, 1.6164812366349395, 0.0157685458139111],
-    [0.0176398574453108, -0.0427706132578085, 0.9421031212354739]
-]);
-REC2020_TO_LMS = np.array([
-    [1688, 2146, 262],
-    [683, 2951, 462],
-    [99, 309, 3688]
-]) / 4096;
-C = np.matmul(REC2020_TO_LMS, XYZ_D65_TO_REC2020);
-Cinv = np.linalg.inv(C);
-
-print(C);
-print(Cinv);
\ No newline at end of file
diff --git a/tools/math/oklab-matrices.py b/tools/math/oklab-matrices.py
deleted file mode 100644
index 6aa1b8de..00000000
--- a/tools/math/oklab-matrices.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import numpy as np;
-
-np.set_printoptions(precision=16, sign='-', floatmode='fixed');
-
-# LRGBtoXYZ65 = np.array([
-# 	[ 0.4123907992659593, 0.357584339383878, 0.1804807884018343 ],
-# 	[ 0.2126390058715102, 0.715168678767756, 0.0721923153607337 ],
-# 	[ 0.0193308187155918, 0.119194779794626, 0.9505321522496607] 
-# ]);
-
-LRGBtoXYZ65 = np.array([
-	[ 506752 / 1228815,  87881 / 245763,   12673 /   70218 ],
-	[  87098 /  409605, 175762 / 245763,   12673 /  175545 ],
-	[   7918 /  409605,  87881 / 737289, 1001167 / 1053270 ],
-]);
-
-XYZ65toLMS = np.array([
-	[ 0.8190224379967030, 0.3619062600528904, -0.1288737815209879 ],
-	[ 0.0329836539323885, 0.9292868615863434,  0.0361446663506424 ],
-	[ 0.0481771893596242, 0.2642395317527308,  0.6335478284694309 ]
-]);
-
-LMStoOKLab = np.array([
-	[ 0.2104542683093140,  0.7936177747023054, -0.0040720430116193 ],
-	[ 1.9779985324311684, -2.4285922420485799,  0.4505937096174110 ],
-	[ 0.0259040424655478,  0.7827717124575296, -0.8086757549230774 ]
-]);
-
-C = np.matmul(XYZ65toLMS, LRGBtoXYZ65);
-Cinv = np.linalg.inv(C);
-
-print(C);
-print(Cinv);
\ No newline at end of file
diff --git a/tools/math/rec2020-matrices.py b/tools/math/rec2020-matrices.py
deleted file mode 100644
index fa4e1c36..00000000
--- a/tools/math/rec2020-matrices.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import numpy as np;
-np.set_printoptions(precision=16, sign='-', floatmode='fixed');
-
-[Xw, Yw, Zw] = [0.3127 / 0.329, 1, (1 - 0.3127 - 0.329) / 0.329];
-[xr, yr, xg, yg, xb, yb] = [0.708, 0.292, 0.170, 0.797, 0.131, 0.046];
-
-# http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html
-
-Xr = xr / yr;
-Yr = 1;
-Zr = (1 - xr - yr) / yr;
-
-Xg = xg / yg;
-Yg = 1;
-Zg = (1 - xg - yg) / yg;
-
-Xb = xb / yb;
-Yb = 1;
-Zb = (1 - xb - yb) / yb;
-
-X = np.array([
-	[Xr, Xg, Xb],
-	[Yr, Yg, Yb],
-	[Zr, Zg, Zb]
-]);
-
-W = np.array([ Xw, Yw, Zw ]);
-
-[Sr, Sg, Sb] = np.matmul(np.linalg.inv(X), W);
-
-M = np.array([
-	[ Sr * Xr, Sg * Xg, Sb * Xb ], 
-	[ Sr * Yr, Sg * Yg, Sb * Yb ], 
-	[ Sr * Zr, Sg * Zg, Sb * Zb ]
-]);
-
-print(M);
-print(np.linalg.inv(M));
\ No newline at end of file
diff --git a/tools/math/requirements.txt b/tools/math/requirements.txt
deleted file mode 100644
index e2ebf769..00000000
--- a/tools/math/requirements.txt
+++ /dev/null
@@ -1 +0,0 @@
-numpy==1.22.0
\ No newline at end of file
diff --git a/tools/ranges.js b/tools/ranges.js
deleted file mode 100644
index f420c593..00000000
--- a/tools/ranges.js
+++ /dev/null
@@ -1,35 +0,0 @@
-import { converter, getMode } from '../src/index.js';
-
-/*
-	Find the channel value ranges (minimum & maximum)
-	for a particular color space, by converting lots of
-	RGB colors to that space.
- */
-let ranges = (mode, step = 1 / 128) => {
-	let conv = converter(mode);
-	let chs = getMode(mode).channels;
-	let res = chs.reduce(
-		(acc, ch) => ((acc[ch] = [Infinity, -Infinity]), acc),
-		{}
-	);
-	let r, g, b, c, v;
-	for (r = 0; r <= 1; r += step) {
-		for (g = 0; g <= 1; g += step) {
-			for (b = 0; b <= 1; b += step) {
-				c = conv({ mode: 'rgb', r, g, b });
-				chs.forEach(ch => {
-					v = c[ch];
-					if (v < res[ch][0]) {
-						res[ch][0] = v;
-					}
-					if (v > res[ch][1]) {
-						res[ch][1] = v;
-					}
-				});
-			}
-		}
-	}
-	return res;
-};
-
-console.log(ranges(process.argv[2], 1 / 512));
