diff --git a/chart-svg.cabal b/chart-svg.cabal
--- a/chart-svg.cabal
+++ b/chart-svg.cabal
@@ -1,6 +1,6 @@
 cabal-version: 3.0
 name: chart-svg
-version: 0.8.3.1
+version: 0.8.3.2
 license: BSD-3-Clause
 license-file: LICENSE
 copyright: Tony Day (c) 2017
@@ -86,7 +86,7 @@
     cubicbezier >=0.6 && <0.7,
     flatparse >=0.5 && <0.6,
     formatn >=0.3 && <0.4,
-    harpie >=0.1 && <0.2,
+    harpie >=0.1 && <0.3,
     lens >=5 && <5.4,
     markup-parse >=0.1 && <0.3,
     mtl >=2.2.2 && <2.4,
@@ -112,13 +112,3 @@
     Data.Path
     Data.Path.Parser
 
-test-suite doctests
-  import: ghc2024-stanza
-  main-is: doctests.hs
-  hs-source-dirs: test
-  build-depends:
-    base >=4.14 && <5,
-    doctest-parallel >=0.3 && <0.5,
-
-  ghc-options: -threaded
-  type: exitcode-stdio-1.0
diff --git a/other/usage.svg b/other/usage.svg
--- a/other/usage.svg
+++ b/other/usage.svg
@@ -1,35 +1,8 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="449" height="300" viewBox="-0.75 -0.5 1.5000 1.0"><style>svg {
-  color-scheme: light dark;
-}
-{
-  .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {
-    fill: rgb(5%, 5%, 5%);
-  }
-  .ticklines g, .tickglyph g, .legendBorder g {
-    stroke: rgb(5%, 5%, 5%);
-  }
-  .legendBorder g {
-    fill: rgb(94%, 94%, 94%);
-  }
-}
-@media (prefers-color-scheme:dark) {
-  .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {
-    fill: rgb(94%, 94%, 94%);
-  }
-  .ticklines g, .tickglyph g, .legendBorder g {
-    stroke: rgb(94%, 94%, 94%);
-  }
-  .legendBorder g {
-    fill: rgb(5%, 5%, 5%);
-  }
-}
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="449" height="300" viewBox="-0.75 -0.5 1.5000 1.0"><style>svg {color-scheme: light dark;} {.canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {fill: rgb(5%, 5%, 5%);} .ticklines g, .tickglyph g, .legendBorder g {stroke: rgb(5%, 5%, 5%);} .legendBorder g {fill: rgb(94%, 94%, 94%);}} @media (prefers-color-scheme:dark) {.canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {fill: rgb(94%, 94%, 94%);} .ticklines g, .tickglyph g, .legendBorder g {stroke: rgb(94%, 94%, 94%);} .legendBorder g {fill: rgb(5%, 5%, 5%);}}
 svg { font-family: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
 }
 
-ticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
-}
-
-</style><g class="chart"><g class="line"><g stroke-width="0.0150" stroke="rgb(2%, 73%, 80%)" stroke-opacity="1.0" fill="none"><polyline points="-0.6371,0.2114 -0.1971,0.2114 0.2429,-0.4495"/></g><g stroke-width="0.0150" stroke="rgb(2%, 29%, 48%)" stroke-opacity="1.0" fill="none"><polyline points="-0.6371,0.3766 0.5949,-0.1191"/></g><g stroke-width="0.0150" stroke="rgb(66%, 7%, 55%)" stroke-opacity="1.0" fill="none"><polyline points="-0.4171,-0.2843 -0.4171,0.3766"/></g></g><g class="datapadding"></g></g><g class="hud"><g class="frame"><g stroke-width="0" stroke="rgb(0%, 0%, 0%)" stroke-opacity="0" fill="rgb(100%, 100%, 100%)" fill-opacity="0.02"><rect width="1.3266" height="0.8384" x="-0.6437" y="-0.4557"/></g></g><g class="axis"><g class="axisbar"><g stroke-width="0" stroke="rgb(0%, 0%, 0%)" stroke-opacity="0" fill="rgb(5%, 5%, 5%)" fill-opacity="0.4"><rect width="1.3236" height="0.0033" x="-0.6388" y="0.3848"/></g></g><g class="ticks"><g class="ticklines"><g stroke-width="0.0050" stroke="rgb(5%, 5%, 5%)" stroke-opacity="0.05" fill="none"><polyline points="-0.6371,0.3766 -0.6371,-0.4495"/><polyline points="-0.4171,0.3766 -0.4171,-0.4495"/><polyline points="-0.1971,0.3766 -0.1971,-0.4495"/><polyline points="0.0229,0.3766 0.0229,-0.4495"/><polyline points="0.2429,0.3766 0.2429,-0.4495"/><polyline points="0.4629,0.3766 0.4629,-0.4495"/><polyline points="0.6830,0.3766 0.6830,-0.4495"/></g></g><g class="tickglyph"><g stroke-width="0.0033" stroke="rgb(5%, 5%, 5%)" stroke-opacity="0.4" fill="rgb(5%, 5%, 5%)" fill-opacity="0.4"><polyline points="-0.6371,0.4114
+ticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;}</style><g class="chart"><g class="line"><g stroke-width="0.0150" stroke="rgb(2%, 73%, 80%)" stroke-opacity="1.0" fill="none"><polyline points="-0.6371,0.2114 -0.1971,0.2114 0.2429,-0.4495"/></g><g stroke-width="0.0150" stroke="rgb(2%, 29%, 48%)" stroke-opacity="1.0" fill="none"><polyline points="-0.6371,0.3766 0.5949,-0.1191"/></g><g stroke-width="0.0150" stroke="rgb(66%, 7%, 55%)" stroke-opacity="1.0" fill="none"><polyline points="-0.4171,-0.2843 -0.4171,0.3766"/></g></g><g class="datapadding"></g></g><g class="hud"><g class="frame"><g stroke-width="0" stroke="rgb(0%, 0%, 0%)" stroke-opacity="0" fill="rgb(100%, 100%, 100%)" fill-opacity="0.02"><rect width="1.3266" height="0.8384" x="-0.6437" y="-0.4557"/></g></g><g class="axis"><g class="axisbar"><g stroke-width="0" stroke="rgb(0%, 0%, 0%)" stroke-opacity="0" fill="rgb(5%, 5%, 5%)" fill-opacity="0.4"><rect width="1.3236" height="0.0033" x="-0.6388" y="0.3848"/></g></g><g class="ticks"><g class="ticklines"><g stroke-width="0.0050" stroke="rgb(5%, 5%, 5%)" stroke-opacity="0.05" fill="none"><polyline points="-0.6371,0.3766 -0.6371,-0.4495"/><polyline points="-0.4171,0.3766 -0.4171,-0.4495"/><polyline points="-0.1971,0.3766 -0.1971,-0.4495"/><polyline points="0.0229,0.3766 0.0229,-0.4495"/><polyline points="0.2429,0.3766 0.2429,-0.4495"/><polyline points="0.4629,0.3766 0.4629,-0.4495"/><polyline points="0.6830,0.3766 0.6830,-0.4495"/></g></g><g class="tickglyph"><g stroke-width="0.0033" stroke="rgb(5%, 5%, 5%)" stroke-opacity="0.4" fill="rgb(5%, 5%, 5%)" fill-opacity="0.4"><polyline points="-0.6371,0.4114
 -0.6371,0.3865"/><polyline points="-0.4171,0.4114
 -0.4171,0.3865"/><polyline points="-0.1971,0.4114
 -0.1971,0.3865"/><polyline points="0.0229,0.4114
diff --git a/src/Chart/Examples.hs b/src/Chart/Examples.hs
--- a/src/Chart/Examples.hs
+++ b/src/Chart/Examples.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE OverloadedLabels #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
 
 -- | Examples of chart construction.
 module Chart.Examples
@@ -58,7 +57,6 @@
 import Data.ByteString (ByteString)
 import Data.Function
 import Data.Maybe
