Repository: facelessuser/coloraide (language: python)

Issue:
RYB Support
I've been working on this off and on, the original issue is here: https://github.com/facelessuser/coloraide-extras/issues/12.

I've basically been evaluating different RYB approaches and trying to see which ones are better.

1. The easiest approach is something like what is described in Junichi Sugita's and Tokiichiro Takahashi's [paper ](http://nishitalab.org/user/UEI/publication/Sugita_IWAIT2015.pdf). This basically just takes the sRGB color space and compresses blue and such to align yellow as a primary color. It has the advantage that it encompasses the entire gamut of sRGB. While in their evaluation they claim decent RYB mixing for watercolors and such, the color space creates some odd discontinuities. This can be seen in the 3D model.
    
    <img width="661" alt="Screenshot 2023-07-29 at 11 04 20 PM" src="https://github.com/facelessuser/coloraide/assets/1055125/6f0aedc4-b6d2-40a8-9e09-01ae0b2b0168">

2. The other approach is the Gosset and Chen approach. They provide a single-direction [algorithm](http://bahamas10.github.io/ryb/assets/ryb.pdf). This approach uses [trilinear interpolation](https://en.wikipedia.org/wiki/Trilinear_interpolation) which is easy to implement and actually creates a color space with pretty consistent smooth transitions in the space. It does have a smaller gamut (things like cyan are not present).

    The round-trip translation is a problem, but I've actually been able to solve this. Digging around, I was able to find an inverse trilinear interpolation approach using the Gauss–Newton algorithm. This works well for colors within the gamut, especially if you tune the initial guesses for problematic cases. I assume the guesses could be tuned to better handle colors outside the gamut as well, but that is less of a concern. We also can reverse their "biasing" using Newton's method as well, tuning the guesses helps improve good round-tripping. Employing these methods, we are able to convert back and forth and generate the 3D model of the space.
    
    <img width="602" alt="Screenshot 2023-07-29 at 11 32 04 PM" src="https://github.com/facelessuser/coloraide/assets/1055125/6fe2ff9d-c525-4999-961e-06a87b526cd1">

    Another approach they employ is using a cubic easing function to bias the colors towards the primaries to produce a non-linear interpolation of the colors. This is done to " limit the use of ambiguous colors in [their] implementation". More specifically they state:

    > Biasing in this manner will ensure that the viewer will encounter a more limited number of easily identiable colors, but still llows
for smooth transitions between colors.

    I actually find this biasing to have downsides. If you are trying to generate monochromatic steps, you get too little variance as you get close to the primary and tertiary colors. The good news is that we do not have to bias if we do not want to. Unless you specifically require further limiting the colors in the space, I would not generally recommend this. Basically, the colors are more localized. The blue is more tightly bunched in its corner, etc.
    
    <img width="641" alt="Screenshot 2023-07-29 at 11 33 41 PM" src="https://github.com/facelessuser/coloraide/assets/1055125/43336d9b-e567-4339-9d4c-13974afd7375">

    They select a number of colors they claim are close-ish to those used by [Itten](https://en.wikipedia.org/wiki/Johannes_Itten). The thing is that there are various color sets by Itten. From different revisions of his book, the color wheel uses different variants of colors. The colors chosen in the paper have some pretty washed-out blues, etc. There are variants of Ittens' supposed colors that have more vibrant colors, and others that are less so. At least for the images here, we are using a pretty common, documented set of Itten colors, but which are the right or best, who knows. We actually, for testing purposes, implemented the Gosset and Chen colors and the Itten colors. Obviously, we'd pick a set to officially ship if we went this route.

    The last thing to note with this approach is that you get a more pigment-like mixing. The absence of colors gives you white, which makes sense, and mixing all colors together will give you a muddy brown, which also makes sense. Which makes sense. You can't really mix achromatic colors as easily. And if you want to darken a color with pure black or white, that can be tricky as that is not how the space works.  I have experimented with an RYBK variant that actually allows you to mix colors in a normal pigment-like fashion, and then using K allows you to mix in pure black to darken.




Discussion / hints:
Example of RYBK normal pigment mixing and mixing with pure black:

<img width="1364" alt="Screenshot 2023-07-30 at 12 05 58 AM" src="https://github.com/facelessuser/coloraide/assets/1055125/41b4289a-2273-46c4-ae33-b8f1cd217cc0">

Moving forward, I think we will be using the Gosset and Chen algorithm.  I think we are just going to ship a traditional RYB space.  It will naturally have a more limited gamut because the primary colors cannot create all colors like CMY can. I think this is a more accurate approach than just squeezing the RGB gamut creating odd bands in the space.

The current hold up is related to some minor round trip values on the edge of the cube. In these few cases, the results are very close, but we'd like to be even closer.  We'd like to ship these with the best precision we can. These Newton algorithms perform best depending on how good your initial guess is. The inverse trilinear guess is generally pretty good for almost any color within the RYB gamut, but near some corners we fall just a bit shorter than we'd like. We are talking about `0.9876` vs `1.0`, so not huge. I'd like to see closer if possible.

We are experimenting with 3 variants. The original Gosset and Chen values. Values by Itten (though we have to guess  a decent brown - all colors mixed together), and a vibrant variant using pure sRGB red, yellow, and blue. I don't know which one we'd ship, or if we'd ship multiple variants, but these are currently under evaluation.
I think we have something fairly reliable for all colors in the gamut. There is no guarantee that colors outside the RYB gamut will round trip though. As a matter of fact, I can probably guarantee there are colors that won't round trip at all.


Fix patch:
diff --git a/coloraide/__meta__.py b/coloraide/__meta__.py
index b65cd0305..70d9afec8 100644
--- a/coloraide/__meta__.py
+++ b/coloraide/__meta__.py
@@ -193,5 +193,5 @@ def parse_version(ver: str) -> Version:
     return Version(major, minor, micro, release, pre, post, dev)
 
 
-__version_info__ = Version(2, 6, 0, "final")
+__version_info__ = Version(2, 7, 0, "final")
 __version__ = __version_info__._get_canonical()
diff --git a/coloraide/algebra.py b/coloraide/algebra.py
index 7e4ede0fd..7b0f2d3c1 100644
--- a/coloraide/algebra.py
+++ b/coloraide/algebra.py
@@ -194,6 +194,231 @@ def lerp(p0: float, p1: float, t: float) -> float:
     return p0 + (p1 - p0) * t
 
 
+def ilerp(p0: float, p1: float, t: float) -> float:
+    """Inverse interpolation."""
+
+    d = (p1 - p0)
+    return (t - p0) / d if d else 0
+
+
+def bilerp(p0: float, p1: float, p2: float, p3: float, tx: float, ty: float) -> float:
+    """Bilinear interpolation."""
+
+    return lerp(lerp(p0, p1, tx), lerp(p2, p3, tx), ty)
+
+
+def lerp2d(vertices: Matrix, t: Vector) -> Vector:
+    """
+    Interpolate in 2D.
+
+    Vertices should be in column form [[x...], [y...]].
+    """
+
+    return [bilerp(*vertices[i], *t) for i in range(2)]
+
+
+def ilerp2d(
+    vertices: Matrix,
+    point: Vector,
+    *,
+    vertices_t: Matrix | None = None,
+    max_iter: int = 20,
+    tol: float = 1e-14
+) -> Vector:
+    """
+    Inverse interpolation of a 2D point.
+
+    Same algorithm as `ilerp3d` just for a 2D point. Based off the forward transform below.
+
+    ```
+    vxy = v00 (1 - x) (1 - y) +
+        v10 x (1 - y) +
+        v01 (1 - x) y +
+        v11 x y
+    ```
+    """
+
+    if vertices_t is None:  # pragma: no cover
+        vertices_t = transpose(vertices)
+
+    # Initial guess
+    xy = [0.5, 0.5]
+
+    try:
+        for _ in range(max_iter):
+
+            # Calculate the residual by using our guess to calculate the what should be the input and compare
+            residual = subtract(lerp2d(vertices, xy), point, dims=D1)
+
+            # If we are close enough to our input, we can quit
+            if math.sqrt(residual[0] ** 2 + residual[1] ** 2) < tol:
+                break
+
+            # Build up the Jacobian matrix so we can solve for the next, closer guess.
+            x, y = xy
+            _x = [-(1 - y), 1 - y, -y, y]
+            jx = [sum(i) for i in zip(*[[xi * c for c in ci] for ci, xi in zip(vertices_t, _x)])]
+
+            _y = [-(1 - x), -x, x, 1 - x]
+            jy = [sum(i) for i in zip(*[[yi * c for c in ci] for ci, yi in zip(vertices_t, _y)])]
+
+            # Create the Jacobian matrix, but we need it in column form
+            j = transpose([jx, jy])
+
+            # Solve for new guess
+            xy = subtract(xy, dot(inv(j), residual, dims=D2_D1), dims=D1)
+    except ValueError:  # pragma: no cover
+        # The Jacobian matrix shouldn't fail inversion if we are in gamut.
+        # Out of gamut may give us one we cannot invert. There are potential
+        # ways to handle this to try and get moving again, but currently, we
+        # just give up. We do not guarantee out of gamut conversions.
+        pass
+
+    return [0.0 if i < tol else i for i in xy]
+
+
+def trilerp(
+    p0: float,
+    p1: float,
+    p2: float,
+    p3: float,
+    p4: float,
+    p5: float,
+    p6: float,
+    p7: float,
+    tx: float,
+    ty: float,
+    tz: float
+) -> float:
+    """Trilinear interpolation."""
+
+    return lerp(bilerp(p0, p1, p2, p3, tx, ty), bilerp(p4, p5, p6, p7, tx, ty), tz)
+
+
+def lerp3d(
+    vertices: Matrix,
+    t: Vector
+) -> Vector:
+    """
+    Interpolation in 3D.
+
+    Vertices should be in column form [[x...], [y...], [z...]].
+    """
+
+    return [trilerp(*vertices[i], *t) for i in range(3)]
+
+
+def ilerp3d(
+    vertices: Matrix,
+    point: Vector,
+    *,
+    vertices_t: Matrix | None = None,
+    max_iter: int = 20,
+    tol: float = 1e-14
+) -> Vector:
+    """
+    Inverse trilinear interpolation.
+
+    Uses Gauss-Newton method to compute the inverse of the trilinear interpolation.
+
+    Original code by Nick Alger https://stackoverflow.com/a/18332009/3609487
+    and adapted for our purposes. As stated in the link:
+
+    > I release the 3D code to the public domain as well if anyone wants to use it.
+    > - Nick Alger Jun 27, 2014 at 7:30
+
+    Utilizes the trilinear interpolation method found here to get the inverse:
+    http://paulbourke.net/miscellaneous/interpolation/. Results are the same as
+    what we do in the forward, but easier to use for the inverse calculations.
+    Forward transform found below with vertices ordered to match the order we store our
+    vertices in.
+
+    ```
+    Vxyz =  V000 (1 - x) (1 - y) (1 - z) +
+        V100 x (1 - y) (1 - z) +
+        V010 (1 - x) y (1 - z) +
+        V110 x y (1 - z) +
+        V001 (1 - x) (1 - y) z +
+        V101 x (1 - y) z +
+        V011 (1 - x) y z +
+        V111 x y z
+    ```
+
+    NOTE: It does seem that selected vertices can have an impact on how well the
+    reverse translation is. Certain combinations can cause us to fall short of
+    resolving the interpolation all the way to 1 when it should. In some cases, it
+    will just stop at `0.9xxxx`, etc. Some sets of vertices have no issues at all.
+    """
+
+    if vertices_t is None:  # pragma: no cover
+        vertices_t = transpose(vertices)
+
+    # Initial guess.
+    xyz = [0.5, 0.5, 0.5]
+
+    try:
+        for _ in range(max_iter):
+
+            # Calculate the residual by using our guess to calculate the what should be the input and compare
+            residual = subtract(lerp3d(vertices, xyz), point, dims=D1)
+
+            # If we are close enough to our input, we can quit
+            if math.sqrt(residual[0] ** 2 + residual[1] ** 2 + residual[2] ** 2) < tol:
+                break
+
+            # Build up the Jacobian matrix so we can solve for the next, closer guess
+            x, y, z = xyz
+            _x = [
+                 -(1 - y) * (1 - z),
+                (1 - y) * (1 - z),
+                -y * (1 - z),
+                y * (1 - z),
+                -(1 - y) * z,
+                (1 - y) * z,
+                -y * z,
+                y * z
+            ]
+            jx = [sum(i) for i in zip(*[[xi * c for c in ci] for ci, xi in zip(vertices_t, _x)])]
+
+            _y = [
+                -(1 - x) * (1 - z),
+                -x * (1 - z),
+                (1 - x) * (1 - z),
+                x * (1 - z),
+                -(1 - x) * z,
+                -x * z,
+                (1 - x) * z,
+                x * z,
+            ]
+            jy = [sum(i) for i in zip(*[[yi * c for c in ci] for ci, yi in zip(vertices_t, _y)])]
+
+            _z = [
+                -(1 - x) * (1 - y),
+                -x * (1 - y),
+                -(1 - x) * y,
+                -x * y,
+                (1 - x) * (1 - y),
+                x * (1 - y),
+                (1 - x) * y,
+                x * y
+            ]
+            jz = [sum(i) for i in zip(*[[zi * c for c in ci] for ci, zi in zip(vertices_t, _z)])]
+
+            # Create the Jacobian matrix, but we need it in column form
+            j = transpose([jx, jy, jz])
+
+            # Solve for new guess
+            xyz = subtract(xyz, dot(inv(j), residual, dims=D2_D1), dims=D1)
+    except ValueError:  # pragma: no cover
+        # The Jacobian matrix shouldn't fail inversion if we are in gamut.
+        # Out of gamut may give us one we cannot invert. There are potential
+        # ways to handle this to try and get moving again, but currently, we
+        # just give up. We do not guarantee out of gamut conversions.
+        pass
+
+    return [0.0 if i < tol else i for i in xyz]
+
+
 @functools.lru_cache(maxsize=10)
 def _matrix_141(n: int) -> Matrix:
     """Get matrix '1 4 1'."""
diff --git a/coloraide/color.py b/coloraide/color.py
index 95d8233b9..cc13a2102 100644
--- a/coloraide/color.py
+++ b/coloraide/color.py
@@ -1095,7 +1095,8 @@ def harmony(
         name: str,
         *,
         space: str | None = None,
-        out_space: str | None = None
+        out_space: str | None = None,
+        **kwargs: Any
     ) -> list[Color]:
         """Acquire the specified color harmonies."""
 
@@ -1105,7 +1106,7 @@ def harmony(
         if out_space is None:
             out_space = space
 
-        return [c.convert(out_space, in_place=True) for c in harmonies.harmonize(self, name, space)]
+        return [c.convert(out_space, in_place=True) for c in harmonies.harmonize(self, name, space, **kwargs)]
 
     def compose(
         self,
diff --git a/coloraide/everything.py b/coloraide/everything.py
index 3be94bead..21857f15e 100644
--- a/coloraide/everything.py
+++ b/coloraide/everything.py
@@ -35,6 +35,7 @@
 from .spaces.hct import HCT
 from .spaces.ucs import UCS
 from .spaces.rec709 import Rec709
+from .spaces.ryb import RYB, RYBBiased
 from .distance.delta_e_itp import DEITP
 from .distance.delta_e_99o import DE99o
 from .distance.delta_e_z import DEZ
@@ -94,6 +95,8 @@ class ColorAll(Base):
         CAM16LCD(),
         HCT(),
         UCS(),
+        RYB(),
+        RYBBiased(),
 
         # Delta E
         DEITP(),
diff --git a/coloraide/spaces/ryb.py b/coloraide/spaces/ryb.py
new file mode 100644
index 000000000..00194536c
--- /dev/null
+++ b/coloraide/spaces/ryb.py
@@ -0,0 +1,145 @@
+"""
+RYB color space.
+
+Gosset and Chen
+http://bahamas10.github.io/ryb/assets/ryb.pdf
+"""
+from __future__ import annotations
+import math
+from ..spaces import Regular, Space
+from .. import algebra as alg
+from ..channels import Channel
+from ..cat import WHITES
+from ..types import Vector, Matrix
+
+# In terms of RGB
+GOSSET_CHEN_CUBE = [
+    [1.0, 1.0, 1.0],      # White (c000)
+    [1.0, 0.0, 0.0],      # Red (c100)
+    [1.0, 1.0, 0.0],      # Yellow (C010)
+    [1.0, 0.5, 0.0],      # Orange (c110)
+    [0.163, 0.373, 0.6],  # Blue (c001)
+    [0.5, 0.0, 0.5],      # Violet (c101)
+    [0.0, 0.66, 0.2],     # Green (c011)
+    [0.2, 0.094, 0.0]     # Black (c111)
+]  # type: Matrix
+
+
+def apply_bias(ryb: Vector) -> Vector:
+    """Apply bias towards corners."""
+
+    return [-2 * t ** 3 + 3 * t ** 2 for t in ryb]
+
+
+def remove_bias(ryb: Vector) -> Vector:
+    """Remove the cubic bias using Newton's method."""
+
+    new = []
+    for c in ryb:
+        target = c
+
+        # Guessing properly is critical for good round tripping with fewest iterations.
+        # Handle scenarios really close to our limits.
+        if abs(c) <= 1e-6:
+            guess = 0.0
+        elif abs(1 - c) < 1e-6:
+            guess = 1.0
+        else:
+            guess = 0.5
+
+        last = float('nan')
+        for _ in range(10):
+            t1 = -2 * guess ** 3 + 3 * guess ** 2 - target
+            t2 = -6 * guess ** 2 + 6 * guess
+
+            if t2 == 0:
+                break
+
+            guess -= (t1 / t2)
+
+            if guess == last:  # pragma: no cover
+                break
+
+            last = guess
+        new.append(guess)
+
+    return new
+
+
+def srgb_to_ryb(rgb: Vector, cube_t: Matrix, cube: Matrix, biased: bool) -> Vector:
+    """Convert RYB to sRGB."""
+
+    # Calculate the RYB value
+    ryb = alg.ilerp3d(cube_t, rgb, vertices_t=cube)
+    return remove_bias(ryb) if biased else ryb
+
+
+def ryb_to_srgb(ryb: Vector, cube_t: Matrix, biased: bool) -> Vector:
+    """Convert RYB to sRGB."""
+
+    # Bias interpolation towards corners
+    if biased:
+        ryb = apply_bias(ryb)
+    return alg.lerp3d(cube_t, ryb)
+
+
+class RYB(Regular, Space):
+    """
+    The RYB color space based on the paper by Gosset and Chen.
+
+    The easing function for biasing colors towards the vertices is not handled in this color space.
+    """
+
+    NAME = "ryb"
+    BASE = "srgb"
+    SERIALIZE = ("--ryb",)
+    CHANNELS = (
+        Channel("r", 0.0, 1.0, bound=True),
+        Channel("y", 0.0, 1.0, bound=True),
+        Channel("b", 0.0, 1.0, bound=True)
+    )
+    CHANNEL_ALIASES = {
+        "red": 'r',
+        "yellow": 'y',
+        "blue": 'b'
+    }
+    WHITE = WHITES['2deg']['D65']
+    RYB_CUBE = GOSSET_CHEN_CUBE
+    RYB_CUBE_T = alg.transpose(RYB_CUBE)
+    BIASED = False
+
+    def is_achromatic(self, coords: Vector) -> bool:
+        """
+        Test if color is achromatic.
+
+        Achromatic colors in the traditional sense is just brown in RYB,
+        so convert to RGB where it is easier to determine an actual achromatic color.
+        """
+
+        coords = self.to_base(coords)
+        for x in alg.vcross(coords, [1, 1, 1]):
+            if not math.isclose(0.0, x, abs_tol=1e-5):
+                return False
+        return True
+
+    def to_base(self, coords: Vector) -> Vector:
+        """To sRGB."""
+
+        return ryb_to_srgb(coords, self.RYB_CUBE_T, self.BIASED)
+
+    def from_base(self, coords: Vector) -> Vector:
+        """From sRGB."""
+
+        return srgb_to_ryb(coords, self.RYB_CUBE_T, self.RYB_CUBE, self.BIASED)
+
+
+class RYBBiased(RYB):
+    """
+    Gosset and Chen RYB with biasing towards the vertices.
+
+    This mimics exactly what was done in the paper.
+    """
+
+    NAME = "ryb-biased"
+    SERIALIZE = ("--ryb-biased",)
+    BIASED = True
diff --git a/docs/src/dictionary/en-custom.txt b/docs/src/dictionary/en-custom.txt
index d44b19b71..70f807137 100644
--- a/docs/src/dictionary/en-custom.txt
+++ b/docs/src/dictionary/en-custom.txt
@@ -8,8 +8,10 @@ Achromatopsia
 Alvy
 Az
 BT
+Baoquan
 Berns
 Bezier
+Bilinear
 Björn
 Boronine
 Brettel
@@ -63,6 +65,8 @@ FNL
 Fairchild
 Florian
 Formatter
+Gosset
+Gossett
 HCT
 HDR
 HLG
@@ -86,12 +90,14 @@ ITP
 ITU
 IgPgTg
 Interpolator
+Itten
 Iz
 Izazbz
 JCh
 JMh
 JND
 JSON
+Jacobian
 Jsh
 Judd
 Jz
@@ -163,6 +169,7 @@ Tetradic
 Tokenize
 Triadic
 Trichromacy
+Trilinear
 Tritan
 Tritanopia
 Twemoji
@@ -194,6 +201,7 @@ backfill
 backfilled
 barycentric
 bezier
+bilinear
 boolean
 broadcasted
 bz
@@ -289,6 +297,7 @@ th
 transmissive
 triadic
 trichromacy
+trilinear
 tristimulus
 tritan
 tritanomaly
diff --git a/docs/src/markdown/about/changelog.md b/docs/src/markdown/about/changelog.md
index 9f30dc9e3..5c5f2de26 100644
--- a/docs/src/markdown/about/changelog.md
+++ b/docs/src/markdown/about/changelog.md
@@ -2,7 +2,8 @@
 
 ## 2.7
 
--   **NEW**: Add `Regular` mixin class for normal, 3 channel color spaces (sRGB, CMY, etc.).
+-   **NEW**: Add new RYB color space.
+-   **NEW**: Add `Regular` mixin class for normal, 3 channel color spaces (sRGB, CMY, RYB, etc.).
 -   **NEW**: `harmony()` can now accept and transform `Labish` and `Regular` color spaces to cylindrical spaces.
 
 ## 2.6
diff --git a/docs/src/markdown/colors/index.md b/docs/src/markdown/colors/index.md
index 0cbeea232..e7c6b5d09 100644
--- a/docs/src/markdown/colors/index.md
+++ b/docs/src/markdown/colors/index.md
@@ -55,6 +55,7 @@ flowchart TB
     srgb-linear --- xyz-d65
         rec709 --- srgb-linear
         srgb --- srgb-linear
+            ryb --- srgb
             orgb --- srgb
             prismatic --- srgb
             hsi --- srgb
@@ -161,6 +162,7 @@ flowchart TB
     cam16-lcd(CAM16 LCD)
     hct(HCT)
     xyb(XYB)
+    ryb(RYB)
 
     click xyz-d65 "./xyz_d65/" _self
     click xyz-d50 "./xyz_d50/" _self
@@ -219,5 +221,6 @@ flowchart TB
     click cam16-lcd "./cam16_lcd/" _self
     click hct "./hct/" _self
     click xyb "./xyb/" _self
+    click ryb "./ryb/" _self
 ```
 ///
diff --git a/docs/src/markdown/colors/ryb.md b/docs/src/markdown/colors/ryb.md
new file mode 100644
index 000000000..d52c6c657
--- /dev/null
+++ b/docs/src/markdown/colors/ryb.md
@@ -0,0 +1,118 @@
+# RYB
+
+/// failure | The RYB color space is not registered in `Color` by default
+///
+
+/// html | div.info-container
+//// info | Properties
+    attrs: {class: inline end}
+
+**Name:** `ryb`
+
+**White Point:** D65
+
+**Coordinates:**
+
+Name | Range
+---- | -----
+`r`  | [0, 1]
+`y`  | [0, 1]
+`b`  | [0, 1]
+
+////
+
+//// html | figure
+
+```py play wheel
+Color('ryb', [1, 0, 0]).harmony('wheel', space='ryb')
+```
+///// html | figcaption
+The RYB color wheel.
+/////
+////
+
+The RYB color model is a subtractive color model in which red, yellow and blue pigments or dyes are added together
+in various ways to reproduce different colors. RYB is the classical way of thinking about colors. While in schools it
+is often still taught that red, yellow, and blue are the primary colors (for pigments), modern wisdom shows that these
+"primaries" are not sufficient. Spaces like CMYK which use cyan, magenta and yellow can create a much wider array of
+colors, even red, yellow, and blue. We've also since learned that the primary colors of light (which operates in an
+additive color space) are red, green, and blue.
+
+Even though in modern day electronic screens and printing we rely on color models such as RGB and CMYK, RYB still holds
+a special place with artists. Color harmony is often used as the model when talking about color harmonies.
+
+There is no standard RYB color model. No standard primaries. The RYB model that ColorAide implements is based on the
+work of Nathan Gossett and Baoquan Chen at the University of Minnesota at Twin Cities. Their paper devised an approach
+of using trilinear interpolation to create a transform from RYB to sRGB. The bases of the model uses colors similar to
+Johannes Itten's color wheel (which we showed an example of above), but in all the literature, there are variants of the
+same color wheel and no precise color codes.
+
+ColorAide implements Gossett and Chen's algorithm to convert from RYB to sRGB, but also uses an algorithm that employs
+Newton's method to approximates the reverse transform. Additionally, their paper implements an easing function that
+biases the color transforms to corners of the cube. While we've also implemented this behavior to be true to the paper,
+the color spaces does not utilize this biasing by default, but we provide an alternative version does. The biasing
+does not improve the color space, but limits the intermediate colors, essentially clumping them near the corners of the
+RYB color cube which was a requirement for the types of data representations that they were performing.
+
+Notice how the colors in the "biased" RYB  are more concentrated at the corners while in the normal RYB they blend more.
+
+//// tab | RYB
+![RYB](../images/ryb-3d.png)
+////
+
+//// tab | RYB Biased
+![RYB](../images/ryb-biased-3d.png)
+////
+
+
+While precisely emulating paint mixing was not entirely the focus, the RYB space does do a better job than other color
+spaces. It should also be noted that when mixing all the colors, you not get black, but a muddy brown, much like with
+paint. To be precise, the color black is not defined within this color space.
+
+```py play
+Color.interpolate(['color(--ryb 0 0 0)', 'color(--ryb 1 1 1)'], space='ryb')
+Color.interpolate(['color(--ryb 1 0 0)', 'color(--ryb 1 1 1)'], space='ryb')
+```
+
+It should be noted that the RYB model does a great job at translating colors within the RYB color gamut, but translation
+of colors outside the gamut will have poor conversions.
+
+[Learn more](http://bahamas10.github.io/ryb/assets/ryb.pdf).
+///
+
+## Channel Aliases
+
+Channels | Aliases
+-------- | -------
+`r`      | `red`
+`y`      | `yellow`
+`b`      | `blue`
+
+## Input/Output
+
+RYB is not currently supported in the CSS spec, the parsed input and string output formats use the
+`#!css-color color()` function format using the custom name `#!css-color --ryb`:
+
+```css-color
+color(--ryb r y b / a)  // Color function
+```
+
+The string representation of the color object and the default string output use the
+`#!css-color color(--ryb r y b / a)` form.
+
+```py play
+Color("ryb", [1, 0, 0])
+Color("ryb", [1, 1, 0]).to_string()
+```
+
+## Registering
+
+```py
+from coloraide import Color as Base
+from coloraide.spaces.ryb import RYB, RYBBiased
+
+class Color(Base): ...
+
+Color.register(RYB())
+Color.register(RYBBiased())
+```
diff --git a/docs/src/markdown/demos/3d_models.html b/docs/src/markdown/demos/3d_models.html
index 86c54ef9f..9c1cc236c 100644
--- a/docs/src/markdown/demos/3d_models.html
+++ b/docs/src/markdown/demos/3d_models.html
@@ -661,7 +661,7 @@ <h1>ColorAide Color Space Models</h1>
 let colorSpaces = null
 let colorGamuts = null
 let lastModel = null
-let package = 'coloraide-2.6-py3-none-any.whl'
+let package = 'coloraide-2.7-py3-none-any.whl'
 const defaultSpace = 'lab'
 const defaultGamut = 'srgb'
 const exceptions = new Set(['hwb', 'hpluv'])
diff --git a/docs/src/markdown/demos/colorpicker.html b/docs/src/markdown/demos/colorpicker.html
index 02d2dee36..4e7858f9a 100644
--- a/docs/src/markdown/demos/colorpicker.html
+++ b/docs/src/markdown/demos/colorpicker.html
@@ -404,7 +404,7 @@ <h1>ColorAide Color Picker</h1>
     let pyodide = null
     let webspace = ''
     let initial = 'oklab(0.69 0.13 -0.1 / 0.85)'
-    let package = 'coloraide-2.6-py3-none-any.whl'
+    let package = 'coloraide-2.7-py3-none-any.whl'
     const displayMapping = 'clip'
 
     const base = `${window.location.origin}/${window.location.pathname.split('/')[1]}/playground/`
diff --git a/docs/src/markdown/harmonies.md b/docs/src/markdown/harmonies.md
index 4cc080a5f..b6b356ef5 100644
--- a/docs/src/markdown/harmonies.md
+++ b/docs/src/markdown/harmonies.md
@@ -15,7 +15,9 @@ that made up the wheel: the primary colors, the secondary colors, and the tertia
 created by evenly mixing the primary colors, and the tertiary colors are created by evenly mixing those primary colors
 with the secondary colors.
 
-![RYB Color Wheel](images/color-wheel.png)
+```py play wheel
+Color('ryb', [1, 0, 0]).harmony('wheel', space='ryb')
+```
 
 The idea of color harmonies originates from the idea that colors, based on their relative position on the wheel, can
 form more pleasing color combinations.
@@ -30,17 +32,17 @@ It should be noted, that the idea of primary colors stems from the idea that the
 all colors can be made from. If you've spent any time with paint, you will know that not all colors can be made from
 red, yellow, and blue. There are colors like `#!color cyan` and `#!color magenta` that cannot be made with the
 traditional primary colors. The early work that helped create the first color wheels was done with the limited paints
-that was available at the time, and the color harmony concepts was built upon the RYB color model.
+that was available at the time, and the color harmony concepts were built upon the early RYB color model.
 
 In modern TVs and monitors, the RYB color model is not used. Paint has subtractive properties, but light has additive
 properties. Electronic screens create all their colors with light based methods that mix red, green, and blue lights. In
 addition, the human eye perceives colors using red, green, and blue light as well. This is As far as light is concerned,
 the primary colors are red, green, and blue.
 
-In reality, we could create a color wheel from any of the various color spaces out there and end up with slightly
-different results. If we were to compose a color wheel based on the common sRGB color space, we could base it off the 3
-primary colors of light. Starting with red (0˚), we could extract the colors at evenly spaced degrees, 30˚ to be exact.
-This would give us our 12 colors for the sRGB color space.
+In reality, we could create a color wheel from any of the various color spaces out there and end up with different
+results. If we were to compose a color wheel based on the common sRGB color space, we could base it off the 3 primary
+colors of light. Starting with red (0˚), we could extract the colors at evenly spaced degrees, 30˚ to be exact. This
+would give us our 12 colors for the sRGB color space.
 
 ```py play
 Steps([Color('hsl', [x, 1, 0.5]) for x in range(0, 360, 30)])
@@ -48,22 +50,34 @@ Steps([Color('hsl', [x, 1, 0.5]) for x in range(0, 360, 30)])
 
 From this we can construct an sRGB color wheel.
 
-![RGB Color Wheel](images/rgb-color-wheel.png)
+```py play wheel
+Color('red').harmony('wheel', space='srgb')
+```
 
-This is different from the RYB color wheel, and more accurate in relation to how light works, but does it yield better
-harmonies for colors?
+This is different from the RYB color wheel we showed earlier, and more accurate in relation to how light works, but does
+it yield better harmonies for colors?
 
-We can use CMY to generate reddish, blueish, yellow color wheel that some would argue is more accurate. Is this better?
+The sRGB color space is additive, just like light, but pigments are subtractive. We can use CMY to generate a
+subtractive wheel with a far greater range that red, green blue creates by use magenta, yellow, and cyan. But does this
+create better harmonies?
 
 ```py play
 Steps(Color('magenta').harmony('wheel', space='cmy'))
 ```
 
-If we were to select the perceptually uniform OkLCh color space, and seed it with red's lightness and chroma, we'd get:
+```py play wheel
+Color('magenta').harmony('wheel', space='cmy')
+```
+
+If we were to select the perceptually uniform OkLCh color space, and seed it with red's lightness and chroma, we'd get
+the wheel below.
 
 ```py play
-c = Color('red').convert('oklch', in_place=True)
-Steps([Color('oklch', [*c[0:2], x]) for x in range(0, 360, 30)])
+Steps(Color('red').harmony('wheel', space='oklch'))
+```
+
+```py play wheel
+Color('red').harmony('wheel', space='oklch')
 ```
 
 This produces colors with visually more uniform lightness, does that mean these are better?
@@ -86,13 +100,19 @@ Steps(Color.steps(['black', 'blue', 'white'], steps=11, space='lch'))
 ```
 
 While OkLCh is the default, we understand that there are many reasons to use other spaces, so use what you like, we
-won't judge :smile:.
+won't judge :smile:. If you are a color theory purist, you can use the classical RYB model.
 
 ```py play
 Steps(Color('red').harmony('complement'))
-Steps(Color('red').harmony('complement', space='hsl'))
+Steps(Color('ryb', [1, 0, 0]).harmony('complement', space='ryb'))
 ```
 
+/// tip | RYB Model
+The RYB model has a more limited color gamut than sRGB as the red, yellow and blue primaries cannot make all colors.
+Additionally, the red, yellow, and blue primaries are not the same as the ones in sRGB, so when using RYB to generate
+harmonies, make sure you are working directly within RYB to ensure you are not out of gamut.
+///
+
 /// tip
 `harmony()` can output the results in any color space you need by setting `out_space`.
 
diff --git a/docs/src/markdown/images/color-wheel.png b/docs/src/markdown/images/color-wheel.png
deleted file mode 100644
index 93e3449d7..000000000
Binary files a/docs/src/markdown/images/color-wheel.png and /dev/null differ
diff --git a/docs/src/markdown/images/rgb-color-wheel.png b/docs/src/markdown/images/rgb-color-wheel.png
deleted file mode 100644
index 281bcc499..000000000
Binary files a/docs/src/markdown/images/rgb-color-wheel.png and /dev/null differ
diff --git a/docs/src/markdown/images/ryb-3d.png b/docs/src/markdown/images/ryb-3d.png
new file mode 100644
index 000000000..a0dbd8263
Binary files /dev/null and b/docs/src/markdown/images/ryb-3d.png differ
diff --git a/docs/src/markdown/images/ryb-biased-3d.png b/docs/src/markdown/images/ryb-biased-3d.png
new file mode 100644
index 000000000..b50732a93
Binary files /dev/null and b/docs/src/markdown/images/ryb-biased-3d.png differ
diff --git a/docs/src/mkdocs.yml b/docs/src/mkdocs.yml
index 4cf991dc6..853c05061 100644
--- a/docs/src/mkdocs.yml
+++ b/docs/src/mkdocs.yml
@@ -122,6 +122,7 @@ nav:
       - Miscellaneous Spaces:
         - xyY: colors/xyy.md
         - CIE 1960 UCS: colors/ucs.md
+        - RYB: colors/ryb.md
         - CMY: colors/cmy.md
         - CMYK: colors/cmyk.md
         - oRGB: colors/orgb.md
@@ -274,7 +275,7 @@ extra_css:
   - assets/coloraide-extras/extra.css
 extra_javascript:
   - https://unpkg.com/mermaid@8.13.3/dist/mermaid.min.js
-  - playground-config-65c43228.js
+  - playground-config-e3b414b9.js
   - https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js
   - assets/coloraide-extras/extra-notebook.js
 
diff --git a/docs/src/py/notebook.py b/docs/src/py/notebook.py
index 48abf2e55..9473a0407 100644
--- a/docs/src/py/notebook.py
+++ b/docs/src/py/notebook.py
@@ -553,7 +553,7 @@ def colorize(src, lang, **options):
 def color_command_validator(language, inputs, options, attrs, md):
     """Color validator."""
 
-    valid_inputs = {'exceptions', 'play'}
+    valid_inputs = {'exceptions', 'play', 'wheel'}
 
     for k, v in inputs.items():
         if k in valid_inputs:
@@ -657,6 +657,7 @@ def _color_command_formatter(src="", language="", class_name=None, options=None,
 
     # Support the new way
     gamut = kwargs.get('gamut', WEBSPACE)
+    wheel = options.get('wheel', False)
     play = options.get('play', False) if options is not None else False
     # Support the old way
     if not play and language == 'playground':
@@ -673,26 +674,93 @@ def _color_command_formatter(src="", language="", class_name=None, options=None,
         )
 
     try:
-        if len(md.preprocessors['fenced_code_block'].extension.stash) == 0:
-            code_id = 0
+        if wheel:
+            exceptions = options.get('exceptions', False) if options is not None else False
 
-        # Check if we should allow exceptions
-        exceptions = options.get('exceptions', False) if options is not None else False
+            _, colors = execute(src.strip(), not exceptions, init=init)
 
-        console, colors = execute(src.strip(), not exceptions, init=init)
-        el = _color_command_console(colors, gamut=gamut)
+            l = len(colors)
+            if l not in (12, 24, 48):
+                raise SuperFencesException("Color wheel requires either 12, 24, or 48 colors")
 
-        el += md.preprocessors['fenced_code_block'].extension.superfences[0]['formatter'](
-            src=console,
-            class_name="highlight",
-            language='pycon',
-            md=md,
-            options=options,
-            **kwargs
-        )
-        el = '<div class="color-command">{}</div>'.format(el)
-        el = template.format(el_id=code_id, raw_source=_escape(src), results=el, gamut=gamut)
-        code_id += 1
+            colors = [c[0].color for c in colors]
+
+            if l == 12:
+                freq = 4
+                offset = 6
+            elif l == 24:
+                freq = 8
+                offset = 12
+            else:
+                freq = 16
+                offset = 24
+
+            primary = list(reversed(colors[::freq]))
+            secondary = list(reversed(colors[offset::freq] + [colors[offset // 3]]))
+            tertiary = list(reversed(colors[::offset // 6]))
+            color_rings = [primary, secondary, tertiary]
+
+            extra_rings_start = ''
+            extra_rings_end = ''
+            if l > 12:
+                extra_rings_start = '<div class="tertiary2">'
+                extra_rings_end += '</div>'
+                color_rings.append(list(reversed(colors[::offset // 12])))
+            if l > 24:
+                extra_rings_start = '<div class="tertiary3">' + extra_rings_start
+                extra_rings_end += '</div>'
+                color_rings.append(list(reversed(colors)))
+
+            color_stops = ''
+            for i, colors in enumerate(color_rings, 1):
+                total = len(colors)
+                percent = 100 / total
+                current = percent
+                last = -1
+
+                stops = []
+                for e, color in enumerate(colors):
+                    color.fit(gamut)
+                    color_str = color.convert(gamut).to_string()
+                    if current:
+                        stops.append('{} {}%'.format(color_str, str(last)))
+                        stops.append('{} {}%'.format(color_str, str(current)))
+                        last = current
+                        if e < (total - 1):
+                            current += percent
+                        else:
+                            current = 100
+                    else:
+                        stops.append(color_str)
+                color_stops += "--color-wheel-stops{}: {};".format(i, ','.join(stops))
+
+            color_wheel = """<div class="color-wheel" style="{}"><div class="wheel">
+{}<div class="tertiary"><div class="secondary"><div class="secondary-inner"><div class="primary"><div class="primary-inner"></div></div></div></div></div></div></div>{}""" .format(  # noqa: E501
+                color_stops, extra_rings_start, extra_rings_end
+            )
+            return color_wheel
+
+        else:
+            if len(md.preprocessors['fenced_code_block'].extension.stash) == 0:
+                code_id = 0
+
+            # Check if we should allow exceptions
+            exceptions = options.get('exceptions', False) if options is not None else False
+
+            console, colors = execute(src.strip(), not exceptions, init=init)
+            el = _color_command_console(colors, gamut=gamut)
+
+            el += md.preprocessors['fenced_code_block'].extension.superfences[0]['formatter'](
+                src=console,
+                class_name="highlight",
+                language='pycon',
+                md=md,
+                options=options,
+                **kwargs
+            )
+            el = '<div class="color-command">{}</div>'.format(el)
+            el = template.format(el_id=code_id, raw_source=_escape(src), results=el, gamut=gamut)
+            code_id += 1
     except SuperFencesException:
         raise
     except Exception:
diff --git a/docs/src/scss/_colorwheel.scss b/docs/src/scss/_colorwheel.scss
new file mode 100644
index 000000000..0aeec92f7
--- /dev/null
+++ b/docs/src/scss/_colorwheel.scss
@@ -0,0 +1,122 @@
+.color-wheel {
+  --color-wheel-stops1: transparent;
+  --color-wheel-stops2: transparent;
+  --color-wheel-stops3: transparent;
+  --color-wheel-stops4: transparent;
+  --color-wheel-stops5: transparent;
+  --color-wheel-bg: var(--md-default-bg-color);
+
+  margin: px2em(16px) 0;
+  overflow-x: scroll;
+  overflow-y: hidden;
+
+  // Override native scrollbar styles
+  &::-webkit-scrollbar {
+    width: px2rem(4px);
+    height: px2rem(4px);
+  }
+
+  &::-webkit-scrollbar-corner {
+    background-color: transparent;
+  }
+
+  // Scrollbar thumb
+  &::-webkit-scrollbar-thumb {
+    background-color: var(--md-default-fg-color--lighter);
+
+    // Hovered scrollbar thumb
+    &:hover {
+      background-color: var(--md-accent-fg-color);
+    }
+  }
+
+  // Firefox scrollbar and thumb
+  scrollbar-color: var(--md-default-fg-color--lighter) transparent;
+  scrollbar-width: thin;
+
+  // Firefox hovered scrollbar and thumb
+  &:hover {
+    scrollbar-color: var(--md-accent-fg-color) transparent;
+  }
+
+  div {
+    overflow: clip;
+  }
+
+  .wheel {
+    min-width: max-content;
+    padding: px2em(5px);
+    border-radius: 1000px;
+
+    .primary {
+      width: 12em;
+      height: 10.39em;
+      margin: auto;
+      clip-path: polygon(50% 0, 100% 100%, 0 100%);
+
+      .primary-inner {
+        width: 12em;
+        height: 14em;
+        background: conic-gradient(in xyz-d65,var(--color-wheel-stops1));
+        transform: rotate(180deg);
+      }
+    }
+
+    .secondary {
+      width: 14em;
+      height: 14em;
+      margin: auto;
+      background: var(--color-wheel-bg);
+      border-radius: 1000px;
+
+      .secondary-inner {
+        width: 14em;
+        height: 14em;
+        margin: auto;
+        background: conic-gradient(in xyz-d65,var(--color-wheel-stops2));
+        transform: rotate(-135deg);
+        clip-path: polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%);
+      }
+    }
+
+    .tertiary {
+      width: 22em;
+      height: 22em;
+      padding: 4em 0;
+      background: conic-gradient(in xyz-d65,var(--color-wheel-stops3));
+      border-radius: 1000px;
+      outline: 5px solid var(--color-wheel-bg);
+      transform: rotate(135deg);
+    }
+
+    .tertiary2 {
+      width: 30em;
+      height: 30em;
+      padding: 4em 0;
+      background: conic-gradient(in xyz-d65,var(--color-wheel-stops4));
+      border-radius: 1000px;
+      outline: 5px solid var(--color-wheel-bg);
+      transform: rotate(128deg);
+
+      .tertiary{
+        margin: auto;
+        transform: rotate(8deg);
+      }
+    }
+
+    .tertiary3 {
+      width: 38em;
+      height: 38em;
+      padding: 4em 0;
+      background: conic-gradient(in xyz-d65,var(--color-wheel-stops5));
+      border-radius: 1000px;
+      outline: 5px solid var(--color-wheel-bg);
+      transform: rotate(123deg);
+
+      .tertiary2 {
+        margin: auto;
+        transform: rotate(4deg);
+      }
+    }
+  }
+}
diff --git a/docs/src/scss/extra.scss b/docs/src/scss/extra.scss
index a75c68943..90898ba48 100644
--- a/docs/src/scss/extra.scss
+++ b/docs/src/scss/extra.scss
@@ -10,6 +10,7 @@
 @import "scroll";
 @import "loader";
 @import "swatch";
+@import "colorwheel";
 @import "playground";
 @import "color_command";
 @import "notebook";
diff --git a/docs/theme/assets/coloraide-extras/extra-391b1ef8ad.css.map b/docs/theme/assets/coloraide-extras/extra-391b1ef8ad.css.map
deleted file mode 100644
index 2ddb31fbb..000000000
--- a/docs/theme/assets/coloraide-extras/extra-391b1ef8ad.css.map
+++ /dev/null
@@ -1,1 +0,0 @@
-{"version":3,"sources":["_buttons.scss","extra.css","_inputs.scss","_scroll.scss","_loader.scss","_swatch.scss","_playground.scss","_color_command.scss","_notebook.scss"],"names":[],"mappings":"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","file":"extra-391b1ef8ad.css","sourcesContent":[":root {\n  --playground-edit-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z' /%3E%3C/svg%3E\");\n  --playground-share-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M14 16V13C10.39 13 7.81 14.43 6 17C6.72 13.33 8.94 9.73 14 9V6L19 11L14 16Z' /%3E%3C/svg%3E\");\n  --playground-run-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20,19V7H4V19H20M20,3A2,2 0 0,1 22,5V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V5C2,3.89 2.9,3 4,3H20M13,17V15H18V17H13M9.58,13L5.57,9H8.4L11.7,12.3C12.09,12.69 12.09,13.33 11.7,13.72L8.42,17H5.59L9.58,13Z' /%3E%3C/svg%3E\");\n  --playground-cancel-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z' /%3E%3C/svg%3E\");\n}\n\n.playground,\n.notebook {\n  button:not(.md-clipboard) {\n    position: relative;\n    padding: 0 1.5em;\n    color: var(--md-typeset-a-color);\n    border-radius: px2rem(2px);\n    transition: color 125ms;\n\n    &::before {\n       position: absolute;\n       left: 0;\n       display: block;\n       box-sizing: border-box;\n       width: 1.25em;\n       height: 1.25em;\n       background-color: var(--md-typeset-a-color);\n       background-size: 1.25em;\n       transition: background-color 125ms;\n       mask-repeat: no-repeat;\n       mask-size: contain;\n       content: \"\";\n    }\n\n    &[disabled] {\n      color: var(--md-code-hl-comment-color);\n\n      &::before {\n        background-color: var(--md-code-hl-comment-color);\n      }\n    }\n\n    &:hover {\n      color: var(--md-accent-fg-color);\n      cursor: pointer;\n\n      &::before {\n        background-color: var(--md-accent-fg-color);\n      }\n    }\n\n    &.playground-edit::before {\n      mask-image: var(--playground-edit-icon);\n    }\n\n    &.playground-share::before {\n      mask-image: var(--playground-share-icon);\n    }\n\n    &#__notebook-submit::before,\n    &.playground-run::before {\n      mask-image: var(--playground-run-icon);\n    }\n\n    &#__notebook-cancel::before,\n    &.playground-cancel::before {\n      mask-image: var(--playground-cancel-icon);\n    }\n\n    &.hidden {\n      display: none;\n    }\n  }\n}\n\n// Special buttons in our toolbar\n.md-typeset .source-link {\n  margin-left: px2rem(8px);\n}\n",":root {\n  --playground-edit-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z' /%3E%3C/svg%3E\");\n  --playground-share-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M14 16V13C10.39 13 7.81 14.43 6 17C6.72 13.33 8.94 9.73 14 9V6L19 11L14 16Z' /%3E%3C/svg%3E\");\n  --playground-run-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20,19V7H4V19H20M20,3A2,2 0 0,1 22,5V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V5C2,3.89 2.9,3 4,3H20M13,17V15H18V17H13M9.58,13L5.57,9H8.4L11.7,12.3C12.09,12.69 12.09,13.33 11.7,13.72L8.42,17H5.59L9.58,13Z' /%3E%3C/svg%3E\");\n  --playground-cancel-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z' /%3E%3C/svg%3E\");\n}\n\n.playground button:not(.md-clipboard),\n.notebook button:not(.md-clipboard) {\n  position: relative;\n  padding: 0 1.5em;\n  color: var(--md-typeset-a-color);\n  border-radius: 0.1rem;\n  transition: color 125ms;\n}\n.playground button:not(.md-clipboard)::before,\n.notebook button:not(.md-clipboard)::before {\n  position: absolute;\n  left: 0;\n  display: block;\n  box-sizing: border-box;\n  width: 1.25em;\n  height: 1.25em;\n  background-color: var(--md-typeset-a-color);\n  background-size: 1.25em;\n  transition: background-color 125ms;\n  mask-repeat: no-repeat;\n  mask-size: contain;\n  content: \"\";\n}\n.playground button:not(.md-clipboard)[disabled],\n.notebook button:not(.md-clipboard)[disabled] {\n  color: var(--md-code-hl-comment-color);\n}\n.playground button:not(.md-clipboard)[disabled]::before,\n.notebook button:not(.md-clipboard)[disabled]::before {\n  background-color: var(--md-code-hl-comment-color);\n}\n.playground button:not(.md-clipboard):hover,\n.notebook button:not(.md-clipboard):hover {\n  color: var(--md-accent-fg-color);\n  cursor: pointer;\n}\n.playground button:not(.md-clipboard):hover::before,\n.notebook button:not(.md-clipboard):hover::before {\n  background-color: var(--md-accent-fg-color);\n}\n.playground button:not(.md-clipboard).playground-edit::before,\n.notebook button:not(.md-clipboard).playground-edit::before {\n  mask-image: var(--playground-edit-icon);\n}\n.playground button:not(.md-clipboard).playground-share::before,\n.notebook button:not(.md-clipboard).playground-share::before {\n  mask-image: var(--playground-share-icon);\n}\n.playground button:not(.md-clipboard)#__notebook-submit::before, .playground button:not(.md-clipboard).playground-run::before,\n.notebook button:not(.md-clipboard)#__notebook-submit::before,\n.notebook button:not(.md-clipboard).playground-run::before {\n  mask-image: var(--playground-run-icon);\n}\n.playground button:not(.md-clipboard)#__notebook-cancel::before, .playground button:not(.md-clipboard).playground-cancel::before,\n.notebook button:not(.md-clipboard)#__notebook-cancel::before,\n.notebook button:not(.md-clipboard).playground-cancel::before {\n  mask-image: var(--playground-cancel-icon);\n}\n.playground button:not(.md-clipboard).hidden,\n.notebook button:not(.md-clipboard).hidden {\n  display: none;\n}\n\n.md-typeset .source-link {\n  margin-left: 0.4rem;\n}\n\ntextarea#__notebook-input,\n.playground-inputs {\n  z-index: 1;\n  display: block;\n  width: 100%;\n  min-height: 3em;\n  margin: 0;\n  padding: 0.7720588235em 1.1764705882em;\n  overflow-x: auto;\n  overflow-y: hidden;\n  color: var(--md-code-fg-color);\n  caret-color: var(--md-code-fg-color);\n  font-size: 0.85em;\n  font-family: var(--md-code-font-family, _), SFMono-Regular, Consolas, Menlo, monospace;\n  font-feature-settings: \"kern\";\n  line-height: 1.4;\n  white-space: pre;\n  word-wrap: unset;\n  background: var(--md-code-bg-color);\n  border: none;\n  outline: none;\n  cursor: text;\n  appearance: textarea;\n  resize: none;\n}\ntextarea#__notebook-input::selection,\n.playground-inputs::selection {\n  color: var(--md-code-bg-color);\n  background: var(--md-code-fg-color);\n}\n\n.md-typeset textarea {\n  scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n  scrollbar-width: thin;\n}\n.md-typeset textarea:hover {\n  scrollbar-color: var(--md-accent-fg-color) transparent;\n}\n.md-typeset textarea::-webkit-scrollbar {\n  width: 0.2rem;\n  height: 0.2rem;\n}\n.md-typeset textarea::-webkit-scrollbar-corner {\n  background-color: transparent;\n}\n.md-typeset textarea::-webkit-scrollbar-thumb {\n  background-color: var(--md-default-fg-color--lighter);\n}\n.md-typeset textarea::-webkit-scrollbar-thumb *:hover {\n  background-color: var(--md-accent-fg-color);\n}\n\n.loading {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 2;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.2);\n  backdrop-filter: blur(2px);\n}\n.loading .loader {\n  position: relative;\n  top: 50%;\n  left: 50%;\n  width: 80px;\n  height: 80px;\n  margin-top: -40px;\n  margin-left: -40px;\n  border-style: solid;\n  border-width: 10px;\n  border-top-color: rgb(0, 255, 255);\n  border-right-color: rgb(255, 255, 0);\n  border-bottom-color: rgb(0, 255, 0);\n  border-left-color: rgb(255, 0, 255);\n  border-radius: 50%;\n  animation: spin 2s linear infinite;\n}\n.loading .loader ~ div {\n  position: absolute;\n  top: 50%;\n  width: 100%;\n  margin-top: 40px;\n  font-weight: 800;\n  font-size: 1rem;\n  text-align: center;\n}\n.loading.relative {\n  position: absolute;\n}\n.loading.relative .loader {\n  width: 2em;\n  height: 2em;\n  margin-top: -1em;\n  margin-left: -1em;\n  border-width: 0.4em;\n}\n.loading.relative .loader ~ div {\n  display: none;\n}\n\n@keyframes spin {\n  0% {\n    transform: rotate(0);\n  }\n  100% {\n    transform: rotate(-360deg);\n  }\n}\n:root {\n  --swatch-bar-border-color: hsl(0, 0%, 90%);\n  --swatch-border-color: hsl(0, 0%, 85%);\n  --swatch-gamut-border-color: hsl(340 82% 52%);\n  --swatch-stops: transparent;\n  --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.1\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #fefefe;\n}\n:root [data-md-color-scheme=slate] {\n  --swatch-border-color: hsla(232, 15%, 25%, 1);\n}\n:root [data-md-color-scheme=dracula] {\n  --swatch-bar-border-color: hsl(231deg 15% 20%);\n  --swatch-border-color: hsl(231deg 15% 25%);\n  --swatch-gamut-border-color: hsl(326, 100%, 74%);\n  --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.45\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #2b2e3b;\n}\n\n.swatch {\n  display: inline-block;\n  box-sizing: border-box;\n  width: 1.25em;\n  height: 1.25em;\n  margin-right: 0.2em;\n  margin-left: 0.25em;\n  line-height: 0;\n  vertical-align: text-bottom;\n  background: var(--transparency);\n  border: 2px solid var(--swatch-border-color);\n  border-radius: 100px;\n  box-shadow: 0.1em 0.1em 0.1em rgba(0, 0, 0, 0.3);\n  transition: all 0.5s ease;\n}\n.swatch:hover {\n  z-index: 2;\n  transform: scale(2);\n}\n.swatch:not(.swatch-gradient):hover {\n  cursor: pointer;\n}\n\n.swatch-color {\n  display: inline-block;\n  width: 1.025em;\n  height: 1.025em;\n  margin: 0;\n  padding: 0;\n  vertical-align: text-bottom;\n  background: linear-gradient(to right, var(--swatch-stops));\n  border-radius: 100px;\n}\n\n.swatch-gradient {\n  width: 100%;\n  height: 3em;\n  margin: 0;\n  border-radius: 0;\n}\n.swatch-gradient .swatch-color {\n  width: 100%;\n  height: 2.75em;\n  border-radius: 0;\n}\n\ndiv.swatch-bar {\n  box-sizing: border-box;\n  background: var(--transparency);\n  background-size: 1em 1em;\n  border: 2px solid var(--swatch-bar-border-color);\n}\ndiv.swatch-bar .swatch {\n  background-position: 0 0, 0 0.5em, 0.5em -0.5em, -0.5em 0px;\n  background-size: 1em 1em;\n}\ndiv.swatch-bar .swatch:not(.out-of-gamut) {\n  box-shadow: none;\n}\ndiv.swatch-bar .swatch:not(.swatch-gradient) {\n  width: 3em;\n  height: 3em;\n  margin: 0;\n  border-radius: 0;\n}\ndiv.swatch-bar .swatch:not(.swatch-gradient) .swatch-color {\n  width: 2.75em;\n  height: 2.75em;\n  margin: 0;\n  border-radius: 0;\n}\ndiv.swatch-bar .swatch:hover {\n  transform: scale(1.2) translateY(-0.2em);\n}\ndiv.swatch-bar .swatch-gradient:hover {\n  transform: scale(1.02, 1.2) translateY(-0.2em);\n}\n\n.swatch.out-of-gamut {\n  padding: 1px;\n  border: 1px solid var(--swatch-gamut-border-color);\n  box-shadow: inset 0 0 0 1px var(--md-code-bg-color);\n}\n\n@media (color-gamut: p3) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n@media (color-gamut: rec2020) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n.playground-code {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  margin-top: 2px;\n  overflow: hidden;\n}\n\n.playground-code.hidden {\n  margin-top: 0;\n}\n\n.playground-code .highlight code {\n  min-height: 3em;\n}\n\n.playground-code .highlight,\n.playground-code .highlight code {\n  margin: 0;\n  overflow: hidden;\n}\n\n.playground-code pre {\n  height: calc(100% + 0.2rem);\n  margin: 0;\n  pointer-events: none;\n}\n\n.playground-results code {\n  min-height: 3em;\n}\n\n.playground-results pre {\n  margin-bottom: 0;\n}\n\n.playground-results .swatch-bar {\n  min-height: calc(3em + 4px);\n}\n\n.playground-results .swatch-bar:empty {\n  display: none;\n}\n\n.playground-results .swatch-bar:empty + .highlight {\n  border-color: transparent;\n}\n\n.playground-results .color-command {\n  margin-bottom: 0;\n}\n\n.hidden .highlight,\n.hidden .playground-inputs {\n  display: none;\n}\n\n.playground-code:not(.hidden) div.highlight {\n  display: none;\n}\n\n.playground-footer {\n  margin-bottom: 1em;\n  padding: 0.2205882353em 1.1764705882em 0.1470588235em;\n  color: var(--md-code-hl-comment-color);\n  font-size: 0.85em;\n  background: var(--md-code-bg-color);\n  border-bottom-right-radius: 0.1rem;\n  border-bottom-left-radius: 0.1rem;\n}\n.playground-footer hr {\n  margin: 0 0 0.1470588235em 0;\n}\n.playground-footer .gamut {\n  float: right;\n}\n\ndiv.color-command {\n  margin: 1em 0;\n  line-height: 0;\n}\ndiv.color-command .highlight {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\ndiv.color-command .highlight:not(:first-child) {\n  border-top: 1px solid var(--md-default-fg-color--lightest);\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\ndiv.color-command .highlight:not(:first-child) pre {\n  margin-top: 0;\n}\n\n@media screen and (max-width: 44.9375em) {\n  .md-typeset > div.color-command {\n    margin-right: -0.8rem;\n    margin-left: -0.8rem;\n  }\n  .md-typeset > div.color-command .highlight code {\n    border-radius: 0;\n  }\n}\n#__notebook-source {\n  height: 100%;\n}\n\n#__notebook-source.hidden,\n#__notebook-render.hidden {\n  display: none;\n}","textarea#__notebook-input,\n.playground-inputs {\n  z-index: 1;\n  display: block;\n  width: 100%;\n  min-height: 3em;\n\n  margin: 0;\n  padding: .7720588235em 1.1764705882em;\n  overflow-x: auto;\n  overflow-y: hidden;\n  color: var(--md-code-fg-color);\n  caret-color: var(--md-code-fg-color);\n\n  font-size: .85em;\n  font-family: var(--md-code-font-family,_),SFMono-Regular,Consolas,Menlo,monospace;\n  font-feature-settings: \"kern\";\n  line-height: 1.4;\n  white-space: pre;\n  word-wrap: unset;\n  background: var(--md-code-bg-color);\n\n  border: none;\n  outline: none;\n  cursor: text;\n  appearance: textarea;\n  resize: none;\n\n  &::selection {\n    color: var(--md-code-bg-color);\n    background: var(--md-code-fg-color);\n  }\n}\n",".md-typeset textarea {\n\n  scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n  scrollbar-width: thin;\n\n  &:hover {\n    scrollbar-color: var(--md-accent-fg-color) transparent;\n  }\n\n  &::-webkit-scrollbar {\n      width: px2rem(4px);\n      height: px2rem(4px);\n  }\n\n  &::-webkit-scrollbar-corner {\n    background-color: transparent;\n  }\n\n  &::-webkit-scrollbar-thumb {\n    background-color: var(--md-default-fg-color--lighter);\n\n    *:hover {\n      background-color: var(--md-accent-fg-color);\n    }\n  }\n}\n",".loading {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 2;\n    width: 100%;\n    height: 100%;\n    background-color: rgba(0,0,0,.2);\n    backdrop-filter: blur(2px);\n\n    .loader {\n        position: relative;\n        top: 50%;\n        left: 50%;\n        width: 80px;\n        height: 80px;\n        margin-top: -40px;\n        margin-left: -40px;\n        border-style: solid;\n        border-width: 10px;\n        border-top-color: rgb(0, 255, 255);\n        border-right-color: rgb(255, 255, 0);\n        border-bottom-color: rgb(0, 255, 0);\n        border-left-color: rgb(255, 0, 255);\n        border-radius: 50%;\n        animation: spin 2s linear infinite;\n\n        ~ div {\n            position: absolute;\n            top: 50%;\n            width: 100%;\n            margin-top: 40px;\n            font-weight: 800;\n            font-size: px2rem(20px);\n            text-align: center;\n        }\n    }\n\n    &.relative {\n        position: absolute;\n\n        .loader {\n            width: 2em;\n            height: 2em;\n            margin-top: -1em;\n            margin-left: -1em;\n            border-width: 0.4em;\n\n            ~ div {\n                display:none;\n            }\n        }\n    }\n}\n\n@keyframes spin {\n    0% {\n        transform: rotate(0);\n    }\n    100% {\n        transform: rotate(-360deg);\n    }\n}\n",":root {\n  --swatch-bar-border-color: hsl(0, 0%, 90%);\n  --swatch-border-color: hsl(0, 0%, 85%);\n  --swatch-gamut-border-color: hsl(340 82% 52%);\n  --swatch-stops: transparent;\n  --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.1\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #fefefe;\n\n  [data-md-color-scheme=\"slate\"] {\n    --swatch-border-color: hsla(232, 15%, 25%, 1);\n  }\n\n  [data-md-color-scheme=\"dracula\"] {\n    --swatch-bar-border-color: hsl(231deg 15% 20%);\n    --swatch-border-color: hsl(231deg 15% 25%);\n    --swatch-gamut-border-color: hsl(326, 100%, 74%);\n    --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.45\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #2b2e3b;\n  }\n}\n\n.swatch {\n  display: inline-block;\n  box-sizing: border-box;\n  width: px2em(20px);\n  height: px2em(20px);\n  margin-right: 0.2em;\n  margin-left: 0.25em;\n  line-height: 0;\n  vertical-align: text-bottom;\n  background: var(--transparency);\n  border: 2px solid var(--swatch-border-color);\n  border-radius: 100px;\n  box-shadow: 0.1em 0.1em 0.1em rgba(0, 0, 0, .3);\n  transition: all 0.5s ease;\n\n  &:hover {\n    z-index: 2;\n    transform: scale(2);\n  }\n\n  &:not(.swatch-gradient):hover {\n    cursor: pointer;\n  }\n}\n\n.swatch-color {\n  display: inline-block;\n  width: px2em(16.4px);\n  height: px2em(16.4px);\n  margin: 0;\n  padding: 0;\n  vertical-align: text-bottom;\n  background: linear-gradient(to right, var(--swatch-stops));\n  border-radius: 100px;\n}\n\n.swatch-gradient {\n  width: 100%;\n  height: px2em(48px);\n  margin: 0;\n  border-radius: 0;\n\n  .swatch-color {\n    width: 100%;\n    height: px2em(44px);\n    border-radius: 0;\n  }\n}\n\ndiv.swatch-bar {\n  box-sizing: border-box;\n  background: var(--transparency);\n  background-size: 1em 1em;\n  border: 2px solid var(--swatch-bar-border-color);\n\n  .swatch {\n    background-position: 0 0, 0 0.50em, 0.50em -0.50em, -0.50em 0px;\n    background-size: 1em 1em;\n\n    &:not(.out-of-gamut) {\n      box-shadow: none;\n    }\n\n    &:not(.swatch-gradient) {\n      width: px2em(48px);\n      height: px2em(48px);\n      margin: 0;\n      border-radius: 0;\n\n      .swatch-color {\n        width: px2em(44px);\n        height: px2em(44px);\n        margin: 0;\n        border-radius: 0;\n      }\n    }\n\n    &:hover {\n      transform: scale(1.2) translateY(-0.2em);\n    }\n  }\n\n  .swatch-gradient:hover {\n    transform: scale(1.02, 1.2) translateY(-0.2em);\n  }\n}\n\n.swatch.out-of-gamut {\n  padding: 1px;\n  border: 1px solid var(--swatch-gamut-border-color);\n  box-shadow: inset 0 0 0 1px var(--md-code-bg-color);\n}\n\n@media (color-gamut: p3) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n\n@media (color-gamut: rec2020) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n",".playground-code {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  margin-top: 2px;\n  overflow: hidden;\n}\n\n.playground-code.hidden {\n  margin-top: 0;\n}\n\n.playground-code .highlight code {\n  min-height: 3em;\n}\n\n.playground-code .highlight,\n.playground-code .highlight code {\n  margin: 0;\n  overflow: hidden;\n}\n\n.playground-code pre {\n  height: calc(100% + px2rem(4px));\n  margin: 0;\n  pointer-events: none;\n}\n\n.playground-results code {\n  min-height: 3em;\n}\n\n.playground-results pre {\n  margin-bottom: 0;\n}\n\n.playground-results .swatch-bar {\n  min-height: calc(3em + 4px);\n}\n\n.playground-results .swatch-bar:empty {\n  display: none;\n}\n\n.playground-results .swatch-bar:empty + .highlight {\n  border-color: transparent;\n}\n\n.playground-results .color-command {\n  margin-bottom: 0;\n}\n\n.hidden .highlight,\n.hidden .playground-inputs {\n  display: none;\n}\n\n.playground-code:not(.hidden) div.highlight {\n  display: none;\n}\n\n.playground-footer {\n  margin-bottom: 1em;\n  padding: px2em(3px, 13.6px) px2em(16px, 13.6px) px2em(2px, 13.6px);\n  color: var(--md-code-hl-comment-color);\n  font-size: px2em(13.6px);\n  background: var(--md-code-bg-color);\n  border-bottom-right-radius: px2rem(2px);\n  border-bottom-left-radius: px2rem(2px);\n\n  hr {\n    margin: 0 0 px2em(2px, 13.6px) 0;\n  }\n\n  .gamut {\n    float: right;\n  }\n}\n","div.color-command {\n  margin: 1em 0;\n  line-height: 0;\n\n  .highlight {\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: 0;\n\n    &:not(:first-child) {\n      border-top: 1px solid var(--md-default-fg-color--lightest);\n      border-top-left-radius: 0;\n      border-top-right-radius: 0;\n\n      pre {\n        margin-top: 0;\n      }\n    }\n  }\n}\n\n@media screen and (max-width: 44.9375em) {\n  .md-typeset > div.color-command {\n    margin-right:  px2rem(-16px);\n    margin-left: px2rem(-16px);\n\n    .highlight code {\n      border-radius: 0;\n    }\n  }\n}\n","#__notebook-source {\n  height: 100%;\n}\n\n#__notebook-source.hidden,\n#__notebook-render.hidden {\n  display: none;\n}\n"]}
\ No newline at end of file
diff --git a/docs/theme/assets/coloraide-extras/extra-391b1ef8ad.css b/docs/theme/assets/coloraide-extras/extra-8411e71fd9.css
similarity index 64%
rename from docs/theme/assets/coloraide-extras/extra-391b1ef8ad.css
rename to docs/theme/assets/coloraide-extras/extra-8411e71fd9.css
index 86a5ed02f..f091c6b6e 100644
--- a/docs/theme/assets/coloraide-extras/extra-391b1ef8ad.css
+++ b/docs/theme/assets/coloraide-extras/extra-8411e71fd9.css
@@ -1,2 +1,2 @@
-:root{--playground-edit-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25Z"/></svg>');--playground-share-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m2 14v-3c-3.61 0-6.19 1.43-8 4 .72-3.67 2.94-7.27 8-8V6l5 5-5 5Z"/></svg>');--playground-run-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20 19V7H4v12h16m0-16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16m-7 14v-2h5v2h-5m-3.42-4L5.57 9H8.4l3.3 3.3c.39.39.39 1.03 0 1.42L8.42 17H5.59l3.99-4Z"/></svg>');--playground-cancel-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91Z"/></svg>')}.notebook button:not(.md-clipboard),.playground button:not(.md-clipboard){position:relative;padding:0 1.5em;color:var(--md-typeset-a-color);border-radius:.1rem;transition:color 125ms}.notebook button:not(.md-clipboard)::before,.playground button:not(.md-clipboard)::before{position:absolute;left:0;display:block;box-sizing:border-box;width:1.25em;height:1.25em;background-color:var(--md-typeset-a-color);background-size:1.25em;transition:background-color 125ms;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;content:""}.notebook button:not(.md-clipboard)[disabled],.playground button:not(.md-clipboard)[disabled]{color:var(--md-code-hl-comment-color)}.notebook button:not(.md-clipboard)[disabled]::before,.playground button:not(.md-clipboard)[disabled]::before{background-color:var(--md-code-hl-comment-color)}.notebook button:not(.md-clipboard):hover,.playground button:not(.md-clipboard):hover{color:var(--md-accent-fg-color);cursor:pointer}.notebook button:not(.md-clipboard):hover::before,.playground button:not(.md-clipboard):hover::before{background-color:var(--md-accent-fg-color)}.notebook button:not(.md-clipboard).playground-edit::before,.playground button:not(.md-clipboard).playground-edit::before{-webkit-mask-image:var(--playground-edit-icon);mask-image:var(--playground-edit-icon)}.notebook button:not(.md-clipboard).playground-share::before,.playground button:not(.md-clipboard).playground-share::before{-webkit-mask-image:var(--playground-share-icon);mask-image:var(--playground-share-icon)}.notebook button:not(.md-clipboard)#__notebook-submit::before,.notebook button:not(.md-clipboard).playground-run::before,.playground button:not(.md-clipboard)#__notebook-submit::before,.playground button:not(.md-clipboard).playground-run::before{-webkit-mask-image:var(--playground-run-icon);mask-image:var(--playground-run-icon)}.notebook button:not(.md-clipboard)#__notebook-cancel::before,.notebook button:not(.md-clipboard).playground-cancel::before,.playground button:not(.md-clipboard)#__notebook-cancel::before,.playground button:not(.md-clipboard).playground-cancel::before{-webkit-mask-image:var(--playground-cancel-icon);mask-image:var(--playground-cancel-icon)}.notebook button:not(.md-clipboard).hidden,.playground button:not(.md-clipboard).hidden{display:none}.md-typeset .source-link{margin-left:.4rem}.playground-inputs,textarea#__notebook-input{z-index:1;display:block;width:100%;min-height:3em;margin:0;padding:.7720588235em 1.1764705882em;overflow-x:auto;overflow-y:hidden;color:var(--md-code-fg-color);caret-color:var(--md-code-fg-color);font-size:.85em;font-family:var(--md-code-font-family,_),SFMono-Regular,Consolas,Menlo,monospace;font-feature-settings:"kern";line-height:1.4;white-space:pre;word-wrap:unset;background:var(--md-code-bg-color);border:none;outline:0;cursor:text;-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;resize:none}.playground-inputs::-moz-selection,textarea#__notebook-input::-moz-selection{color:var(--md-code-bg-color);background:var(--md-code-fg-color)}.playground-inputs::selection,textarea#__notebook-input::selection{color:var(--md-code-bg-color);background:var(--md-code-fg-color)}.md-typeset textarea{scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-typeset textarea:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset textarea::-webkit-scrollbar{width:.2rem;height:.2rem}.md-typeset textarea::-webkit-scrollbar-corner{background-color:transparent}.md-typeset textarea::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset textarea::-webkit-scrollbar-thumb :hover{background-color:var(--md-accent-fg-color)}.loading{position:fixed;top:0;right:0;bottom:0;left:0;z-index:2;width:100%;height:100%;background-color:rgba(0,0,0,.2);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.loading .loader{position:relative;top:50%;left:50%;width:80px;height:80px;margin-top:-40px;margin-left:-40px;border-style:solid;border-width:10px;border-top-color:#0ff;border-right-color:#ff0;border-bottom-color:#0f0;border-left-color:#f0f;border-radius:50%;animation:spin 2s linear infinite}.loading .loader~div{position:absolute;top:50%;width:100%;margin-top:40px;font-weight:800;font-size:1rem;text-align:center}.loading.relative{position:absolute}.loading.relative .loader{width:2em;height:2em;margin-top:-1em;margin-left:-1em;border-width:.4em}.loading.relative .loader~div{display:none}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(-360deg)}}:root{--swatch-bar-border-color:hsl(0, 0%, 90%);--swatch-border-color:hsl(0, 0%, 85%);--swatch-gamut-border-color:hsl(340 82% 52%);--swatch-stops:transparent;--transparency:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" fill-opacity=".1" viewBox="0 0 100 100"><path d="M0 0h50v50H0zM50 50h50v50H50z"/></svg>') 0 0/0.5em 0.5em #fefefe}:root [data-md-color-scheme=slate]{--swatch-border-color:hsla(232, 15%, 25%, 1)}:root [data-md-color-scheme=dracula]{--swatch-bar-border-color:hsl(231deg 15% 20%);--swatch-border-color:hsl(231deg 15% 25%);--swatch-gamut-border-color:hsl(326, 100%, 74%);--transparency:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" fill-opacity=".45" viewBox="0 0 100 100"><path d="M0 0h50v50H0zM50 50h50v50H50z"/></svg>') 0 0/0.5em 0.5em #2b2e3b}.swatch{display:inline-block;box-sizing:border-box;width:1.25em;height:1.25em;margin-right:.2em;margin-left:.25em;line-height:0;vertical-align:text-bottom;background:var(--transparency);border:2px solid var(--swatch-border-color);border-radius:100px;box-shadow:.1em .1em .1em rgba(0,0,0,.3);transition:all .5s ease}.swatch:hover{z-index:2;transform:scale(2)}.swatch:not(.swatch-gradient):hover{cursor:pointer}.swatch-color{display:inline-block;width:1.025em;height:1.025em;margin:0;padding:0;vertical-align:text-bottom;background:linear-gradient(to right,var(--swatch-stops));border-radius:100px}.swatch-gradient{width:100%;height:3em;margin:0;border-radius:0}.swatch-gradient .swatch-color{width:100%;height:2.75em;border-radius:0}div.swatch-bar{box-sizing:border-box;background:var(--transparency);background-size:1em 1em;border:2px solid var(--swatch-bar-border-color)}div.swatch-bar .swatch{background-position:0 0,0 .5em,.5em -.5em,-.5em 0;background-size:1em 1em}div.swatch-bar .swatch:not(.out-of-gamut){box-shadow:none}div.swatch-bar .swatch:not(.swatch-gradient){width:3em;height:3em;margin:0;border-radius:0}div.swatch-bar .swatch:not(.swatch-gradient) .swatch-color{width:2.75em;height:2.75em;margin:0;border-radius:0}div.swatch-bar .swatch:hover{transform:scale(1.2) translateY(-.2em)}div.swatch-bar .swatch-gradient:hover{transform:scale(1.02,1.2) translateY(-.2em)}.swatch.out-of-gamut{padding:1px;border:1px solid var(--swatch-gamut-border-color);box-shadow:inset 0 0 0 1px var(--md-code-bg-color)}.playground-code{position:relative;width:100%;height:100%;margin-top:2px;overflow:hidden}.playground-code.hidden{margin-top:0}.playground-code .highlight code{min-height:3em}.playground-code .highlight,.playground-code .highlight code{margin:0;overflow:hidden}.playground-code pre{height:calc(100% + .2rem);margin:0;pointer-events:none}.playground-results code{min-height:3em}.playground-results pre{margin-bottom:0}.playground-results .swatch-bar{min-height:calc(3em + 4px)}.playground-results .swatch-bar:empty{display:none}.playground-results .swatch-bar:empty+.highlight{border-color:transparent}.playground-results .color-command{margin-bottom:0}.hidden .highlight,.hidden .playground-inputs{display:none}.playground-code:not(.hidden) div.highlight{display:none}.playground-footer{margin-bottom:1em;padding:.2205882353em 1.1764705882em .1470588235em;color:var(--md-code-hl-comment-color);font-size:.85em;background:var(--md-code-bg-color);border-bottom-right-radius:.1rem;border-bottom-left-radius:.1rem}.playground-footer hr{margin:0 0 .1470588235em 0}.playground-footer .gamut{float:right}div.color-command{margin:1em 0;line-height:0}div.color-command .highlight{border-bottom-right-radius:0;border-bottom-left-radius:0}div.color-command .highlight:not(:first-child){border-top:1px solid var(--md-default-fg-color--lightest);border-top-left-radius:0;border-top-right-radius:0}div.color-command .highlight:not(:first-child) pre{margin-top:0}#__notebook-source{height:100%}#__notebook-render.hidden,#__notebook-source.hidden{display:none}@media (color-gamut:p3){.swatch-color{background:linear-gradient(in xyz-d65 to right,var(--swatch-stops))}}@media (color-gamut:rec2020){.swatch-color{background:linear-gradient(in xyz-d65 to right,var(--swatch-stops))}}@media screen and (max-width:44.9375em){.md-typeset>div.color-command{margin-right:-.8rem;margin-left:-.8rem}.md-typeset>div.color-command .highlight code{border-radius:0}}
-/*# sourceMappingURL=extra-391b1ef8ad.css.map */
+:root{--playground-edit-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25Z"/></svg>');--playground-share-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2m2 14v-3c-3.61 0-6.19 1.43-8 4 .72-3.67 2.94-7.27 8-8V6l5 5-5 5Z"/></svg>');--playground-run-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20 19V7H4v12h16m0-16a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16m-7 14v-2h5v2h-5m-3.42-4L5.57 9H8.4l3.3 3.3c.39.39.39 1.03 0 1.42L8.42 17H5.59l3.99-4Z"/></svg>');--playground-cancel-icon:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="currentColor" d="M20 6.91 17.09 4 12 9.09 6.91 4 4 6.91 9.09 12 4 17.09 6.91 20 12 14.91 17.09 20 20 17.09 14.91 12 20 6.91Z"/></svg>')}.notebook button:not(.md-clipboard),.playground button:not(.md-clipboard){position:relative;padding:0 1.5em;color:var(--md-typeset-a-color);border-radius:.1rem;transition:color 125ms}.notebook button:not(.md-clipboard)::before,.playground button:not(.md-clipboard)::before{position:absolute;left:0;display:block;box-sizing:border-box;width:1.25em;height:1.25em;background-color:var(--md-typeset-a-color);background-size:1.25em;transition:background-color 125ms;-webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;-webkit-mask-size:contain;mask-size:contain;content:""}.notebook button:not(.md-clipboard)[disabled],.playground button:not(.md-clipboard)[disabled]{color:var(--md-code-hl-comment-color)}.notebook button:not(.md-clipboard)[disabled]::before,.playground button:not(.md-clipboard)[disabled]::before{background-color:var(--md-code-hl-comment-color)}.notebook button:not(.md-clipboard):hover,.playground button:not(.md-clipboard):hover{color:var(--md-accent-fg-color);cursor:pointer}.notebook button:not(.md-clipboard):hover::before,.playground button:not(.md-clipboard):hover::before{background-color:var(--md-accent-fg-color)}.notebook button:not(.md-clipboard).playground-edit::before,.playground button:not(.md-clipboard).playground-edit::before{-webkit-mask-image:var(--playground-edit-icon);mask-image:var(--playground-edit-icon)}.notebook button:not(.md-clipboard).playground-share::before,.playground button:not(.md-clipboard).playground-share::before{-webkit-mask-image:var(--playground-share-icon);mask-image:var(--playground-share-icon)}.notebook button:not(.md-clipboard)#__notebook-submit::before,.notebook button:not(.md-clipboard).playground-run::before,.playground button:not(.md-clipboard)#__notebook-submit::before,.playground button:not(.md-clipboard).playground-run::before{-webkit-mask-image:var(--playground-run-icon);mask-image:var(--playground-run-icon)}.notebook button:not(.md-clipboard)#__notebook-cancel::before,.notebook button:not(.md-clipboard).playground-cancel::before,.playground button:not(.md-clipboard)#__notebook-cancel::before,.playground button:not(.md-clipboard).playground-cancel::before{-webkit-mask-image:var(--playground-cancel-icon);mask-image:var(--playground-cancel-icon)}.notebook button:not(.md-clipboard).hidden,.playground button:not(.md-clipboard).hidden{display:none}.md-typeset .source-link{margin-left:.4rem}.playground-inputs,textarea#__notebook-input{z-index:1;display:block;width:100%;min-height:3em;margin:0;padding:.7720588235em 1.1764705882em;overflow-x:auto;overflow-y:hidden;color:var(--md-code-fg-color);caret-color:var(--md-code-fg-color);font-size:.85em;font-family:var(--md-code-font-family,_),SFMono-Regular,Consolas,Menlo,monospace;font-feature-settings:"kern";line-height:1.4;white-space:pre;word-wrap:unset;background:var(--md-code-bg-color);border:none;outline:0;cursor:text;-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;resize:none}.playground-inputs::-moz-selection,textarea#__notebook-input::-moz-selection{color:var(--md-code-bg-color);background:var(--md-code-fg-color)}.playground-inputs::selection,textarea#__notebook-input::selection{color:var(--md-code-bg-color);background:var(--md-code-fg-color)}.md-typeset textarea{scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.md-typeset textarea:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.md-typeset textarea::-webkit-scrollbar{width:.2rem;height:.2rem}.md-typeset textarea::-webkit-scrollbar-corner{background-color:transparent}.md-typeset textarea::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.md-typeset textarea::-webkit-scrollbar-thumb :hover{background-color:var(--md-accent-fg-color)}.loading{position:fixed;top:0;right:0;bottom:0;left:0;z-index:2;width:100%;height:100%;background-color:rgba(0,0,0,.2);-webkit-backdrop-filter:blur(2px);backdrop-filter:blur(2px)}.loading .loader{position:relative;top:50%;left:50%;width:80px;height:80px;margin-top:-40px;margin-left:-40px;border-style:solid;border-width:10px;border-top-color:#0ff;border-right-color:#ff0;border-bottom-color:#0f0;border-left-color:#f0f;border-radius:50%;animation:spin 2s linear infinite}.loading .loader~div{position:absolute;top:50%;width:100%;margin-top:40px;font-weight:800;font-size:1rem;text-align:center}.loading.relative{position:absolute}.loading.relative .loader{width:2em;height:2em;margin-top:-1em;margin-left:-1em;border-width:.4em}.loading.relative .loader~div{display:none}@keyframes spin{0%{transform:rotate(0)}100%{transform:rotate(-360deg)}}:root{--swatch-bar-border-color:hsl(0, 0%, 90%);--swatch-border-color:hsl(0, 0%, 85%);--swatch-gamut-border-color:hsl(340 82% 52%);--swatch-stops:transparent;--transparency:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" fill-opacity=".1" viewBox="0 0 100 100"><path d="M0 0h50v50H0zM50 50h50v50H50z"/></svg>') 0 0/0.5em 0.5em #fefefe}:root [data-md-color-scheme=slate]{--swatch-border-color:hsla(232, 15%, 25%, 1)}:root [data-md-color-scheme=dracula]{--swatch-bar-border-color:hsl(231deg 15% 20%);--swatch-border-color:hsl(231deg 15% 25%);--swatch-gamut-border-color:hsl(326, 100%, 74%);--transparency:url('data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg" fill-opacity=".45" viewBox="0 0 100 100"><path d="M0 0h50v50H0zM50 50h50v50H50z"/></svg>') 0 0/0.5em 0.5em #2b2e3b}.swatch{display:inline-block;box-sizing:border-box;width:1.25em;height:1.25em;margin-right:.2em;margin-left:.25em;line-height:0;vertical-align:text-bottom;background:var(--transparency);border:2px solid var(--swatch-border-color);border-radius:100px;box-shadow:.1em .1em .1em rgba(0,0,0,.3);transition:all .5s ease}.swatch:hover{z-index:2;transform:scale(2)}.swatch:not(.swatch-gradient):hover{cursor:pointer}.swatch-color{display:inline-block;width:1.025em;height:1.025em;margin:0;padding:0;vertical-align:text-bottom;background:linear-gradient(to right,var(--swatch-stops));border-radius:100px}.swatch-gradient{width:100%;height:3em;margin:0;border-radius:0}.swatch-gradient .swatch-color{width:100%;height:2.75em;border-radius:0}div.swatch-bar{box-sizing:border-box;background:var(--transparency);background-size:1em 1em;border:2px solid var(--swatch-bar-border-color)}div.swatch-bar .swatch{background-position:0 0,0 .5em,.5em -.5em,-.5em 0;background-size:1em 1em}div.swatch-bar .swatch:not(.out-of-gamut){box-shadow:none}div.swatch-bar .swatch:not(.swatch-gradient){width:3em;height:3em;margin:0;border-radius:0}div.swatch-bar .swatch:not(.swatch-gradient) .swatch-color{width:2.75em;height:2.75em;margin:0;border-radius:0}div.swatch-bar .swatch:hover{transform:scale(1.2) translateY(-.2em)}div.swatch-bar .swatch-gradient:hover{transform:scale(1.02,1.2) translateY(-.2em)}.swatch.out-of-gamut{padding:1px;border:1px solid var(--swatch-gamut-border-color);box-shadow:inset 0 0 0 1px var(--md-code-bg-color)}.color-wheel{--color-wheel-stops1:transparent;--color-wheel-stops2:transparent;--color-wheel-stops3:transparent;--color-wheel-stops4:transparent;--color-wheel-stops5:transparent;--color-wheel-bg:var(--md-default-bg-color);margin:1em 0;overflow-x:scroll;overflow-y:hidden;scrollbar-color:var(--md-default-fg-color--lighter) transparent;scrollbar-width:thin}.color-wheel::-webkit-scrollbar{width:.2rem;height:.2rem}.color-wheel::-webkit-scrollbar-corner{background-color:transparent}.color-wheel::-webkit-scrollbar-thumb{background-color:var(--md-default-fg-color--lighter)}.color-wheel::-webkit-scrollbar-thumb:hover{background-color:var(--md-accent-fg-color)}.color-wheel:hover{scrollbar-color:var(--md-accent-fg-color) transparent}.color-wheel div{overflow:clip}.color-wheel .wheel{min-width:-moz-max-content;min-width:max-content;padding:.3125em;border-radius:1000px}.color-wheel .wheel .primary{width:12em;height:10.39em;margin:auto;-webkit-clip-path:polygon(50% 0,100% 100%,0 100%);clip-path:polygon(50% 0,100% 100%,0 100%)}.color-wheel .wheel .primary .primary-inner{width:12em;height:14em;background:conic-gradient(in xyz-d65,var(--color-wheel-stops1));transform:rotate(180deg)}.color-wheel .wheel .secondary{width:14em;height:14em;margin:auto;background:var(--color-wheel-bg);border-radius:1000px}.color-wheel .wheel .secondary .secondary-inner{width:14em;height:14em;margin:auto;background:conic-gradient(in xyz-d65,var(--color-wheel-stops2));transform:rotate(-135deg);-webkit-clip-path:polygon(50% 0,93% 25%,93% 75%,50% 100%,7% 75%,7% 25%);clip-path:polygon(50% 0,93% 25%,93% 75%,50% 100%,7% 75%,7% 25%)}.color-wheel .wheel .tertiary{width:22em;height:22em;padding:4em 0;background:conic-gradient(in xyz-d65,var(--color-wheel-stops3));border-radius:1000px;outline:5px solid var(--color-wheel-bg);transform:rotate(135deg)}.color-wheel .wheel .tertiary2{width:30em;height:30em;padding:4em 0;background:conic-gradient(in xyz-d65,var(--color-wheel-stops4));border-radius:1000px;outline:5px solid var(--color-wheel-bg);transform:rotate(128deg)}.color-wheel .wheel .tertiary2 .tertiary{margin:auto;transform:rotate(8deg)}.color-wheel .wheel .tertiary3{width:38em;height:38em;padding:4em 0;background:conic-gradient(in xyz-d65,var(--color-wheel-stops5));border-radius:1000px;outline:5px solid var(--color-wheel-bg);transform:rotate(123deg)}.color-wheel .wheel .tertiary3 .tertiary2{margin:auto;transform:rotate(4deg)}.playground-code{position:relative;width:100%;height:100%;margin-top:2px;overflow:hidden}.playground-code.hidden{margin-top:0}.playground-code .highlight code{min-height:3em}.playground-code .highlight,.playground-code .highlight code{margin:0;overflow:hidden}.playground-code pre{height:calc(100% + .2rem);margin:0;pointer-events:none}.playground-results code{min-height:3em}.playground-results pre{margin-bottom:0}.playground-results .swatch-bar{min-height:calc(3em + 4px)}.playground-results .swatch-bar:empty{display:none}.playground-results .swatch-bar:empty+.highlight{border-color:transparent}.playground-results .color-command{margin-bottom:0}.hidden .highlight,.hidden .playground-inputs{display:none}.playground-code:not(.hidden) div.highlight{display:none}.playground-footer{margin-bottom:1em;padding:.2205882353em 1.1764705882em .1470588235em;color:var(--md-code-hl-comment-color);font-size:.85em;background:var(--md-code-bg-color);border-bottom-right-radius:.1rem;border-bottom-left-radius:.1rem}.playground-footer hr{margin:0 0 .1470588235em 0}.playground-footer .gamut{float:right}div.color-command{margin:1em 0;line-height:0}div.color-command .highlight{border-bottom-right-radius:0;border-bottom-left-radius:0}div.color-command .highlight:not(:first-child){border-top:1px solid var(--md-default-fg-color--lightest);border-top-left-radius:0;border-top-right-radius:0}div.color-command .highlight:not(:first-child) pre{margin-top:0}#__notebook-source{height:100%}#__notebook-render.hidden,#__notebook-source.hidden{display:none}@media (color-gamut:p3){.swatch-color{background:linear-gradient(in xyz-d65 to right,var(--swatch-stops))}}@media (color-gamut:rec2020){.swatch-color{background:linear-gradient(in xyz-d65 to right,var(--swatch-stops))}}@media screen and (max-width:44.9375em){.md-typeset>div.color-command{margin-right:-.8rem;margin-left:-.8rem}.md-typeset>div.color-command .highlight code{border-radius:0}}
+/*# sourceMappingURL=extra-8411e71fd9.css.map */
diff --git a/docs/theme/assets/coloraide-extras/extra-8411e71fd9.css.map b/docs/theme/assets/coloraide-extras/extra-8411e71fd9.css.map
new file mode 100644
index 000000000..04016aa12
--- /dev/null
+++ b/docs/theme/assets/coloraide-extras/extra-8411e71fd9.css.map
@@ -0,0 +1,1 @@
+{"version":3,"sources":["_buttons.scss","extra.css","_inputs.scss","_scroll.scss","_loader.scss","_swatch.scss","_colorwheel.scss","_playground.scss","_color_command.scss","_notebook.scss"],"names":[],"mappings":"AAAA,MACE,uBAAA,qRACA,wBAAA,uQACA,sBAAA,wTACA,yBAAA,sPCIF,oCDCE,sCACE,SAAA,SACA,QAAA,EAAA,MACA,MAAA,0BACA,cAAA,MACA,WAAA,MAAA,MCEJ,4CDAI,8CACG,SAAA,SACA,KAAA,EACA,QAAA,MACA,WAAA,WACA,MAAA,OACA,OAAA,OACA,iBAAA,0BACA,gBAAA,OACA,WAAA,iBAAA,MACA,oBAAA,UAAA,YAAA,UACA,kBAAA,QAAA,UAAA,QACA,QAAA,GCKP,8CDFI,gDACE,MAAA,gCCKN,sDDHM,wDACE,iBAAA,gCCMR,0CDFI,4CACE,MAAA,0BACA,OAAA,QCKN,kDDHM,oDACE,iBAAA,0BCMR,4DDFI,8DACE,mBAAA,4BAAA,WAAA,4BCMN,6DDHI,+DACE,mBAAA,6BAAA,WAAA,6BCON,8DACA,2DDLI,gEAAA,6DAEE,mBAAA,2BAAA,WAAA,2BCQN,8DACA,8DDNI,gEAAA,gEAEE,mBAAA,8BAAA,WAAA,8BCSN,2CDNI,6CACE,QAAA,KAMN,yBACE,YAAA,MCOF,mBCjFA,0BAEE,QAAA,EACA,QAAA,MACA,MAAA,KACA,WAAA,IAEA,OAAA,EACA,QAAA,cAAA,eACA,WAAA,KACA,WAAA,OACA,MAAA,wBACA,YAAA,wBAEA,UAAA,MACA,YAAA,4BAAA,CAAA,cAAA,CAAA,QAAA,CAAA,KAAA,CAAA,UACA,sBAAA,OACA,YAAA,IACA,YAAA,IACA,UAAA,MACA,WAAA,wBAEA,OAAA,KACA,QAAA,EACA,OAAA,KACA,mBAAA,SAAA,gBAAA,SAAA,WAAA,SACA,OAAA,KAEA,mCAAA,0CACE,MAAA,wBACA,WAAA,wBDkFJ,8BCpFE,qCACE,MAAA,wBACA,WAAA,wBC9BJ,qBAEE,gBAAA,oCAAA,YACA,gBAAA,KAEA,2BACE,gBAAA,0BAAA,YAGF,wCACI,MAAA,MACA,OAAA,MAGJ,+CACE,iBAAA,YAGF,8CACE,iBAAA,oCAEA,qDACE,iBAAA,0BCtBN,SACI,SAAA,MACA,IAAA,EACA,MAAA,EACA,OAAA,EACA,KAAA,EACA,QAAA,EACA,MAAA,KACA,OAAA,KACA,iBAAA,eACA,wBAAA,UAAA,gBAAA,UAEA,iBACI,SAAA,SACA,IAAA,IACA,KAAA,IACA,MAAA,KACA,OAAA,KACA,WAAA,MACA,YAAA,MACA,aAAA,MACA,aAAA,KACA,iBAAA,KACA,mBAAA,KACA,oBAAA,KACA,kBAAA,KACA,cAAA,IACA,UAAA,KAAA,GAAA,OAAA,SAEA,qBACI,SAAA,SACA,IAAA,IACA,MAAA,KACA,WAAA,KACA,YAAA,IACA,UAAA,KACA,WAAA,OAIR,kBACI,SAAA,SAEA,0BACI,MAAA,IACA,OAAA,IACA,WAAA,KACA,YAAA,KACA,aAAA,KAEA,8BACI,QAAA,KAMhB,gBACI,GACI,UAAA,UAEJ,KACI,UAAA,iBC9DR,MACE,0BAAA,gBACA,sBAAA,gBACA,4BAAA,iBACA,eAAA,YACA,eAAA,wKJwMA,EAAE,CAAE,CAAE,MAAM,MAAM,QIrMlB,mCACE,sBAAA,uBAGF,qCACE,0BAAA,oBACA,sBAAA,oBACA,4BAAA,oBACA,eAAA,yKJuMF,EAAE,CAAE,CAAE,MAAM,MAAM,QIlMpB,QACE,QAAA,aACA,WAAA,WACA,MAAA,OACA,OAAA,OACA,aAAA,KACA,YAAA,MACA,YAAA,EACA,eAAA,YACA,WAAA,oBACA,OAAA,IAAA,MAAA,2BACA,cAAA,MACA,WAAA,KAAA,KAAA,KAAA,eACA,WAAA,IAAA,IAAA,KAEA,cACE,QAAA,EACA,UAAA,SAGF,oCACE,OAAA,QAIJ,cACE,QAAA,aACA,MAAA,QACA,OAAA,QACA,OAAA,EACA,QAAA,EACA,eAAA,YACA,WAAA,8CACA,cAAA,MAGF,iBACE,MAAA,KACA,OAAA,IACA,OAAA,EACA,cAAA,EAEA,+BACE,MAAA,KACA,OAAA,OACA,cAAA,EAIJ,eACE,WAAA,WACA,WAAA,oBACA,gBAAA,IAAA,IACA,OAAA,IAAA,MAAA,+BAEA,uBACE,oBAAA,EAAA,CAAA,CAAA,EAAA,IAAA,CAAA,KAAA,KAAA,CAAA,MAAA,EACA,gBAAA,IAAA,IAEA,0CACE,WAAA,KAGF,6CACE,MAAA,IACA,OAAA,IACA,OAAA,EACA,cAAA,EAEA,2DACE,MAAA,OACA,OAAA,OACA,OAAA,EACA,cAAA,EAIJ,6BACE,UAAA,WAAA,kBAIJ,sCACE,UAAA,gBAAA,kBAIJ,qBACE,QAAA,IACA,OAAA,IAAA,MAAA,iCACA,WAAA,MAAA,EAAA,EAAA,EAAA,IAAA,wBC/GF,aACE,qBAAA,YACA,qBAAA,YACA,qBAAA,YACA,qBAAA,YACA,qBAAA,YACA,iBAAA,2BAEA,OAAA,IAAA,EACA,WAAA,OACA,WAAA,OAuBA,gBAAA,oCAAA,YACA,gBAAA,KArBA,gCACE,MAAA,MACA,OAAA,MAGF,uCACE,iBAAA,YAIF,sCACE,iBAAA,oCAGA,4CACE,iBAAA,0BASJ,mBACE,gBAAA,0BAAA,YAGF,iBACE,SAAA,KAGF,oBACE,UAAA,iBAAA,UAAA,YACA,QAAA,QACA,cAAA,OAEA,6BACE,MAAA,KACA,OAAA,QACA,OAAA,KACA,kBAAA,gCAAA,UAAA,gCAEA,4CACE,MAAA,KACA,OAAA,KACA,WAAA,qDACA,UAAA,eAIJ,+BACE,MAAA,KACA,OAAA,KACA,OAAA,KACA,WAAA,sBACA,cAAA,OAEA,gDACE,MAAA,KACA,OAAA,KACA,OAAA,KACA,WAAA,qDACA,UAAA,gBACA,kBAAA,sDAAA,UAAA,sDAIJ,8BACE,MAAA,KACA,OAAA,KACA,QAAA,IAAA,EACA,WAAA,qDACA,cAAA,OACA,QAAA,IAAA,MAAA,sBACA,UAAA,eAGF,+BACE,MAAA,KACA,OAAA,KACA,QAAA,IAAA,EACA,WAAA,qDACA,cAAA,OACA,QAAA,IAAA,MAAA,sBACA,UAAA,eAEA,yCACE,OAAA,KACA,UAAA,aAIJ,+BACE,MAAA,KACA,OAAA,KACA,QAAA,IAAA,EACA,WAAA,qDACA,cAAA,OACA,QAAA,IAAA,MAAA,sBACA,UAAA,eAEA,0CACE,OAAA,KACA,UAAA,aCrHR,iBACE,SAAA,SACA,MAAA,KACA,OAAA,KACA,WAAA,IACA,SAAA,OAGF,wBACE,WAAA,EAGF,iCACE,WAAA,IAGF,4BNqZA,iCMnZE,OAAA,EACA,SAAA,OAGF,qBACE,OAAA,mBACA,OAAA,EACA,eAAA,KAGF,yBACE,WAAA,IAGF,wBACE,cAAA,EAGF,gCACE,WAAA,gBAGF,sCACE,QAAA,KAGF,iDACE,aAAA,YAGF,mCACE,cAAA,EAGF,mBNqZA,2BMnZE,QAAA,KAGF,4CACE,QAAA,KAGF,mBACE,cAAA,IACA,QAAA,cAAA,eAAA,cACA,MAAA,gCACA,UAAA,MACA,WAAA,wBACA,2BAAA,MACA,0BAAA,MAEA,sBACE,OAAA,EAAA,EAAA,cAAA,EAGF,0BACE,MAAA,MC3EJ,kBACE,OAAA,IAAA,EACA,YAAA,EAEA,6BACE,2BAAA,EACA,0BAAA,EAEA,+CACE,WAAA,IAAA,MAAA,qCACA,uBAAA,EACA,wBAAA,EAEA,mDACE,WAAA,ECdR,mBACE,OAAA,KRqfF,0BQlfA,0BAEE,QAAA,KJ4GF,wBACE,cACE,WAAA,0DAIJ,6BACE,cACE,WAAA,0DGtGJ,wCACE,8BACE,aAAA,OACA,YAAA,OAEA,8CACE,cAAA","file":"extra-8411e71fd9.css","sourcesContent":[":root {\n  --playground-edit-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z' /%3E%3C/svg%3E\");\n  --playground-share-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M14 16V13C10.39 13 7.81 14.43 6 17C6.72 13.33 8.94 9.73 14 9V6L19 11L14 16Z' /%3E%3C/svg%3E\");\n  --playground-run-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20,19V7H4V19H20M20,3A2,2 0 0,1 22,5V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V5C2,3.89 2.9,3 4,3H20M13,17V15H18V17H13M9.58,13L5.57,9H8.4L11.7,12.3C12.09,12.69 12.09,13.33 11.7,13.72L8.42,17H5.59L9.58,13Z' /%3E%3C/svg%3E\");\n  --playground-cancel-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z' /%3E%3C/svg%3E\");\n}\n\n.playground,\n.notebook {\n  button:not(.md-clipboard) {\n    position: relative;\n    padding: 0 1.5em;\n    color: var(--md-typeset-a-color);\n    border-radius: px2rem(2px);\n    transition: color 125ms;\n\n    &::before {\n       position: absolute;\n       left: 0;\n       display: block;\n       box-sizing: border-box;\n       width: 1.25em;\n       height: 1.25em;\n       background-color: var(--md-typeset-a-color);\n       background-size: 1.25em;\n       transition: background-color 125ms;\n       mask-repeat: no-repeat;\n       mask-size: contain;\n       content: \"\";\n    }\n\n    &[disabled] {\n      color: var(--md-code-hl-comment-color);\n\n      &::before {\n        background-color: var(--md-code-hl-comment-color);\n      }\n    }\n\n    &:hover {\n      color: var(--md-accent-fg-color);\n      cursor: pointer;\n\n      &::before {\n        background-color: var(--md-accent-fg-color);\n      }\n    }\n\n    &.playground-edit::before {\n      mask-image: var(--playground-edit-icon);\n    }\n\n    &.playground-share::before {\n      mask-image: var(--playground-share-icon);\n    }\n\n    &#__notebook-submit::before,\n    &.playground-run::before {\n      mask-image: var(--playground-run-icon);\n    }\n\n    &#__notebook-cancel::before,\n    &.playground-cancel::before {\n      mask-image: var(--playground-cancel-icon);\n    }\n\n    &.hidden {\n      display: none;\n    }\n  }\n}\n\n// Special buttons in our toolbar\n.md-typeset .source-link {\n  margin-left: px2rem(8px);\n}\n",":root {\n  --playground-edit-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20.71,7.04C21.1,6.65 21.1,6 20.71,5.63L18.37,3.29C18,2.9 17.35,2.9 16.96,3.29L15.12,5.12L18.87,8.87M3,17.25V21H6.75L17.81,9.93L14.06,6.18L3,17.25Z' /%3E%3C/svg%3E\");\n  --playground-share-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M12 2C6.5 2 2 6.5 2 12S6.5 22 12 22 22 17.5 22 12 17.5 2 12 2M14 16V13C10.39 13 7.81 14.43 6 17C6.72 13.33 8.94 9.73 14 9V6L19 11L14 16Z' /%3E%3C/svg%3E\");\n  --playground-run-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20,19V7H4V19H20M20,3A2,2 0 0,1 22,5V19A2,2 0 0,1 20,21H4A2,2 0 0,1 2,19V5C2,3.89 2.9,3 4,3H20M13,17V15H18V17H13M9.58,13L5.57,9H8.4L11.7,12.3C12.09,12.69 12.09,13.33 11.7,13.72L8.42,17H5.59L9.58,13Z' /%3E%3C/svg%3E\");\n  --playground-cancel-icon: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='currentColor' d='M20 6.91L17.09 4L12 9.09L6.91 4L4 6.91L9.09 12L4 17.09L6.91 20L12 14.91L17.09 20L20 17.09L14.91 12L20 6.91Z' /%3E%3C/svg%3E\");\n}\n\n.playground button:not(.md-clipboard),\n.notebook button:not(.md-clipboard) {\n  position: relative;\n  padding: 0 1.5em;\n  color: var(--md-typeset-a-color);\n  border-radius: 0.1rem;\n  transition: color 125ms;\n}\n.playground button:not(.md-clipboard)::before,\n.notebook button:not(.md-clipboard)::before {\n  position: absolute;\n  left: 0;\n  display: block;\n  box-sizing: border-box;\n  width: 1.25em;\n  height: 1.25em;\n  background-color: var(--md-typeset-a-color);\n  background-size: 1.25em;\n  transition: background-color 125ms;\n  mask-repeat: no-repeat;\n  mask-size: contain;\n  content: \"\";\n}\n.playground button:not(.md-clipboard)[disabled],\n.notebook button:not(.md-clipboard)[disabled] {\n  color: var(--md-code-hl-comment-color);\n}\n.playground button:not(.md-clipboard)[disabled]::before,\n.notebook button:not(.md-clipboard)[disabled]::before {\n  background-color: var(--md-code-hl-comment-color);\n}\n.playground button:not(.md-clipboard):hover,\n.notebook button:not(.md-clipboard):hover {\n  color: var(--md-accent-fg-color);\n  cursor: pointer;\n}\n.playground button:not(.md-clipboard):hover::before,\n.notebook button:not(.md-clipboard):hover::before {\n  background-color: var(--md-accent-fg-color);\n}\n.playground button:not(.md-clipboard).playground-edit::before,\n.notebook button:not(.md-clipboard).playground-edit::before {\n  mask-image: var(--playground-edit-icon);\n}\n.playground button:not(.md-clipboard).playground-share::before,\n.notebook button:not(.md-clipboard).playground-share::before {\n  mask-image: var(--playground-share-icon);\n}\n.playground button:not(.md-clipboard)#__notebook-submit::before, .playground button:not(.md-clipboard).playground-run::before,\n.notebook button:not(.md-clipboard)#__notebook-submit::before,\n.notebook button:not(.md-clipboard).playground-run::before {\n  mask-image: var(--playground-run-icon);\n}\n.playground button:not(.md-clipboard)#__notebook-cancel::before, .playground button:not(.md-clipboard).playground-cancel::before,\n.notebook button:not(.md-clipboard)#__notebook-cancel::before,\n.notebook button:not(.md-clipboard).playground-cancel::before {\n  mask-image: var(--playground-cancel-icon);\n}\n.playground button:not(.md-clipboard).hidden,\n.notebook button:not(.md-clipboard).hidden {\n  display: none;\n}\n\n.md-typeset .source-link {\n  margin-left: 0.4rem;\n}\n\ntextarea#__notebook-input,\n.playground-inputs {\n  z-index: 1;\n  display: block;\n  width: 100%;\n  min-height: 3em;\n  margin: 0;\n  padding: 0.7720588235em 1.1764705882em;\n  overflow-x: auto;\n  overflow-y: hidden;\n  color: var(--md-code-fg-color);\n  caret-color: var(--md-code-fg-color);\n  font-size: 0.85em;\n  font-family: var(--md-code-font-family, _), SFMono-Regular, Consolas, Menlo, monospace;\n  font-feature-settings: \"kern\";\n  line-height: 1.4;\n  white-space: pre;\n  word-wrap: unset;\n  background: var(--md-code-bg-color);\n  border: none;\n  outline: none;\n  cursor: text;\n  appearance: textarea;\n  resize: none;\n}\ntextarea#__notebook-input::selection,\n.playground-inputs::selection {\n  color: var(--md-code-bg-color);\n  background: var(--md-code-fg-color);\n}\n\n.md-typeset textarea {\n  scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n  scrollbar-width: thin;\n}\n.md-typeset textarea:hover {\n  scrollbar-color: var(--md-accent-fg-color) transparent;\n}\n.md-typeset textarea::-webkit-scrollbar {\n  width: 0.2rem;\n  height: 0.2rem;\n}\n.md-typeset textarea::-webkit-scrollbar-corner {\n  background-color: transparent;\n}\n.md-typeset textarea::-webkit-scrollbar-thumb {\n  background-color: var(--md-default-fg-color--lighter);\n}\n.md-typeset textarea::-webkit-scrollbar-thumb *:hover {\n  background-color: var(--md-accent-fg-color);\n}\n\n.loading {\n  position: fixed;\n  top: 0;\n  right: 0;\n  bottom: 0;\n  left: 0;\n  z-index: 2;\n  width: 100%;\n  height: 100%;\n  background-color: rgba(0, 0, 0, 0.2);\n  backdrop-filter: blur(2px);\n}\n.loading .loader {\n  position: relative;\n  top: 50%;\n  left: 50%;\n  width: 80px;\n  height: 80px;\n  margin-top: -40px;\n  margin-left: -40px;\n  border-style: solid;\n  border-width: 10px;\n  border-top-color: rgb(0, 255, 255);\n  border-right-color: rgb(255, 255, 0);\n  border-bottom-color: rgb(0, 255, 0);\n  border-left-color: rgb(255, 0, 255);\n  border-radius: 50%;\n  animation: spin 2s linear infinite;\n}\n.loading .loader ~ div {\n  position: absolute;\n  top: 50%;\n  width: 100%;\n  margin-top: 40px;\n  font-weight: 800;\n  font-size: 1rem;\n  text-align: center;\n}\n.loading.relative {\n  position: absolute;\n}\n.loading.relative .loader {\n  width: 2em;\n  height: 2em;\n  margin-top: -1em;\n  margin-left: -1em;\n  border-width: 0.4em;\n}\n.loading.relative .loader ~ div {\n  display: none;\n}\n\n@keyframes spin {\n  0% {\n    transform: rotate(0);\n  }\n  100% {\n    transform: rotate(-360deg);\n  }\n}\n:root {\n  --swatch-bar-border-color: hsl(0, 0%, 90%);\n  --swatch-border-color: hsl(0, 0%, 85%);\n  --swatch-gamut-border-color: hsl(340 82% 52%);\n  --swatch-stops: transparent;\n  --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.1\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #fefefe;\n}\n:root [data-md-color-scheme=slate] {\n  --swatch-border-color: hsla(232, 15%, 25%, 1);\n}\n:root [data-md-color-scheme=dracula] {\n  --swatch-bar-border-color: hsl(231deg 15% 20%);\n  --swatch-border-color: hsl(231deg 15% 25%);\n  --swatch-gamut-border-color: hsl(326, 100%, 74%);\n  --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.45\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #2b2e3b;\n}\n\n.swatch {\n  display: inline-block;\n  box-sizing: border-box;\n  width: 1.25em;\n  height: 1.25em;\n  margin-right: 0.2em;\n  margin-left: 0.25em;\n  line-height: 0;\n  vertical-align: text-bottom;\n  background: var(--transparency);\n  border: 2px solid var(--swatch-border-color);\n  border-radius: 100px;\n  box-shadow: 0.1em 0.1em 0.1em rgba(0, 0, 0, 0.3);\n  transition: all 0.5s ease;\n}\n.swatch:hover {\n  z-index: 2;\n  transform: scale(2);\n}\n.swatch:not(.swatch-gradient):hover {\n  cursor: pointer;\n}\n\n.swatch-color {\n  display: inline-block;\n  width: 1.025em;\n  height: 1.025em;\n  margin: 0;\n  padding: 0;\n  vertical-align: text-bottom;\n  background: linear-gradient(to right, var(--swatch-stops));\n  border-radius: 100px;\n}\n\n.swatch-gradient {\n  width: 100%;\n  height: 3em;\n  margin: 0;\n  border-radius: 0;\n}\n.swatch-gradient .swatch-color {\n  width: 100%;\n  height: 2.75em;\n  border-radius: 0;\n}\n\ndiv.swatch-bar {\n  box-sizing: border-box;\n  background: var(--transparency);\n  background-size: 1em 1em;\n  border: 2px solid var(--swatch-bar-border-color);\n}\ndiv.swatch-bar .swatch {\n  background-position: 0 0, 0 0.5em, 0.5em -0.5em, -0.5em 0px;\n  background-size: 1em 1em;\n}\ndiv.swatch-bar .swatch:not(.out-of-gamut) {\n  box-shadow: none;\n}\ndiv.swatch-bar .swatch:not(.swatch-gradient) {\n  width: 3em;\n  height: 3em;\n  margin: 0;\n  border-radius: 0;\n}\ndiv.swatch-bar .swatch:not(.swatch-gradient) .swatch-color {\n  width: 2.75em;\n  height: 2.75em;\n  margin: 0;\n  border-radius: 0;\n}\ndiv.swatch-bar .swatch:hover {\n  transform: scale(1.2) translateY(-0.2em);\n}\ndiv.swatch-bar .swatch-gradient:hover {\n  transform: scale(1.02, 1.2) translateY(-0.2em);\n}\n\n.swatch.out-of-gamut {\n  padding: 1px;\n  border: 1px solid var(--swatch-gamut-border-color);\n  box-shadow: inset 0 0 0 1px var(--md-code-bg-color);\n}\n\n@media (color-gamut: p3) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n@media (color-gamut: rec2020) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n.color-wheel {\n  --color-wheel-stops1: transparent;\n  --color-wheel-stops2: transparent;\n  --color-wheel-stops3: transparent;\n  --color-wheel-stops4: transparent;\n  --color-wheel-stops5: transparent;\n  --color-wheel-bg: var(--md-default-bg-color);\n  margin: 1em 0;\n  overflow-x: scroll;\n  overflow-y: hidden;\n  scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n  scrollbar-width: thin;\n}\n.color-wheel::-webkit-scrollbar {\n  width: 0.2rem;\n  height: 0.2rem;\n}\n.color-wheel::-webkit-scrollbar-corner {\n  background-color: transparent;\n}\n.color-wheel::-webkit-scrollbar-thumb {\n  background-color: var(--md-default-fg-color--lighter);\n}\n.color-wheel::-webkit-scrollbar-thumb:hover {\n  background-color: var(--md-accent-fg-color);\n}\n.color-wheel:hover {\n  scrollbar-color: var(--md-accent-fg-color) transparent;\n}\n.color-wheel div {\n  overflow: clip;\n}\n.color-wheel .wheel {\n  min-width: max-content;\n  padding: 0.3125em;\n  border-radius: 1000px;\n}\n.color-wheel .wheel .primary {\n  width: 12em;\n  height: 10.39em;\n  margin: auto;\n  clip-path: polygon(50% 0, 100% 100%, 0 100%);\n}\n.color-wheel .wheel .primary .primary-inner {\n  width: 12em;\n  height: 14em;\n  background: conic-gradient(in xyz-d65, var(--color-wheel-stops1));\n  transform: rotate(180deg);\n}\n.color-wheel .wheel .secondary {\n  width: 14em;\n  height: 14em;\n  margin: auto;\n  background: var(--color-wheel-bg);\n  border-radius: 1000px;\n}\n.color-wheel .wheel .secondary .secondary-inner {\n  width: 14em;\n  height: 14em;\n  margin: auto;\n  background: conic-gradient(in xyz-d65, var(--color-wheel-stops2));\n  transform: rotate(-135deg);\n  clip-path: polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%);\n}\n.color-wheel .wheel .tertiary {\n  width: 22em;\n  height: 22em;\n  padding: 4em 0;\n  background: conic-gradient(in xyz-d65, var(--color-wheel-stops3));\n  border-radius: 1000px;\n  outline: 5px solid var(--color-wheel-bg);\n  transform: rotate(135deg);\n}\n.color-wheel .wheel .tertiary2 {\n  width: 30em;\n  height: 30em;\n  padding: 4em 0;\n  background: conic-gradient(in xyz-d65, var(--color-wheel-stops4));\n  border-radius: 1000px;\n  outline: 5px solid var(--color-wheel-bg);\n  transform: rotate(128deg);\n}\n.color-wheel .wheel .tertiary2 .tertiary {\n  margin: auto;\n  transform: rotate(8deg);\n}\n.color-wheel .wheel .tertiary3 {\n  width: 38em;\n  height: 38em;\n  padding: 4em 0;\n  background: conic-gradient(in xyz-d65, var(--color-wheel-stops5));\n  border-radius: 1000px;\n  outline: 5px solid var(--color-wheel-bg);\n  transform: rotate(123deg);\n}\n.color-wheel .wheel .tertiary3 .tertiary2 {\n  margin: auto;\n  transform: rotate(4deg);\n}\n\n.playground-code {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  margin-top: 2px;\n  overflow: hidden;\n}\n\n.playground-code.hidden {\n  margin-top: 0;\n}\n\n.playground-code .highlight code {\n  min-height: 3em;\n}\n\n.playground-code .highlight,\n.playground-code .highlight code {\n  margin: 0;\n  overflow: hidden;\n}\n\n.playground-code pre {\n  height: calc(100% + 0.2rem);\n  margin: 0;\n  pointer-events: none;\n}\n\n.playground-results code {\n  min-height: 3em;\n}\n\n.playground-results pre {\n  margin-bottom: 0;\n}\n\n.playground-results .swatch-bar {\n  min-height: calc(3em + 4px);\n}\n\n.playground-results .swatch-bar:empty {\n  display: none;\n}\n\n.playground-results .swatch-bar:empty + .highlight {\n  border-color: transparent;\n}\n\n.playground-results .color-command {\n  margin-bottom: 0;\n}\n\n.hidden .highlight,\n.hidden .playground-inputs {\n  display: none;\n}\n\n.playground-code:not(.hidden) div.highlight {\n  display: none;\n}\n\n.playground-footer {\n  margin-bottom: 1em;\n  padding: 0.2205882353em 1.1764705882em 0.1470588235em;\n  color: var(--md-code-hl-comment-color);\n  font-size: 0.85em;\n  background: var(--md-code-bg-color);\n  border-bottom-right-radius: 0.1rem;\n  border-bottom-left-radius: 0.1rem;\n}\n.playground-footer hr {\n  margin: 0 0 0.1470588235em 0;\n}\n.playground-footer .gamut {\n  float: right;\n}\n\ndiv.color-command {\n  margin: 1em 0;\n  line-height: 0;\n}\ndiv.color-command .highlight {\n  border-bottom-right-radius: 0;\n  border-bottom-left-radius: 0;\n}\ndiv.color-command .highlight:not(:first-child) {\n  border-top: 1px solid var(--md-default-fg-color--lightest);\n  border-top-left-radius: 0;\n  border-top-right-radius: 0;\n}\ndiv.color-command .highlight:not(:first-child) pre {\n  margin-top: 0;\n}\n\n@media screen and (max-width: 44.9375em) {\n  .md-typeset > div.color-command {\n    margin-right: -0.8rem;\n    margin-left: -0.8rem;\n  }\n  .md-typeset > div.color-command .highlight code {\n    border-radius: 0;\n  }\n}\n#__notebook-source {\n  height: 100%;\n}\n\n#__notebook-source.hidden,\n#__notebook-render.hidden {\n  display: none;\n}","textarea#__notebook-input,\n.playground-inputs {\n  z-index: 1;\n  display: block;\n  width: 100%;\n  min-height: 3em;\n\n  margin: 0;\n  padding: .7720588235em 1.1764705882em;\n  overflow-x: auto;\n  overflow-y: hidden;\n  color: var(--md-code-fg-color);\n  caret-color: var(--md-code-fg-color);\n\n  font-size: .85em;\n  font-family: var(--md-code-font-family,_),SFMono-Regular,Consolas,Menlo,monospace;\n  font-feature-settings: \"kern\";\n  line-height: 1.4;\n  white-space: pre;\n  word-wrap: unset;\n  background: var(--md-code-bg-color);\n\n  border: none;\n  outline: none;\n  cursor: text;\n  appearance: textarea;\n  resize: none;\n\n  &::selection {\n    color: var(--md-code-bg-color);\n    background: var(--md-code-fg-color);\n  }\n}\n",".md-typeset textarea {\n\n  scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n  scrollbar-width: thin;\n\n  &:hover {\n    scrollbar-color: var(--md-accent-fg-color) transparent;\n  }\n\n  &::-webkit-scrollbar {\n      width: px2rem(4px);\n      height: px2rem(4px);\n  }\n\n  &::-webkit-scrollbar-corner {\n    background-color: transparent;\n  }\n\n  &::-webkit-scrollbar-thumb {\n    background-color: var(--md-default-fg-color--lighter);\n\n    *:hover {\n      background-color: var(--md-accent-fg-color);\n    }\n  }\n}\n",".loading {\n    position: fixed;\n    top: 0;\n    right: 0;\n    bottom: 0;\n    left: 0;\n    z-index: 2;\n    width: 100%;\n    height: 100%;\n    background-color: rgba(0,0,0,.2);\n    backdrop-filter: blur(2px);\n\n    .loader {\n        position: relative;\n        top: 50%;\n        left: 50%;\n        width: 80px;\n        height: 80px;\n        margin-top: -40px;\n        margin-left: -40px;\n        border-style: solid;\n        border-width: 10px;\n        border-top-color: rgb(0, 255, 255);\n        border-right-color: rgb(255, 255, 0);\n        border-bottom-color: rgb(0, 255, 0);\n        border-left-color: rgb(255, 0, 255);\n        border-radius: 50%;\n        animation: spin 2s linear infinite;\n\n        ~ div {\n            position: absolute;\n            top: 50%;\n            width: 100%;\n            margin-top: 40px;\n            font-weight: 800;\n            font-size: px2rem(20px);\n            text-align: center;\n        }\n    }\n\n    &.relative {\n        position: absolute;\n\n        .loader {\n            width: 2em;\n            height: 2em;\n            margin-top: -1em;\n            margin-left: -1em;\n            border-width: 0.4em;\n\n            ~ div {\n                display:none;\n            }\n        }\n    }\n}\n\n@keyframes spin {\n    0% {\n        transform: rotate(0);\n    }\n    100% {\n        transform: rotate(-360deg);\n    }\n}\n",":root {\n  --swatch-bar-border-color: hsl(0, 0%, 90%);\n  --swatch-border-color: hsl(0, 0%, 85%);\n  --swatch-gamut-border-color: hsl(340 82% 52%);\n  --swatch-stops: transparent;\n  --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.1\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #fefefe;\n\n  [data-md-color-scheme=\"slate\"] {\n    --swatch-border-color: hsla(232, 15%, 25%, 1);\n  }\n\n  [data-md-color-scheme=\"dracula\"] {\n    --swatch-bar-border-color: hsl(231deg 15% 20%);\n    --swatch-border-color: hsl(231deg 15% 25%);\n    --swatch-gamut-border-color: hsl(326, 100%, 74%);\n    --transparency: url('data:image/svg+xml,<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" fill-opacity=\"0.45\"><rect width=\"50\" height=\"50\" /><rect x=\"50\" y=\"50\" width=\"50\" height=\"50\" /></svg>')\n  0 0 / 0.5em 0.5em #2b2e3b;\n  }\n}\n\n.swatch {\n  display: inline-block;\n  box-sizing: border-box;\n  width: px2em(20px);\n  height: px2em(20px);\n  margin-right: 0.2em;\n  margin-left: 0.25em;\n  line-height: 0;\n  vertical-align: text-bottom;\n  background: var(--transparency);\n  border: 2px solid var(--swatch-border-color);\n  border-radius: 100px;\n  box-shadow: 0.1em 0.1em 0.1em rgba(0, 0, 0, .3);\n  transition: all 0.5s ease;\n\n  &:hover {\n    z-index: 2;\n    transform: scale(2);\n  }\n\n  &:not(.swatch-gradient):hover {\n    cursor: pointer;\n  }\n}\n\n.swatch-color {\n  display: inline-block;\n  width: px2em(16.4px);\n  height: px2em(16.4px);\n  margin: 0;\n  padding: 0;\n  vertical-align: text-bottom;\n  background: linear-gradient(to right, var(--swatch-stops));\n  border-radius: 100px;\n}\n\n.swatch-gradient {\n  width: 100%;\n  height: px2em(48px);\n  margin: 0;\n  border-radius: 0;\n\n  .swatch-color {\n    width: 100%;\n    height: px2em(44px);\n    border-radius: 0;\n  }\n}\n\ndiv.swatch-bar {\n  box-sizing: border-box;\n  background: var(--transparency);\n  background-size: 1em 1em;\n  border: 2px solid var(--swatch-bar-border-color);\n\n  .swatch {\n    background-position: 0 0, 0 0.50em, 0.50em -0.50em, -0.50em 0px;\n    background-size: 1em 1em;\n\n    &:not(.out-of-gamut) {\n      box-shadow: none;\n    }\n\n    &:not(.swatch-gradient) {\n      width: px2em(48px);\n      height: px2em(48px);\n      margin: 0;\n      border-radius: 0;\n\n      .swatch-color {\n        width: px2em(44px);\n        height: px2em(44px);\n        margin: 0;\n        border-radius: 0;\n      }\n    }\n\n    &:hover {\n      transform: scale(1.2) translateY(-0.2em);\n    }\n  }\n\n  .swatch-gradient:hover {\n    transform: scale(1.02, 1.2) translateY(-0.2em);\n  }\n}\n\n.swatch.out-of-gamut {\n  padding: 1px;\n  border: 1px solid var(--swatch-gamut-border-color);\n  box-shadow: inset 0 0 0 1px var(--md-code-bg-color);\n}\n\n@media (color-gamut: p3) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n\n@media (color-gamut: rec2020) {\n  .swatch-color {\n    background: linear-gradient(in xyz-d65 to right, var(--swatch-stops)); /* stylelint-disable-line function-linear-gradient-no-nonstandard-direction */\n  }\n}\n",".color-wheel {\n  --color-wheel-stops1: transparent;\n  --color-wheel-stops2: transparent;\n  --color-wheel-stops3: transparent;\n  --color-wheel-stops4: transparent;\n  --color-wheel-stops5: transparent;\n  --color-wheel-bg: var(--md-default-bg-color);\n\n  margin: px2em(16px) 0;\n  overflow-x: scroll;\n  overflow-y: hidden;\n\n  // Override native scrollbar styles\n  &::-webkit-scrollbar {\n    width: px2rem(4px);\n    height: px2rem(4px);\n  }\n\n  &::-webkit-scrollbar-corner {\n    background-color: transparent;\n  }\n\n  // Scrollbar thumb\n  &::-webkit-scrollbar-thumb {\n    background-color: var(--md-default-fg-color--lighter);\n\n    // Hovered scrollbar thumb\n    &:hover {\n      background-color: var(--md-accent-fg-color);\n    }\n  }\n\n  // Firefox scrollbar and thumb\n  scrollbar-color: var(--md-default-fg-color--lighter) transparent;\n  scrollbar-width: thin;\n\n  // Firefox hovered scrollbar and thumb\n  &:hover {\n    scrollbar-color: var(--md-accent-fg-color) transparent;\n  }\n\n  div {\n    overflow: clip;\n  }\n\n  .wheel {\n    min-width: max-content;\n    padding: px2em(5px);\n    border-radius: 1000px;\n\n    .primary {\n      width: 12em;\n      height: 10.39em;\n      margin: auto;\n      clip-path: polygon(50% 0, 100% 100%, 0 100%);\n\n      .primary-inner {\n        width: 12em;\n        height: 14em;\n        background: conic-gradient(in xyz-d65,var(--color-wheel-stops1));\n        transform: rotate(180deg);\n      }\n    }\n\n    .secondary {\n      width: 14em;\n      height: 14em;\n      margin: auto;\n      background: var(--color-wheel-bg);\n      border-radius: 1000px;\n\n      .secondary-inner {\n        width: 14em;\n        height: 14em;\n        margin: auto;\n        background: conic-gradient(in xyz-d65,var(--color-wheel-stops2));\n        transform: rotate(-135deg);\n        clip-path: polygon(50% 0, 93% 25%, 93% 75%, 50% 100%, 7% 75%, 7% 25%);\n      }\n    }\n\n    .tertiary {\n      width: 22em;\n      height: 22em;\n      padding: 4em 0;\n      background: conic-gradient(in xyz-d65,var(--color-wheel-stops3));\n      border-radius: 1000px;\n      outline: 5px solid var(--color-wheel-bg);\n      transform: rotate(135deg);\n    }\n\n    .tertiary2 {\n      width: 30em;\n      height: 30em;\n      padding: 4em 0;\n      background: conic-gradient(in xyz-d65,var(--color-wheel-stops4));\n      border-radius: 1000px;\n      outline: 5px solid var(--color-wheel-bg);\n      transform: rotate(128deg);\n\n      .tertiary{\n        margin: auto;\n        transform: rotate(8deg);\n      }\n    }\n\n    .tertiary3 {\n      width: 38em;\n      height: 38em;\n      padding: 4em 0;\n      background: conic-gradient(in xyz-d65,var(--color-wheel-stops5));\n      border-radius: 1000px;\n      outline: 5px solid var(--color-wheel-bg);\n      transform: rotate(123deg);\n\n      .tertiary2 {\n        margin: auto;\n        transform: rotate(4deg);\n      }\n    }\n  }\n}\n",".playground-code {\n  position: relative;\n  width: 100%;\n  height: 100%;\n  margin-top: 2px;\n  overflow: hidden;\n}\n\n.playground-code.hidden {\n  margin-top: 0;\n}\n\n.playground-code .highlight code {\n  min-height: 3em;\n}\n\n.playground-code .highlight,\n.playground-code .highlight code {\n  margin: 0;\n  overflow: hidden;\n}\n\n.playground-code pre {\n  height: calc(100% + px2rem(4px));\n  margin: 0;\n  pointer-events: none;\n}\n\n.playground-results code {\n  min-height: 3em;\n}\n\n.playground-results pre {\n  margin-bottom: 0;\n}\n\n.playground-results .swatch-bar {\n  min-height: calc(3em + 4px);\n}\n\n.playground-results .swatch-bar:empty {\n  display: none;\n}\n\n.playground-results .swatch-bar:empty + .highlight {\n  border-color: transparent;\n}\n\n.playground-results .color-command {\n  margin-bottom: 0;\n}\n\n.hidden .highlight,\n.hidden .playground-inputs {\n  display: none;\n}\n\n.playground-code:not(.hidden) div.highlight {\n  display: none;\n}\n\n.playground-footer {\n  margin-bottom: 1em;\n  padding: px2em(3px, 13.6px) px2em(16px, 13.6px) px2em(2px, 13.6px);\n  color: var(--md-code-hl-comment-color);\n  font-size: px2em(13.6px);\n  background: var(--md-code-bg-color);\n  border-bottom-right-radius: px2rem(2px);\n  border-bottom-left-radius: px2rem(2px);\n\n  hr {\n    margin: 0 0 px2em(2px, 13.6px) 0;\n  }\n\n  .gamut {\n    float: right;\n  }\n}\n","div.color-command {\n  margin: 1em 0;\n  line-height: 0;\n\n  .highlight {\n    border-bottom-right-radius: 0;\n    border-bottom-left-radius: 0;\n\n    &:not(:first-child) {\n      border-top: 1px solid var(--md-default-fg-color--lightest);\n      border-top-left-radius: 0;\n      border-top-right-radius: 0;\n\n      pre {\n        margin-top: 0;\n      }\n    }\n  }\n}\n\n@media screen and (max-width: 44.9375em) {\n  .md-typeset > div.color-command {\n    margin-right:  px2rem(-16px);\n    margin-left: px2rem(-16px);\n\n    .highlight code {\n      border-radius: 0;\n    }\n  }\n}\n","#__notebook-source {\n  height: 100%;\n}\n\n#__notebook-source.hidden,\n#__notebook-render.hidden {\n  display: none;\n}\n"]}
\ No newline at end of file
diff --git a/docs/theme/assets/coloraide-extras/extra-notebook-ba27d60b.js b/docs/theme/assets/coloraide-extras/extra-notebook-ba27d60b.js
new file mode 100644
index 000000000..38508c475
--- /dev/null
+++ b/docs/theme/assets/coloraide-extras/extra-notebook-ba27d60b.js
@@ -0,0 +1,2 @@
+function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}var runtime=function(t){"use strict";var e,n=Object.prototype,o=n.hasOwnProperty,r=Object.defineProperty||function(t,e,n){t[e]=n.value},i="function"==typeof Symbol?Symbol:{},a=i.iterator||"@@iterator",s=i.asyncIterator||"@@asyncIterator",l=i.toStringTag||"@@toStringTag";function c(t,e,n){return Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{c({},"")}catch(t){c=function(t,e,n){return t[e]=n}}function u(t,e,n,o){var i=e&&e.prototype instanceof h?e:h,a=Object.create(i.prototype),s=new I(o||[]);return r(a,"_invoke",{value:S(t,n,s)}),a}function d(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}t.wrap=u;var p="suspendedStart",f="suspendedYield",m="executing",_="completed",g={};function h(){}function y(){}function v(){}var w={};c(w,a,(function(){return this}));var x=Object.getPrototypeOf,b=x&&x(x(T([])));b&&b!==n&&o.call(b,a)&&(w=b);var E=v.prototype=h.prototype=Object.create(w);function k(t){["next","throw","return"].forEach((function(e){c(t,e,(function(t){return this._invoke(e,t)}))}))}function L(t,e){function n(r,i,a,s){var l=d(t[r],t,i);if("throw"!==l.type){var c=l.arg,u=c.value;return u&&"object"===_typeof(u)&&o.call(u,"__await")?e.resolve(u.__await).then((function(t){n("next",t,a,s)}),(function(t){n("throw",t,a,s)})):e.resolve(u).then((function(t){c.value=t,a(c)}),(function(t){return n("throw",t,a,s)}))}s(l.arg)}var i;r(this,"_invoke",{value:function(t,o){function r(){return new e((function(e,r){n(t,o,e,r)}))}return i=i?i.then(r,r):r()}})}function S(t,e,n){var o=p;return function(r,i){if(o===m)throw new Error("Generator is already running");if(o===_){if("throw"===r)throw i;return O()}for(n.method=r,n.arg=i;;){var a=n.delegate;if(a){var s=A(a,n);if(s){if(s===g)continue;return s}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===p)throw o=_,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=m;var l=d(t,e,n);if("normal"===l.type){if(o=n.done?_:f,l.arg===g)continue;return{value:l.arg,done:n.done}}"throw"===l.type&&(o=_,n.method="throw",n.arg=l.arg)}}}function A(t,n){var o=n.method,r=t.iterator[o];if(r===e)return n.delegate=null,"throw"===o&&t.iterator.return&&(n.method="return",n.arg=e,A(t,n),"throw"===n.method)||"return"!==o&&(n.method="throw",n.arg=new TypeError("The iterator does not provide a '"+o+"' method")),g;var i=d(r,t.iterator,n.arg);if("throw"===i.type)return n.method="throw",n.arg=i.arg,n.delegate=null,g;var a=i.arg;return a?a.done?(n[t.resultName]=a.value,n.next=t.nextLoc,"return"!==n.method&&(n.method="next",n.arg=e),n.delegate=null,g):a:(n.method="throw",n.arg=new TypeError("iterator result is not an object"),n.delegate=null,g)}function C(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function B(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function I(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(C,this),this.reset(!0)}function T(t){if(t){var n=t[a];if(n)return n.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var r=-1,i=function n(){for(;++r<t.length;)if(o.call(t,r))return n.value=t[r],n.done=!1,n;return n.value=e,n.done=!0,n};return i.next=i}}return{next:O}}function O(){return{value:e,done:!0}}return y.prototype=v,r(E,"constructor",{value:v,configurable:!0}),r(v,"constructor",{value:y,configurable:!0}),y.displayName=c(v,l,"GeneratorFunction"),t.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===y||"GeneratorFunction"===(e.displayName||e.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,v):(t.__proto__=v,c(t,l,"GeneratorFunction")),t.prototype=Object.create(E),t},t.awrap=function(t){return{__await:t}},k(L.prototype),c(L.prototype,s,(function(){return this})),t.AsyncIterator=L,t.async=function(e,n,o,r,i){void 0===i&&(i=Promise);var a=new L(u(e,n,o,r),i);return t.isGeneratorFunction(n)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},k(E),c(E,l,"Generator"),c(E,a,(function(){return this})),c(E,"toString",(function(){return"[object Generator]"})),t.keys=function(t){var e=Object(t),n=[];for(var o in e)n.push(o);return n.reverse(),function t(){for(;n.length;){var o=n.pop();if(o in e)return t.value=o,t.done=!1,t}return t.done=!0,t}},t.values=T,I.prototype={constructor:I,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=e,this.done=!1,this.delegate=null,this.method="next",this.arg=e,this.tryEntries.forEach(B),!t)for(var n in this)"t"===n.charAt(0)&&o.call(this,n)&&!isNaN(+n.slice(1))&&(this[n]=e)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var n=this;function r(o,r){return s.type="throw",s.arg=t,n.next=o,r&&(n.method="next",n.arg=e),!!r}for(var i=this.tryEntries.length-1;i>=0;--i){var a=this.tryEntries[i],s=a.completion;if("root"===a.tryLoc)return r("end");if(a.tryLoc<=this.prev){var l=o.call(a,"catchLoc"),c=o.call(a,"finallyLoc");if(l&&c){if(this.prev<a.catchLoc)return r(a.catchLoc,!0);if(this.prev<a.finallyLoc)return r(a.finallyLoc)}else if(l){if(this.prev<a.catchLoc)return r(a.catchLoc,!0)}else{if(!c)throw new Error("try statement without catch or finally");if(this.prev<a.finallyLoc)return r(a.finallyLoc)}}}},abrupt:function(t,e){for(var n=this.tryEntries.length-1;n>=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,"finallyLoc")&&this.prev<r.finallyLoc){var i=r;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=e&&e<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=e,i?(this.method="next",this.next=i.finallyLoc,g):this.complete(a)},complete:function(t,e){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&e&&(this.next=e),g},finish:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),B(n),g}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var o=n.completion;if("throw"===o.type){var r=o.arg;B(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(t,n,o){return this.delegate={iterator:T(t),resultName:n,nextLoc:o},"next"===this.method&&(this.arg=e),g}},t}("object"===("undefined"==typeof module?"undefined":_typeof(module))?module.exports:{});try{regeneratorRuntime=runtime}catch(t){"object"===("undefined"==typeof globalThis?"undefined":_typeof(globalThis))?globalThis.regeneratorRuntime=runtime:Function("r","regeneratorRuntime = r")(runtime)}!function(){"use strict";function t(){t=function(){return e};var e={},n=Object.prototype,o=n.hasOwnProperty,r=Object.defineProperty||function(t,e,n){t[e]=n.value},i="function"==typeof Symbol?Symbol:{},a=i.iterator||"@@iterator",s=i.asyncIterator||"@@asyncIterator",l=i.toStringTag||"@@toStringTag";function c(t,e,n){return Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{c({},"")}catch(t){c=function(t,e,n){return t[e]=n}}function u(t,e,n,o){var i=e&&e.prototype instanceof f?e:f,a=Object.create(i.prototype),s=new S(o||[]);return r(a,"_invoke",{value:b(t,n,s)}),a}function d(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}e.wrap=u;var p={};function f(){}function m(){}function _(){}var g={};c(g,a,(function(){return this}));var h=Object.getPrototypeOf,y=h&&h(h(A([])));y&&y!==n&&o.call(y,a)&&(g=y);var v=_.prototype=f.prototype=Object.create(g);function w(t){["next","throw","return"].forEach((function(e){c(t,e,(function(t){return this._invoke(e,t)}))}))}function x(t,e){function n(r,i,a,s){var l=d(t[r],t,i);if("throw"!==l.type){var c=l.arg,u=c.value;return u&&"object"==_typeof(u)&&o.call(u,"__await")?e.resolve(u.__await).then((function(t){n("next",t,a,s)}),(function(t){n("throw",t,a,s)})):e.resolve(u).then((function(t){c.value=t,a(c)}),(function(t){return n("throw",t,a,s)}))}s(l.arg)}var i;r(this,"_invoke",{value:function(t,o){function r(){return new e((function(e,r){n(t,o,e,r)}))}return i=i?i.then(r,r):r()}})}function b(t,e,n){var o="suspendedStart";return function(r,i){if("executing"===o)throw new Error("Generator is already running");if("completed"===o){if("throw"===r)throw i;return C()}for(n.method=r,n.arg=i;;){var a=n.delegate;if(a){var s=E(a,n);if(s){if(s===p)continue;return s}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if("suspendedStart"===o)throw o="completed",n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o="executing";var l=d(t,e,n);if("normal"===l.type){if(o=n.done?"completed":"suspendedYield",l.arg===p)continue;return{value:l.arg,done:n.done}}"throw"===l.type&&(o="completed",n.method="throw",n.arg=l.arg)}}}function E(t,e){var n=e.method,o=t.iterator[n];if(void 0===o)return e.delegate=null,"throw"===n&&t.iterator.return&&(e.method="return",e.arg=void 0,E(t,e),"throw"===e.method)||"return"!==n&&(e.method="throw",e.arg=new TypeError("The iterator does not provide a '"+n+"' method")),p;var r=d(o,t.iterator,e.arg);if("throw"===r.type)return e.method="throw",e.arg=r.arg,e.delegate=null,p;var i=r.arg;return i?i.done?(e[t.resultName]=i.value,e.next=t.nextLoc,"return"!==e.method&&(e.method="next",e.arg=void 0),e.delegate=null,p):i:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,p)}function k(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function L(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function S(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(k,this),this.reset(!0)}function A(t){if(t){var e=t[a];if(e)return e.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,r=function e(){for(;++n<t.length;)if(o.call(t,n))return e.value=t[n],e.done=!1,e;return e.value=void 0,e.done=!0,e};return r.next=r}}return{next:C}}function C(){return{value:void 0,done:!0}}return m.prototype=_,r(v,"constructor",{value:_,configurable:!0}),r(_,"constructor",{value:m,configurable:!0}),m.displayName=c(_,l,"GeneratorFunction"),e.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===m||"GeneratorFunction"===(e.displayName||e.name))},e.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,_):(t.__proto__=_,c(t,l,"GeneratorFunction")),t.prototype=Object.create(v),t},e.awrap=function(t){return{__await:t}},w(x.prototype),c(x.prototype,s,(function(){return this})),e.AsyncIterator=x,e.async=function(t,n,o,r,i){void 0===i&&(i=Promise);var a=new x(u(t,n,o,r),i);return e.isGeneratorFunction(n)?a:a.next().then((function(t){return t.done?t.value:a.next()}))},w(v),c(v,l,"Generator"),c(v,a,(function(){return this})),c(v,"toString",(function(){return"[object Generator]"})),e.keys=function(t){var e=Object(t),n=[];for(var o in e)n.push(o);return n.reverse(),function t(){for(;n.length;){var o=n.pop();if(o in e)return t.value=o,t.done=!1,t}return t.done=!0,t}},e.values=A,S.prototype={constructor:S,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(L),!t)for(var e in this)"t"===e.charAt(0)&&o.call(this,e)&&!isNaN(+e.slice(1))&&(this[e]=void 0)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var e=this;function n(n,o){return a.type="throw",a.arg=t,e.next=n,o&&(e.method="next",e.arg=void 0),!!o}for(var r=this.tryEntries.length-1;r>=0;--r){var i=this.tryEntries[r],a=i.completion;if("root"===i.tryLoc)return n("end");if(i.tryLoc<=this.prev){var s=o.call(i,"catchLoc"),l=o.call(i,"finallyLoc");if(s&&l){if(this.prev<i.catchLoc)return n(i.catchLoc,!0);if(this.prev<i.finallyLoc)return n(i.finallyLoc)}else if(s){if(this.prev<i.catchLoc)return n(i.catchLoc,!0)}else{if(!l)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return n(i.finallyLoc)}}}},abrupt:function(t,e){for(var n=this.tryEntries.length-1;n>=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,"finallyLoc")&&this.prev<r.finallyLoc){var i=r;break}}i&&("break"===t||"continue"===t)&&i.tryLoc<=e&&e<=i.finallyLoc&&(i=null);var a=i?i.completion:{};return a.type=t,a.arg=e,i?(this.method="next",this.next=i.finallyLoc,p):this.complete(a)},complete:function(t,e){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&e&&(this.next=e),p},finish:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),L(n),p}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var o=n.completion;if("throw"===o.type){var r=o.arg;L(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:A(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=void 0),p}},e}function e(t,e,n,o,r,i,a){try{var s=t[i](a),l=s.value}catch(t){return void n(t)}s.done?e(l):Promise.resolve(l).then(o,r)}function n(t){return function(){var n=this,o=arguments;return new Promise((function(r,i){var a=t.apply(n,o);function s(t){e(a,r,i,s,l,"next",t)}function l(t){e(a,r,i,s,l,"throw",t)}s(void 0)}))}}function o(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function r(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=function(t,e){if(t){if("string"==typeof t)return o(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?o(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var r=0,i=function(){};return{s:i,n:function(){return r>=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,s=!0,l=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return s=t.done,t},e:function(t){l=!0,a=t},f:function(){try{s||null==n.return||n.return()}finally{if(l)throw a}}}}!function(){var e="";try{var o="srgb";window.matchMedia("(color-gamut: rec2020)").matches?o="rec2020":window.matchMedia("(color-gamut: p3)").matches&&(o="display-p3"),e=CSS.supports("color: color(display-p3 1 0 0)")?o:"srgb"}catch(t){e="srgb"}var i=null,a=!1,s="",l="",c={},u=/.*?_(\d+)$/,d=!1,p="",f=!1,m=/^( {1,4}|\t)/,_="\n_P='<div class=\"color-command\">{}</div>'\n_O='swatch'\n_N='transparent'\n_M='pycon'\n_L='playground'\n_K='gamut'\n_J='color'\n_I='{} {}%'\n_H='exceptions'\n_G='highlight'\n_F='class'\n_E='eval'\n_D='<string>'\n_C=None\n_B=True\n_A=False\nimport xml.etree.ElementTree as Etree\nfrom collections.abc import Sequence,Mapping\nfrom collections import namedtuple\nimport ast\nfrom io import StringIO\nimport sys,re\nfrom functools import partial\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters import find_formatter_class\nfrom coloraide import Color\nfrom coloraide.interpolate import Interpolator,normalize_domain\ntry:from coloraide_extras.everything import ColorAll\nexcept ImportError:from coloraide.everything import ColorAll\nPY310=(3,10)<=sys.version_info\nPY311=(3,11)<=sys.version_info\nWEBSPACE='srgb'\nAST_BLOCKS=ast.If,ast.For,ast.While,ast.Try,ast.With,ast.FunctionDef,ast.ClassDef,ast.AsyncFor,ast.AsyncWith,ast.AsyncFunctionDef\nif PY310:AST_BLOCKS=AST_BLOCKS+(ast.Match,)\nif PY311:AST_BLOCKS=AST_BLOCKS+(ast.TryStar,)\nRE_INIT=re.compile('^\\\\s*#\\\\s*pragma:\\\\s*init\\\\n(.*?)#\\\\s*pragma:\\\\s*init\\\\n',re.DOTALL|re.I)\nRE_COLOR_START=re.compile('(?i)(?:\\\\b(?<![-#&$])(?:color|hsla?|lch|lab|hwb|rgba?)\\\\(|\\\\b(?<![-#&$])[\\\\w]{3,}(?![(-])\\\\b|(?<![&])#)')\nLIVE_INIT='\\nfrom coloraide import *\\nimport coloraide\\ntry:\\n    import coloraide_extras\\n    from coloraide_extras.everything import ColorAll as Color\\nexcept ImportError:\\n    from coloraide.everything import ColorAll as Color\\n'\ntemplate='<div class=\"playground\" id=\"__playground_{el_id}\">\\n<div class=\"playground-results\" id=\"__playground-results_{el_id}\">\\n{results}\\n</div>\\n<div class=\"playground-code hidden\" id=\"__playground-code_{el_id}\" data-search-exclude>\\n<form autocomplete=\"off\">\\n<textarea class=\"playground-inputs\" id=\"__playground-inputs_{el_id}\" spellcheck=\"false\">{raw_source}</textarea>\\n</form>\\n</div>\\n<div class=\"playground-footer\" data-search-exclude>\\n<hr>\\n<button id=\"__playground-edit_{el_id}\" class=\"playground-edit\" title=\"Edit the current snippet\">Edit</button>\\n<button id=\"__playground-share_{el_id}\" class=\"playground-share\" title=\"Copy URL to current snippet\">Share</button>\\n<button id=\"__playground-run_{el_id}\" class=\"playground-run hidden\" title=\"Run code (Ctrl + Enter)\">Run</button>\\n<button id=\"__playground-cancel_{el_id}\" class=\"playground-cancel hidden\" title=\"Cancel edit (Escape)\">Cancel</button>\\n<span class=\\'gamut\\'>Gamut: {gamut}</span>\\n</div>\\n</div>'\ncode_id=0\nclass Ramp(list):0\nclass Steps(list):0\nclass Row(list):0\nclass ColorTuple(namedtuple('ColorTuple',['string',_J])):0\nclass AtomicString(str):0\nclass Break(Exception):0\nclass Continue(Exception):0\nHtmlRow=Row\nHtmlSteps=Steps\nHtmlGradient=Ramp\ndef _escape(txt):txt=txt.replace('&','&amp;');txt=txt.replace('<','&lt;');txt=txt.replace('>','&gt;');return txt\nclass StreamOut:\n\tdef __init__(self):self.old=sys.stdout;self.stdout=StringIO();sys.stdout=self.stdout\n\tdef read(self):\n\t\tvalue=''\n\t\tif self.stdout is not _C:self.stdout.flush();value=self.stdout.getvalue();self.stdout=StringIO();sys.stdout=self.stdout\n\t\treturn value\n\tdef __enter__(self):return self\n\tdef __exit__(self,type,value,traceback):sys.stdout=self.old;self.old=_C;self.stdout=_C\ndef get_colors(result):\n\tdomain=[]\n\tif isinstance(result,AtomicString):yield find_colors(result)\n\tif isinstance(result,Row):yield Row([ColorTuple(c.to_string(fit=_A),c.clone())if isinstance(c,Color)else ColorTuple(c,ColorAll(c))for c in result])\n\telif isinstance(result,(Steps,Ramp)):t=type(result);yield t([c.clone()if isinstance(c,Color)else ColorAll(c)for c in result])\n\telif isinstance(result,Color):yield[ColorTuple(result.to_string(fit=_A),result.clone())]\n\telif isinstance(result,Interpolator):\n\t\tif result._domain:domain=result._domain;result.domain(normalize_domain(result._domain))\n\t\tgrad=Ramp(result.steps(steps=5,max_delta_e=2.3))\n\t\tif domain:result._domain=domain;domain=[]\n\t\tyield grad\n\telif isinstance(result,str):\n\t\ttry:yield[ColorTuple(result,ColorAll(result))]\n\t\texcept Exception:pass\n\telif isinstance(result,(list,tuple)):\n\t\tfor r in result:\n\t\t\tfor x in get_colors(r):\n\t\t\t\tif x:yield x\ndef find_colors(text):\n\tcolors=[]\n\tfor m in RE_COLOR_START.finditer(text):\n\t\tstart=m.start();mcolor=ColorAll.match(text,start=start)\n\t\tif mcolor is not _C:colors.append(ColorTuple(text[mcolor.start:mcolor.end],mcolor.color))\n\treturn colors\ndef evaluate_with(node,g,loop,index=0):\n\tl=len(node.items)-1;withitem=node.items[index]\n\tif withitem.context_expr:\n\t\twith eval(compile(ast.Expression(withitem.context_expr),_D,_E),g)as w:\n\t\t\tg[withitem.optional_vars.id]=w\n\t\t\tif index<l:evaluate_with(node,g,loop,index+1)\n\t\t\telse:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\telse:\n\t\twith eval(compile(ast.Expression(withitem.context_expr),_D,_E),g):\n\t\t\tif index<l:evaluate_with(node,g,loop,index+1)\n\t\t\telse:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\ndef compare_match(s,g,node):\n\tif isinstance(node,ast.MatchOr):\n\t\tfor pattern in node.patterns:\n\t\t\tif compare_match(s,g,pattern):return _B\n\telif isinstance(node,ast.MatchValue):p=eval(compile(ast.Expression(node.value),_D,_E),g);return s==p\n\telif isinstance(node,ast.MatchSingleton):return s is node.value\n\telif isinstance(node,ast.MatchSequence):\n\t\tif isinstance(s,Sequence):\n\t\t\tstar=isinstance(node.patterns[-1],ast.MatchStar);l1,l2=len(s),len(node.patterns)\n\t\t\tif star and l1>=l2-1 or l1==l2:\n\t\t\t\tfor (e,p) in enumerate(node.patterns[:-1]if star else node.patterns):\n\t\t\t\t\tif not compare_match(s[e],g,p):return _A\n\t\t\t\tif star and node.patterns[-1].name:g[node.patterns[-1].name]=s[l2-1:]\n\t\t\t\treturn _B\n\t\treturn _A\n\telif isinstance(node,ast.MatchMapping):\n\t\tif isinstance(s,Mapping):\n\t\t\tstar=node.rest;l1,l2=len(s),len(node.patterns)\n\t\t\tif star and l1>=l2 or l1==l2:\n\t\t\t\tkeys=set()\n\t\t\t\tfor (kp,vp) in zip(node.keys,node.patterns):\n\t\t\t\t\tkey=eval(compile(ast.Expression(kp),_D,_E),g);keys.add(key)\n\t\t\t\t\tif key not in s:return _A\n\t\t\t\t\tif not compare_match(s[key],g,vp):return _A\n\t\t\t\tif star:g[star]={k:v for(k,v)in s.items()if k not in keys}\n\t\t\t\treturn _B\n\t\treturn _A\n\telif isinstance(node,ast.MatchClass):\n\t\tname=g.get(node.cls.id,_C)\n\t\tif name is _C:raise NameError(\"name '{}' is not defined\".format(node.cls.id))\n\t\tif not isinstance(s,name):return _A\n\t\tma=getattr(s,'__match_args__',());l1=len(ma);l2=len(node.patterns)\n\t\tif l1<l2:raise TypeError('{}() accepts {} positional sub-patterns ({} given)'.format(name,l1,l2))\n\t\tfor (e,p) in enumerate(node.patterns):\n\t\t\tif not hasattr(s,ma[e]):return _A\n\t\t\tif not compare_match(getattr(s,ma[e]),g,p):return _A\n\t\tfor (a,p) in zip(node.kwd_attrs,node.kwd_patterns):\n\t\t\tif not hasattr(s,a):return _A\n\t\t\tif not compare_match(getattr(s,a),g,p):return _A\n\t\treturn _B\n\telif isinstance(node,ast.MatchAs):\n\t\tif node.name is not _C:g[node.name]=s\n\t\tif node.pattern:return compare_match(s,g,node.pattern)\n\t\treturn _B\n\traise RuntimeError('Unknown Match pattern {}'.format(str(node)))\ndef evaluate_except(node,e,g,loop=_A):\n\tfor n in node.handlers:\n\t\tif n.name:g[n.name]=e\n\t\tif n.type is _C:\n\t\t\tfor ne in n.body:yield from evaluate(ne,g,loop)\n\t\t\tbreak\n\t\telif isinstance(e,eval(compile(ast.Expression(n.type),_D,_E),g)):\n\t\t\tfor ne in n.body:yield from evaluate(ne,g,loop)\n\t\t\tbreak\n\telse:raise\ndef evaluate(node,g,loop=_A):\n\tif loop and isinstance(node,ast.Break):raise Break\n\tif loop and isinstance(node,ast.Continue):raise Continue\n\tif isinstance(node,ast.Expr):_eval=ast.Expression(node.value);yield eval(compile(_eval,_D,_E),g)\n\telif isinstance(node,ast.If):\n\t\tif eval(compile(ast.Expression(node.test),_D,_E),g):\n\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\t\telif node.orelse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\telif isinstance(node,ast.While):\n\t\twhile eval(compile(ast.Expression(node.test),_D,_E),g):\n\t\t\ttry:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,_B)\n\t\t\texcept Break:break\n\t\t\texcept Continue:continue\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\telif isinstance(node,ast.For):\n\t\tfor x in eval(compile(ast.Expression(node.iter),_D,_E),g):\n\t\t\tif isinstance(node.target,ast.Tuple):\n\t\t\t\tfor (e,t) in enumerate(node.target.dims):g[t.id]=x[e]\n\t\t\telse:g[node.target.id]=x\n\t\t\ttry:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,_B)\n\t\t\texcept Break:break\n\t\t\texcept Continue:continue\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\telif isinstance(node,ast.Try):\n\t\ttry:\n\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\t\texcept Exception as e:yield from evaluate_except(node,e,g,loop)\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\t\tfinally:\n\t\t\tfor n in node.finalbody:yield from evaluate(n,g,loop)\n\telif PY311 and isinstance(node,ast.TryStar):\n\t\ttry:\n\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\t\texcept ExceptionGroup as e:\n\t\t\tfor n in node.handlers:\n\t\t\t\tif n.name:g[n.name]=e\n\t\t\t\tm,e=e.split(eval(compile(ast.Expression(n.type),_D,_E),g))\n\t\t\t\tif m is not _C:\n\t\t\t\t\tfor ne in n.body:yield from evaluate(ne,g,loop)\n\t\t\t\tif e is _C:break\n\t\t\tif e is not _C:raise e\n\t\texcept Exception as e:yield from evaluate_except(node,e,g,loop)\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\t\tfinally:\n\t\t\tfor n in node.finalbody:yield from evaluate(n,g,loop)\n\telif PY310 and isinstance(node,ast.Match):\n\t\ts=eval(compile(ast.Expression(node.subject),_D,_E),g)\n\t\tfor c in node.cases:\n\t\t\tif compare_match(s,g,c.pattern):\n\t\t\t\tif not c.guard or eval(compile(ast.Expression(c.guard),_D,_E),g):\n\t\t\t\t\tfor n in c.body:yield from evaluate(n,g,loop)\n\t\t\t\t\tbreak\n\telif isinstance(node,ast.With):yield from evaluate_with(node,g,loop)\n\telse:_exec=ast.Module([node],[]);exec(compile(_exec,_D,'exec'),g);yield _C\ndef execute(cmd,no_except=_B,inline=_A,init='',g=_C):\n\tA='\\n';console='';colors=[]\n\tif g is _C:g={'Ramp':Ramp,'Steps':Steps,'Row':Row,'HtmlRow':HtmlRow,'HtmlSteps':HtmlSteps,'HtmlGradient':HtmlGradient}\n\tif init:execute(init.strip(),g=g)\n\tm=RE_INIT.match(cmd)\n\tif m:block_init=m.group(1);src=cmd[m.end():];execute(block_init,g=g)\n\telse:src=cmd\n\tlines=src.split(A)\n\ttry:tree=ast.parse(src)\n\texcept Exception as e:\n\t\tif no_except:\n\t\t\tif not inline:from pymdownx.superfences import SuperFencesException;raise SuperFencesException from e\n\t\t\telse:from pymdownx.inlinehilite import InlineHiliteException;raise InlineHiliteException from e\n\t\timport traceback;return '{}'.format(traceback.format_exc()),colors\n\tfor node in tree.body:\n\t\tresult=[];start=node.lineno;end=node.end_lineno;stmt=lines[start-1:end];command=''\n\t\tfor (i,line) in enumerate(stmt,0):\n\t\t\tif i==0:stmt[i]='>>> '+line\n\t\t\telse:stmt[i]='... '+line\n\t\tcommand+=A.join(stmt)\n\t\tif isinstance(node,AST_BLOCKS):command+='\\n... '\n\t\ttry:\n\t\t\twith StreamOut()as s:\n\t\t\t\tfor x in evaluate(node,g):\n\t\t\t\t\tresult.append(x);text=s.read()\n\t\t\t\t\tif text:result.append(AtomicString(text))\n\t\t\t\tconsole+=command\n\t\texcept Exception as e:\n\t\t\tif no_except:\n\t\t\t\tif not inline:from pymdownx.superfences import SuperFencesException;raise SuperFencesException from e\n\t\t\t\telse:from pymdownx.inlinehilite import InlineHiliteException;raise InlineHiliteException from e\n\t\t\timport traceback;console+='{}\\n{}'.format(command,traceback.format_exc());break\n\t\tresult_text=A\n\t\tfor r in result:\n\t\t\tif r is _C:continue\n\t\t\tfor clist in get_colors(r):\n\t\t\t\tif clist:colors.append(clist)\n\t\t\tresult_text+='{}{}'.format(repr(r)if isinstance(r,str)and not isinstance(r,AtomicString)else str(r),A if not isinstance(r,AtomicString)else'')\n\t\tconsole+=result_text\n\treturn console,colors\ndef colorize(src,lang,**options):HtmlFormatter=find_formatter_class('html');lexer=get_lexer_by_name(lang,**options);formatter=HtmlFormatter(cssclass=_G,wrapcode=_B);return highlight(src,lexer,formatter).strip()\ndef color_command_validator(language,inputs,options,attrs,md):\n\tvalid_inputs={_H,'play','wheel'}\n\tfor (k,v) in inputs.items():\n\t\tif k in valid_inputs:options[k]=_B;continue\n\t\tattrs[k]=v\n\treturn _B\ndef _color_command_console(colors,gamut=WEBSPACE):\n\tB=' ';A='<div class=\"swatch-bar\">{}</div>';el='';bar=_A;values=[]\n\tfor item in colors:\n\t\tis_grad=isinstance(item,HtmlGradient);is_steps=isinstance(item,Steps)\n\t\tif is_grad or is_steps:\n\t\t\tcurrent=total=percent=last=0\n\t\t\tif isinstance(item,Steps):total=len(item);percent=100/total;current=percent\n\t\t\tif bar:el+=A.format(B.join(values));values=[]\n\t\t\tsub_el1='<div class=\"swatch-bar\"><span class=\"swatch swatch-gradient\">{}</span></div>';style='--swatch-stops: ';stops=[]\n\t\t\tfor (e,color) in enumerate(item):\n\t\t\t\tcolor.fit(gamut);color_str=color.convert(gamut).to_string()\n\t\t\t\tif current:\n\t\t\t\t\tif is_steps:stops.append(_I.format(color_str,str(last)));stops.append(_I.format(color_str,str(current)))\n\t\t\t\t\telse:stops.append(color_str)\n\t\t\t\t\tlast=current\n\t\t\t\t\tif e<total-1:current+=percent\n\t\t\t\t\telse:current=100\n\t\t\t\telse:stops.append(color_str)\n\t\t\tif not stops:stops.extend([_N]*2)\n\t\t\tif len(stops)==1:stops.append(stops[0])\n\t\t\tstyle+=','.join(stops);sub_el2='<span class=\"swatch-color\" style=\"{}\"></span>'.format(style);el+=sub_el1.format(sub_el2);bar=_A\n\t\telse:\n\t\t\tis_row=_A\n\t\t\tif isinstance(item,Row):\n\t\t\t\tis_row=_B\n\t\t\t\tif bar and values:el+=A.format(B.join(values));values=[]\n\t\t\t\tbar=_A\n\t\t\tbar=_B\n\t\t\tfor color in item:\n\t\t\t\tbase_classes=_O\n\t\t\t\tif not color.color.in_gamut(gamut):base_classes+=' out-of-gamut'\n\t\t\t\tcolor.color.fit(gamut);srgb=color.color.convert(gamut);value1=srgb.to_string(alpha=_A);value2=srgb.to_string();style='--swatch-stops: {} 50%, {} 50%'.format(value1,value2);title=color.string;classes=base_classes;c='<span class=\"swatch-color\" style=\"{style}\"></span>'.format(style=style);c='<span class=\"{classes}\" title=\"{title}&#013;Copy to clipboard\">{color}</span>'.format(classes=classes,color=c,title=title);values.append(c)\n\t\t\tif is_row and values:el+=A.format(B.join(values));values=[];bar=_A\n\tif bar:el+=A.format(B.join(values));values=[]\n\treturn el\ndef _color_command_formatter(src='',language='',class_name=_C,options=_C,md='',init='',**kwargs):\n\tC='</div>';B='formatter';A='fenced_code_block';global code_id;from pymdownx.superfences import SuperFencesException;gamut=kwargs.get(_K,WEBSPACE);wheel=options.get('wheel',_A);play=options.get('play',_A)if options is not _C else _A\n\tif not play and language==_L:play=_B\n\tif not play:return md.preprocessors[A].extension.superfences[0][B](src=src,class_name=class_name,language='py',md=md,options=options,**kwargs)\n\ttry:\n\t\tif wheel:\n\t\t\texceptions=options.get(_H,_A)if options is not _C else _A;_,colors=execute(src.strip(),not exceptions,init=init);l=len(colors)\n\t\t\tif l not in(12,24,48):raise SuperFencesException('Color wheel requires either 12, 24, or 48 colors')\n\t\t\tcolors=[c[0].color for c in colors]\n\t\t\tif l==12:freq=4;offset=6\n\t\t\telif l==24:freq=8;offset=12\n\t\t\telse:freq=16;offset=24\n\t\t\tprimary=list(reversed(colors[::freq]));secondary=list(reversed(colors[offset::freq]+[colors[offset//3]]));tertiary=list(reversed(colors[::offset//6]));color_rings=[primary,secondary,tertiary];extra_rings_start='';extra_rings_end=''\n\t\t\tif l>12:extra_rings_start='<div class=\"tertiary2\">';extra_rings_end+=C;color_rings.append(list(reversed(colors[::offset//12])))\n\t\t\tif l>24:extra_rings_start='<div class=\"tertiary3\">'+extra_rings_start;extra_rings_end+=C;color_rings.append(list(reversed(colors)))\n\t\t\tcolor_stops=''\n\t\t\tfor (i,colors) in enumerate(color_rings,1):\n\t\t\t\ttotal=len(colors);percent=100/total;current=percent;last=-1;stops=[]\n\t\t\t\tfor (e,color) in enumerate(colors):\n\t\t\t\t\tcolor.fit(gamut);color_str=color.convert(gamut).to_string()\n\t\t\t\t\tif current:\n\t\t\t\t\t\tstops.append(_I.format(color_str,str(last)));stops.append(_I.format(color_str,str(current)));last=current\n\t\t\t\t\t\tif e<total-1:current+=percent\n\t\t\t\t\t\telse:current=100\n\t\t\t\t\telse:stops.append(color_str)\n\t\t\t\tcolor_stops+='--color-wheel-stops{}: {};'.format(i,','.join(stops))\n\t\t\tcolor_wheel='<div class=\"color-wheel\" style=\"{}\"><div class=\"wheel\">\\n{}<div class=\"tertiary\"><div class=\"secondary\"><div class=\"secondary-inner\"><div class=\"primary\"><div class=\"primary-inner\"></div></div></div></div></div></div></div>{}'.format(color_stops,extra_rings_start,extra_rings_end);return color_wheel\n\t\telse:\n\t\t\tif len(md.preprocessors[A].extension.stash)==0:code_id=0\n\t\t\texceptions=options.get(_H,_A)if options is not _C else _A;console,colors=execute(src.strip(),not exceptions,init=init);el=_color_command_console(colors,gamut=gamut);el+=md.preprocessors[A].extension.superfences[0][B](src=console,class_name=_G,language=_M,md=md,options=options,**kwargs);el=_P.format(el);el=template.format(el_id=code_id,raw_source=_escape(src),results=el,gamut=gamut);code_id+=1\n\texcept SuperFencesException:raise\n\texcept Exception:from pymdownx import superfences;import traceback;print(traceback.format_exc());return superfences.fence_code_format(src,'text',class_name,options,md,**kwargs)\n\treturn el\ndef color_command_formatter(init='',gamut=WEBSPACE):return partial(_color_command_formatter,init=init,gamut=gamut)\ndef _color_formatter(src='',language='',class_name=_C,md='',exceptions=_B,init='',gamut=WEBSPACE):\n\tE='backtick';D='title';C='Only one color allowed';B=' 50%';A='span';from pymdownx.inlinehilite import InlineHiliteException\n\ttry:\n\t\tresult=src.strip()\n\t\ttry:color=ColorAll(result.strip())\n\t\texcept Exception as e:\n\t\t\t_,colors=execute(result,exceptions,inline=_B,init=init)\n\t\t\tif len(colors)!=1 or len(colors[0])!=1:\n\t\t\t\tif exceptions:raise InlineHiliteException(C) from e\n\t\t\t\telse:raise ValueError(C) from e\n\t\t\tcolor=colors[0][0].color;result=colors[0][0].string\n\t\tel=Etree.Element(A);stops=[]\n\t\tif not color.in_gamut(gamut):\n\t\t\tcolor.fit(gamut);attributes={_F:'swatch out-of-gamut',D:result};sub_el=Etree.SubElement(el,A,attributes);stops.append(color.convert(gamut).to_string(hex=_B,alpha=_A))\n\t\t\tif color[-1]<1.0:stops[-1]+=B;stops.append(color.convert(gamut).to_string(hex=_B)+B)\n\t\telse:\n\t\t\tattributes={_F:_O,D:result};sub_el=Etree.SubElement(el,A,attributes);stops.append(color.convert(gamut).to_string(hex=_B,alpha=_A))\n\t\t\tif color[-1]<1.0:stops[-1]+=B;stops.append(color.convert(gamut).to_string(hex=_B)+B)\n\t\tif not stops:stops.extend([_N]*2)\n\t\tif len(stops)==1:stops.append(stops[0])\n\t\tEtree.SubElement(sub_el,A,{_F:'swatch-color','style':'--swatch-stops: {};'.format(','.join(stops))});el.append(md.inlinePatterns[E].handle_code('css-color',result))\n\texcept InlineHiliteException:raise\n\texcept Exception:import traceback;print(traceback.format_exc());el=md.inlinePatterns[E].handle_code('text',src)\n\treturn el\ndef color_formatter(init='',gamut=WEBSPACE):return partial(_color_formatter,init=init,gamut=gamut)\ndef _live_color_command_formatter(src,init='',gamut=WEBSPACE):\n\ttry:\n\t\tconsole,colors=execute(src.strip(),_A,init=init);el=_color_command_console(colors,gamut=gamut)\n\t\tif not colors:el+='<div class=\"swatch-bar\"></div>'\n\t\tel+=colorize(console,_M,**{'python3':_B,'stripnl':_A});el=_P.format(el)\n\texcept Exception:import traceback;return '<div class=\"color-command\"><div class=\"swatch-bar\"></div>{}</div>'.format(colorize(traceback.format_exc(),_M))\n\treturn el\ndef live_color_command_formatter(init='',gamut=WEBSPACE):return partial(_live_color_command_formatter,init=init,gamut=gamut)\ndef live_color_command_validator(language,inputs,options,attrs,md):value=color_command_validator(language,inputs,options,attrs,md);options[_H]=_B;return value\ndef render_console(*args,**kwargs):\n\tC='.swatch-bar';B='code';A='id_num';from js import document;gamut=kwargs.get(_K,WEBSPACE)\n\ttry:\n\t\tinputs=document.getElementById('__playground-inputs_{}'.format(globals()[A]));results=document.getElementById('__playground-results_{}'.format(globals()[A]));footer=document.querySelector('#__playground_{} .gamut'.format(globals()[A]));result=live_color_command_formatter(LIVE_INIT,gamut)(inputs.value);temp=document.createElement('div');temp.innerHTML=result;cmd=results.querySelector('.color-command')\n\t\tfor el in cmd.querySelectorAll(C):el.remove()\n\t\tfor el in temp.querySelectorAll(C):cmd.insertBefore(el,cmd.lastChild)\n\t\tfooter.innerHTML='Gamut: {}'.format(gamut);pre=cmd.querySelector('pre');pre.replaceChild(temp.querySelector(B),pre.querySelector(B));temp.remove();scrollingElement=results.querySelector(B);scrollingElement.scrollTop=scrollingElement.scrollHeight\n\texcept Exception as e:print(e)\ndef render_notebook(*args,**kwargs):\n\tM='diagram';L='pymdownx.blocks.tab';K='pymdownx.blocks.admonition';J='pymdownx.arithmatex';I='pymdownx.keys';H='pymdownx.magiclink';G='pymdownx.inlinehilite';F='pymdownx.superfences';E='markdown.extensions.smarty';D='markdown.extensions.toc';C='validator';B='format';A='name';import markdown;from pymdownx import slugs,superfences;from js import document;gamut=kwargs.get(_K,WEBSPACE);text=globals().get('content','');extensions=[D,E,'pymdownx.betterem','markdown.extensions.attr_list','markdown.extensions.tables','markdown.extensions.abbr','markdown.extensions.footnotes',F,'pymdownx.highlight',G,H,'pymdownx.tilde','pymdownx.caret','pymdownx.smartsymbols','pymdownx.emoji','pymdownx.escapeall','pymdownx.tasklist','pymdownx.striphtml','pymdownx.snippets',I,'pymdownx.saneheaders',J,K,'pymdownx.blocks.details','pymdownx.blocks.html','pymdownx.blocks.definition',L];extension_configs={D:{'slugify':slugs.slugify(case='lower'),'permalink':''},E:{'smart_quotes':_A},J:{'generic':_B,'block_tag':'pre'},F:{'preserve_tabs':_B,'custom_fences':[{A:M,_F:M,B:superfences.fence_code_format},{A:_L,_F:_L,B:color_command_formatter(LIVE_INIT,gamut),C:live_color_command_validator},{A:'python',_F:_G,B:color_command_formatter(LIVE_INIT,gamut),C:live_color_command_validator},{A:'py',_F:_G,B:color_command_formatter(LIVE_INIT,gamut),C:live_color_command_validator}]},G:{'custom_inline':[{A:_J,_F:_J,B:color_formatter(LIVE_INIT,gamut)}]},H:{'repo_url_shortener':_B,'repo_url_shorthand':_B,'social_url_shorthand':_B,'user':'facelessuser','repo':'coloraide'},I:{'separator':'＋'},L:{'alternate_style':_B},K:{'types':['new','settings','note','abstract','info','tip','success','question','warning','failure','danger','bug','example','quote']}}\n\ttry:html=markdown.markdown(text,extensions=extensions,extension_configs=extension_configs)\n\texcept Exception:html=''\n\tcontent=document.getElementById('__notebook-render');content.innerHTML=html\n\naction = globals().get('action')\nif action == 'notebook':\n    callback = render_notebook\nelse:\n    callback = render_console\n\ncallback(gamut='".concat(e,"')\n"),g=window.colorNotebook.defaultPlayground,h=function(t){return"\n/// new | This notebook is powered by [Pyodide](https://github.com/pyodide/pyodide). Learn more [here](?notebook=https://gist.githubusercontent.com/facelessuser/7c819668b5eb248ecb9ac608d91391cf/raw/playground.md). Preview, convert, interpolate, and explore!\n///\n\n````````py play\n".concat(t,"\n````````\n")},y=!1,v=!1,w=function(){f=!0,window.document.dispatchEvent(new Event("DOMContentLoaded",{bubbles:!0,cancelable:!0})),window.document$.next()},x=function(t){var e=window.pageXOffset||(document.documentElement||document.body.parentNode||document.body).scrollLeft,n=window.pageYOffset||(document.documentElement||document.body.parentNode||document.body).scrollTop;t.style.height="5px",t.style.height="".concat(t.scrollHeight,"px"),window.scrollTo(e,n)},b=function(t){return encodeURIComponent(t).replace(/[.!'()*]/g,(function(t){return"%".concat(t.charCodeAt(0).toString(16))}))},E=function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return(o=document.getElementById("__playground-inputs_".concat(n))).setAttribute("readonly",""),i.globals.set("id_num",n),i.globals.set("action","playground"),t.next=6,i.runPythonAsync(_);case 6:o.removeAttribute("readonly");case 7:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),k=function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return i.globals.set("content",n),i.globals.set("action","notebook"),t.next=4,i.runPythonAsync(_);case 4:(o=document.getElementById("__notebook-input"))&&(s=n,o.value=n),window.location.hash&&(window.location.href=window.location.href);case 7:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),L=function(){var e=n(t().mark((function e(n){var o,a,s,l,c,u;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(d){t.next=5;break}return d=!0,t.next=4,loadPyodide({indexURL:"https://cdn.jsdelivr.net/pyodide/v0.23.4/full/",fullStdLib:!1});case 4:i=t.sent;case 5:if((y||!n)&&(v||n)){t.next=14;break}o="".concat(window.location.origin,"/").concat(window.location.pathname.split("/")[1],"/playground/"),a=n?window.colorNotebook.notebookWheels:window.colorNotebook.playgroundWheels,s=[],n?y=!0:v=!0,l=r(a);try{for(l.s();!(c=l.n()).done;)(u=c.value).endsWith(".whl")?s.push(o+u):s.push(u)}catch(t){l.e(t)}finally{l.f()}return t.next=14,i.loadPackage(s);case 14:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),S=function(t,e,n){var o=null==e?"Loading...":e,r=n?"loading relative":"loading",i=document.createElement("template");i.innerHTML='<div class="'.concat(r,'"><div class="loader"></div><div>').concat(o,"</div></div>"),t.appendChild(i.content.firstChild)},A=function(t){t.querySelector(".loading")&&t.removeChild(t.querySelector(".loading"))},C=function(t){if("Tab"===t.key){var e=t.target;if(e.selectionStart!==e.selectionEnd){t.preventDefault();for(var n=e.selectionStart,o=e.selectionEnd,r=e.value;n>0&&"\n"!==r[n-1];)n--;for(;o>0&&"\n"!==r[o-1]&&o<r.length;)o++;for(var i=r.substr(n,o-n).split("\n"),a=0;a<i.length;a++)a===i.length-1&&0===i[a].length||(t.shiftKey?i[a]=i[a].replace(m,""):i[a]="    ".concat(i[a]));i=i.join("\n"),e.value=r.substr(0,n)+i+r.substr(o),e.selectionStart=n,e.selectionEnd=n+i.length}}},B=function(){var e=n(t().mark((function e(o){var r;return t().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:r=document.getElementById("__notebook-source"),document.querySelectorAll(".playground").forEach((function(e){var i=e.id.replace(u,"$1"),d=document.getElementById("__playground-inputs_".concat(i)),p=document.getElementById("__playground-results_".concat(i)),f=document.getElementById("__playground-code_".concat(i)),m=document.querySelector("button#__playground-edit_".concat(i)),_=document.querySelector("button#__playground-share_".concat(i)),g=document.querySelector("button#__playground-run_".concat(i)),h=document.querySelector("button#__playground-cancel_".concat(i));if(d.addEventListener("input",(function(){x(d)})),d.addEventListener("keydown",C),r&&o){var y=document.getElementById("__notebook-input");y.addEventListener("input",(function(t){x(t.target)})),y.addEventListener("keydown",C),document.getElementById("__notebook-edit").addEventListener("click",(function(){c[y.id]=y.value,document.getElementById("__notebook-render").classList.toggle("hidden"),document.getElementById("__notebook-source").classList.toggle("hidden"),x(document.getElementById("__notebook-input"))})),document.getElementById("__notebook-md-gist").addEventListener("click",function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:null!==(o=prompt("Please enter link to the Markdown page source:",l))&&(o=b(o),n.preventDefault(),history.pushState({notebook:o},"","?".concat(new URLSearchParams("notebook=".concat(o)).toString())),I(!1));case 2:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}()),document.getElementById("__notebook-py-gist").addEventListener("click",function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:null!==(o=prompt("Please enter the link to the Python code source:",l))&&(o=b(o),n.preventDefault(),history.pushState({source:o},"","?".concat(new URLSearchParams("source=".concat(o)).toString())),I(!1));case 2:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}()),document.getElementById("__notebook-input").value=s,document.getElementById("__notebook-cancel").addEventListener("click",(function(){y.value=c[y.id],delete c[y.id],document.getElementById("__notebook-render").classList.toggle("hidden"),document.getElementById("__notebook-source").classList.toggle("hidden")})),document.getElementById("__notebook-submit").addEventListener("click",n(t().mark((function e(){var n,o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=document.getElementById("__notebook-render"),s=document.getElementById("__notebook-input").value,n.classList.toggle("hidden"),document.getElementById("__notebook-source").classList.toggle("hidden"),o=document.querySelector("article"),S(o,"Loading Notebook..."),n.innerHTML="",c={},t.next=10,L(!0);case 10:return t.next=12,k(s);case 12:return t.next=14,B();case 14:A(o),w();case 16:case"end":return t.stop()}}),e)}))))}d.addEventListener("touchmove",(function(t){t.stopPropagation()})),p.addEventListener("click",(function(t){var e=t.target;if(e.matches("span.swatch-color")){var n="",o=e.parentNode;if(!o.matches("span.swatch-gradient")){if(n=(n=o.getAttribute("title").replace("Copy to clipboard","")).replace("\n",""),window.clipboardData&&window.clipboardData.setData)return window.clipboardData.setData("Text",n);if(document.queryCommandSupported&&document.queryCommandSupported("copy")){var r=document.createElement("textarea");r.textContent=n,r.style.position="fixed",document.body.appendChild(r),r.select();try{return document.execCommand("copy")}catch(t){return prompt("Copy to clipboard: Ctrl+C, Enter",n)}finally{document.body.removeChild(r)}}}}})),m.addEventListener("click",n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:c[i]=d.value,f.classList.toggle("hidden"),p.classList.toggle("hidden"),g.classList.toggle("hidden"),h.classList.toggle("hidden"),m.classList.toggle("hidden"),_.classList.toggle("hidden"),x(d),d.focus();case 9:case"end":return t.stop()}}),e)})))),_.addEventListener("click",n(t().mark((function e(){var o,r,i,a,s;return t().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:o=window.location.pathname.split("/")[1],r=b(d.value),i=window.location,a="/playground/",i.pathname.startsWith("/".concat(o,"/"))&&(a="/".concat(o,"/playground/")),(s="".concat(i.protocol,"//").concat(i.host).concat(a,"?code=").concat(r)).length>2e3?alert("Code must be small enough to generate a shareable URL under 2000 characters!"):navigator.clipboard.writeText(s).then(n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:alert("Link copied to clipboard :)");case 1:case"end":return t.stop()}}),e)}))),n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:alert("Failed to copy link clipboard!");case 1:case"end":return t.stop()}}),e)}))));case 7:case"end":return e.stop()}}),e)})))),g.addEventListener("click",n(t().mark((function e(){var n,o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(!a){t.next=2;break}return t.abrupt("return");case 2:return a=!0,n=f.querySelector("form"),S(n,null,!0),(o=document.querySelectorAll(".playground .playground-run"))&&o.forEach((function(t){t.setAttribute("disabled","")})),t.next=9,L(!1);case 9:return p.querySelector("code").innerHTML="",t.next=12,E(i);case 12:o&&o.forEach((function(t){t.removeAttribute("disabled")})),A(n),f.classList.toggle("hidden"),p.classList.toggle("hidden"),m.classList.toggle("hidden"),_.classList.toggle("hidden"),g.classList.toggle("hidden"),h.classList.toggle("hidden"),delete c[i],a=!1;case 22:case"end":return t.stop()}}),e)})))),h.addEventListener("click",(function(){d.value=c[i],delete c[i],f.classList.toggle("hidden"),p.classList.toggle("hidden"),m.classList.toggle("hidden"),_.classList.toggle("hidden"),g.classList.toggle("hidden"),h.classList.toggle("hidden")}))}));case 3:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),I=function(){var e=n(t().mark((function e(o,r){var i,a,s,u,d,f,m,_,y;return t().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(c={},!window.location.pathname.endsWith("/playground/")){e.next=32;break}if(i=r||new URLSearchParams(window.location.search),a="Loading Pyodide...",s="Loading Notebook...",u=i.has("source")?i.get("source"):i.get("notebook"),d=document.querySelector("article"),null===u||!u.trim()){e.next=16;break}return S(d,a),e.next=11,L(!0);case 11:A(d),S(d,s);try{f=i.has("source")?"source":"notebook",p=decodeURIComponent(i.toString()),m="",_=new XMLHttpRequest,l=u,_.open("GET",u,!0),_.onload=n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return 4===_.readyState&&200===_.status&&(m=_.responseText),"source"===f&&(m=h(m)),t.next=4,k(m);case 4:return t.next=6,B(o);case 6:A(d),w();case 8:case"end":return t.stop()}}),e)}))),_.send()}catch(t){}e.next=30;break;case 16:return l="",y=h(i.has("code")?i.get("code"):g),p=decodeURIComponent(i.toString()),S(d,a),e.next=22,L(!0);case 22:return A(d),S(d,s),e.next=26,k(y);case 26:return e.next=28,B(o);case 28:A(d),w();case 30:e.next=35;break;case 32:l="",p="",B(o);case 35:case"end":return e.stop()}}),e)})));return function(t,n){return e.apply(this,arguments)}}();document.addEventListener("click",(function(t){var e=window.location.pathname.split("/")[1],n=t.target||t.srcElement;if("A"===n.tagName&&I&&n.getAttribute("href")&&n.host===window.location.host&&window.location.pathname==="/".concat(e,"/playground/")&&window.location.pathname===n.pathname&&window.location.search!==n.search){t.preventDefault();var o=new URLSearchParams(n.search);I(!1,o)}}),!0),window.addEventListener("popstate",(function(){var t=window.location.pathname.split("/")[1];window.location.pathname==="/".concat(t,"/playground/")&&(decodeURIComponent(new URLSearchParams(window.location.search).toString())!==p&&I(!1))})),window.addEventListener("unload",(function(){f=!1})),window.document$.subscribe((function(){f?f=!1:I(!0)}))}()}();
+//# sourceMappingURL=extra-notebook-ba27d60b.js.map
diff --git a/docs/theme/assets/coloraide-extras/extra-notebook-f321e406.js.map b/docs/theme/assets/coloraide-extras/extra-notebook-ba27d60b.js.map
similarity index 99%
rename from docs/theme/assets/coloraide-extras/extra-notebook-f321e406.js.map
rename to docs/theme/assets/coloraide-extras/extra-notebook-ba27d60b.js.map
index 875860c2e..4d863a40d 100644
--- a/docs/theme/assets/coloraide-extras/extra-notebook-f321e406.js.map
+++ b/docs/theme/assets/coloraide-extras/extra-notebook-ba27d60b.js.map
@@ -1,1 +1,1 @@
-{"version":3,"file":"extra-notebook-f321e406.js","sources":["extra-notebook.js"],"sourcesContent":["(() => {\n  let webspace = ''\n  try {\n    let gamut = 'srgb'\n    if (window.matchMedia(\"(color-gamut: rec2020)\").matches) {\n      gamut = 'rec2020'\n    } else if (window.matchMedia(\"(color-gamut: p3)\").matches) {\n      gamut = 'display-p3'\n    }\n    webspace = (CSS.supports('color: color(display-p3 1 0 0)')) ? gamut : 'srgb'\n  } catch {\n    webspace = 'srgb'\n  }\n  let pyodide = null\n  let busy = false\n  let raw = \"\"\n  let gist = \"\"\n  let editTemp = {}\n  const reIdNum = /.*?_(\\d+)$/\n  let initialized = false\n  let lastSearch = \"\"\n  let fake = false\n  const tabStart = /^( {1,4}|\\t)/\n  // This is the Python payload that will be executed when the user\n  // presses the `Run` button. It will execute the code, create a\n  // Python console output, find color references, steps, and interpolation\n  // references and render the appropriate preview.\n  const pycode = `\n{{pycode}}\n\naction = globals().get('action')\nif action == 'notebook':\n    callback = render_notebook\nelse:\n    callback = render_console\n\ncallback(gamut='${webspace}')\n`\n\n  const defContent = window.colorNotebook.defaultPlayground\n\n  const getContent = content => {\n    return `\n/// new | This notebook is powered by [Pyodide](https://github.com/pyodide/pyodide). \\\nLearn more [here](\\\n?notebook=https://gist.githubusercontent.com/facelessuser/7c819668b5eb248ecb9ac608d91391cf/raw/playground.md\\\n). Preview, convert, interpolate, and explore!\n///\n\n\\`\\`\\`\\`\\`\\`\\`\\`py play\n${content}\n\\`\\`\\`\\`\\`\\`\\`\\`\n`\n  }\n\n  let notebookInstalled = false\n  let playgroundInstalled = false\n\n  const fakeDOMContentLoaded = () => {\n    // Send a fake `DOMContentLoaded`\n    fake = true\n    window.document.dispatchEvent(new Event(\"DOMContentLoaded\", {\n      bubbles: true,\n      cancelable: true\n    }))\n    window.document$.next()\n  }\n\n  const textResize = inpt => {\n    // Resize inputs based on text height.\n\n    const scrollLeft = window.pageXOffset ||\n      (document.documentElement || document.body.parentNode || document.body).scrollLeft\n\n    const scrollTop  = window.pageYOffset ||\n      (document.documentElement || document.body.parentNode || document.body).scrollTop\n\n    inpt.style.height = \"5px\"\n    inpt.style.height = `${inpt.scrollHeight}px`\n\n    window.scrollTo(scrollLeft, scrollTop)\n  }\n\n  const encodeuri = uri => {\n    // Encode the URI component.\n\n    return encodeURIComponent(uri).replace(/[.!'()*]/g, c => {\n      return `%${c.charCodeAt(0).toString(16)}`\n    })\n  }\n\n  const pyexecute = async currentID => {\n    // Execute Python code inside a playground\n\n    const currentInputs = document.getElementById(`__playground-inputs_${currentID}`)\n    currentInputs.setAttribute(\"readonly\", \"\")\n    pyodide.globals.set(\"id_num\", currentID)\n    pyodide.globals.set(\"action\", \"playground\")\n    await pyodide.runPythonAsync(pycode)\n    currentInputs.removeAttribute(\"readonly\")\n  }\n\n  const pyrender = async text => {\n    // Render an entire notebook page\n\n    pyodide.globals.set(\"content\", text)\n    pyodide.globals.set(\"action\", \"notebook\")\n    await pyodide.runPythonAsync(pycode)\n    const src = document.getElementById(\"__notebook-input\")\n    if (src) {\n      raw = text\n      src.value = text\n    }\n    if (window.location.hash) {\n      // Force jumping to hashes\n      window.location.href = window.location.href // eslint-disable-line no-self-assign\n    }\n  }\n\n  const setupPyodide = async full => {\n    // Load `Pyodide` and the any default packages we can need and can load.\n\n    if (!initialized) {\n      initialized = true\n      pyodide = await loadPyodide({ // eslint-disable-line no-undef\n        indexURL: \"https://cdn.jsdelivr.net/pyodide/v0.23.4/full/\",\n        fullStdLib: false\n      })\n    }\n\n    if ((!notebookInstalled && full) || (!playgroundInstalled && !full)) {\n      const base = `${window.location.origin}/${window.location.pathname.split('/')[1]}/playground/`\n      const packages = (full) ? window.colorNotebook.notebookWheels : window.colorNotebook.playgroundWheels\n      const installs = []\n      if (full) {\n        notebookInstalled = true\n      } else {\n        playgroundInstalled = true\n      }\n      for (const s of packages) {\n        if (s.endsWith('.whl')) {\n          installs.push(base + s)\n        } else {\n          installs.push(s)\n        }\n      }\n      await pyodide.loadPackage(installs)\n    }\n  }\n\n  const showBusy = (target, label, relative) => {\n    // Show busy indicator\n\n    const loaderLabel = (typeof label === \"undefined\" || label === null) ? \"Loading...\" : label\n    const classes = relative ? \"loading relative\" : \"loading\"\n    const template = document.createElement(\"template\")\n    template.innerHTML = `<div class=\"${classes}\"><div class=\"loader\"></div><div>${loaderLabel}</div></div>`\n    target.appendChild(template.content.firstChild)\n  }\n\n  const hideBusy = target => {\n    // Hide busy indicator\n\n    const loading = target.querySelector(\".loading\")\n    if (loading) {\n      target.removeChild(target.querySelector(\".loading\"))\n    }\n  }\n\n  const popState = () => {\n    // Handle notebook history\n\n    const base = window.location.pathname.split('/')[1]\n    if (\n      window.location.pathname === `/${base}/playground/`\n    ) {\n      const current = decodeURIComponent(new URLSearchParams(window.location.search).toString())\n      if (current !== lastSearch) {\n        main(false) // eslint-disable-line no-use-before-define\n      }\n    }\n  }\n\n  const interceptClickEvent = e => {\n    // Catch links to other notebook pages and handle them\n\n    const base = window.location.pathname.split('/')[1]\n    const target = e.target || e.srcElement\n    if (target.tagName === \"A\" && main) { // eslint-disable-line no-use-before-define\n      if (\n        target.getAttribute(\"href\") &&\n        target.host === window.location.host &&\n        window.location.pathname === `/${base}/playground/` &&\n        window.location.pathname === target.pathname &&\n        window.location.search !== target.search\n      ) {\n        e.preventDefault()\n        const search = new URLSearchParams(target.search)\n        main(false, search) // eslint-disable-line no-use-before-define\n      }\n    }\n  }\n\n  const handleTab = e => {\n    // Prevent tab from tabbing out.\n\n    if (e.key === 'Tab') {\n      const target = e.target\n\n      if (target.selectionStart !== target.selectionEnd) {\n        e.preventDefault()\n\n        let start = target.selectionStart\n        let end = target.selectionEnd\n\n        const text = target.value\n\n        while (start > 0 && text[start - 1] !== '\\n') {\n          start--\n        }\n        while (end > 0 && text[end - 1] !== '\\n' && end < text.length) {\n          end++\n        }\n\n        let lines = text.substr(start, end - start).split('\\n')\n\n        for (let i = 0; i < lines.length; i++) {\n\n          // Don't indent last line if cursor at start of line\n          if (i === lines.length - 1 && lines[i].length === 0) {\n            continue\n          }\n\n          // Indent or deindent\n          if (e.shiftKey) {\n            lines[i] = lines[i].replace(tabStart, '')\n          } else {\n            lines[i] = `    ${lines[i]}`\n          }\n        }\n        lines = lines.join('\\n')\n\n        // Update the text area\n        target.value = text.substr(0, start) + lines + text.substr(end)\n        target.selectionStart = start\n        target.selectionEnd = start + lines.length\n      }\n    }\n  }\n\n  const init = async first => {\n    // Setup input highlighting and events to run Python code blocks.\n\n    const notebook = document.getElementById(\"__notebook-source\")\n    const playgrounds = document.querySelectorAll(\".playground\")\n    playgrounds.forEach(pg => {\n\n      const currentID = pg.id.replace(reIdNum, \"$1\")\n      const inputs = document.getElementById(`__playground-inputs_${currentID}`)\n      const results = document.getElementById(`__playground-results_${currentID}`)\n      const pgcode = document.getElementById(`__playground-code_${currentID}`)\n      const buttonEdit = document.querySelector(`button#__playground-edit_${currentID}`)\n      const buttonShare = document.querySelector(`button#__playground-share_${currentID}`)\n      const buttonRun = document.querySelector(`button#__playground-run_${currentID}`)\n      const buttonCancel = document.querySelector(`button#__playground-cancel_${currentID}`)\n\n      inputs.addEventListener(\"input\", () => {\n        // Adjust textarea height on text input.\n\n        textResize(inputs)\n      })\n\n      inputs.addEventListener('keydown', handleTab)\n\n      if (notebook && first) {\n        const notebookInput = document.getElementById(\"__notebook-input\")\n\n        notebookInput.addEventListener(\"input\", e => {\n          // Adjust textarea height on text input.\n\n          textResize(e.target)\n        })\n\n        notebookInput.addEventListener('keydown', handleTab)\n\n        const editPage = document.getElementById(\"__notebook-edit\")\n        editPage.addEventListener(\"click\", () => {\n          editTemp[notebookInput.id] = notebookInput.value\n          document.getElementById(\"__notebook-render\").classList.toggle(\"hidden\")\n          document.getElementById(\"__notebook-source\").classList.toggle(\"hidden\")\n          textResize(document.getElementById(\"__notebook-input\"))\n        })\n\n        document.getElementById(\"__notebook-md-gist\").addEventListener(\"click\", async e => {\n          let uri = prompt(\"Please enter link to the Markdown page source:\", gist) // eslint-disable-line no-alert\n          if (uri !== null) {\n            uri = encodeuri(uri)\n            e.preventDefault()\n            history.pushState({notebook: uri}, \"\", `?${new URLSearchParams(`notebook=${uri}`).toString()}`)\n            main(false) // eslint-disable-line no-use-before-define\n          }\n        })\n\n        document.getElementById(\"__notebook-py-gist\").addEventListener(\"click\", async e => {\n          let uri = prompt(\"Please enter the link to the Python code source:\", gist) // eslint-disable-line no-alert\n          if (uri !== null) {\n            uri = encodeuri(uri)\n            e.preventDefault()\n            history.pushState({source: uri}, \"\", `?${new URLSearchParams(`source=${uri}`).toString()}`)\n            main(false) // eslint-disable-line no-use-before-define\n          }\n        })\n\n        document.getElementById(\"__notebook-input\").value = raw\n        document.getElementById(\"__notebook-cancel\").addEventListener(\"click\", () => {\n          notebookInput.value = editTemp[notebookInput.id]\n          delete editTemp[notebookInput.id]\n          document.getElementById(\"__notebook-render\").classList.toggle(\"hidden\")\n          document.getElementById(\"__notebook-source\").classList.toggle(\"hidden\")\n        })\n\n        document.getElementById(\"__notebook-submit\").addEventListener(\"click\", async() => {\n          const render = document.getElementById(\"__notebook-render\")\n          raw = document.getElementById(\"__notebook-input\").value\n          render.classList.toggle(\"hidden\")\n          document.getElementById(\"__notebook-source\").classList.toggle(\"hidden\")\n          const article = document.querySelector(\"article\")\n          showBusy(article, \"Loading Notebook...\")\n          render.innerHTML = \"\"\n          editTemp = {}\n          await setupPyodide(true)\n          await pyrender(raw)\n          await init()\n          hideBusy(article)\n          fakeDOMContentLoaded()\n        })\n      }\n\n      inputs.addEventListener(\"touchmove\", e => {\n        // Stop propagation on \"touchmove\".\n\n        e.stopPropagation()\n      })\n\n      results.addEventListener(\"click\", e => {\n        // Handle clicks on results and copies color from single color swatch when clicked.\n\n        const el = e.target\n        if (el.matches('span.swatch-color')) {\n          let content = ''\n          const parent = el.parentNode\n          if (!parent.matches('span.swatch-gradient')) {\n            content = parent.getAttribute('title').replace('Copy to clipboard', '')\n            content = content.replace('\\n', '')\n            if (window.clipboardData && window.clipboardData.setData) {\n              // Old `IE`` handling, do we really need this?\n              return window.clipboardData.setData(\"Text\", content)\n            } else if (document.queryCommandSupported && document.queryCommandSupported(\"copy\")) {\n              const textarea = document.createElement(\"textarea\")\n              textarea.textContent = content\n              textarea.style.position = \"fixed\"\n              document.body.appendChild(textarea)\n              textarea.select()\n              try {\n                return document.execCommand(\"copy\")\n              } catch (ex) {\n                return prompt(\"Copy to clipboard: Ctrl+C, Enter\", content) // eslint-disable-line no-alert\n              } finally {\n                document.body.removeChild(textarea)\n              }\n            }\n          }\n        }\n      })\n\n      buttonEdit.addEventListener(\"click\", async() => {\n        // Handle the button click: show source or execute source.\n\n        editTemp[currentID] = inputs.value\n        pgcode.classList.toggle(\"hidden\")\n        results.classList.toggle(\"hidden\")\n        buttonRun.classList.toggle(\"hidden\")\n        buttonCancel.classList.toggle(\"hidden\")\n        buttonEdit.classList.toggle(\"hidden\")\n        buttonShare.classList.toggle(\"hidden\")\n        textResize(inputs)\n        inputs.focus()\n      })\n\n      buttonShare.addEventListener(\"click\", async() => {\n        // Handle the share click: copy URL with code as parameter.\n\n        const base = window.location.pathname.split('/')[1]\n        const uri = encodeuri(inputs.value)\n        const loc = window.location\n        let pathname = \"/playground/\"\n        if (loc.pathname.startsWith(`/${base}/`)) {\n          pathname = `/${base}/playground/`\n        }\n        const path = `${loc.protocol}//${loc.host}${pathname}?code=${uri}`\n        if (path.length > 2000) {\n          alert( // eslint-disable-line no-alert\n            \"Code must be small enough to generate a shareable URL under 2000 characters!\"\n          )\n        } else {\n          navigator.clipboard.writeText(path).then(async() => {\n            alert(\"Link copied to clipboard :)\") // eslint-disable-line no-alert\n          }, async() => {\n            alert(\"Failed to copy link clipboard!\") // eslint-disable-line no-alert\n          })\n        }\n      })\n\n      buttonRun.addEventListener(\"click\", async() => {\n        // Handle the button click: show source or execute source.\n\n        if (busy) {\n          return\n        }\n\n        busy = true\n        // Load Pyodide and related packages.\n        const form = pgcode.querySelector(\"form\")\n        showBusy(form, null, true)\n        const buttons = document.querySelectorAll(\".playground .playground-run\")\n        if (buttons) {\n          buttons.forEach(b => {\n            b.setAttribute(\"disabled\", \"\")\n          })\n        }\n        await setupPyodide(false)\n        results.querySelector(\"code\").innerHTML = \"\"\n        await pyexecute(currentID)\n        if (buttons) {\n          buttons.forEach(b => {\n            b.removeAttribute(\"disabled\")\n          })\n        }\n        hideBusy(form)\n        pgcode.classList.toggle(\"hidden\")\n        results.classList.toggle(\"hidden\")\n        buttonEdit.classList.toggle(\"hidden\")\n        buttonShare.classList.toggle(\"hidden\")\n        buttonRun.classList.toggle(\"hidden\")\n        buttonCancel.classList.toggle(\"hidden\")\n\n        delete editTemp[currentID]\n        busy = false\n      })\n\n      buttonCancel.addEventListener(\"click\", () => {\n        // Cancel edit.\n\n        inputs.value = editTemp[currentID]\n        delete editTemp[currentID]\n        pgcode.classList.toggle(\"hidden\")\n        results.classList.toggle(\"hidden\")\n        buttonEdit.classList.toggle(\"hidden\")\n        buttonShare.classList.toggle(\"hidden\")\n        buttonRun.classList.toggle(\"hidden\")\n        buttonCancel.classList.toggle(\"hidden\")\n      })\n    })\n  }\n\n  const main = async(first, search) => {\n    // Load external source to render in a playground.\n    // This can be something like a file on a gist we must read in (?source=)\n    // or raw code (?code=).\n\n    editTemp = {}\n\n    if (window.location.pathname.endsWith(\"/playground/\")) {\n      const params = search || new URLSearchParams(window.location.search)\n      const loadMsg = \"Loading Pyodide...\"\n      const pageMsg = \"Loading Notebook...\"\n      const uri = params.has(\"source\") ? params.get(\"source\") : params.get(\"notebook\")\n      const article = document.querySelector(\"article\")\n      if (uri !== null && uri.trim()) {\n        // A source was specified, so load it.\n        showBusy(article, loadMsg)\n        await setupPyodide(true)\n        hideBusy(article)\n        showBusy(article, pageMsg)\n        try {\n          const gistType = params.has(\"source\") ? \"source\" : \"notebook\"\n          lastSearch = decodeURIComponent(params.toString())\n          let value = \"\"\n          const xhr = new XMLHttpRequest()\n          gist = uri\n          xhr.open(\"GET\", uri, true)\n          xhr.onload = async() => {\n            // Try and load the requested content\n            if (xhr.readyState === 4) {\n              if (xhr.status === 200) {\n                value = xhr.responseText\n              }\n            }\n\n            if (gistType === \"source\") {\n              value = getContent(value)\n            }\n            await pyrender(value)\n            await init(first)\n            hideBusy(article)\n            fakeDOMContentLoaded()\n          }\n          xhr.send()\n        } catch (err) {} // eslint-disable-line no-empty\n      } else {\n        gist = \"\"\n        const content = getContent(params.has(\"code\") ? params.get(\"code\") : defContent)\n        lastSearch = decodeURIComponent(params.toString())\n        showBusy(article, loadMsg)\n        await setupPyodide(true)\n        hideBusy(article)\n        showBusy(article, pageMsg)\n        await pyrender(content)\n        await init(first)\n        hideBusy(article)\n        fakeDOMContentLoaded()\n      }\n    } else {\n      gist = \"\"\n      lastSearch = \"\"\n      init(first)\n    }\n  }\n\n  // Capture links in notebook pages so that we can make playgound links load instantly\n  document.addEventListener(\"click\", interceptClickEvent, true)\n\n  // Handle history of notebook pages as they are loaded dynamically\n  window.addEventListener(\"popstate\", popState)\n\n  // Before leaving, turn off fake, just in case we navigated away before finished\n  window.addEventListener(\"unload\", () => {\n    fake = false\n  })\n\n  // Attach main via subscribe (subscribes to Materials on page load and instant page loads)\n  window.document$.subscribe(() => {\n    // To get other libraries to reload, we may create a fake `DOMContentLoaded`\n    // No need to process these events.\n    if (fake) {\n      fake = false\n      return\n    }\n    main(true)\n  })\n})()\n"],"names":["webspace","gamut","window","matchMedia","matches","CSS","supports","_unused","pyodide","busy","raw","gist","editTemp","reIdNum","initialized","lastSearch","fake","tabStart","pycode","concat","defContent","colorNotebook","defaultPlayground","getContent","content","notebookInstalled","playgroundInstalled","fakeDOMContentLoaded","document","dispatchEvent","Event","bubbles","cancelable","document$","next","textResize","inpt","scrollLeft","pageXOffset","documentElement","body","parentNode","scrollTop","pageYOffset","style","height","scrollHeight","scrollTo","encodeuri","uri","encodeURIComponent","replace","c","charCodeAt","toString","pyexecute","_ref","_asyncToGenerator","_regeneratorRuntime","mark","_callee","currentID","currentInputs","wrap","_context","prev","getElementById","setAttribute","globals","set","runPythonAsync","removeAttribute","stop","_x","apply","this","arguments","pyrender","_ref2","_callee2","text","src","_context2","value","location","hash","href","_x2","setupPyodide","_ref3","_callee3","full","base","packages","installs","_iterator","_step","s","_context3","loadPyodide","indexURL","fullStdLib","sent","origin","pathname","split","notebookWheels","playgroundWheels","_createForOfIteratorHelper","n","done","endsWith","push","err","e","f","loadPackage","_x3","showBusy","target","label","relative","loaderLabel","classes","template","createElement","innerHTML","appendChild","firstChild","hideBusy","querySelector","removeChild","handleTab","key","selectionStart","selectionEnd","preventDefault","start","end","length","lines","substr","i","shiftKey","join","init","_ref4","_callee12","first","notebook","_context12","querySelectorAll","forEach","pg","id","inputs","results","pgcode","buttonEdit","buttonShare","buttonRun","buttonCancel","addEventListener","notebookInput","classList","toggle","_ref5","_callee4","_context4","prompt","history","pushState","URLSearchParams","main","_x5","_ref6","_callee5","_context5","source","_x6","_callee6","render","article","_context6","stopPropagation","el","parent","getAttribute","clipboardData","setData","queryCommandSupported","textarea","textContent","position","select","execCommand","ex","_callee7","_context7","focus","_callee10","loc","path","_context10","startsWith","protocol","host","alert","navigator","clipboard","writeText","then","_callee8","_context8","_callee9","_context9","_callee11","form","buttons","_context11","abrupt","b","_x4","_ref13","_callee14","search","params","loadMsg","pageMsg","gistType","xhr","_context14","has","get","trim","decodeURIComponent","XMLHttpRequest","open","onload","_callee13","_context13","readyState","status","responseText","send","_x7","_x8","srcElement","tagName","subscribe"],"mappings":"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"}
\ No newline at end of file
+{"version":3,"file":"extra-notebook-ba27d60b.js","sources":["extra-notebook.js"],"sourcesContent":["(() => {\n  let webspace = ''\n  try {\n    let gamut = 'srgb'\n    if (window.matchMedia(\"(color-gamut: rec2020)\").matches) {\n      gamut = 'rec2020'\n    } else if (window.matchMedia(\"(color-gamut: p3)\").matches) {\n      gamut = 'display-p3'\n    }\n    webspace = (CSS.supports('color: color(display-p3 1 0 0)')) ? gamut : 'srgb'\n  } catch {\n    webspace = 'srgb'\n  }\n  let pyodide = null\n  let busy = false\n  let raw = \"\"\n  let gist = \"\"\n  let editTemp = {}\n  const reIdNum = /.*?_(\\d+)$/\n  let initialized = false\n  let lastSearch = \"\"\n  let fake = false\n  const tabStart = /^( {1,4}|\\t)/\n  // This is the Python payload that will be executed when the user\n  // presses the `Run` button. It will execute the code, create a\n  // Python console output, find color references, steps, and interpolation\n  // references and render the appropriate preview.\n  const pycode = `\n{{pycode}}\n\naction = globals().get('action')\nif action == 'notebook':\n    callback = render_notebook\nelse:\n    callback = render_console\n\ncallback(gamut='${webspace}')\n`\n\n  const defContent = window.colorNotebook.defaultPlayground\n\n  const getContent = content => {\n    return `\n/// new | This notebook is powered by [Pyodide](https://github.com/pyodide/pyodide). \\\nLearn more [here](\\\n?notebook=https://gist.githubusercontent.com/facelessuser/7c819668b5eb248ecb9ac608d91391cf/raw/playground.md\\\n). Preview, convert, interpolate, and explore!\n///\n\n\\`\\`\\`\\`\\`\\`\\`\\`py play\n${content}\n\\`\\`\\`\\`\\`\\`\\`\\`\n`\n  }\n\n  let notebookInstalled = false\n  let playgroundInstalled = false\n\n  const fakeDOMContentLoaded = () => {\n    // Send a fake `DOMContentLoaded`\n    fake = true\n    window.document.dispatchEvent(new Event(\"DOMContentLoaded\", {\n      bubbles: true,\n      cancelable: true\n    }))\n    window.document$.next()\n  }\n\n  const textResize = inpt => {\n    // Resize inputs based on text height.\n\n    const scrollLeft = window.pageXOffset ||\n      (document.documentElement || document.body.parentNode || document.body).scrollLeft\n\n    const scrollTop  = window.pageYOffset ||\n      (document.documentElement || document.body.parentNode || document.body).scrollTop\n\n    inpt.style.height = \"5px\"\n    inpt.style.height = `${inpt.scrollHeight}px`\n\n    window.scrollTo(scrollLeft, scrollTop)\n  }\n\n  const encodeuri = uri => {\n    // Encode the URI component.\n\n    return encodeURIComponent(uri).replace(/[.!'()*]/g, c => {\n      return `%${c.charCodeAt(0).toString(16)}`\n    })\n  }\n\n  const pyexecute = async currentID => {\n    // Execute Python code inside a playground\n\n    const currentInputs = document.getElementById(`__playground-inputs_${currentID}`)\n    currentInputs.setAttribute(\"readonly\", \"\")\n    pyodide.globals.set(\"id_num\", currentID)\n    pyodide.globals.set(\"action\", \"playground\")\n    await pyodide.runPythonAsync(pycode)\n    currentInputs.removeAttribute(\"readonly\")\n  }\n\n  const pyrender = async text => {\n    // Render an entire notebook page\n\n    pyodide.globals.set(\"content\", text)\n    pyodide.globals.set(\"action\", \"notebook\")\n    await pyodide.runPythonAsync(pycode)\n    const src = document.getElementById(\"__notebook-input\")\n    if (src) {\n      raw = text\n      src.value = text\n    }\n    if (window.location.hash) {\n      // Force jumping to hashes\n      window.location.href = window.location.href // eslint-disable-line no-self-assign\n    }\n  }\n\n  const setupPyodide = async full => {\n    // Load `Pyodide` and the any default packages we can need and can load.\n\n    if (!initialized) {\n      initialized = true\n      pyodide = await loadPyodide({ // eslint-disable-line no-undef\n        indexURL: \"https://cdn.jsdelivr.net/pyodide/v0.23.4/full/\",\n        fullStdLib: false\n      })\n    }\n\n    if ((!notebookInstalled && full) || (!playgroundInstalled && !full)) {\n      const base = `${window.location.origin}/${window.location.pathname.split('/')[1]}/playground/`\n      const packages = (full) ? window.colorNotebook.notebookWheels : window.colorNotebook.playgroundWheels\n      const installs = []\n      if (full) {\n        notebookInstalled = true\n      } else {\n        playgroundInstalled = true\n      }\n      for (const s of packages) {\n        if (s.endsWith('.whl')) {\n          installs.push(base + s)\n        } else {\n          installs.push(s)\n        }\n      }\n      await pyodide.loadPackage(installs)\n    }\n  }\n\n  const showBusy = (target, label, relative) => {\n    // Show busy indicator\n\n    const loaderLabel = (typeof label === \"undefined\" || label === null) ? \"Loading...\" : label\n    const classes = relative ? \"loading relative\" : \"loading\"\n    const template = document.createElement(\"template\")\n    template.innerHTML = `<div class=\"${classes}\"><div class=\"loader\"></div><div>${loaderLabel}</div></div>`\n    target.appendChild(template.content.firstChild)\n  }\n\n  const hideBusy = target => {\n    // Hide busy indicator\n\n    const loading = target.querySelector(\".loading\")\n    if (loading) {\n      target.removeChild(target.querySelector(\".loading\"))\n    }\n  }\n\n  const popState = () => {\n    // Handle notebook history\n\n    const base = window.location.pathname.split('/')[1]\n    if (\n      window.location.pathname === `/${base}/playground/`\n    ) {\n      const current = decodeURIComponent(new URLSearchParams(window.location.search).toString())\n      if (current !== lastSearch) {\n        main(false) // eslint-disable-line no-use-before-define\n      }\n    }\n  }\n\n  const interceptClickEvent = e => {\n    // Catch links to other notebook pages and handle them\n\n    const base = window.location.pathname.split('/')[1]\n    const target = e.target || e.srcElement\n    if (target.tagName === \"A\" && main) { // eslint-disable-line no-use-before-define\n      if (\n        target.getAttribute(\"href\") &&\n        target.host === window.location.host &&\n        window.location.pathname === `/${base}/playground/` &&\n        window.location.pathname === target.pathname &&\n        window.location.search !== target.search\n      ) {\n        e.preventDefault()\n        const search = new URLSearchParams(target.search)\n        main(false, search) // eslint-disable-line no-use-before-define\n      }\n    }\n  }\n\n  const handleTab = e => {\n    // Prevent tab from tabbing out.\n\n    if (e.key === 'Tab') {\n      const target = e.target\n\n      if (target.selectionStart !== target.selectionEnd) {\n        e.preventDefault()\n\n        let start = target.selectionStart\n        let end = target.selectionEnd\n\n        const text = target.value\n\n        while (start > 0 && text[start - 1] !== '\\n') {\n          start--\n        }\n        while (end > 0 && text[end - 1] !== '\\n' && end < text.length) {\n          end++\n        }\n\n        let lines = text.substr(start, end - start).split('\\n')\n\n        for (let i = 0; i < lines.length; i++) {\n\n          // Don't indent last line if cursor at start of line\n          if (i === lines.length - 1 && lines[i].length === 0) {\n            continue\n          }\n\n          // Indent or deindent\n          if (e.shiftKey) {\n            lines[i] = lines[i].replace(tabStart, '')\n          } else {\n            lines[i] = `    ${lines[i]}`\n          }\n        }\n        lines = lines.join('\\n')\n\n        // Update the text area\n        target.value = text.substr(0, start) + lines + text.substr(end)\n        target.selectionStart = start\n        target.selectionEnd = start + lines.length\n      }\n    }\n  }\n\n  const init = async first => {\n    // Setup input highlighting and events to run Python code blocks.\n\n    const notebook = document.getElementById(\"__notebook-source\")\n    const playgrounds = document.querySelectorAll(\".playground\")\n    playgrounds.forEach(pg => {\n\n      const currentID = pg.id.replace(reIdNum, \"$1\")\n      const inputs = document.getElementById(`__playground-inputs_${currentID}`)\n      const results = document.getElementById(`__playground-results_${currentID}`)\n      const pgcode = document.getElementById(`__playground-code_${currentID}`)\n      const buttonEdit = document.querySelector(`button#__playground-edit_${currentID}`)\n      const buttonShare = document.querySelector(`button#__playground-share_${currentID}`)\n      const buttonRun = document.querySelector(`button#__playground-run_${currentID}`)\n      const buttonCancel = document.querySelector(`button#__playground-cancel_${currentID}`)\n\n      inputs.addEventListener(\"input\", () => {\n        // Adjust textarea height on text input.\n\n        textResize(inputs)\n      })\n\n      inputs.addEventListener('keydown', handleTab)\n\n      if (notebook && first) {\n        const notebookInput = document.getElementById(\"__notebook-input\")\n\n        notebookInput.addEventListener(\"input\", e => {\n          // Adjust textarea height on text input.\n\n          textResize(e.target)\n        })\n\n        notebookInput.addEventListener('keydown', handleTab)\n\n        const editPage = document.getElementById(\"__notebook-edit\")\n        editPage.addEventListener(\"click\", () => {\n          editTemp[notebookInput.id] = notebookInput.value\n          document.getElementById(\"__notebook-render\").classList.toggle(\"hidden\")\n          document.getElementById(\"__notebook-source\").classList.toggle(\"hidden\")\n          textResize(document.getElementById(\"__notebook-input\"))\n        })\n\n        document.getElementById(\"__notebook-md-gist\").addEventListener(\"click\", async e => {\n          let uri = prompt(\"Please enter link to the Markdown page source:\", gist) // eslint-disable-line no-alert\n          if (uri !== null) {\n            uri = encodeuri(uri)\n            e.preventDefault()\n            history.pushState({notebook: uri}, \"\", `?${new URLSearchParams(`notebook=${uri}`).toString()}`)\n            main(false) // eslint-disable-line no-use-before-define\n          }\n        })\n\n        document.getElementById(\"__notebook-py-gist\").addEventListener(\"click\", async e => {\n          let uri = prompt(\"Please enter the link to the Python code source:\", gist) // eslint-disable-line no-alert\n          if (uri !== null) {\n            uri = encodeuri(uri)\n            e.preventDefault()\n            history.pushState({source: uri}, \"\", `?${new URLSearchParams(`source=${uri}`).toString()}`)\n            main(false) // eslint-disable-line no-use-before-define\n          }\n        })\n\n        document.getElementById(\"__notebook-input\").value = raw\n        document.getElementById(\"__notebook-cancel\").addEventListener(\"click\", () => {\n          notebookInput.value = editTemp[notebookInput.id]\n          delete editTemp[notebookInput.id]\n          document.getElementById(\"__notebook-render\").classList.toggle(\"hidden\")\n          document.getElementById(\"__notebook-source\").classList.toggle(\"hidden\")\n        })\n\n        document.getElementById(\"__notebook-submit\").addEventListener(\"click\", async() => {\n          const render = document.getElementById(\"__notebook-render\")\n          raw = document.getElementById(\"__notebook-input\").value\n          render.classList.toggle(\"hidden\")\n          document.getElementById(\"__notebook-source\").classList.toggle(\"hidden\")\n          const article = document.querySelector(\"article\")\n          showBusy(article, \"Loading Notebook...\")\n          render.innerHTML = \"\"\n          editTemp = {}\n          await setupPyodide(true)\n          await pyrender(raw)\n          await init()\n          hideBusy(article)\n          fakeDOMContentLoaded()\n        })\n      }\n\n      inputs.addEventListener(\"touchmove\", e => {\n        // Stop propagation on \"touchmove\".\n\n        e.stopPropagation()\n      })\n\n      results.addEventListener(\"click\", e => {\n        // Handle clicks on results and copies color from single color swatch when clicked.\n\n        const el = e.target\n        if (el.matches('span.swatch-color')) {\n          let content = ''\n          const parent = el.parentNode\n          if (!parent.matches('span.swatch-gradient')) {\n            content = parent.getAttribute('title').replace('Copy to clipboard', '')\n            content = content.replace('\\n', '')\n            if (window.clipboardData && window.clipboardData.setData) {\n              // Old `IE`` handling, do we really need this?\n              return window.clipboardData.setData(\"Text\", content)\n            } else if (document.queryCommandSupported && document.queryCommandSupported(\"copy\")) {\n              const textarea = document.createElement(\"textarea\")\n              textarea.textContent = content\n              textarea.style.position = \"fixed\"\n              document.body.appendChild(textarea)\n              textarea.select()\n              try {\n                return document.execCommand(\"copy\")\n              } catch (ex) {\n                return prompt(\"Copy to clipboard: Ctrl+C, Enter\", content) // eslint-disable-line no-alert\n              } finally {\n                document.body.removeChild(textarea)\n              }\n            }\n          }\n        }\n      })\n\n      buttonEdit.addEventListener(\"click\", async() => {\n        // Handle the button click: show source or execute source.\n\n        editTemp[currentID] = inputs.value\n        pgcode.classList.toggle(\"hidden\")\n        results.classList.toggle(\"hidden\")\n        buttonRun.classList.toggle(\"hidden\")\n        buttonCancel.classList.toggle(\"hidden\")\n        buttonEdit.classList.toggle(\"hidden\")\n        buttonShare.classList.toggle(\"hidden\")\n        textResize(inputs)\n        inputs.focus()\n      })\n\n      buttonShare.addEventListener(\"click\", async() => {\n        // Handle the share click: copy URL with code as parameter.\n\n        const base = window.location.pathname.split('/')[1]\n        const uri = encodeuri(inputs.value)\n        const loc = window.location\n        let pathname = \"/playground/\"\n        if (loc.pathname.startsWith(`/${base}/`)) {\n          pathname = `/${base}/playground/`\n        }\n        const path = `${loc.protocol}//${loc.host}${pathname}?code=${uri}`\n        if (path.length > 2000) {\n          alert( // eslint-disable-line no-alert\n            \"Code must be small enough to generate a shareable URL under 2000 characters!\"\n          )\n        } else {\n          navigator.clipboard.writeText(path).then(async() => {\n            alert(\"Link copied to clipboard :)\") // eslint-disable-line no-alert\n          }, async() => {\n            alert(\"Failed to copy link clipboard!\") // eslint-disable-line no-alert\n          })\n        }\n      })\n\n      buttonRun.addEventListener(\"click\", async() => {\n        // Handle the button click: show source or execute source.\n\n        if (busy) {\n          return\n        }\n\n        busy = true\n        // Load Pyodide and related packages.\n        const form = pgcode.querySelector(\"form\")\n        showBusy(form, null, true)\n        const buttons = document.querySelectorAll(\".playground .playground-run\")\n        if (buttons) {\n          buttons.forEach(b => {\n            b.setAttribute(\"disabled\", \"\")\n          })\n        }\n        await setupPyodide(false)\n        results.querySelector(\"code\").innerHTML = \"\"\n        await pyexecute(currentID)\n        if (buttons) {\n          buttons.forEach(b => {\n            b.removeAttribute(\"disabled\")\n          })\n        }\n        hideBusy(form)\n        pgcode.classList.toggle(\"hidden\")\n        results.classList.toggle(\"hidden\")\n        buttonEdit.classList.toggle(\"hidden\")\n        buttonShare.classList.toggle(\"hidden\")\n        buttonRun.classList.toggle(\"hidden\")\n        buttonCancel.classList.toggle(\"hidden\")\n\n        delete editTemp[currentID]\n        busy = false\n      })\n\n      buttonCancel.addEventListener(\"click\", () => {\n        // Cancel edit.\n\n        inputs.value = editTemp[currentID]\n        delete editTemp[currentID]\n        pgcode.classList.toggle(\"hidden\")\n        results.classList.toggle(\"hidden\")\n        buttonEdit.classList.toggle(\"hidden\")\n        buttonShare.classList.toggle(\"hidden\")\n        buttonRun.classList.toggle(\"hidden\")\n        buttonCancel.classList.toggle(\"hidden\")\n      })\n    })\n  }\n\n  const main = async(first, search) => {\n    // Load external source to render in a playground.\n    // This can be something like a file on a gist we must read in (?source=)\n    // or raw code (?code=).\n\n    editTemp = {}\n\n    if (window.location.pathname.endsWith(\"/playground/\")) {\n      const params = search || new URLSearchParams(window.location.search)\n      const loadMsg = \"Loading Pyodide...\"\n      const pageMsg = \"Loading Notebook...\"\n      const uri = params.has(\"source\") ? params.get(\"source\") : params.get(\"notebook\")\n      const article = document.querySelector(\"article\")\n      if (uri !== null && uri.trim()) {\n        // A source was specified, so load it.\n        showBusy(article, loadMsg)\n        await setupPyodide(true)\n        hideBusy(article)\n        showBusy(article, pageMsg)\n        try {\n          const gistType = params.has(\"source\") ? \"source\" : \"notebook\"\n          lastSearch = decodeURIComponent(params.toString())\n          let value = \"\"\n          const xhr = new XMLHttpRequest()\n          gist = uri\n          xhr.open(\"GET\", uri, true)\n          xhr.onload = async() => {\n            // Try and load the requested content\n            if (xhr.readyState === 4) {\n              if (xhr.status === 200) {\n                value = xhr.responseText\n              }\n            }\n\n            if (gistType === \"source\") {\n              value = getContent(value)\n            }\n            await pyrender(value)\n            await init(first)\n            hideBusy(article)\n            fakeDOMContentLoaded()\n          }\n          xhr.send()\n        } catch (err) {} // eslint-disable-line no-empty\n      } else {\n        gist = \"\"\n        const content = getContent(params.has(\"code\") ? params.get(\"code\") : defContent)\n        lastSearch = decodeURIComponent(params.toString())\n        showBusy(article, loadMsg)\n        await setupPyodide(true)\n        hideBusy(article)\n        showBusy(article, pageMsg)\n        await pyrender(content)\n        await init(first)\n        hideBusy(article)\n        fakeDOMContentLoaded()\n      }\n    } else {\n      gist = \"\"\n      lastSearch = \"\"\n      init(first)\n    }\n  }\n\n  // Capture links in notebook pages so that we can make playgound links load instantly\n  document.addEventListener(\"click\", interceptClickEvent, true)\n\n  // Handle history of notebook pages as they are loaded dynamically\n  window.addEventListener(\"popstate\", popState)\n\n  // Before leaving, turn off fake, just in case we navigated away before finished\n  window.addEventListener(\"unload\", () => {\n    fake = false\n  })\n\n  // Attach main via subscribe (subscribes to Materials on page load and instant page loads)\n  window.document$.subscribe(() => {\n    // To get other libraries to reload, we may create a fake `DOMContentLoaded`\n    // No need to process these events.\n    if (fake) {\n      fake = false\n      return\n    }\n    main(true)\n  })\n})()\n"],"names":["webspace","gamut","window","matchMedia","matches","CSS","supports","_unused","pyodide","busy","raw","gist","editTemp","reIdNum","initialized","lastSearch","fake","tabStart","pycode","concat","defContent","colorNotebook","defaultPlayground","getContent","content","notebookInstalled","playgroundInstalled","fakeDOMContentLoaded","document","dispatchEvent","Event","bubbles","cancelable","document$","next","textResize","inpt","scrollLeft","pageXOffset","documentElement","body","parentNode","scrollTop","pageYOffset","style","height","scrollHeight","scrollTo","encodeuri","uri","encodeURIComponent","replace","c","charCodeAt","toString","pyexecute","_ref","_asyncToGenerator","_regeneratorRuntime","mark","_callee","currentID","currentInputs","wrap","_context","prev","getElementById","setAttribute","globals","set","runPythonAsync","removeAttribute","stop","_x","apply","this","arguments","pyrender","_ref2","_callee2","text","src","_context2","value","location","hash","href","_x2","setupPyodide","_ref3","_callee3","full","base","packages","installs","_iterator","_step","s","_context3","loadPyodide","indexURL","fullStdLib","sent","origin","pathname","split","notebookWheels","playgroundWheels","_createForOfIteratorHelper","n","done","endsWith","push","err","e","f","loadPackage","_x3","showBusy","target","label","relative","loaderLabel","classes","template","createElement","innerHTML","appendChild","firstChild","hideBusy","querySelector","removeChild","handleTab","key","selectionStart","selectionEnd","preventDefault","start","end","length","lines","substr","i","shiftKey","join","init","_ref4","_callee12","first","notebook","_context12","querySelectorAll","forEach","pg","id","inputs","results","pgcode","buttonEdit","buttonShare","buttonRun","buttonCancel","addEventListener","notebookInput","classList","toggle","_ref5","_callee4","_context4","prompt","history","pushState","URLSearchParams","main","_x5","_ref6","_callee5","_context5","source","_x6","_callee6","render","article","_context6","stopPropagation","el","parent","getAttribute","clipboardData","setData","queryCommandSupported","textarea","textContent","position","select","execCommand","ex","_callee7","_context7","focus","_callee10","loc","path","_context10","startsWith","protocol","host","alert","navigator","clipboard","writeText","then","_callee8","_context8","_callee9","_context9","_callee11","form","buttons","_context11","abrupt","b","_x4","_ref13","_callee14","search","params","loadMsg","pageMsg","gistType","xhr","_context14","has","get","trim","decodeURIComponent","XMLHttpRequest","open","onload","_callee13","_context13","readyState","status","responseText","send","_x7","_x8","srcElement","tagName","subscribe"],"mappings":"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"}
\ No newline at end of file
diff --git a/docs/theme/assets/coloraide-extras/extra-notebook-f321e406.js b/docs/theme/assets/coloraide-extras/extra-notebook-f321e406.js
deleted file mode 100644
index 2fa351f9b..000000000
--- a/docs/theme/assets/coloraide-extras/extra-notebook-f321e406.js
+++ /dev/null
@@ -1,2 +0,0 @@
-function _typeof(t){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},_typeof(t)}var runtime=function(t){"use strict";var e,n=Object.prototype,o=n.hasOwnProperty,r=Object.defineProperty||function(t,e,n){t[e]=n.value},a="function"==typeof Symbol?Symbol:{},i=a.iterator||"@@iterator",s=a.asyncIterator||"@@asyncIterator",l=a.toStringTag||"@@toStringTag";function c(t,e,n){return Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{c({},"")}catch(t){c=function(t,e,n){return t[e]=n}}function u(t,e,n,o){var a=e&&e.prototype instanceof _?e:_,i=Object.create(a.prototype),s=new I(o||[]);return r(i,"_invoke",{value:S(t,n,s)}),i}function d(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}t.wrap=u;var p="suspendedStart",f="suspendedYield",m="executing",g="completed",h={};function _(){}function y(){}function v(){}var w={};c(w,i,(function(){return this}));var x=Object.getPrototypeOf,b=x&&x(x(T([])));b&&b!==n&&o.call(b,i)&&(w=b);var E=v.prototype=_.prototype=Object.create(w);function k(t){["next","throw","return"].forEach((function(e){c(t,e,(function(t){return this._invoke(e,t)}))}))}function L(t,e){function n(r,a,i,s){var l=d(t[r],t,a);if("throw"!==l.type){var c=l.arg,u=c.value;return u&&"object"===_typeof(u)&&o.call(u,"__await")?e.resolve(u.__await).then((function(t){n("next",t,i,s)}),(function(t){n("throw",t,i,s)})):e.resolve(u).then((function(t){c.value=t,i(c)}),(function(t){return n("throw",t,i,s)}))}s(l.arg)}var a;r(this,"_invoke",{value:function(t,o){function r(){return new e((function(e,r){n(t,o,e,r)}))}return a=a?a.then(r,r):r()}})}function S(t,e,n){var o=p;return function(r,a){if(o===m)throw new Error("Generator is already running");if(o===g){if("throw"===r)throw a;return O()}for(n.method=r,n.arg=a;;){var i=n.delegate;if(i){var s=A(i,n);if(s){if(s===h)continue;return s}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if(o===p)throw o=g,n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o=m;var l=d(t,e,n);if("normal"===l.type){if(o=n.done?g:f,l.arg===h)continue;return{value:l.arg,done:n.done}}"throw"===l.type&&(o=g,n.method="throw",n.arg=l.arg)}}}function A(t,n){var o=n.method,r=t.iterator[o];if(r===e)return n.delegate=null,"throw"===o&&t.iterator.return&&(n.method="return",n.arg=e,A(t,n),"throw"===n.method)||"return"!==o&&(n.method="throw",n.arg=new TypeError("The iterator does not provide a '"+o+"' method")),h;var a=d(r,t.iterator,n.arg);if("throw"===a.type)return n.method="throw",n.arg=a.arg,n.delegate=null,h;var i=a.arg;return i?i.done?(n[t.resultName]=i.value,n.next=t.nextLoc,"return"!==n.method&&(n.method="next",n.arg=e),n.delegate=null,h):i:(n.method="throw",n.arg=new TypeError("iterator result is not an object"),n.delegate=null,h)}function C(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function B(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function I(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(C,this),this.reset(!0)}function T(t){if(t){var n=t[i];if(n)return n.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var r=-1,a=function n(){for(;++r<t.length;)if(o.call(t,r))return n.value=t[r],n.done=!1,n;return n.value=e,n.done=!0,n};return a.next=a}}return{next:O}}function O(){return{value:e,done:!0}}return y.prototype=v,r(E,"constructor",{value:v,configurable:!0}),r(v,"constructor",{value:y,configurable:!0}),y.displayName=c(v,l,"GeneratorFunction"),t.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===y||"GeneratorFunction"===(e.displayName||e.name))},t.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,v):(t.__proto__=v,c(t,l,"GeneratorFunction")),t.prototype=Object.create(E),t},t.awrap=function(t){return{__await:t}},k(L.prototype),c(L.prototype,s,(function(){return this})),t.AsyncIterator=L,t.async=function(e,n,o,r,a){void 0===a&&(a=Promise);var i=new L(u(e,n,o,r),a);return t.isGeneratorFunction(n)?i:i.next().then((function(t){return t.done?t.value:i.next()}))},k(E),c(E,l,"Generator"),c(E,i,(function(){return this})),c(E,"toString",(function(){return"[object Generator]"})),t.keys=function(t){var e=Object(t),n=[];for(var o in e)n.push(o);return n.reverse(),function t(){for(;n.length;){var o=n.pop();if(o in e)return t.value=o,t.done=!1,t}return t.done=!0,t}},t.values=T,I.prototype={constructor:I,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=e,this.done=!1,this.delegate=null,this.method="next",this.arg=e,this.tryEntries.forEach(B),!t)for(var n in this)"t"===n.charAt(0)&&o.call(this,n)&&!isNaN(+n.slice(1))&&(this[n]=e)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var n=this;function r(o,r){return s.type="throw",s.arg=t,n.next=o,r&&(n.method="next",n.arg=e),!!r}for(var a=this.tryEntries.length-1;a>=0;--a){var i=this.tryEntries[a],s=i.completion;if("root"===i.tryLoc)return r("end");if(i.tryLoc<=this.prev){var l=o.call(i,"catchLoc"),c=o.call(i,"finallyLoc");if(l&&c){if(this.prev<i.catchLoc)return r(i.catchLoc,!0);if(this.prev<i.finallyLoc)return r(i.finallyLoc)}else if(l){if(this.prev<i.catchLoc)return r(i.catchLoc,!0)}else{if(!c)throw new Error("try statement without catch or finally");if(this.prev<i.finallyLoc)return r(i.finallyLoc)}}}},abrupt:function(t,e){for(var n=this.tryEntries.length-1;n>=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,"finallyLoc")&&this.prev<r.finallyLoc){var a=r;break}}a&&("break"===t||"continue"===t)&&a.tryLoc<=e&&e<=a.finallyLoc&&(a=null);var i=a?a.completion:{};return i.type=t,i.arg=e,a?(this.method="next",this.next=a.finallyLoc,h):this.complete(i)},complete:function(t,e){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&e&&(this.next=e),h},finish:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),B(n),h}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var o=n.completion;if("throw"===o.type){var r=o.arg;B(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(t,n,o){return this.delegate={iterator:T(t),resultName:n,nextLoc:o},"next"===this.method&&(this.arg=e),h}},t}("object"===("undefined"==typeof module?"undefined":_typeof(module))?module.exports:{});try{regeneratorRuntime=runtime}catch(t){"object"===("undefined"==typeof globalThis?"undefined":_typeof(globalThis))?globalThis.regeneratorRuntime=runtime:Function("r","regeneratorRuntime = r")(runtime)}!function(){"use strict";function t(){t=function(){return e};var e={},n=Object.prototype,o=n.hasOwnProperty,r=Object.defineProperty||function(t,e,n){t[e]=n.value},a="function"==typeof Symbol?Symbol:{},i=a.iterator||"@@iterator",s=a.asyncIterator||"@@asyncIterator",l=a.toStringTag||"@@toStringTag";function c(t,e,n){return Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}),t[e]}try{c({},"")}catch(t){c=function(t,e,n){return t[e]=n}}function u(t,e,n,o){var a=e&&e.prototype instanceof f?e:f,i=Object.create(a.prototype),s=new S(o||[]);return r(i,"_invoke",{value:b(t,n,s)}),i}function d(t,e,n){try{return{type:"normal",arg:t.call(e,n)}}catch(t){return{type:"throw",arg:t}}}e.wrap=u;var p={};function f(){}function m(){}function g(){}var h={};c(h,i,(function(){return this}));var _=Object.getPrototypeOf,y=_&&_(_(A([])));y&&y!==n&&o.call(y,i)&&(h=y);var v=g.prototype=f.prototype=Object.create(h);function w(t){["next","throw","return"].forEach((function(e){c(t,e,(function(t){return this._invoke(e,t)}))}))}function x(t,e){function n(r,a,i,s){var l=d(t[r],t,a);if("throw"!==l.type){var c=l.arg,u=c.value;return u&&"object"==_typeof(u)&&o.call(u,"__await")?e.resolve(u.__await).then((function(t){n("next",t,i,s)}),(function(t){n("throw",t,i,s)})):e.resolve(u).then((function(t){c.value=t,i(c)}),(function(t){return n("throw",t,i,s)}))}s(l.arg)}var a;r(this,"_invoke",{value:function(t,o){function r(){return new e((function(e,r){n(t,o,e,r)}))}return a=a?a.then(r,r):r()}})}function b(t,e,n){var o="suspendedStart";return function(r,a){if("executing"===o)throw new Error("Generator is already running");if("completed"===o){if("throw"===r)throw a;return C()}for(n.method=r,n.arg=a;;){var i=n.delegate;if(i){var s=E(i,n);if(s){if(s===p)continue;return s}}if("next"===n.method)n.sent=n._sent=n.arg;else if("throw"===n.method){if("suspendedStart"===o)throw o="completed",n.arg;n.dispatchException(n.arg)}else"return"===n.method&&n.abrupt("return",n.arg);o="executing";var l=d(t,e,n);if("normal"===l.type){if(o=n.done?"completed":"suspendedYield",l.arg===p)continue;return{value:l.arg,done:n.done}}"throw"===l.type&&(o="completed",n.method="throw",n.arg=l.arg)}}}function E(t,e){var n=e.method,o=t.iterator[n];if(void 0===o)return e.delegate=null,"throw"===n&&t.iterator.return&&(e.method="return",e.arg=void 0,E(t,e),"throw"===e.method)||"return"!==n&&(e.method="throw",e.arg=new TypeError("The iterator does not provide a '"+n+"' method")),p;var r=d(o,t.iterator,e.arg);if("throw"===r.type)return e.method="throw",e.arg=r.arg,e.delegate=null,p;var a=r.arg;return a?a.done?(e[t.resultName]=a.value,e.next=t.nextLoc,"return"!==e.method&&(e.method="next",e.arg=void 0),e.delegate=null,p):a:(e.method="throw",e.arg=new TypeError("iterator result is not an object"),e.delegate=null,p)}function k(t){var e={tryLoc:t[0]};1 in t&&(e.catchLoc=t[1]),2 in t&&(e.finallyLoc=t[2],e.afterLoc=t[3]),this.tryEntries.push(e)}function L(t){var e=t.completion||{};e.type="normal",delete e.arg,t.completion=e}function S(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(k,this),this.reset(!0)}function A(t){if(t){var e=t[i];if(e)return e.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,r=function e(){for(;++n<t.length;)if(o.call(t,n))return e.value=t[n],e.done=!1,e;return e.value=void 0,e.done=!0,e};return r.next=r}}return{next:C}}function C(){return{value:void 0,done:!0}}return m.prototype=g,r(v,"constructor",{value:g,configurable:!0}),r(g,"constructor",{value:m,configurable:!0}),m.displayName=c(g,l,"GeneratorFunction"),e.isGeneratorFunction=function(t){var e="function"==typeof t&&t.constructor;return!!e&&(e===m||"GeneratorFunction"===(e.displayName||e.name))},e.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,g):(t.__proto__=g,c(t,l,"GeneratorFunction")),t.prototype=Object.create(v),t},e.awrap=function(t){return{__await:t}},w(x.prototype),c(x.prototype,s,(function(){return this})),e.AsyncIterator=x,e.async=function(t,n,o,r,a){void 0===a&&(a=Promise);var i=new x(u(t,n,o,r),a);return e.isGeneratorFunction(n)?i:i.next().then((function(t){return t.done?t.value:i.next()}))},w(v),c(v,l,"Generator"),c(v,i,(function(){return this})),c(v,"toString",(function(){return"[object Generator]"})),e.keys=function(t){var e=Object(t),n=[];for(var o in e)n.push(o);return n.reverse(),function t(){for(;n.length;){var o=n.pop();if(o in e)return t.value=o,t.done=!1,t}return t.done=!0,t}},e.values=A,S.prototype={constructor:S,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=void 0,this.done=!1,this.delegate=null,this.method="next",this.arg=void 0,this.tryEntries.forEach(L),!t)for(var e in this)"t"===e.charAt(0)&&o.call(this,e)&&!isNaN(+e.slice(1))&&(this[e]=void 0)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var e=this;function n(n,o){return i.type="throw",i.arg=t,e.next=n,o&&(e.method="next",e.arg=void 0),!!o}for(var r=this.tryEntries.length-1;r>=0;--r){var a=this.tryEntries[r],i=a.completion;if("root"===a.tryLoc)return n("end");if(a.tryLoc<=this.prev){var s=o.call(a,"catchLoc"),l=o.call(a,"finallyLoc");if(s&&l){if(this.prev<a.catchLoc)return n(a.catchLoc,!0);if(this.prev<a.finallyLoc)return n(a.finallyLoc)}else if(s){if(this.prev<a.catchLoc)return n(a.catchLoc,!0)}else{if(!l)throw new Error("try statement without catch or finally");if(this.prev<a.finallyLoc)return n(a.finallyLoc)}}}},abrupt:function(t,e){for(var n=this.tryEntries.length-1;n>=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,"finallyLoc")&&this.prev<r.finallyLoc){var a=r;break}}a&&("break"===t||"continue"===t)&&a.tryLoc<=e&&e<=a.finallyLoc&&(a=null);var i=a?a.completion:{};return i.type=t,i.arg=e,a?(this.method="next",this.next=a.finallyLoc,p):this.complete(i)},complete:function(t,e){if("throw"===t.type)throw t.arg;return"break"===t.type||"continue"===t.type?this.next=t.arg:"return"===t.type?(this.rval=this.arg=t.arg,this.method="return",this.next="end"):"normal"===t.type&&e&&(this.next=e),p},finish:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.finallyLoc===t)return this.complete(n.completion,n.afterLoc),L(n),p}},catch:function(t){for(var e=this.tryEntries.length-1;e>=0;--e){var n=this.tryEntries[e];if(n.tryLoc===t){var o=n.completion;if("throw"===o.type){var r=o.arg;L(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(t,e,n){return this.delegate={iterator:A(t),resultName:e,nextLoc:n},"next"===this.method&&(this.arg=void 0),p}},e}function e(t,e,n,o,r,a,i){try{var s=t[a](i),l=s.value}catch(t){return void n(t)}s.done?e(l):Promise.resolve(l).then(o,r)}function n(t){return function(){var n=this,o=arguments;return new Promise((function(r,a){var i=t.apply(n,o);function s(t){e(i,r,a,s,l,"next",t)}function l(t){e(i,r,a,s,l,"throw",t)}s(void 0)}))}}function o(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,o=new Array(e);n<e;n++)o[n]=t[n];return o}function r(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=function(t,e){if(t){if("string"==typeof t)return o(t,e);var n=Object.prototype.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?o(t,e):void 0}}(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var r=0,a=function(){};return{s:a,n:function(){return r>=t.length?{done:!0}:{done:!1,value:t[r++]}},e:function(t){throw t},f:a}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var i,s=!0,l=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return s=t.done,t},e:function(t){l=!0,i=t},f:function(){try{s||null==n.return||n.return()}finally{if(l)throw i}}}}!function(){var e="";try{var o="srgb";window.matchMedia("(color-gamut: rec2020)").matches?o="rec2020":window.matchMedia("(color-gamut: p3)").matches&&(o="display-p3"),e=CSS.supports("color: color(display-p3 1 0 0)")?o:"srgb"}catch(t){e="srgb"}var a=null,i=!1,s="",l="",c={},u=/.*?_(\d+)$/,d=!1,p="",f=!1,m=/^( {1,4}|\t)/,g="\n_O='<div class=\"color-command\">{}</div>'\n_N='swatch'\n_M='transparent'\n_L='pycon'\n_K='playground'\n_J='gamut'\n_I='exceptions'\n_H='color'\n_G='highlight'\n_F='class'\n_E='eval'\n_D='<string>'\n_C=None\n_B=True\n_A=False\nimport xml.etree.ElementTree as Etree\nfrom collections.abc import Sequence,Mapping\nfrom collections import namedtuple\nimport ast\nfrom io import StringIO\nimport sys,re\nfrom functools import partial\nfrom pygments import highlight\nfrom pygments.lexers import get_lexer_by_name\nfrom pygments.formatters import find_formatter_class\nfrom coloraide import Color\nfrom coloraide.interpolate import Interpolator,normalize_domain\ntry:from coloraide_extras.everything import ColorAll\nexcept ImportError:from coloraide.everything import ColorAll\nPY310=(3,10)<=sys.version_info\nPY311=(3,11)<=sys.version_info\nWEBSPACE='srgb'\nAST_BLOCKS=ast.If,ast.For,ast.While,ast.Try,ast.With,ast.FunctionDef,ast.ClassDef,ast.AsyncFor,ast.AsyncWith,ast.AsyncFunctionDef\nif PY310:AST_BLOCKS=AST_BLOCKS+(ast.Match,)\nif PY311:AST_BLOCKS=AST_BLOCKS+(ast.TryStar,)\nRE_INIT=re.compile('^\\\\s*#\\\\s*pragma:\\\\s*init\\\\n(.*?)#\\\\s*pragma:\\\\s*init\\\\n',re.DOTALL|re.I)\nRE_COLOR_START=re.compile('(?i)(?:\\\\b(?<![-#&$])(?:color|hsla?|lch|lab|hwb|rgba?)\\\\(|\\\\b(?<![-#&$])[\\\\w]{3,}(?![(-])\\\\b|(?<![&])#)')\nLIVE_INIT='\\nfrom coloraide import *\\nimport coloraide\\ntry:\\n    import coloraide_extras\\n    from coloraide_extras.everything import ColorAll as Color\\nexcept ImportError:\\n    from coloraide.everything import ColorAll as Color\\n'\ntemplate='<div class=\"playground\" id=\"__playground_{el_id}\">\\n<div class=\"playground-results\" id=\"__playground-results_{el_id}\">\\n{results}\\n</div>\\n<div class=\"playground-code hidden\" id=\"__playground-code_{el_id}\" data-search-exclude>\\n<form autocomplete=\"off\">\\n<textarea class=\"playground-inputs\" id=\"__playground-inputs_{el_id}\" spellcheck=\"false\">{raw_source}</textarea>\\n</form>\\n</div>\\n<div class=\"playground-footer\" data-search-exclude>\\n<hr>\\n<button id=\"__playground-edit_{el_id}\" class=\"playground-edit\" title=\"Edit the current snippet\">Edit</button>\\n<button id=\"__playground-share_{el_id}\" class=\"playground-share\" title=\"Copy URL to current snippet\">Share</button>\\n<button id=\"__playground-run_{el_id}\" class=\"playground-run hidden\" title=\"Run code (Ctrl + Enter)\">Run</button>\\n<button id=\"__playground-cancel_{el_id}\" class=\"playground-cancel hidden\" title=\"Cancel edit (Escape)\">Cancel</button>\\n<span class=\\'gamut\\'>Gamut: {gamut}</span>\\n</div>\\n</div>'\ncode_id=0\nclass Ramp(list):0\nclass Steps(list):0\nclass Row(list):0\nclass ColorTuple(namedtuple('ColorTuple',['string',_H])):0\nclass AtomicString(str):0\nclass Break(Exception):0\nclass Continue(Exception):0\nHtmlRow=Row\nHtmlSteps=Steps\nHtmlGradient=Ramp\ndef _escape(txt):txt=txt.replace('&','&amp;');txt=txt.replace('<','&lt;');txt=txt.replace('>','&gt;');return txt\nclass StreamOut:\n\tdef __init__(self):self.old=sys.stdout;self.stdout=StringIO();sys.stdout=self.stdout\n\tdef read(self):\n\t\tvalue=''\n\t\tif self.stdout is not _C:self.stdout.flush();value=self.stdout.getvalue();self.stdout=StringIO();sys.stdout=self.stdout\n\t\treturn value\n\tdef __enter__(self):return self\n\tdef __exit__(self,type,value,traceback):sys.stdout=self.old;self.old=_C;self.stdout=_C\ndef get_colors(result):\n\tdomain=[]\n\tif isinstance(result,AtomicString):yield find_colors(result)\n\tif isinstance(result,Row):yield Row([ColorTuple(c.to_string(fit=_A),c.clone())if isinstance(c,Color)else ColorTuple(c,ColorAll(c))for c in result])\n\telif isinstance(result,(Steps,Ramp)):t=type(result);yield t([c.clone()if isinstance(c,Color)else ColorAll(c)for c in result])\n\telif isinstance(result,Color):yield[ColorTuple(result.to_string(fit=_A),result.clone())]\n\telif isinstance(result,Interpolator):\n\t\tif result._domain:domain=result._domain;result.domain(normalize_domain(result._domain))\n\t\tgrad=Ramp(result.steps(steps=5,max_delta_e=2.3))\n\t\tif domain:result._domain=domain;domain=[]\n\t\tyield grad\n\telif isinstance(result,str):\n\t\ttry:yield[ColorTuple(result,ColorAll(result))]\n\t\texcept Exception:pass\n\telif isinstance(result,(list,tuple)):\n\t\tfor r in result:\n\t\t\tfor x in get_colors(r):\n\t\t\t\tif x:yield x\ndef find_colors(text):\n\tcolors=[]\n\tfor m in RE_COLOR_START.finditer(text):\n\t\tstart=m.start();mcolor=ColorAll.match(text,start=start)\n\t\tif mcolor is not _C:colors.append(ColorTuple(text[mcolor.start:mcolor.end],mcolor.color))\n\treturn colors\ndef evaluate_with(node,g,loop,index=0):\n\tl=len(node.items)-1;withitem=node.items[index]\n\tif withitem.context_expr:\n\t\twith eval(compile(ast.Expression(withitem.context_expr),_D,_E),g)as w:\n\t\t\tg[withitem.optional_vars.id]=w\n\t\t\tif index<l:evaluate_with(node,g,loop,index+1)\n\t\t\telse:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\telse:\n\t\twith eval(compile(ast.Expression(withitem.context_expr),_D,_E),g):\n\t\t\tif index<l:evaluate_with(node,g,loop,index+1)\n\t\t\telse:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\ndef compare_match(s,g,node):\n\tif isinstance(node,ast.MatchOr):\n\t\tfor pattern in node.patterns:\n\t\t\tif compare_match(s,g,pattern):return _B\n\telif isinstance(node,ast.MatchValue):p=eval(compile(ast.Expression(node.value),_D,_E),g);return s==p\n\telif isinstance(node,ast.MatchSingleton):return s is node.value\n\telif isinstance(node,ast.MatchSequence):\n\t\tif isinstance(s,Sequence):\n\t\t\tstar=isinstance(node.patterns[-1],ast.MatchStar);l1,l2=len(s),len(node.patterns)\n\t\t\tif star and l1>=l2-1 or l1==l2:\n\t\t\t\tfor (e,p) in enumerate(node.patterns[:-1]if star else node.patterns):\n\t\t\t\t\tif not compare_match(s[e],g,p):return _A\n\t\t\t\tif star and node.patterns[-1].name:g[node.patterns[-1].name]=s[l2-1:]\n\t\t\t\treturn _B\n\t\treturn _A\n\telif isinstance(node,ast.MatchMapping):\n\t\tif isinstance(s,Mapping):\n\t\t\tstar=node.rest;l1,l2=len(s),len(node.patterns)\n\t\t\tif star and l1>=l2 or l1==l2:\n\t\t\t\tkeys=set()\n\t\t\t\tfor (kp,vp) in zip(node.keys,node.patterns):\n\t\t\t\t\tkey=eval(compile(ast.Expression(kp),_D,_E),g);keys.add(key)\n\t\t\t\t\tif key not in s:return _A\n\t\t\t\t\tif not compare_match(s[key],g,vp):return _A\n\t\t\t\tif star:g[star]={k:v for(k,v)in s.items()if k not in keys}\n\t\t\t\treturn _B\n\t\treturn _A\n\telif isinstance(node,ast.MatchClass):\n\t\tname=g.get(node.cls.id,_C)\n\t\tif name is _C:raise NameError(\"name '{}' is not defined\".format(node.cls.id))\n\t\tif not isinstance(s,name):return _A\n\t\tma=getattr(s,'__match_args__',tuple());l1=len(ma);l2=len(node.patterns)\n\t\tif l1<l2:raise TypeError('{}() accepts {} positional sub-patterns ({} given)'.format(name,l1,l2))\n\t\tfor (e,p) in enumerate(node.patterns):\n\t\t\tif not hasattr(s,ma[e]):return _A\n\t\t\tif not compare_match(getattr(s,ma[e]),g,p):return _A\n\t\tfor (a,p) in zip(node.kwd_attrs,node.kwd_patterns):\n\t\t\tif not hasattr(s,a):return _A\n\t\t\tif not compare_match(getattr(s,a),g,p):return _A\n\t\treturn _B\n\telif isinstance(node,ast.MatchAs):\n\t\tif node.name is not _C:g[node.name]=s\n\t\tif node.pattern:return compare_match(s,g,node.pattern)\n\t\treturn _B\n\traise RuntimeError('Unknown Match pattern {}'.format(str(node)))\ndef evaluate_except(node,e,g,loop=_A):\n\tfor n in node.handlers:\n\t\tif n.name:g[n.name]=e\n\t\tif n.type is _C:\n\t\t\tfor ne in n.body:yield from evaluate(ne,g,loop)\n\t\t\tbreak\n\t\telif isinstance(e,eval(compile(ast.Expression(n.type),_D,_E),g)):\n\t\t\tfor ne in n.body:yield from evaluate(ne,g,loop)\n\t\t\tbreak\n\telse:raise\ndef evaluate(node,g,loop=_A):\n\tif loop and isinstance(node,ast.Break):raise Break\n\tif loop and isinstance(node,ast.Continue):raise Continue\n\tif isinstance(node,ast.Expr):_eval=ast.Expression(node.value);yield eval(compile(_eval,_D,_E),g)\n\telif isinstance(node,ast.If):\n\t\tif eval(compile(ast.Expression(node.test),_D,_E),g):\n\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\t\telif node.orelse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\telif isinstance(node,ast.While):\n\t\twhile eval(compile(ast.Expression(node.test),_D,_E),g):\n\t\t\ttry:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,_B)\n\t\t\texcept Break:break\n\t\t\texcept Continue:continue\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\telif isinstance(node,ast.For):\n\t\tfor x in eval(compile(ast.Expression(node.iter),_D,_E),g):\n\t\t\tif isinstance(node.target,ast.Tuple):\n\t\t\t\tfor (e,t) in enumerate(node.target.dims):g[t.id]=x[e]\n\t\t\telse:g[node.target.id]=x\n\t\t\ttry:\n\t\t\t\tfor n in node.body:yield from evaluate(n,g,_B)\n\t\t\texcept Break:break\n\t\t\texcept Continue:continue\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\telif isinstance(node,ast.Try):\n\t\ttry:\n\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\t\texcept Exception as e:yield from evaluate_except(node,e,g,loop)\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\t\tfinally:\n\t\t\tfor n in node.finalbody:yield from evaluate(n,g,loop)\n\telif PY311 and isinstance(node,ast.TryStar):\n\t\ttry:\n\t\t\tfor n in node.body:yield from evaluate(n,g,loop)\n\t\texcept ExceptionGroup as e:\n\t\t\tfor n in node.handlers:\n\t\t\t\tif n.name:g[n.name]=e\n\t\t\t\tm,e=e.split(eval(compile(ast.Expression(n.type),_D,_E),g))\n\t\t\t\tif m is not _C:\n\t\t\t\t\tfor ne in n.body:yield from evaluate(ne,g,loop)\n\t\t\t\tif e is _C:break\n\t\t\tif e is not _C:raise e\n\t\texcept Exception as e:yield from evaluate_except(node,e,g,loop)\n\t\telse:\n\t\t\tfor n in node.orelse:yield from evaluate(n,g,loop)\n\t\tfinally:\n\t\t\tfor n in node.finalbody:yield from evaluate(n,g,loop)\n\telif PY310 and isinstance(node,ast.Match):\n\t\ts=eval(compile(ast.Expression(node.subject),_D,_E),g)\n\t\tfor c in node.cases:\n\t\t\tif compare_match(s,g,c.pattern):\n\t\t\t\tif not c.guard or eval(compile(ast.Expression(c.guard),_D,_E),g):\n\t\t\t\t\tfor n in c.body:yield from evaluate(n,g,loop)\n\t\t\t\t\tbreak\n\telif isinstance(node,ast.With):yield from evaluate_with(node,g,loop)\n\telse:_exec=ast.Module([node],[]);exec(compile(_exec,_D,'exec'),g);yield _C\ndef execute(cmd,no_except=_B,inline=_A,init='',g=_C):\n\tA='\\n';console='';colors=[]\n\tif g is _C:g={'Ramp':Ramp,'Steps':Steps,'Row':Row,'HtmlRow':HtmlRow,'HtmlSteps':HtmlSteps,'HtmlGradient':HtmlGradient}\n\tif init:execute(init.strip(),g=g)\n\tm=RE_INIT.match(cmd)\n\tif m:block_init=m.group(1);src=cmd[m.end():];execute(block_init,g=g)\n\telse:src=cmd\n\tlines=src.split(A)\n\ttry:tree=ast.parse(src)\n\texcept Exception as e:\n\t\tif no_except:\n\t\t\tif not inline:from pymdownx.superfences import SuperFencesException;raise SuperFencesException from e\n\t\t\telse:from pymdownx.inlinehilite import InlineHiliteException;raise InlineHiliteException from e\n\t\timport traceback;return '{}'.format(traceback.format_exc()),colors\n\tfor node in tree.body:\n\t\tresult=[];start=node.lineno;end=node.end_lineno;stmt=lines[start-1:end];command=''\n\t\tfor (i,line) in enumerate(stmt,0):\n\t\t\tif i==0:stmt[i]='>>> '+line\n\t\t\telse:stmt[i]='... '+line\n\t\tcommand+=A.join(stmt)\n\t\tif isinstance(node,AST_BLOCKS):command+='\\n... '\n\t\ttry:\n\t\t\twith StreamOut()as s:\n\t\t\t\tfor x in evaluate(node,g):\n\t\t\t\t\tresult.append(x);text=s.read()\n\t\t\t\t\tif text:result.append(AtomicString(text))\n\t\t\t\tconsole+=command\n\t\texcept Exception as e:\n\t\t\tif no_except:\n\t\t\t\tif not inline:from pymdownx.superfences import SuperFencesException;raise SuperFencesException from e\n\t\t\t\telse:from pymdownx.inlinehilite import InlineHiliteException;raise InlineHiliteException from e\n\t\t\timport traceback;console+='{}\\n{}'.format(command,traceback.format_exc());break\n\t\tresult_text=A\n\t\tfor r in result:\n\t\t\tif r is _C:continue\n\t\t\tfor clist in get_colors(r):\n\t\t\t\tif clist:colors.append(clist)\n\t\t\tresult_text+='{}{}'.format(repr(r)if isinstance(r,str)and not isinstance(r,AtomicString)else str(r),A if not isinstance(r,AtomicString)else'')\n\t\tconsole+=result_text\n\treturn console,colors\ndef colorize(src,lang,**options):HtmlFormatter=find_formatter_class('html');lexer=get_lexer_by_name(lang,**options);formatter=HtmlFormatter(cssclass=_G,wrapcode=_B);return highlight(src,lexer,formatter).strip()\ndef color_command_validator(language,inputs,options,attrs,md):\n\tvalid_inputs=set([_I,'play'])\n\tfor (k,v) in inputs.items():\n\t\tif k in valid_inputs:options[k]=_B;continue\n\t\tattrs[k]=v\n\treturn _B\ndef _color_command_console(colors,gamut=WEBSPACE):\n\tC='{} {}%';B=' ';A='<div class=\"swatch-bar\">{}</div>';el='';bar=_A;values=[]\n\tfor item in colors:\n\t\tis_grad=isinstance(item,HtmlGradient);is_steps=isinstance(item,Steps)\n\t\tif is_grad or is_steps:\n\t\t\tcurrent=total=percent=last=0\n\t\t\tif isinstance(item,Steps):total=len(item);percent=100/total;current=percent\n\t\t\tif bar:el+=A.format(B.join(values));values=[]\n\t\t\tsub_el1='<div class=\"swatch-bar\"><span class=\"swatch swatch-gradient\">{}</span></div>';style='--swatch-stops: ';stops=[]\n\t\t\tfor (e,color) in enumerate(item):\n\t\t\t\tcolor.fit(gamut);color_str=color.convert(gamut).to_string()\n\t\t\t\tif current:\n\t\t\t\t\tif is_steps:stops.append(C.format(color_str,str(last)));stops.append(C.format(color_str,str(current)))\n\t\t\t\t\telse:stops.append(color_str)\n\t\t\t\t\tlast=current\n\t\t\t\t\tif e<total-1:current+=percent\n\t\t\t\t\telse:current=100\n\t\t\t\telse:stops.append(color_str)\n\t\t\tif not stops:stops.extend([_M]*2)\n\t\t\tif len(stops)==1:stops.append(stops[0])\n\t\t\tstyle+=','.join(stops);sub_el2='<span class=\"swatch-color\" style=\"{}\"></span>'.format(style);el+=sub_el1.format(sub_el2);bar=_A\n\t\telse:\n\t\t\tis_row=_A\n\t\t\tif isinstance(item,Row):\n\t\t\t\tis_row=_B\n\t\t\t\tif bar and values:el+=A.format(B.join(values));values=[]\n\t\t\t\tbar=_A\n\t\t\tbar=_B\n\t\t\tfor color in item:\n\t\t\t\tbase_classes=_N\n\t\t\t\tif not color.color.in_gamut(gamut):base_classes+=' out-of-gamut'\n\t\t\t\tcolor.color.fit(gamut);srgb=color.color.convert(gamut);value1=srgb.to_string(alpha=_A);value2=srgb.to_string();style='--swatch-stops: {} 50%, {} 50%'.format(value1,value2);title=color.string;classes=base_classes;c='<span class=\"swatch-color\" style=\"{style}\"></span>'.format(style=style);c='<span class=\"{classes}\" title=\"{title}&#013;Copy to clipboard\">{color}</span>'.format(classes=classes,color=c,title=title);values.append(c)\n\t\t\tif is_row and values:el+=A.format(B.join(values));values=[];bar=_A\n\tif bar:el+=A.format(B.join(values));values=[]\n\treturn el\ndef _color_command_formatter(src='',language='',class_name=_C,options=_C,md='',init='',**kwargs):\n\tB='formatter';A='fenced_code_block';global code_id;from pymdownx.superfences import SuperFencesException;gamut=kwargs.get(_J,WEBSPACE);play=options.get('play',_A)if options is not _C else _A\n\tif not play and language==_K:play=_B\n\tif not play:return md.preprocessors[A].extension.superfences[0][B](src=src,class_name=class_name,language='py',md=md,options=options,**kwargs)\n\ttry:\n\t\tif len(md.preprocessors[A].extension.stash)==0:code_id=0\n\t\texceptions=options.get(_I,_A)if options is not _C else _A;console,colors=execute(src.strip(),not exceptions,init=init);el=_color_command_console(colors,gamut=gamut);el+=md.preprocessors[A].extension.superfences[0][B](src=console,class_name=_G,language=_L,md=md,options=options,**kwargs);el=_O.format(el);el=template.format(el_id=code_id,raw_source=_escape(src),results=el,gamut=gamut);code_id+=1\n\texcept SuperFencesException:raise\n\texcept Exception:from pymdownx import superfences;import traceback;print(traceback.format_exc());return superfences.fence_code_format(src,'text',class_name,options,md,**kwargs)\n\treturn el\ndef color_command_formatter(init='',gamut=WEBSPACE):return partial(_color_command_formatter,init=init,gamut=gamut)\ndef _color_formatter(src='',language='',class_name=_C,md='',exceptions=_B,init='',gamut=WEBSPACE):\n\tE='backtick';D='title';C='Only one color allowed';B=' 50%';A='span';from pymdownx.inlinehilite import InlineHiliteException\n\ttry:\n\t\tresult=src.strip()\n\t\ttry:color=ColorAll(result.strip())\n\t\texcept Exception:\n\t\t\t_,colors=execute(result,exceptions,inline=_B,init=init)\n\t\t\tif len(colors)!=1 or len(colors[0])!=1:\n\t\t\t\tif exceptions:raise InlineHiliteException(C)\n\t\t\t\telse:raise ValueError(C)\n\t\t\tcolor=colors[0][0].color;result=colors[0][0].string\n\t\tel=Etree.Element(A);stops=[]\n\t\tif not color.in_gamut(gamut):\n\t\t\tcolor.fit(gamut);attributes={_F:'swatch out-of-gamut',D:result};sub_el=Etree.SubElement(el,A,attributes);stops.append(color.convert(gamut).to_string(hex=_B,alpha=_A))\n\t\t\tif color[-1]<1.0:stops[-1]+=B;stops.append(color.convert(gamut).to_string(hex=_B)+B)\n\t\telse:\n\t\t\tattributes={_F:_N,D:result};sub_el=Etree.SubElement(el,A,attributes);stops.append(color.convert(gamut).to_string(hex=_B,alpha=_A))\n\t\t\tif color[-1]<1.0:stops[-1]+=B;stops.append(color.convert(gamut).to_string(hex=_B)+B)\n\t\tif not stops:stops.extend([_M]*2)\n\t\tif len(stops)==1:stops.append(stops[0])\n\t\tEtree.SubElement(sub_el,A,{_F:'swatch-color','style':'--swatch-stops: {};'.format(','.join(stops))});el.append(md.inlinePatterns[E].handle_code('css-color',result))\n\texcept InlineHiliteException:raise\n\texcept Exception:import traceback;print(traceback.format_exc());el=md.inlinePatterns[E].handle_code('text',src)\n\treturn el\ndef color_formatter(init='',gamut=WEBSPACE):return partial(_color_formatter,init=init,gamut=gamut)\ndef _live_color_command_formatter(src,init='',gamut=WEBSPACE):\n\ttry:\n\t\tconsole,colors=execute(src.strip(),_A,init=init);el=_color_command_console(colors,gamut=gamut)\n\t\tif not colors:el+='<div class=\"swatch-bar\"></div>'\n\t\tel+=colorize(console,_L,**{'python3':_B,'stripnl':_A});el=_O.format(el)\n\texcept Exception:import traceback;return '<div class=\"color-command\"><div class=\"swatch-bar\"></div>{}</div>'.format(colorize(traceback.format_exc(),_L))\n\treturn el\ndef live_color_command_formatter(init='',gamut=WEBSPACE):return partial(_live_color_command_formatter,init=init,gamut=gamut)\ndef live_color_command_validator(language,inputs,options,attrs,md):value=color_command_validator(language,inputs,options,attrs,md);options[_I]=_B;return value\ndef render_console(*args,**kwargs):\n\tC='.swatch-bar';B='code';A='id_num';from js import document;gamut=kwargs.get(_J,WEBSPACE)\n\ttry:\n\t\tinputs=document.getElementById('__playground-inputs_{}'.format(globals()[A]));results=document.getElementById('__playground-results_{}'.format(globals()[A]));footer=document.querySelector('#__playground_{} .gamut'.format(globals()[A]));result=live_color_command_formatter(LIVE_INIT,gamut)(inputs.value);temp=document.createElement('div');temp.innerHTML=result;cmd=results.querySelector('.color-command')\n\t\tfor el in cmd.querySelectorAll(C):el.remove()\n\t\tfor el in temp.querySelectorAll(C):cmd.insertBefore(el,cmd.lastChild)\n\t\tfooter.innerHTML='Gamut: {}'.format(gamut);pre=cmd.querySelector('pre');pre.replaceChild(temp.querySelector(B),pre.querySelector(B));temp.remove();scrollingElement=results.querySelector(B);scrollingElement.scrollTop=scrollingElement.scrollHeight\n\texcept Exception as e:print(e)\ndef render_notebook(*args,**kwargs):\n\tM='diagram';L='pymdownx.blocks.tab';K='pymdownx.blocks.admonition';J='pymdownx.arithmatex';I='pymdownx.keys';H='pymdownx.magiclink';G='pymdownx.inlinehilite';F='pymdownx.superfences';E='markdown.extensions.smarty';D='markdown.extensions.toc';C='validator';B='format';A='name';import markdown;from pymdownx import slugs,superfences;from js import document;gamut=kwargs.get(_J,WEBSPACE);text=globals().get('content','');extensions=[D,E,'pymdownx.betterem','markdown.extensions.attr_list','markdown.extensions.tables','markdown.extensions.abbr','markdown.extensions.footnotes',F,'pymdownx.highlight',G,H,'pymdownx.tilde','pymdownx.caret','pymdownx.smartsymbols','pymdownx.emoji','pymdownx.escapeall','pymdownx.tasklist','pymdownx.striphtml','pymdownx.snippets',I,'pymdownx.saneheaders',J,K,'pymdownx.blocks.details','pymdownx.blocks.html','pymdownx.blocks.definition',L];extension_configs={D:{'slugify':slugs.slugify(case='lower'),'permalink':''},E:{'smart_quotes':_A},J:{'generic':_B,'block_tag':'pre'},F:{'preserve_tabs':_B,'custom_fences':[{A:M,_F:M,B:superfences.fence_code_format},{A:_K,_F:_K,B:color_command_formatter(LIVE_INIT,gamut),C:live_color_command_validator},{A:'python',_F:_G,B:color_command_formatter(LIVE_INIT,gamut),C:live_color_command_validator},{A:'py',_F:_G,B:color_command_formatter(LIVE_INIT,gamut),C:live_color_command_validator}]},G:{'custom_inline':[{A:_H,_F:_H,B:color_formatter(LIVE_INIT,gamut)}]},H:{'repo_url_shortener':_B,'repo_url_shorthand':_B,'social_url_shorthand':_B,'user':'facelessuser','repo':'coloraide'},I:{'separator':'＋'},L:{'alternate_style':_B},K:{'types':['new','settings','note','abstract','info','tip','success','question','warning','failure','danger','bug','example','quote']}}\n\ttry:html=markdown.markdown(text,extensions=extensions,extension_configs=extension_configs)\n\texcept Exception:html=''\n\tcontent=document.getElementById('__notebook-render');content.innerHTML=html\n\naction = globals().get('action')\nif action == 'notebook':\n    callback = render_notebook\nelse:\n    callback = render_console\n\ncallback(gamut='".concat(e,"')\n"),h=window.colorNotebook.defaultPlayground,_=function(t){return"\n/// new | This notebook is powered by [Pyodide](https://github.com/pyodide/pyodide). Learn more [here](?notebook=https://gist.githubusercontent.com/facelessuser/7c819668b5eb248ecb9ac608d91391cf/raw/playground.md). Preview, convert, interpolate, and explore!\n///\n\n````````py play\n".concat(t,"\n````````\n")},y=!1,v=!1,w=function(){f=!0,window.document.dispatchEvent(new Event("DOMContentLoaded",{bubbles:!0,cancelable:!0})),window.document$.next()},x=function(t){var e=window.pageXOffset||(document.documentElement||document.body.parentNode||document.body).scrollLeft,n=window.pageYOffset||(document.documentElement||document.body.parentNode||document.body).scrollTop;t.style.height="5px",t.style.height="".concat(t.scrollHeight,"px"),window.scrollTo(e,n)},b=function(t){return encodeURIComponent(t).replace(/[.!'()*]/g,(function(t){return"%".concat(t.charCodeAt(0).toString(16))}))},E=function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return(o=document.getElementById("__playground-inputs_".concat(n))).setAttribute("readonly",""),a.globals.set("id_num",n),a.globals.set("action","playground"),t.next=6,a.runPythonAsync(g);case 6:o.removeAttribute("readonly");case 7:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),k=function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return a.globals.set("content",n),a.globals.set("action","notebook"),t.next=4,a.runPythonAsync(g);case 4:(o=document.getElementById("__notebook-input"))&&(s=n,o.value=n),window.location.hash&&(window.location.href=window.location.href);case 7:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),L=function(){var e=n(t().mark((function e(n){var o,i,s,l,c,u;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(d){t.next=5;break}return d=!0,t.next=4,loadPyodide({indexURL:"https://cdn.jsdelivr.net/pyodide/v0.23.4/full/",fullStdLib:!1});case 4:a=t.sent;case 5:if((y||!n)&&(v||n)){t.next=14;break}o="".concat(window.location.origin,"/").concat(window.location.pathname.split("/")[1],"/playground/"),i=n?window.colorNotebook.notebookWheels:window.colorNotebook.playgroundWheels,s=[],n?y=!0:v=!0,l=r(i);try{for(l.s();!(c=l.n()).done;)(u=c.value).endsWith(".whl")?s.push(o+u):s.push(u)}catch(t){l.e(t)}finally{l.f()}return t.next=14,a.loadPackage(s);case 14:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),S=function(t,e,n){var o=null==e?"Loading...":e,r=n?"loading relative":"loading",a=document.createElement("template");a.innerHTML='<div class="'.concat(r,'"><div class="loader"></div><div>').concat(o,"</div></div>"),t.appendChild(a.content.firstChild)},A=function(t){t.querySelector(".loading")&&t.removeChild(t.querySelector(".loading"))},C=function(t){if("Tab"===t.key){var e=t.target;if(e.selectionStart!==e.selectionEnd){t.preventDefault();for(var n=e.selectionStart,o=e.selectionEnd,r=e.value;n>0&&"\n"!==r[n-1];)n--;for(;o>0&&"\n"!==r[o-1]&&o<r.length;)o++;for(var a=r.substr(n,o-n).split("\n"),i=0;i<a.length;i++)i===a.length-1&&0===a[i].length||(t.shiftKey?a[i]=a[i].replace(m,""):a[i]="    ".concat(a[i]));a=a.join("\n"),e.value=r.substr(0,n)+a+r.substr(o),e.selectionStart=n,e.selectionEnd=n+a.length}}},B=function(){var e=n(t().mark((function e(o){var r;return t().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:r=document.getElementById("__notebook-source"),document.querySelectorAll(".playground").forEach((function(e){var a=e.id.replace(u,"$1"),d=document.getElementById("__playground-inputs_".concat(a)),p=document.getElementById("__playground-results_".concat(a)),f=document.getElementById("__playground-code_".concat(a)),m=document.querySelector("button#__playground-edit_".concat(a)),g=document.querySelector("button#__playground-share_".concat(a)),h=document.querySelector("button#__playground-run_".concat(a)),_=document.querySelector("button#__playground-cancel_".concat(a));if(d.addEventListener("input",(function(){x(d)})),d.addEventListener("keydown",C),r&&o){var y=document.getElementById("__notebook-input");y.addEventListener("input",(function(t){x(t.target)})),y.addEventListener("keydown",C),document.getElementById("__notebook-edit").addEventListener("click",(function(){c[y.id]=y.value,document.getElementById("__notebook-render").classList.toggle("hidden"),document.getElementById("__notebook-source").classList.toggle("hidden"),x(document.getElementById("__notebook-input"))})),document.getElementById("__notebook-md-gist").addEventListener("click",function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:null!==(o=prompt("Please enter link to the Markdown page source:",l))&&(o=b(o),n.preventDefault(),history.pushState({notebook:o},"","?".concat(new URLSearchParams("notebook=".concat(o)).toString())),I(!1));case 2:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}()),document.getElementById("__notebook-py-gist").addEventListener("click",function(){var e=n(t().mark((function e(n){var o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:null!==(o=prompt("Please enter the link to the Python code source:",l))&&(o=b(o),n.preventDefault(),history.pushState({source:o},"","?".concat(new URLSearchParams("source=".concat(o)).toString())),I(!1));case 2:case"end":return t.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}()),document.getElementById("__notebook-input").value=s,document.getElementById("__notebook-cancel").addEventListener("click",(function(){y.value=c[y.id],delete c[y.id],document.getElementById("__notebook-render").classList.toggle("hidden"),document.getElementById("__notebook-source").classList.toggle("hidden")})),document.getElementById("__notebook-submit").addEventListener("click",n(t().mark((function e(){var n,o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return n=document.getElementById("__notebook-render"),s=document.getElementById("__notebook-input").value,n.classList.toggle("hidden"),document.getElementById("__notebook-source").classList.toggle("hidden"),o=document.querySelector("article"),S(o,"Loading Notebook..."),n.innerHTML="",c={},t.next=10,L(!0);case 10:return t.next=12,k(s);case 12:return t.next=14,B();case 14:A(o),w();case 16:case"end":return t.stop()}}),e)}))))}d.addEventListener("touchmove",(function(t){t.stopPropagation()})),p.addEventListener("click",(function(t){var e=t.target;if(e.matches("span.swatch-color")){var n="",o=e.parentNode;if(!o.matches("span.swatch-gradient")){if(n=(n=o.getAttribute("title").replace("Copy to clipboard","")).replace("\n",""),window.clipboardData&&window.clipboardData.setData)return window.clipboardData.setData("Text",n);if(document.queryCommandSupported&&document.queryCommandSupported("copy")){var r=document.createElement("textarea");r.textContent=n,r.style.position="fixed",document.body.appendChild(r),r.select();try{return document.execCommand("copy")}catch(t){return prompt("Copy to clipboard: Ctrl+C, Enter",n)}finally{document.body.removeChild(r)}}}}})),m.addEventListener("click",n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:c[a]=d.value,f.classList.toggle("hidden"),p.classList.toggle("hidden"),h.classList.toggle("hidden"),_.classList.toggle("hidden"),m.classList.toggle("hidden"),g.classList.toggle("hidden"),x(d),d.focus();case 9:case"end":return t.stop()}}),e)})))),g.addEventListener("click",n(t().mark((function e(){var o,r,a,i,s;return t().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:o=window.location.pathname.split("/")[1],r=b(d.value),a=window.location,i="/playground/",a.pathname.startsWith("/".concat(o,"/"))&&(i="/".concat(o,"/playground/")),(s="".concat(a.protocol,"//").concat(a.host).concat(i,"?code=").concat(r)).length>2e3?alert("Code must be small enough to generate a shareable URL under 2000 characters!"):navigator.clipboard.writeText(s).then(n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:alert("Link copied to clipboard :)");case 1:case"end":return t.stop()}}),e)}))),n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:alert("Failed to copy link clipboard!");case 1:case"end":return t.stop()}}),e)}))));case 7:case"end":return e.stop()}}),e)})))),h.addEventListener("click",n(t().mark((function e(){var n,o;return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:if(!i){t.next=2;break}return t.abrupt("return");case 2:return i=!0,n=f.querySelector("form"),S(n,null,!0),(o=document.querySelectorAll(".playground .playground-run"))&&o.forEach((function(t){t.setAttribute("disabled","")})),t.next=9,L(!1);case 9:return p.querySelector("code").innerHTML="",t.next=12,E(a);case 12:o&&o.forEach((function(t){t.removeAttribute("disabled")})),A(n),f.classList.toggle("hidden"),p.classList.toggle("hidden"),m.classList.toggle("hidden"),g.classList.toggle("hidden"),h.classList.toggle("hidden"),_.classList.toggle("hidden"),delete c[a],i=!1;case 22:case"end":return t.stop()}}),e)})))),_.addEventListener("click",(function(){d.value=c[a],delete c[a],f.classList.toggle("hidden"),p.classList.toggle("hidden"),m.classList.toggle("hidden"),g.classList.toggle("hidden"),h.classList.toggle("hidden"),_.classList.toggle("hidden")}))}));case 3:case"end":return e.stop()}}),e)})));return function(t){return e.apply(this,arguments)}}(),I=function(){var e=n(t().mark((function e(o,r){var a,i,s,u,d,f,m,g,y;return t().wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(c={},!window.location.pathname.endsWith("/playground/")){e.next=32;break}if(a=r||new URLSearchParams(window.location.search),i="Loading Pyodide...",s="Loading Notebook...",u=a.has("source")?a.get("source"):a.get("notebook"),d=document.querySelector("article"),null===u||!u.trim()){e.next=16;break}return S(d,i),e.next=11,L(!0);case 11:A(d),S(d,s);try{f=a.has("source")?"source":"notebook",p=decodeURIComponent(a.toString()),m="",g=new XMLHttpRequest,l=u,g.open("GET",u,!0),g.onload=n(t().mark((function e(){return t().wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return 4===g.readyState&&200===g.status&&(m=g.responseText),"source"===f&&(m=_(m)),t.next=4,k(m);case 4:return t.next=6,B(o);case 6:A(d),w();case 8:case"end":return t.stop()}}),e)}))),g.send()}catch(t){}e.next=30;break;case 16:return l="",y=_(a.has("code")?a.get("code"):h),p=decodeURIComponent(a.toString()),S(d,i),e.next=22,L(!0);case 22:return A(d),S(d,s),e.next=26,k(y);case 26:return e.next=28,B(o);case 28:A(d),w();case 30:e.next=35;break;case 32:l="",p="",B(o);case 35:case"end":return e.stop()}}),e)})));return function(t,n){return e.apply(this,arguments)}}();document.addEventListener("click",(function(t){var e=window.location.pathname.split("/")[1],n=t.target||t.srcElement;if("A"===n.tagName&&I&&n.getAttribute("href")&&n.host===window.location.host&&window.location.pathname==="/".concat(e,"/playground/")&&window.location.pathname===n.pathname&&window.location.search!==n.search){t.preventDefault();var o=new URLSearchParams(n.search);I(!1,o)}}),!0),window.addEventListener("popstate",(function(){var t=window.location.pathname.split("/")[1];window.location.pathname==="/".concat(t,"/playground/")&&(decodeURIComponent(new URLSearchParams(window.location.search).toString())!==p&&I(!1))})),window.addEventListener("unload",(function(){f=!1})),window.document$.subscribe((function(){f?f=!1:I(!0)}))}()}();
-//# sourceMappingURL=extra-notebook-f321e406.js.map
diff --git a/docs/theme/playground-config-65c43228.js b/docs/theme/playground-config-e3b414b9.js
similarity index 77%
rename from docs/theme/playground-config-65c43228.js
rename to docs/theme/playground-config-e3b414b9.js
index 0930d7d9b..0909708e6 100644
--- a/docs/theme/playground-config-65c43228.js
+++ b/docs/theme/playground-config-e3b414b9.js
@@ -1,5 +1,5 @@
 var colorNotebook = {
-    "playgroundWheels": ['Pygments-2.12.0-py3-none-any.whl', 'coloraide-2.6-py3-none-any.whl'],
-    "notebookWheels": ['pyyaml', 'Markdown-3.3.4-py3-none-any.whl', 'pymdown_extensions-9.10-py3-none-any.whl', 'Pygments-2.12.0-py3-none-any.whl', 'coloraide-2.6-py3-none-any.whl'],
+    "playgroundWheels": ['Pygments-2.12.0-py3-none-any.whl', 'coloraide-2.7-py3-none-any.whl'],
+    "notebookWheels": ['pyyaml', 'Markdown-3.3.4-py3-none-any.whl', 'pymdown_extensions-9.10-py3-none-any.whl', 'Pygments-2.12.0-py3-none-any.whl', 'coloraide-2.7-py3-none-any.whl'],
     "defaultPlayground": "import coloraide\ncoloraide.__version__\nColor('red')"
 }
diff --git a/mkdocs.yml b/mkdocs.yml
index c8bf1f93c..533833955 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -122,6 +122,7 @@ nav:
       - Miscellaneous Spaces:
         - xyY: colors/xyy.md
         - CIE 1960 UCS: colors/ucs.md
+        - RYB: colors/ryb.md
         - CMY: colors/cmy.md
         - CMYK: colors/cmyk.md
         - oRGB: colors/orgb.md
@@ -271,12 +272,12 @@ markdown_extensions:
       alternate_style: True
 
 extra_css:
-  - assets/coloraide-extras/extra-391b1ef8ad.css
+  - assets/coloraide-extras/extra-8411e71fd9.css
 extra_javascript:
   - https://unpkg.com/mermaid@8.13.3/dist/mermaid.min.js
-  - playground-config-65c43228.js
+  - playground-config-e3b414b9.js
   - https://cdn.jsdelivr.net/pyodide/v0.23.4/full/pyodide.js
-  - assets/coloraide-extras/extra-notebook-f321e406.js
+  - assets/coloraide-extras/extra-notebook-ba27d60b.js
 
 extra:
   social:
diff --git a/tools/gen_3d_models.py b/tools/gen_3d_models.py
index 761b9746f..59def2dce 100644
--- a/tools/gen_3d_models.py
+++ b/tools/gen_3d_models.py
@@ -70,6 +70,8 @@ def plot_model(name, title, filename, gamut='srgb', elev=45, azim=-60.0):
     'orgb': {'title': TEMPLATE.format('oRGB'), 'filename': 'orgb-3d.png', 'elev': 72},
     'xyb': {'title': TEMPLATE.format('XYB'), 'filename': 'xyb-3d.png', 'azim': 45},
     'ucs': {'title': TEMPLATE.format('UCS'), 'filename': 'ucs-3d.png', 'azim': 60, 'elev': 10},
+    'ryb': {'title': 'RYB Color Space', 'filename': 'ryb-3d.png', 'gamut': 'ryb'},
+    'ryb-biased': {'title': 'RYB Color Space (Biased)', 'filename': 'ryb-biased-3d.png', 'gamut': 'ryb-biased'}
 }
 
 


Test patch:
diff --git a/tests/test_algebra.py b/tests/test_algebra.py
index d6a33744b..5ce683fe9 100644
--- a/tests/test_algebra.py
+++ b/tests/test_algebra.py
@@ -1644,3 +1644,40 @@ def test_linspace(self):
 
         with self.assertRaises(ValueError):
             alg.linspace([0, 0], [1, 1, 1], 3)
+
+    def test_ilerp(self):
+        """Test inverse interpolation."""
+
+        t = 0.5
+        v = alg.lerp(0.2, 1.8, t)
+        self.assertEqual(round(alg.ilerp(0.2, 1.8, v), 5), t)
+
+    def test_lerp2d(self):
+        """Test 2D interpolation."""
+
+        m = [[0.1, 0.0], [1.0, 0.0], [0.0, .95], [1, 1]]
+        v = alg.lerp2d(alg.transpose(m), [0.5, 0.5])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [0.525, 0.4875])]
+        v = alg.lerp2d(alg.transpose(m), [0.0, 0.0])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [0.1, 0.0])]
+        v = alg.lerp2d(alg.transpose(m), [1.0, 0.0])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [1.0, 0.0])]
+        v = alg.lerp2d(alg.transpose(m), [0.0, 1.0])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [0.0, .95])]
+        v = alg.lerp2d(alg.transpose(m), [1.0, 1.0])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [1, 1])]
+
+    def test_ilerp2d(self):
+        """Test inverse 2D interpolation."""
+
+        m = [[0.1, 0.0], [1.0, 0.0], [0.0, .95], [1, 1]]
+        v = alg.ilerp2d(alg.transpose(m), [0.525, 0.4875])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [0.5, 0.5])]
+        v = alg.ilerp2d(alg.transpose(m), [0.1, 0.0])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [0.0, 0.0])]
+        v = alg.ilerp2d(alg.transpose(m), [1.0, 0.0])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [1.0, 0.0])]
+        v = alg.ilerp2d(alg.transpose(m), [0.0, .95])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [0.0, 1.0])]
+        v = alg.ilerp2d(alg.transpose(m), [1, 1])
+        [self.assertAlmostEqual(a, b) for a, b in zip(v, [1.0, 1.0])]
diff --git a/tests/test_roundtrip.py b/tests/test_roundtrip.py
index d6ffb5189..00a85460a 100644
--- a/tests/test_roundtrip.py
+++ b/tests/test_roundtrip.py
@@ -19,6 +19,8 @@ class Color(Base):
         """Local color object."""
 
     Color.deregister('space:hpluv')
