diff --git a/BlogLiterately.cabal b/BlogLiterately.cabal
--- a/BlogLiterately.cabal
+++ b/BlogLiterately.cabal
@@ -1,5 +1,5 @@
 Name:           BlogLiterately
-Version:        0.8.6.3
+Version:        0.8.7
 Synopsis:       A tool for posting Haskelly articles to blogs
 Description:    Write blog posts in Markdown format, then use BlogLiterately
                 to do syntax highlighting, format ghci sessions, and upload
@@ -26,7 +26,7 @@
 Maintainer:     Brent Yorgey <byorgey@gmail.com>
 Stability:      experimental
 Build-Type:     Simple
-Tested-With:    GHC ==8.0.2, GHC ==8.2.2, GHC ==8.4.4, GHC ==8.6.3
+Tested-With:    GHC ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.3 || ==8.10.1
 Extra-Source-Files: CHANGES.md
                     README.markdown
                     doc/BlogLiteratelyDoc.lhs
@@ -39,7 +39,7 @@
   location: git://github.com/byorgey/BlogLiterately.git
 
 Library
-  Build-Depends:   base >= 4.0 && < 4.13,
+  Build-Depends:   base >= 4.0 && < 4.15,
                    process,
                    filepath,
                    directory,
@@ -58,12 +58,12 @@
                    blaze-html >= 0.5 && < 0.10,
                    cmdargs >= 0.9.5 && < 0.11,
                    haxr >= 3000.11 && < 3000.12,
-                   pandoc >= 2.0 && < 2.8,
-                   pandoc-types >= 1.16 && < 1.20,
-                   pandoc-citeproc >= 0.1.2 && < 0.17,
+                   pandoc >= 2.0 && < 2.11,
+                   pandoc-types >= 1.20 && < 1.22,
+                   pandoc-citeproc >= 0.1.2 && < 0.18,
                    highlighting-kate >= 0.5 && < 0.7,
                    data-default >= 0.5 && < 0.8,
-                   lens >= 3.8 && < 4.18,
+                   lens >= 3.8 && < 4.20,
                    tagsoup >= 0.13.4 && < 0.15,
                    HTTP >= 4000.3 && < 4000.4
   Exposed-modules: Text.BlogLiterately
diff --git a/CHANGES.md b/CHANGES.md
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -1,3 +1,9 @@
+0.8.7 (21 July 2020)
+--------------------
+
+  - Add support for GHC 8.8, 8.10
+  - Switch to `pandoc-2.9` and `text`
+
 0.8.6.3 (4 March 2019)
 ----------------------
 
diff --git a/src/Text/BlogLiterately/Block.hs b/src/Text/BlogLiterately/Block.hs
--- a/src/Text/BlogLiterately/Block.hs
+++ b/src/Text/BlogLiterately/Block.hs
@@ -16,21 +16,26 @@
     , onTag
     ) where
 
-import           Data.Char                     (toLower)
-import           Text.Pandoc                   (Attr, Block (CodeBlock))
-import           Text.ParserCombinators.Parsec
+import           Data.Text        (Text)
+import qualified Data.Text        as T
+import           Text.Pandoc      (Attr, Block (CodeBlock))
+import           Text.Parsec
+import           Text.Parsec.Text
 
--- | Given a block, if begins with a tag in square brackets, strip off
+-- switch to megaparsec, use e.g. https://hackage.haskell.org/package/megaparsec-8.0.0/docs/Text-Megaparsec.html#v:takeWhileP ?
+
+-- | Given a block, if it begins with a tag in square brackets, strip off
 --   the tag and return a pair consisting of the tag and de-tagged
 --   block.  Otherwise, return @Nothing@ and the unchanged block.
-unTag :: String -> (Maybe String, String)
+unTag :: Text -> (Maybe Text, Text)
 unTag s = either (const (Nothing, s)) id $ parse tag "" s
   where
+    tag :: Parser (Maybe Text, Text)
     tag = do