-import Data.String.Interpolate
 import Data.Text (Text)
 import Data.Text qualified as Text
 import Data.Time
@@ -383,24 +381,7 @@
     & set (#markupOptions % #cssOptions % #preferColorScheme) PreferHud
     & set
       (#markupOptions % #cssOptions % #cssExtra)
-      [i|
-{
-  .chart g {
-    stroke: #{showRGBA dark};
-  }
-  .chart g text {
-    fill: #{showRGBA dark};
-  }
-}
-@media (prefers-color-scheme:dark) {
-  .chart g {
-    stroke: #{showRGBA light};
-  }
-  .chart g text {
-    fill: #{showRGBA light};
-  }
-}
-|]
+      ("{.chart g {stroke: " <> showRGBA dark <> ";} .chart g text {fill: " <> showRGBA dark <> ";}} @media (prefers-color-scheme:dark) {.chart g {stroke: " <> showRGBA light <> ";} .chart g text {fill: " <> showRGBA light <> ";}}")
   where
     rowLarge =
       unnamed
@@ -562,20 +543,7 @@
     & set (#markupOptions % #cssOptions % #preferColorScheme) PreferHud
     & set
       (#markupOptions % #cssOptions % #cssExtra)
-      [i|
-{
-  .arrow g {
-    fill: #{showRGBA dark};
-    stroke: #{showRGBA dark};
-  }
-}
-@media (prefers-color-scheme:dark) {
-  .arrow g {
-    fill: #{showRGBA light};
-    stroke: #{showRGBA light};
-  }
-}
-|]
+      ("{.arrow g {fill: " <> showRGBA dark <> "; stroke: " <> showRGBA dark <> ";}} @media (prefers-color-scheme:dark) {.arrow g {fill: " <> showRGBA light <> "; stroke: " <> showRGBA light <> ";}}")
   where
     f = snd . bimap ((-1.0) *) (fmap ((-1.0) *)) . rosenbrock 1 10
     ps = grid MidPos (one :: Rect Double) (Point 10 10 :: Point Int) :: [Point Double]
diff --git a/src/Chart/Markup.hs b/src/Chart/Markup.hs
--- a/src/Chart/Markup.hs
+++ b/src/Chart/Markup.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE OverloadedLabels #-}
 {-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE QuasiQuotes #-}
 
 -- | Conversion between 'ChartOptions' and 'Markup' representations.
 module Chart.Markup
@@ -45,7 +44,6 @@
 import Data.Maybe
 import Data.Path
 import Data.Path.Parser
-import Data.String.Interpolate
 import Data.Text (Text)
 import Data.Text.Encoding (decodeUtf8, encodeUtf8)
 import GHC.Generics
@@ -331,52 +329,14 @@
 -- | CSS prefer-color-scheme text snippet
 --
 -- >>> cssPreferColorScheme (light, dark) PreferHud
--- "svg {\n  color-scheme: light dark;\n}\n{\n  .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {\n    fill: rgb(5%, 5%, 5%);\n  }\n  .ticklines g, .tickglyph g, .legendBorder g {\n    stroke: rgb(5%, 5%, 5%);\n  }\n  .legendBorder g {\n    fill: rgb(94%, 94%, 94%);\n  }\n}\n@media (prefers-color-scheme:dark) {\n  .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {\n    fill: rgb(94%, 94%, 94%);\n  }\n  .ticklines g, .tickglyph g, .legendBorder g {\n    stroke: rgb(94%, 94%, 94%);\n  }\n  .legendBorder g {\n    fill: rgb(5%, 5%, 5%);\n  }\n}"
+-- "svg {color-scheme: light dark;} {.canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {fill: rgb(5%, 5%, 5%);} .ticklines g, .tickglyph g, .legendBorder g {stroke: rgb(5%, 5%, 5%);} .legendBorder g {fill: rgb(94%, 94%, 94%);}} @media (prefers-color-scheme:dark) {.canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {fill: rgb(94%, 94%, 94%);} .ticklines g, .tickglyph g, .legendBorder g {stroke: rgb(94%, 94%, 94%);} .legendBorder g {fill: rgb(5%, 5%, 5%);}}"
 cssPreferColorScheme :: (Colour, Colour) -> PreferColorScheme -> ByteString
 cssPreferColorScheme (cl, cd) PreferHud =
-  [i|svg {
-  color-scheme: light dark;
-}
-{
-  .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {
-    fill: #{showRGB cd};
-  }
-  .ticklines g, .tickglyph g, .legendBorder g {
-    stroke: #{showRGB cd};
-  }
-  .legendBorder g {
-    fill: #{showRGB cl};
-  }
-}
-@media (prefers-color-scheme:dark) {
-  .canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {
-    fill: #{showRGB cl};
-  }
-  .ticklines g, .tickglyph g, .legendBorder g {
-    stroke: #{showRGB cl};
-  }
-  .legendBorder g {
-    fill: #{showRGB cd};
-  }
-}|]
+  "svg {color-scheme: light dark;} {.canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {fill: " <> showRGB cd <> ";} .ticklines g, .tickglyph g, .legendBorder g {stroke: " <> showRGB cd <> ";} .legendBorder g {fill: " <> showRGB cl <> ";}} @media (prefers-color-scheme:dark) {.canvas g, .title g, .axisbar g, .ticktext g, .tickglyph g, .ticklines g, .legendContent g text {fill: " <> showRGB cl <> ";} .ticklines g, .tickglyph g, .legendBorder g {stroke: " <> showRGB cl <> ";} .legendBorder g {fill: " <> showRGB cd <> ";}}"
 cssPreferColorScheme (cl, _) PreferLight =
-  [i|svg {
-      color-scheme: light dark;
-    }
-    @media (prefers-color-scheme:dark) {
-      markup {
-        background-color: #{showRGB cl};
-      }
-    }|]
+  "svg {color-scheme: light dark;} @media (prefers-color-scheme:dark) {markup {background-color: " <> showRGB cl <> ";}}"
 cssPreferColorScheme (_, cd) PreferDark =
-  [i|svg {
-      color-scheme: light dark;
-    }
-    @media (prefers-color-scheme:light) {
-      markup {
-        background-color: #{showRGB cd};
-      }
-    }|]
+  "svg {color-scheme: light dark;} @media (prefers-color-scheme:light) {markup {background-color: " <> showRGB cd <> ";}}"
 cssPreferColorScheme _ PreferNormal = mempty
 
 -- | CSS snippet to switch between dark and light mode
@@ -386,23 +346,12 @@
 -- ... will default to color1 for elements of the "stuff" class, but switch to color2 if "dark" mode is preferred by the user.
 fillSwitch :: (Colour, Colour) -> ByteString -> ByteString -> ByteString
 fillSwitch (colorNormal, colorPrefer) prefer item =
-  [i|
-{
-  .#{item} g {
-    fill: #{showRGB colorNormal};
-  }
-}
-@media (prefers-color-scheme:#{prefer}) {
-  .#{item} g {
-    fill: #{showRGB colorPrefer};
-  }
-}
-|]
+  " {." <> item <> " g {fill: " <> showRGB colorNormal <> ";}} @media (prefers-color-scheme: " <> prefer <> ") {." <> item <> " g {fill: " <> showRGB colorPrefer <> ";}}"
 
 -- | Markup options.
 --
 -- >>> defaultMarkupOptions
--- MarkupOptions {markupHeight = Just 300.0, chartAspect = FixedAspect 1.5, cssOptions = CssOptions {shapeRendering = NoShapeRendering, preferColorScheme = PreferHud, fontFamilies = "\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;\n}\n\n", cssExtra = ""}, renderStyle = Compact}
+-- MarkupOptions {markupHeight = Just 300.0, chartAspect = FixedAspect 1.5, cssOptions = CssOptions {shapeRendering = NoShapeRendering, preferColorScheme = PreferHud, fontFamilies = "\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;}", cssExtra = ""}, renderStyle = Compact}
 data MarkupOptions = MarkupOptions
   { markupHeight :: Maybe Double,
     chartAspect :: ChartAspect,
@@ -417,15 +366,7 @@
 
 -- | default fonts.
 defaultCssFontFamilies :: ByteString
-defaultCssFontFamilies =
-  [i|
-svg { font-family: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";
-}
-
-ticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;
-}
-
-|]
+defaultCssFontFamilies = "\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";" <> "\n" <> "}" <> "\n\n" <> "ticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;}"
 
 -- | CSS glyphShape rendering options
 data ShapeRendering
@@ -446,7 +387,7 @@
 -- | css options
 --
 -- >>> defaultCssOptions
--- CssOptions {shapeRendering = NoShapeRendering, preferColorScheme = PreferHud, fontFamilies = "\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;\n}\n\n", cssExtra = ""}
+-- CssOptions {shapeRendering = NoShapeRendering, preferColorScheme = PreferHud, fontFamilies = "\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;}", cssExtra = ""}
 data CssOptions
   = CssOptions {shapeRendering :: ShapeRendering, preferColorScheme :: PreferColorScheme, fontFamilies :: ByteString, cssExtra :: ByteString}
   deriving (Eq, Show, Generic, Data)
@@ -509,7 +450,7 @@
 -- | Convert ChartOptions to Markup
 --
 -- >>> markupChartOptions (ChartOptions (defaultMarkupOptions & #cssOptions % #preferColorScheme .~ PreferNormal) mempty mempty) & markdown_ Compact Xml
--- "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"300\" height=\"300\" viewBox=\"-0.5 -0.5 1.0 1.0\"><style>\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;\n}\n\n</style><g class=\"chart\"></g><g class=\"hud\"></g></svg>"
+-- "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"300\" height=\"300\" viewBox=\"-0.5 -0.5 1.0 1.0\"><style>\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;}</style><g class=\"chart\"></g><g class=\"hud\"></g></svg>"
 markupChartOptions :: ChartOptions -> Markup
 markupChartOptions co =
   header
@@ -529,14 +470,14 @@
 -- | Render ChartOptions to an SVG ByteString
 --
 -- >>> encodeChartOptions (ChartOptions (defaultMarkupOptions & #cssOptions % #preferColorScheme .~ PreferNormal) mempty mempty)
--- "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"300\" height=\"300\" viewBox=\"-0.5 -0.5 1.0 1.0\"><style>\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;\n}\n\n</style><g class=\"chart\"></g><g class=\"hud\"></g></svg>"
+-- "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"300\" height=\"300\" viewBox=\"-0.5 -0.5 1.0 1.0\"><style>\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;}</style><g class=\"chart\"></g><g class=\"hud\"></g></svg>"
 encodeChartOptions :: ChartOptions -> ByteString
 encodeChartOptions co = markdown_ (view (#markupOptions % #renderStyle) co) Xml $ markupChartOptions co
 
 -- | Render ChartOptions to an SVG Text snippet
 --
 -- >>> renderChartOptions (ChartOptions (defaultMarkupOptions & #cssOptions % #preferColorScheme .~ PreferNormal) mempty mempty)
--- "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"300\" height=\"300\" viewBox=\"-0.5 -0.5 1.0 1.0\"><style>\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;\n}\n\n</style><g class=\"chart\"></g><g class=\"hud\"></g></svg>"
+-- "<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" width=\"300\" height=\"300\" viewBox=\"-0.5 -0.5 1.0 1.0\"><style>\nsvg { font-family: system-ui,-apple-system,\"Segoe UI\",Roboto,\"Helvetica Neue\",Arial,\"Noto Sans\",\"Liberation Sans\",sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",\"Segoe UI Symbol\",\"Noto Color Emoji\";\n}\n\nticktext { font-family: SFMono-Regular,Menlo,Monaco,Consolas,\"Liberation Mono\",\"Courier New\",monospace;}</style><g class=\"chart\"></g><g class=\"hud\"></g></svg>"
 renderChartOptions :: ChartOptions -> Text
 renderChartOptions = decodeUtf8 . encodeChartOptions
 
diff --git a/src/Data/Colour.hs b/src/Data/Colour.hs
--- a/src/Data/Colour.hs
+++ b/src/Data/Colour.hs
@@ -1,6 +1,5 @@
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE PatternSynonyms #-}
-{-# LANGUAGE QuasiQuotes #-}
 
 -- | Colour representations and combinations.
 module Data.Colour
@@ -63,10 +62,10 @@
 import Chart.Data
 import Data.Bool (bool)
 import Data.ByteString (ByteString)
+import Data.ByteString.Char8 (pack)
 import Data.Data
 import Data.FormatN
 import Data.List qualified as List
-import Data.String.Interpolate
 import Data.Text (Text)
 import Data.Text qualified as Text
 import GHC.Generics hiding (prec)
@@ -107,7 +106,7 @@
 -- | CSS-style representation
 showRGBA :: Colour -> ByteString
 showRGBA (Colour r' g' b' a') =
-  [i|rgba(#{r}, #{g}, #{b}, #{a})|]
+  pack $ Text.unpack $ "rgba(" <> r <> ", " <> g <> ", " <> b <> ", " <> a <> ")"
   where
     r = percent (fixedSF (Just 0)) (Just 2) r'
     g = percent (fixedSF (Just 0)) (Just 2) g'
@@ -117,7 +116,7 @@
 -- | CSS-style representation
 showRGB :: Colour -> ByteString
 showRGB (Colour r' g' b' _) =
-  [i|rgb(#{r}, #{g}, #{b})|]
+  pack $ Text.unpack $ "rgb(" <> r <> ", " <> g <> ", " <> b <> ")"
   where
     r = percent (fixedSF (Just 0)) (Just 2) r'
     g = percent (fixedSF (Just 0)) (Just 2) g'
@@ -152,10 +151,7 @@
 
 -- | CSS-style representation
 showOpacity :: Colour -> ByteString
-showOpacity c =
-  [i|#{o}|]
-  where
-    o = formatOrShow (FixedStyle 2) Nothing (opac c)
+showOpacity c = pack $ Text.unpack $ formatOrShow (FixedStyle 2) Nothing (opac c)
 
 -- | lens for opacity (or alpha channel)
 opac' :: Lens' Colour Double
@@ -559,20 +555,18 @@
 -- >>> showSwatch "swatch" dark
 -- "<div class=swatch style=\"background:rgba(5%, 5%, 5%, 1.00);\">swatch</div>"
 showSwatch :: Text -> Colour -> Text
-showSwatch label c =
-  [i|<div class=swatch style="background:#{rgba};">#{label}</div>|]
+showSwatch label (Colour r' g' b' a') =
+  "<div class=swatch style=\"background:" <> rgba <> ";\">" <> label <> "</div>"
   where
-    rgba = showRGBA c
+    rgba = "rgba(" <> r <> ", " <> g <> ", " <> b <> ", " <> a <> ")"
+    r = percent (fixedSF (Just 0)) (Just 2) r'
+    g = percent (fixedSF (Just 0)) (Just 2) g'
+    b = percent (fixedSF (Just 0)) (Just 2) b'
+    a = fixed (Just 2) a'
 
 -- | Show multiple colors with embedded text.
 showSwatches :: Text -> Text -> [(Text, Colour)] -> Text
-showSwatches pref suff hs =
-  [i|<div>
- #{pref}
- #{divs}
- #{suff}
-</div>
-|]
+showSwatches pref suff hs = "<div>" <> "\n" <> pref <> "\n" <> divs <> "\n" <> suff <> "\n" <> "</div>"
   where
     divs = Text.intercalate "\n" (uncurry showSwatch <$> hs)
 
diff --git a/test/doctests.hs b/test/doctests.hs
deleted file mode 100644
--- a/test/doctests.hs
+++ /dev/null
@@ -1,7 +0,0 @@
-module Main where
-
-import System.Environment (getArgs)
-import Test.DocTest (mainFromCabal)
-
-main :: IO ()
-main = mainFromCabal "chart-svg" =<< getArgs