+    Color.deregister('space:ryb')
+    Color.deregister('space:ryb-biased')
 
     SPACES = {k: 5 for k in Color.CS_MAP.keys()}
     # Not as accurate due to bisect back to CAM16
@@ -88,6 +90,8 @@ class Color(Base):
         """Local color object."""
 
     Color.deregister('space:hpluv')
+    Color.deregister('space:ryb')
+    Color.deregister('space:ryb-biased')
 
     SPACES = {k: 5 for k in Color.CS_MAP.keys()}
     # Precision just isn't as high for these in achromatic region
@@ -107,3 +111,79 @@ def test_round_trip(self, space):
 
         for c in self.COLORS:
             self.assert_round_trip(c, space)
+
+
+class TestRYBRoundTrip(TestRoundTrip):
+    """
+    Test RYB round trip.
+
+    We are only interested in testing this against sRGB.
+    """
+
+    class Color(Base):
+        """Local color object."""
+
+    SPACES = {'srgb': 5}
+
+    COLORS = [
+        Color('ryb', [1, 1, 1]),
+        Color('ryb', [1, 0, 0]),
+        Color('ryb', [1, 0, 0]),
+        Color('ryb', [0, 1, 0]),
+        Color('ryb', [0, 0, 1]),
+        Color('ryb', [1, 1, 0]),
+        Color('ryb', [0, 1, 1]),
+        Color('ryb', [1, 0, 1]),
+        Color('ryb', [0, 0, 0]),
+        Color('ryb', [0.2, 5, 0.7]),
+        Color('ryb', [0.8, 0.65, 0.21]),
+        Color('ryb', [0.8, 0.65, 0.21]),
+        Color('ryb', [0.8, 0.65, 0.21]),
+        Color('ryb', [0.9, 0.8, 0.21]),
+        Color('ryb', [0.1, 0.3, 0.05])
+    ]
+
+    @pytest.mark.parametrize('space', SPACES)
+    def test_round_trip(self, space):
+        """Test round trip."""
+
+        for c in self.COLORS:
+            self.assert_round_trip(c, space)
+
+
+class TestRYBBiasedRoundTrip(TestRoundTrip):
+    """
+    Test RYB round trip.
+
+    We are only interested in testing this against sRGB.
+    """
+
+    class Color(Base):
+        """Local color object."""
+
+    SPACES = {'srgb': 5}
+
+    COLORS = [
+        Color('ryb-biased', [1, 1, 1]),
+        Color('ryb-biased', [1, 0, 0]),
+        Color('ryb-biased', [1, 0, 0]),
+        Color('ryb-biased', [0, 1, 0]),
+        Color('ryb-biased', [0, 0, 1]),
+        Color('ryb-biased', [1, 1, 0]),
+        Color('ryb-biased', [0, 1, 1]),
+        Color('ryb-biased', [1, 0, 1]),
+        Color('ryb-biased', [0, 0, 0]),
+        Color('ryb-biased', [0.2, 5, 0.7]),
+        Color('ryb-biased', [0.8, 0.65, 0.21]),
+        Color('ryb-biased', [0.8, 0.65, 0.21]),
+        Color('ryb-biased', [0.8, 0.65, 0.21]),
+        Color('ryb-biased', [0.9, 0.8, 0.21]),
+        Color('ryb-biased', [0.1, 0.3, 0.05])
+    ]
+
+    @pytest.mark.parametrize('space', SPACES)
+    def test_round_trip(self, space):
+        """Test round trip."""
+
+        for c in self.COLORS:
+            self.assert_round_trip(c, space)
diff --git a/tests/test_ryb.py b/tests/test_ryb.py
new file mode 100644
index 000000000..b6d08fe0a
--- /dev/null
+++ b/tests/test_ryb.py
@@ -0,0 +1,128 @@
+"""Test RYB."""
+import unittest
+from . import util
+from coloraide.everything import ColorAll as Color, NaN
+import pytest
+
+
+class TestRYB(util.ColorAssertsPyTest):
+    """Test RYB."""
+
+    COLORS = [
+        ('color(srgb 1.0 1.0 1.0)', 'color(--ryb 0 0 0)'),
+        ('color(srgb 1.0 0.0 0.0)', 'color(--ryb 1 0 0)'),
+        ('color(srgb 1.0 1.0 0.0)', 'color(--ryb 0 1 0)'),
+        ('color(srgb 1.0 0.5 0.0)', 'color(--ryb 1 1 0)'),
+        ('color(srgb 0.163 0.373 0.6)', 'color(--ryb 0 0 1)'),
+        ('color(srgb 0.5 0.0 0.5)', 'color(--ryb 1 0 1)'),
+        ('color(srgb 0.0 0.66 0.2)', 'color(--ryb 0 1 1)'),
+        ('color(srgb 0.2 0.094 0.0)', 'color(--ryb 1 1 1)'),
+        # # Test CSS color
+        ('color(--ryb 0 0.50196 0)', 'color(--ryb 0 0.50196 0)'),
+        ('color(--ryb 0 0.50196 0 / 0.5)', 'color(--ryb 0 0.50196 0 / 0.5)'),
+        ('color(--ryb 50% 50% 50% / 50%)', 'color(--ryb 0.5 0.5 0.5 / 0.5)'),
+        ('color(--ryb none none none / none)', 'color(--ryb none none none / none)'),
+        # # Test range
+        ('color(--ryb 0% 0% 0%)', 'color(--ryb 0 0 0)'),
+        ('color(--ryb 100% 100% 100%)', 'color(--ryb 1 1 1)'),
+        ('color(--ryb -100% -100% -100%)', 'color(--ryb -1 -1 -1)')
+    ]
+
+    @pytest.mark.parametrize('color1,color2', COLORS)
+    def test_cmy_colors(self, color1, color2):
+        """Test colors."""
+
+        self.assertColorEqual(Color(color1).convert('ryb'), Color(color2))
+
+
+class TestRYBBiased(util.ColorAssertsPyTest):
+    """Test RYB biased."""
+
+    COLORS = [
+        ('color(srgb 1.0 1.0 1.0)', 'color(--ryb-biased 0 0 0)'),
+        ('color(srgb 1.0 0.0 0.0)', 'color(--ryb-biased 1 0 0)'),
+        ('color(srgb 1.0 1.0 0.0)', 'color(--ryb-biased 0 1 0)'),
+        ('color(srgb 1.0 0.5 0.0)', 'color(--ryb-biased 1 1 0)'),
+        ('color(srgb 0.163 0.373 0.6)', 'color(--ryb-biased 0 0 1)'),
+        ('color(srgb 0.5 0.0 0.5)', 'color(--ryb-biased 1 0 1)'),
+        ('color(srgb 0.0 0.66 0.2)', 'color(--ryb-biased 0 1 1)'),
+        ('color(srgb 0.2 0.094 0.0)', 'color(--ryb-biased 1 1 1)'),
+    ]
+
+    @pytest.mark.parametrize('color1,color2', COLORS)
+    def test_cmy_colors(self, color1, color2):
+        """Test colors."""
+
+        self.assertColorEqual(Color(color1).convert('ryb-biased'), Color(color2))
+
+
+class TestRYBSerialize(util.ColorAssertsPyTest):
+    """Test RYB serialization."""
+
+    COLORS = [
+        # Test color
+        ('color(--ryb 0 0.3 0.75 / 0.5)', {}, 'color(--ryb 0 0.3 0.75 / 0.5)'),
+        # Test alpha
+        ('color(--ryb 0 0.3 0.75)', {'alpha': True}, 'color(--ryb 0 0.3 0.75 / 1)'),
+        ('color(--ryb 0 0.3 0.75 / 0.5)', {'alpha': False}, 'color(--ryb 0 0.3 0.75)'),
+        # Test None
+        ('color(--ryb none 0.3 0.75)', {}, 'color(--ryb 0 0.3 0.75)'),
+        ('color(--ryb none 0.3 0.75)', {'none': True}, 'color(--ryb none 0.3 0.75)'),
+        # Test Fit
+        ('color(--ryb 1.2 0.2 0)', {}, 'color(--ryb 1 0.77702 0.18561)'),
+        ('color(--ryb 1.2 0.2 0)', {'fit': False}, 'color(--ryb 1.2 0.2 0)')
+    ]
+
+    @pytest.mark.parametrize('color1,options,color2', COLORS)
+    def test_colors(self, color1, options, color2):
+        """Test colors."""
+
+        self.assertEqual(Color(color1).to_string(**options), color2)
+
+
+class TestRYBPoperties(util.ColorAsserts, unittest.TestCase):
+    """Test RYB."""
+
+    def test_c(self):
+        """Test `c`."""
+
+        c = Color('color(--ryb 0 0 1)')
+        self.assertEqual(c['r'], 0)
+        c['r'] = 0.2
+        self.assertEqual(c['r'], 0.2)
+
+    def test_m(self):
+        """Test `m`."""
+
+        c = Color('color(--ryb 0 0 1)')
+        self.assertEqual(c['y'], 0)
+        c['y'] = 0.1
+        self.assertEqual(c['y'], 0.1)
+
+    def test_y(self):
+        """Test `y`."""
+
+        c = Color('color(--ryb 0 0 1)')
+        self.assertEqual(c['b'], 1)
+        c['b'] = 0.1
+        self.assertEqual(c['b'], 0.1)
+
+    def test_alpha(self):
+        """Test `alpha`."""
+
+        c = Color('color(--ryb 0 0 1)')
+        self.assertEqual(c['alpha'], 1)
+        c['alpha'] = 0.5
+        self.assertEqual(c['alpha'], 0.5)
+
+
+class TestsAchromatic(util.ColorAsserts, unittest.TestCase):
+    """Test achromatic."""
+
+    def test_achromatic(self):
+        """Test when color is achromatic."""
+
+        self.assertEqual(Color('srgb', [0.3, 0.3, 0.3]).convert('ryb').is_achromatic(), True)
+        self.assertEqual(Color('srgb', [0.3, 0.3, 0.30000001]).convert('ryb').is_achromatic(), True)
+        self.assertEqual(Color('srgb', [0.3, 0.4, 0.3]).convert('ryb').is_achromatic(), False)
+        self.assertEqual(Color('ryb', [1.0, 1.0, NaN]).convert('ryb').is_achromatic(), False)