-      tg <- between (char '[') (char ']') $ many $ noneOf "[]"
+      tg <- T.pack <$> (between (char '[') (char ']') $ many $ noneOf "[]")
       skipMany $ oneOf " \t"
       _   <- (string "\r\n" <|> string "\n")
-      txt <- many $ anyToken
+      txt <- T.pack <$> many anyToken
       eof
       return (Just tg, txt)
 
@@ -38,13 +43,10 @@
 --   blocks with a tag matching the given tag (case insensitive).  On
 --   any other blocks (which don't have a matching tag, or are not code
 --   blocks), run the other function.
-onTag :: String -> (Attr -> String -> a) -> (Block -> a) -> Block -> a
+onTag :: Text -> (Attr -> Text -> a) -> (Block -> a) -> Block -> a
 onTag t f def b@(CodeBlock attr@(_, as, _) s)
-  | lowercase t `elem` map lowercase (maybe id (:) tag $ as)
+  | T.toLower t `elem` map T.toLower (maybe id (:) tag $ as)
     = f attr src
   | otherwise = def b
   where (tag, src) = unTag s
 onTag _ _ def b = def b
-
-lowercase :: String -> String
-lowercase = map toLower
diff --git a/src/Text/BlogLiterately/Ghci.hs b/src/Text/BlogLiterately/Ghci.hs
--- a/src/Text/BlogLiterately/Ghci.hs
+++ b/src/Text/BlogLiterately/Ghci.hs
@@ -41,6 +41,8 @@
 import           Data.Char                  (isSpace)
 import           Data.Functor               ((<$>))
 import           Data.List                  (intercalate, isPrefixOf)
+import           Data.Text                  (Text)
+import qualified Data.Text                  as T
 import           System.FilePath            (takeFileName)
 import           System.IO
 import qualified System.IO.Strict           as Strict
@@ -194,14 +196,14 @@
 formatInlineGhci f = withGhciProcess f . bottomUpM formatInlineGhci'
   where
     formatInlineGhci' :: Block -> ReaderT ProcessInfo IO Block
-    formatInlineGhci' = onTag "ghci" formatGhciBlock return
+    formatInlineGhci' = onTag (T.pack "ghci") formatGhciBlock return
 
     formatGhciBlock attr src = do
       let inputs = parseGhciInputs src
       results <- zipWith GhciLine inputs <$> mapM ghciEval inputs
-      return $ CodeBlock attr (intercalate "\n" $ map formatGhciResult results)
+      return $ CodeBlock attr (T.intercalate (T.pack "\n") $ map (T.pack . formatGhciResult) results)
 
-parseGhciInputs :: String -> [GhciInput]
+parseGhciInputs :: Text -> [GhciInput]
 parseGhciInputs = map mkGhciInput
                 . split
                   ( dropInitBlank
@@ -210,6 +212,7 @@
                   $ whenElt (not . (" " `isPrefixOf`))
                   )
                 . lines
+                . T.unpack
 
 mkGhciInput :: [String] -> GhciInput
 mkGhciInput []       = GhciInput "" Nothing
diff --git a/src/Text/BlogLiterately/Highlight.hs b/src/Text/BlogLiterately/Highlight.hs
--- a/src/Text/BlogLiterately/Highlight.hs
+++ b/src/Text/BlogLiterately/Highlight.hs
@@ -1,4 +1,5 @@
 {-# LANGUAGE DeriveDataTypeable #-}
+{-# LANGUAGE OverloadedStrings  #-}
 {-# LANGUAGE TemplateHaskell    #-}
 
 -----------------------------------------------------------------------------
@@ -26,6 +27,12 @@
     , colourisePandoc
     ) where
 
+-- xmlParse (from HaXmL) uses String
+-- hscolour uses String
+
+import           Data.Text                           (Text)
+import qualified Data.Text                           as T
+
 import           Control.Lens                        (makePrisms)
 import           Control.Monad                       (liftM)
 import           Data.Char                           (toLower)
@@ -39,7 +46,7 @@
 import           Text.Highlighting.Kate
 import           Text.Pandoc.Definition
 import           Text.Pandoc.Shared                  (safeRead)
-import           Text.XML.HaXml                      hiding (find, attr, html)
+import           Text.XML.HaXml                      hiding (attr, find, html)
 import           Text.XML.HaXml.Posn                 (noPos)
 
 import           Text.BlogLiterately.Block           (unTag)
@@ -67,9 +74,9 @@
 The `Attr` component has metadata about what's in the code block:
 
     [haskell]
-    type Attr = ( String,             -- code block identifier
-                , [String]            -- list of code classes
-                , [(String, String)]  -- name/value pairs
+    type Attr = ( Text,           -- code block identifier
+                , [Text]          -- list of code classes
+                , [(Text, Text)]  -- name/value pairs
                 )
 
 Thanks to some feedback from the Pandoc author, John MacFarlane, I
@@ -147,9 +154,9 @@
 
 -- | Use hscolour to syntax highlight some Haskell code.  The first
 -- argument indicates whether the code is literate Haskell.
-colourIt :: Bool -> String -> String
+colourIt :: Bool -> Text -> String
 colourIt literate srcTxt =
-    wrapCode $ hscolour CSS defaultColourPrefs False True "" literate srcTxt'
+    wrapCode $ hscolour CSS defaultColourPrefs False True "" literate (T.unpack srcTxt')
     where srcTxt' | literate  = litify srcTxt
                   | otherwise = srcTxt
           -- wrap the result in a <pre><code> tag, similar to
@@ -164,8 +171,8 @@
                     `when` tag "pre"
 
 -- | Prepend literate Haskell markers to some source code.
-litify :: String -> String
-litify = unlines . map ("> " ++) . lines
+litify :: Text -> Text
+litify = T.unlines . map (T.append "> ") . T.lines
 
 {-
 Hscolour uses HTML `span` elements and CSS classes like 'hs-keyword'
@@ -259,8 +266,8 @@
   | ctag == Just "haskell" || haskell
   = case hsHighlight of
         HsColourInline style ->
-            rawHtml $ bakeStyles style $ colourIt lit src
-        HsColourCSS   -> rawHtml $ colourIt lit src
+            rawHtmlT . bakeStyles style $ colourIt lit src
+        HsColourCSS   -> rawHtmlT $ colourIt lit src
         HsNoHighlight -> rawHtml $ simpleHTML hsrc
         HsKate        -> case ctag of
             Nothing -> myHighlightK attr hsrc
@@ -283,11 +290,12 @@
         | otherwise    = src
     lit          = "sourceCode" `elem` classes
     haskell      = "haskell" `elem` classes
-    simpleHTML h = "<pre><code>" ++ h ++ "</code></pre>"
+    simpleHTML h = T.append "<pre><code>" (T.append h "</code></pre>")
     myHighlightK attrs h = case highlight formatHtmlBlock attrs h of
-        Nothing   -> rawHtml $ simpleHTML s
-        Just html -> rawHtml $ replaceBreaks $ renderHtml html
-    rawHtml = RawBlock (Format "html")
+        Nothing   -> rawHtml  $ simpleHTML s
+        Just html -> rawHtmlT $ replaceBreaks $ renderHtml html
+    rawHtmlT = rawHtml . T.pack
+    rawHtml  = RawBlock (Format "html")
 
 colouriseCodeBlock _ _ b = b
 
@@ -311,21 +319,21 @@
 lcLanguages = map (map toLower) languages
 
 highlight :: (FormatOptions -> [SourceLine] -> a) -- ^ Formatter
-          -> Attr -- ^ Attributes of the CodeBlock
-          -> String -- ^ Raw contents of the CodeBlock
+          -> Attr    -- ^ Attributes of the CodeBlock
+          -> Text    -- ^ Raw contents of the CodeBlock
           -> Maybe a -- ^ Maybe the formatted result
 highlight formatter (_, classes, keyvals) rawCode =
   let firstNum = case safeRead (fromMaybe "1" $ lookup "startFrom" keyvals) of
-                      Just n -> n
+                      Just n  -> n
                       Nothing -> 1
       fmtOpts = defaultFormatOpts{
                   startNumber = firstNum,
                   numberLines = any (`elem`
                         ["number","numberLines", "number-lines"]) classes }
-      lcclasses = map (map toLower) classes
+      lcclasses = map (T.unpack . T.toLower) classes
   in case find (`elem` lcLanguages) lcclasses of
             Nothing -> Nothing
             Just language -> Just
                               $ formatter fmtOpts{ codeClasses = [language],
-                                                   containerClasses = classes }
-                              $ highlightAs language rawCode
+                                                   containerClasses = map T.unpack classes }
+                              $ highlightAs language (T.unpack rawCode)
diff --git a/src/Text/BlogLiterately/Image.hs b/src/Text/BlogLiterately/Image.hs
--- a/src/Text/BlogLiterately/Image.hs
+++ b/src/Text/BlogLiterately/Image.hs
@@ -19,6 +19,8 @@
     , mkMediaObject
     ) where
 
+import qualified Data.Text                   as T
+
 import           Control.Monad.IO.Class      (liftIO)
 import           Control.Monad.Trans.Class   (lift)
 import           Control.Monad.Trans.State   (StateT, get, modify, runStateT)
@@ -55,21 +57,24 @@
     _           -> return p
   where
     uploadOneImage :: String -> Inline -> StateT (M.Map FilePath URL) IO Inline
-    uploadOneImage xmlrpc i@(Image attr altText (imgUrl, imgTitle))
+    uploadOneImage xmlrpc i@(Image attr altText (imgUrlT, imgTitle))
       | isLocal imgUrl = do
           uploaded <- get
           case M.lookup imgUrl uploaded of
-            Just url -> return $ Image attr altText (url, imgTitle)
+            Just url -> return $ Image attr altText (T.pack url, imgTitle)
             Nothing  -> do
               res <- lift $ uploadIt xmlrpc imgUrl bl
               case res of
                 Just (ValueStruct (lookup "url" -> Just (ValueString newUrl))) -> do
                   modify (M.insert imgUrl newUrl)
-                  return $ Image attr altText (newUrl, imgTitle)
+                  return $ Image attr altText (T.pack newUrl, imgTitle)
                 _ -> do
                   liftIO . putStrLn $ "Warning: upload of " ++ imgUrl ++ " failed."
                   return i
       | otherwise      = return i
+      where
+        imgUrl = T.unpack imgUrlT
+
     uploadOneImage _ i = return i
 
     isLocal imgUrl = none (`isPrefixOf` imgUrl) ["http", "/"]
diff --git a/src/Text/BlogLiterately/LaTeX.hs b/src/Text/BlogLiterately/LaTeX.hs
--- a/src/Text/BlogLiterately/LaTeX.hs
+++ b/src/Text/BlogLiterately/LaTeX.hs
@@ -10,26 +10,32 @@
 --
 -----------------------------------------------------------------------------
 
+{-# LANGUAGE OverloadedStrings #-}
+
 module Text.BlogLiterately.LaTeX
     (
       rawTeXify
     , wpTeXify
     ) where
 
-import           Data.List   (isPrefixOf)
+import           Data.Text   (Text)
+import qualified Data.Text   as T
 import           Text.Pandoc
 
+bracket :: Text -> Text -> Text -> Text
+bracket l r t = T.append l (T.append t r)
+
 -- | Pass LaTeX through unchanged.
 rawTeXify :: Pandoc -> Pandoc
 rawTeXify = bottomUp formatDisplayTex . bottomUp formatInlineTex
   where formatInlineTex :: [Inline] -> [Inline]
         formatInlineTex (Math InlineMath tex : is)
-          = (RawInline (Format "html") ("$" ++ tex ++ "$")) : is
+          = (RawInline (Format "html") (bracket "$" "$" tex)) : is
         formatInlineTex is = is
 
         formatDisplayTex :: [Block] -> [Block]
         formatDisplayTex (Para [Math DisplayMath tex] : bs)
-          = RawBlock (Format "html") ("\n\\[" ++ tex ++ "\\]\n")
+          = RawBlock (Format "html") (bracket "\n\\[" "\\]\n" tex)
           : bs
         formatDisplayTex bs = bs
 
@@ -40,17 +46,17 @@
 wpTeXify = bottomUp formatDisplayTex . bottomUp formatInlineTex
   where formatInlineTex :: [Inline] -> [Inline]
         formatInlineTex (Math InlineMath tex : is)
-          = (Str $ "$latex " ++ unPrefix "latex" tex ++ "$") : is
+          = (Str $ bracket "$latex " "$" (unPrefix "latex" tex)) : is
         formatInlineTex is = is
 
         formatDisplayTex :: [Block] -> [Block]
         formatDisplayTex (Para [Math DisplayMath tex] : bs)
           = RawBlock (Format "html") "<p><div style=\"text-align: center\">"
-          : Plain [Str $ "$latex " ++ "\\displaystyle " ++ unPrefix "latex" tex ++ "$"]
+          : Plain [Str $ bracket "$latex \\displaystyle " "$" (unPrefix "latex" tex)]
           : RawBlock (Format "html") "</div></p>"
           : bs
         formatDisplayTex bs = bs
 
         unPrefix pre s
-          | pre `isPrefixOf` s = drop (length pre) s
-          | otherwise          = s
+          | pre `T.isPrefixOf` s = T.drop (T.length pre) s
+          | otherwise            = s
diff --git a/src/Text/BlogLiterately/Transform.hs b/src/Text/BlogLiterately/Transform.hs
--- a/src/Text/BlogLiterately/Transform.hs
+++ b/src/Text/BlogLiterately/Transform.hs
@@ -1,5 +1,6 @@
 {-# LANGUAGE FlexibleContexts  #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards   #-}
 {-# LANGUAGE TupleSections     #-}
 {-# LANGUAGE TypeOperators     #-}
@@ -276,7 +277,7 @@
 --
 --   is a simple 'SpecialLink' which causes links of the form
 --   @twitter::user@ to be replaced by @https://twitter.com/user@.
-type SpecialLink = (String, String -> BlogLiterately -> IO String)
+type SpecialLink = (Text, Text -> BlogLiterately -> IO Text)
 
 -- | Create a transformation which looks for the given special links
 --   and replaces them appropriately. You can use this function with
@@ -292,7 +293,7 @@
     specialLink :: Inline -> IO Inline
     specialLink i@(Link attrs alt (url, title))
       | Just (typ, target) <- getSpecial url
-      = mkLink <$> case lookup (map toLower typ) links of
+      = mkLink <$> case lookup (T.toLower typ) links of
                      Just mkURL -> mkURL target bl
                      Nothing    -> return target
       where
@@ -301,9 +302,9 @@
     specialLink i = return i
 
     getSpecial url
-      | "::" `isInfixOf` url =
-          let (typ:rest) = splitOn "::" url
-          in  Just (typ, intercalate "::" rest)
+      | "::" `T.isInfixOf` url =
+          let (typ:rest) = T.splitOn "::" url
+          in  Just (typ, T.intercalate "::" rest)
       | otherwise = Nothing
 
 -- | Turn @lucky::<search>@ into a link to the first Google result for
@@ -311,12 +312,16 @@
 luckyLink :: SpecialLink
 luckyLink = ("lucky", getLucky)
   where
+    getLucky :: Text -> BlogLiterately -> IO Text
     getLucky searchTerm _ = do
-      results <- openURL $ "http://www.google.com/search?q=" ++ searchTerm
+      results <- openURL $ "http://www.google.com/search?q=" ++ (T.unpack searchTerm)
       let tags   = parseTags results
-          anchor = take 1 . dropWhile (~/= "<a>") . dropWhile (~/= "<h3 class='r'>") $ tags
+          anchor = take 1
+            . dropWhile (~/= ("<a>" :: String))
+            . dropWhile (~/= ("<h3 class='r'>" :: String))
+            $ tags
           url = case anchor of
-            [t@(TagOpen{})] -> takeWhile (/='&') . dropWhile (/='h') . fromAttrib "href" $ t
+            [t@(TagOpen{})] -> T.pack . takeWhile (/='&') . dropWhile (/='h') . fromAttrib "href" $ t
             _ -> searchTerm
       return url
 
@@ -327,7 +332,7 @@
 -- | Given @wiki::<title>@, generate a link to the Wikipedia page for
 --   @<title>@.  Note that the page is not checked for existence.
 wikiLink :: SpecialLink
-wikiLink = ("wiki", \target _ -> return $ "https://en.wikipedia.org/wiki/" ++ target)
+wikiLink = ("wiki", \target _ -> return $ T.append "https://en.wikipedia.org/wiki/" target)
 
 -- | @postLink@ handles two types of special links.
 --
@@ -341,12 +346,13 @@
 postLink :: SpecialLink
 postLink = ("post", getPostLink)
   where
+    getPostLink :: Text -> BlogLiterately -> IO Text
     getPostLink target bl =
-      fromMaybe target <$>
-        case (all isDigit target, bl ^. blog) of
+      (fromMaybe target . fmap T.pack) <$>
+        case (T.all isDigit target, bl ^. blog) of
           (_    , Nothing ) -> return Nothing
-          (True , Just url) -> getPostURL url target (user' bl) (password' bl)
-          (False, Just url) -> findTitle 20 url target (user' bl) (password' bl)
+          (True , Just url) -> getPostURL url (T.unpack target) (user' bl) (password' bl)
+          (False, Just url) -> findTitle 20 url (T.unpack target) (user' bl) (password' bl)
 
           -- If all digits, replace with permalink for that postid
           -- Otherwise, search titles of 20 most recent posts.
@@ -363,10 +369,11 @@
 githubLink :: SpecialLink
 githubLink = ("github", getGithubLink)
   where
-    getGithubLink target bl =
-      case splitOn "/" target of
-        (user : repo : ghTarget) -> return $ github </> user </> repo </> mkTarget ghTarget
-        _ -> return $ github </> target
+    getGithubLink :: Text -> BlogLiterately -> IO Text
+    getGithubLink target bl = return . T.pack $
+      case splitOn "/" (T.unpack target) of
+        (user : repo : ghTarget) -> github </> user </> repo </> mkTarget ghTarget
+        _ -> github </> (T.unpack target)
     github = "https://github.com/"
     mkTarget []                 = ""
     mkTarget (('@': hash) : _)  = "commit" </> hash
@@ -377,7 +384,8 @@
 hackageLink :: SpecialLink
 hackageLink = ("hackage", getHackageLink)
   where
-    getHackageLink pkg bl = return $ hackagePrefix ++ pkg
+    getHackageLink :: Text -> BlogLiterately -> IO Text
+    getHackageLink pkg bl = return $ T.append hackagePrefix pkg
     hackagePrefix = "http://hackage.haskell.org/package/"
 
 -- | Potentially extract a title from the metadata block, and set it
@@ -389,9 +397,9 @@
       (Pandoc (Meta m) _) <- gets snd
       case M.lookup "title" m of
         Just (MetaString s) ->
-          setTitle s
+          setTitle (T.unpack s)
         Just (MetaInlines is) ->
-          setTitle (intercalate " " [s | Str s <- is])
+          setTitle (intercalate " " [T.unpack s | Str s <- is])
         _ -> return ()
 
     -- title set explicitly with --title takes precedence.
@@ -412,7 +420,7 @@
 --   options record.  If the blog is not tagged with @[BLOpts]@ these
 --   will just be empty.
 extractOptions :: Block -> ([ParseError], BlogLiterately)
-extractOptions = onTag "blopts" (const readBLOptions) (const mempty)
+extractOptions = onTag "blopts" (const (readBLOptions . T.unpack)) (const mempty)
 
 -- | Delete any blocks tagged with @[BLOpts]@.
 killOptionBlocks :: Block -> Block
@@ -533,14 +541,17 @@
 -- | Transform a complete input document string to an HTML output
 --   string, given a list of transformation passes.
 xformDoc :: BlogLiterately -> [Transform] -> String -> IO (Either PandocError (BlogLiterately, String))
-xformDoc bl xforms = runIO .
+xformDoc bl xforms s = do
+  Right tpl <- compileTemplate "" blHtmlTemplate
+  runIO .
     (     fixLineEndings
       >>> T.pack
       >>> parseFile parseOpts
       >=> (liftIO . runTransforms xforms bl)
-      >=> (\(bl', p) -> (bl',) <$> writeHtml5String (writeOpts bl') p)
+      >=> (\(bl', p) -> (bl',) <$> writeHtml5String (writeOpts bl' tpl) p)
       >=> _2 (return . T.unpack)
     )
+    $ s
   where
     parseFile :: ReaderOptions -> Text -> PandocIO Pandoc
     parseFile opts =
@@ -572,44 +583,45 @@
             -- Ext_pandoc_title_block
             -- Ext_citations
       }
-    writeOpts bl = def
-      { writerReferenceLinks = True
+    writeOpts bl tpl = def
+      { writerReferenceLinks  = True
       , writerTableOfContents = toc' bl
-      , writerHTMLMathMethod =
+      , writerHTMLMathMethod  =
           case math' bl of
             ""  -> PlainMath
-            opt -> mathOption opt
-      , writerTemplate       = Just blHtmlTemplate
+            opt -> mathOption (T.pack opt)
+      , writerTemplate        = Just tpl
       }
 
     mathOption opt
-      | opt `isPrefixOf` "mathml"      = MathML
-      | opt `isPrefixOf` "mimetex"     =
+      | opt `T.isPrefixOf` "mathml"      = MathML
+      | opt `T.isPrefixOf` "mimetex"     =
           WebTeX (mathUrl "/cgi-bin/mimetex.cgi?" opt)
-      | opt `isPrefixOf` "webtex"      = WebTeX (mathUrl webTeXURL opt)
-      | opt `isPrefixOf` "mathjax"     = MathJax (mathUrl mathJaxURL opt)
+      | opt `T.isPrefixOf` "webtex"      = WebTeX (mathUrl webTeXURL opt)
+      | opt `T.isPrefixOf` "mathjax"     = MathJax (mathUrl mathJaxURL opt)
       | otherwise                      = PlainMath
 
     webTeXURL  = "http://chart.apis.google.com/chart?cht=tx&chl="
-    mathJaxURL = "http://cdn.mathjax.org/mathjax/latest/MathJax.js"
-                 ++ "?config=TeX-AMS-MML_HTMLorMML"
+    mathJaxURL = T.append "http://cdn.mathjax.org/mathjax/latest/MathJax.js"
+                   "?config=TeX-AMS-MML_HTMLorMML"
 
-    urlPart = drop 1 . dropWhile (/='=')
+    urlPart :: Text -> Text
+    urlPart = T.drop 1 . T.dropWhile (/='=')
 
     mathUrl dflt opt  = case urlPart opt of "" -> dflt; x -> x
 
 -- | Turn @CRLF@ pairs into a single @LF@.  This is necessary since
 --   'readMarkdown' is picky about line endings.
 fixLineEndings :: String -> String
-fixLineEndings [] = []
+fixLineEndings []             = []
 fixLineEndings ('\r':'\n':cs) = '\n':fixLineEndings cs
-fixLineEndings (c:cs) = c:fixLineEndings cs
+fixLineEndings (c:cs)         = c:fixLineEndings cs
 
 -- We use a special template with the "standalone" pandoc writer.  We
 -- don't actually want truly "standalone" HTML documents because they
 -- have to sit inside another web page.  But we do want things like
 -- math typesetting and a table of contents.
-blHtmlTemplate = unlines
+blHtmlTemplate = T.unlines
   [ "$if(highlighting-css)$"
   , "  <style type=\"text/css\">"
   , "$highlighting-css$"
