diff --git a/src/Data/CSS/Preprocessor/Conditions.hs b/src/Data/CSS/Preprocessor/Conditions.hs
--- a/src/Data/CSS/Preprocessor/Conditions.hs
+++ b/src/Data/CSS/Preprocessor/Conditions.hs
@@ -1,7 +1,11 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Evaluates conditional CSS @rules.
+-- Parse a CSS stylesheet to `ConditionalStyles` to evaluate @document & @supports rules.
+-- Call `loadImports` to resolve any @import rules to @media rules.
+-- And call `resolve` to convert into another `StyleSheet` instance whilst resolving @media rules.
 module Data.CSS.Preprocessor.Conditions(
         ConditionalStyles(..), conditionalStyles, ConditionalRule(..),
-        extractImports, resolveImports, loadImports, resolve,
+        extractImports, resolveImports, loadImports, resolve, testIsStyled,
         Datum(..)
     ) where
 
@@ -16,19 +20,29 @@
 import Data.Text.Internal (Text(..))
 import Data.Text (unpack)
 import Network.URI (URI(..), URIAuth(..), parseURI)
+import Control.Concurrent.Async (forConcurrently)
 
 import Data.List
 
+-- | Collects and evaluates conditional at-rules.
 data ConditionalStyles p = ConditionalStyles {
+    -- | The URL to the webpage being styled, for `@document` rules.
     hostURL :: URI,
+    -- | The type of document, `@document domain(...)` rules.
     mediaDocument :: String,
+    -- | Whether the page provided any of it's own styling (valid or not)
+    isUnstyled :: Bool,
+    -- | Queued style rules, to be evaluated later.
     rules :: [ConditionalRule p],
+    -- | PropertyParser to test against for `@supports` rules.
     propertyParser :: p
 }
 
+-- | Constructs an empty `ConditionalStyles`.
 conditionalStyles :: PropertyParser p => URI -> String -> ConditionalStyles p
-conditionalStyles uri mediaDocument' = ConditionalStyles uri mediaDocument' [] temp
+conditionalStyles uri mediaDocument' = ConditionalStyles uri mediaDocument' False [] temp
 
+-- | Style rules that can be queued in a `ConditionalStyles`.
 data ConditionalRule p = Priority Int | StyleRule' StyleRule | AtRule Text [Token] |
     External Query.Expr URI | Internal Query.Expr (ConditionalStyles p)
 
@@ -66,6 +80,10 @@
     addAtRule self "document" (Function "media-document":String match:RightParen:toks)
         | unpack match == mediaDocument self = parseAtBlock self toks
         | otherwise = addAtRule self "document" toks
+    -- Rhapsode-specific: matches if the document didn't provide any of it's own stylings.
+    addAtRule self "document" (Ident "unstyled":toks)
+        | isUnstyled self = parseAtBlock self toks
+        | otherwise = addAtRule self "document" toks
     -- TODO Support regexp() conditions, requires new dependency
     addAtRule self "document" tokens = (self, skipAtRule tokens)
 
@@ -87,6 +105,12 @@
 
     addAtRule self rule tokens = let (block, rest) = scanAtRule tokens in
         (addRule' self $ AtRule rule block, rest)
+
+-- | Flags whether any style rules have been applied yet,
+-- for the sake of evaluating "@document unstyled {...}".
+testIsStyled :: ConditionalStyles p -> ConditionalStyles p
+testIsStyled styles = styles { isUnstyled = null $ rules styles }
+
 --------
 ---- @import/@media
 --------
@@ -97,10 +121,12 @@
         (addRule' self $ External cond uri, toks')
 parseAtImport self _ toks = (self, skipAtRule toks)
 
+-- | Returns `@import` URLs that need to be imported.
 extractImports :: (Text -> Query.Datum) -> (Token -> Query.Datum) -> ConditionalStyles p -> [URI]
 extractImports vars evalToken self =
     [uri | External cond uri <- rules self, Query.eval vars evalToken cond]
 
+-- | Substitutes external values in for `@import` rules.
 resolveImports :: ConditionalStyles p -> [(URI, ConditionalStyles p)] -> ConditionalStyles p
 resolveImports self responses = self {rules = map resolveImport $ rules self}
     where
@@ -108,22 +134,20 @@
             Internal cond body
         resolveImport x = x
 
+-- | Evaluates a given "loader" to resolve any `@import` rules.
 loadImports :: PropertyParser p => (URI -> IO Text) -> (Text -> Query.Datum) -> (Token -> Query.Datum) ->
         ConditionalStyles p -> [URI] -> IO (ConditionalStyles p)
 loadImports loader vars evalToken self blocklist = do
         let imports = extractImports vars evalToken self
-        imported <- loadAll [url | url <- imports, url `notElem` blocklist] Nothing
-        return $ resolveImports self imported
-    where
-        loadAll urls Nothing = loadAll urls $ Just urls
-        loadAll (url:urls) (Just blocklist') = do
+        let urls = [url | url <- imports, url `notElem` blocklist]
+        imported <- forConcurrently urls $ \url -> do
             source <- loader url
             let parsed = parse self {rules = []} source
-            styles <- loadImports loader vars evalToken parsed (blocklist ++ blocklist')
-            rest <- loadAll urls $ Just blocklist'
-            return ((url, styles):rest)
-        loadAll [] _ = return []
+            styles <- loadImports loader vars evalToken parsed (blocklist ++ urls)
+            return (url, styles)
+        return $ resolveImports self imported
 
+-- | Evaluates any media queries, returning a new StyleSheet with the queued operations.
 resolve :: StyleSheet s => (Text -> Query.Datum) -> (Token -> Query.Datum) ->
         s -> ConditionalStyles p -> s
 resolve v t styles self = resolve' v t (reverse $ rules self) styles
diff --git a/src/Data/CSS/Preprocessor/Conditions/Expr.hs b/src/Data/CSS/Preprocessor/Conditions/Expr.hs
--- a/src/Data/CSS/Preprocessor/Conditions/Expr.hs
+++ b/src/Data/CSS/Preprocessor/Conditions/Expr.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Evaluates CSS media queries for @import & @media.
+-- INTERNAL MODULE
 module Data.CSS.Preprocessor.Conditions.Expr(
         Expr, Op(..), parse, parse', eval, Datum(..)
     ) where
@@ -7,16 +9,30 @@
 import Data.Text.Internal (Text(..))
 import Data.Text (stripPrefix)
 
+-- | A parsed (post-order) expression.
 type Expr = [Op]
-data Op = And | Or | Not | Var Text | Tok Token | MkRatio | Func Text [Token]
-    | Less | LessEq | Equal | Greater | GreaterEq deriving (Show, Eq)
+-- | Operators understood by media queries.
+data Op = And -- ^ Is true if both operands are true
+    | Or -- ^ Is true if either operand is true
+    | Not -- ^ Is true if it's operand isn't.
+    | Var Text -- ^ Queries the value of an externally-specified parameter.
+    | Tok Token -- ^ Tokens to be evaluated as specified by caller.
+    | MkRatio -- ^ Pushes a ratio value to stack, for querying screensize.
+    | Less -- ^ Is the left operand smaller than right?
+    | LessEq -- ^ Is the left operand smaller or the same as right?
+    | Equal -- ^ Are the operands the same?
+    | Greater -- ^ Is the left operand bigger than right?
+    | GreaterEq -- ^ Is the left operand bigger or the same as right?
+    deriving (Show, Eq)
 
+-- | Parses a media query to postorder form, returning the tokens after the given delimiter.
 parse :: Token -> [Token] -> (Expr, [Token])
 parse end toks = let (toks', rest) = break (== end) toks in (parse' toks' [], rest)
 
 --------
 ---- Shunting Yard parser
 --------
+-- | Parses a media query to postorder form, given an operator stack.
 parse' :: [Token] -> [(Op, Int)] -> Expr
 parse' (Whitespace:toks) ops = parse' toks ops
 
@@ -55,8 +71,10 @@
 --------
 ---- Shunting Yard Evaluator
 --------
+-- | Dynamic types for evaluating media queries.
 data Datum = B Bool | N Float | Ratio Float Float deriving Eq
 
+-- | Evaluates a media query with the given functions for evaluating vars & tokens.
 eval :: (Text -> Datum) -> (Token -> Datum) -> Expr -> Bool
 eval = eval' []
 
diff --git a/src/Data/CSS/Style.hs b/src/Data/CSS/Style.hs
--- a/src/Data/CSS/Style.hs
+++ b/src/Data/CSS/Style.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Queries computed styles out of a specially-parsed CSS stylesheet.
+-- See in particular `QueryableStyleSheet`, `queryRules`, & `cascade'`.
 module Data.CSS.Style(
         QueryableStyleSheet, QueryableStyleSheet'(..), queryableStyleSheet,
         queryRules,
@@ -21,16 +23,22 @@
 import Data.Text (isPrefixOf)
 import Data.List (elemIndex)
 
+-- | A parsed CSS stylesheet from which you can query styles to match an element.
 type QueryableStyleSheet parser = QueryableStyleSheet' (ImportanceSplitter (
         PropertyExpander parser (OrderedRuleStore (InterpretedRuleStore StyleIndex))
     )) parser
 
+-- | More generic version of `QueryableStyleSheet`.
 data QueryableStyleSheet' store parser = QueryableStyleSheet' {
+    -- | Internal datastructure for efficient style lookup.
     store :: store,
+    -- | The "PropertyParser" to use for property syntax validation.
     parser :: parser,
+    -- | Whether author, useragent, or user styles are currently being parsed.
     priority :: Int -- author vs user agent vs user styles
 }
 
+-- | Constructs an empty QueryableStyleSheet'.
 queryableStyleSheet :: PropertyParser p => QueryableStyleSheet p
 queryableStyleSheet = QueryableStyleSheet' {store = new, parser = temp, priority = 0}
 
@@ -41,14 +49,17 @@
         }
 
 --- Reexpose cascade methods
+-- | Looks up style rules matching the specified element, grouped by psuedoelement.
 queryRules :: (PropertyParser p, RuleStore s) =>
     QueryableStyleSheet' s p -> Element -> HashMap Text [StyleRule']
 queryRules (QueryableStyleSheet' store' _ _) = Cascade.query store'
 
+-- | Selects used property values from the given style rules,
+-- & populates into a new `PropertyParser` inheriting from the one given.
 cascade' :: PropertyParser p => [StyleRule'] -> Props -> p -> p
 cascade' = Cascade.cascade
 
---- Facade for trivial cases
+-- | Facade over `queryRules` & `cascade'` for simple cases you don't care about psuedoelements.
 cascade :: PropertyParser p => QueryableStyleSheet p -> Element -> Props -> p -> p
 cascade self el = cascade' $ lookupDefault [] "" $ queryRules self el
 
@@ -71,6 +82,7 @@
 --------
 ---- var()
 --------
+-- | `PropertyParser` that lowers var() calls before forwarding to another.
 data VarParser a = VarParser {vars :: Props, innerParser :: a}
 
 instance PropertyParser p => PropertyParser (VarParser p) where
diff --git a/src/Data/CSS/Style/Cascade.hs b/src/Data/CSS/Style/Cascade.hs
--- a/src/Data/CSS/Style/Cascade.hs
+++ b/src/Data/CSS/Style/Cascade.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Applies CSS selection, cascade, & inheritance.
+-- INTERNAL MODULE.
 module Data.CSS.Style.Cascade(
         query, cascade,
         TrivialPropertyParser(..), PropertyParser(..), Props
@@ -12,34 +14,43 @@
 import Data.HashMap.Strict
 import Data.Text (unpack, pack, isPrefixOf)
 
+-- | Defines how to parse CSS properties into an output "style" format.
 class PropertyParser a where
+    -- | Default styles.
     temp :: a
+    -- | Creates a style inherited from a parent style.
     inherit :: a -> a
     inherit = id
 
+    -- | Expand a shorthand property into longhand properties.
     shorthand :: a -> Text -> [Token] -> [(Text, [Token])]
     shorthand self key value | Just _ <- longhand self self key value = [(key, value)]
         | otherwise = []
     -- longhand parent self name value
     longhand :: a -> a -> Text -> [Token] -> Maybe a
 
+    -- | Retrieve stored variables, optional.
     getVars :: a -> Props
     getVars _ = []
+    -- | Save variable values, optional.
     setVars :: Props -> a -> a
     setVars _ = id
 
+-- | Gather properties into a hashmap.
 data TrivialPropertyParser = TrivialPropertyParser (HashMap String [Token])
 instance PropertyParser TrivialPropertyParser where
     temp = TrivialPropertyParser empty
     longhand _ (TrivialPropertyParser self) key value =
         Just $ TrivialPropertyParser $ insert (unpack key) value self
 
+-- | "key: value;" entries to be parsed into an output type.
 type Props = [(Text, [Token])]
 
 --------
 ---- Query/Psuedo-elements
 --------
 
+-- | Looks up style rules for an element, grouped by psuedoelement.
 query :: RuleStore s => s -> Element -> HashMap Text [StyleRule']
 query self el = Prelude.foldr yield empty $ lookupRules self el
     where yield rule store = insertWith (++) (psuedoElement rule) [resolveAttr rule el] store
@@ -48,6 +59,8 @@
 ---- Cascade/Inheritance
 --------
 
+-- | Applies cascade for the given `StyleRule'`s & explicit styles,
+-- parsed to a value of the same `PropertyParser` type passed in & inheriting from it.
 cascade :: PropertyParser p => [StyleRule'] -> Props -> p -> p
 cascade styles overrides base =
     construct base $ toList $ cascadeRules (getVars base ++ overrides) styles
diff --git a/src/Data/CSS/Style/Common.hs b/src/Data/CSS/Style/Common.hs
--- a/src/Data/CSS/Style/Common.hs
+++ b/src/Data/CSS/Style/Common.hs
@@ -1,3 +1,5 @@
+-- | Central infrastructure for implementing queryable stylesheets.
+-- NOTE: This internal module isn't intended to be fully documented.
 module Data.CSS.Style.Common(
         RuleStore(..), StyleRule'(..), selector, properties, psuedoElement, styleRule',
         Element(..), Attribute(..),
@@ -10,12 +12,18 @@
 import Data.CSS.Syntax.Tokens
 import Data.Text.Internal (Text(..))
 
+-- | An inversely-linked tree of elements, to apply CSS selectors to.
 data Element = ElementNode {
+    -- | The element's parent in the tree.
     parent :: Maybe Element,
+    -- | The element's previous sibling in the tree.
     previous :: Maybe Element,
+    -- | The element's name.
     name :: Text,
-    attributes :: [Attribute] -- in sorted order.
+    -- | The element's attributes, in sorted order.
+    attributes :: [Attribute]
 }
+-- | A key-value attribute.
 data Attribute = Attribute Text String deriving (Eq, Ord)
 
 class RuleStore a where
diff --git a/src/Data/CSS/Style/Importance.hs b/src/Data/CSS/Style/Importance.hs
--- a/src/Data/CSS/Style/Importance.hs
+++ b/src/Data/CSS/Style/Importance.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Evaluates !important.
+-- INTERNAL MODULE.
 module Data.CSS.Style.Importance (
         ImportanceSplitter(..)
     ) where
@@ -18,6 +20,7 @@
 --- NOTE: Prorities are defined with lower numbers being more important,
 ---     so negate to be consistant with other priority sources.
 --- This API decision started out being accidental, but I find it more intuitive.
+-- | Evaluates "!important" by splitting all `StyleRule'` in two.
 data ImportanceSplitter a = ImportanceSplitter a
 instance RuleStore inner => RuleStore (ImportanceSplitter inner) where
     new = ImportanceSplitter new
diff --git a/src/Data/CSS/Style/Selector/Index.hs b/src/Data/CSS/Style/Selector/Index.hs
--- a/src/Data/CSS/Style/Selector/Index.hs
+++ b/src/Data/CSS/Style/Selector/Index.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Fast lookup & storage for style rules.
+-- INTERNAL MODULE.
 module Data.CSS.Style.Selector.Index (
         StyleIndex(..),
         rulesForElement
@@ -13,6 +15,7 @@
 import Data.Text (unpack, pack)
 import Data.CSS.Syntax.Tokens (serialize) -- for easy hashing
 
+-- | Fast lookup & storage for style rules.
 data StyleIndex = StyleIndex {
     indexed :: HashMap SimpleSelector [StyleRule'],
     unindexed :: [StyleRule']
@@ -31,6 +34,7 @@
             index = indexed self
             rules = unindexed self : Prelude.map get (testsForElement element)
 
+-- | LEGACY TESTING API.
 rulesForElement :: StyleIndex -> Element -> [StyleRule] -- For testing
 rulesForElement self element = Prelude.map inner $ lookupRules self element
 
diff --git a/src/Data/CSS/Style/Selector/Interpret.hs b/src/Data/CSS/Style/Selector/Interpret.hs
--- a/src/Data/CSS/Style/Selector/Interpret.hs
+++ b/src/Data/CSS/Style/Selector/Interpret.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Evaluates CSS selectors over an element.
+-- INTERNAL MODULE.
 module Data.CSS.Style.Selector.Interpret(
         compile, SelectorFunc,
         InterpretedRuleStore(..)
@@ -10,9 +12,11 @@
 import Data.List
 import Data.Maybe
 
+-- | A compiled(?) CSS selector.
 type SelectorFunc = Element -> Bool
 type AttrsFunc = [Attribute] -> Bool
 
+-- | Converts a parsed CSS selector into a callable function.
 compile :: Selector -> SelectorFunc
 compile (Element sel) = compileInner sel
 compile (Child upSel sel) = direct parent (compile upSel) $ compileInner sel
@@ -88,6 +92,7 @@
 --------
 ---- RuleStore wrapper
 --------
+-- | Compiles & fully evaluates CSS selectors.
 data InterpretedRuleStore inner = InterpretedRuleStore inner
 instance RuleStore inner => RuleStore (InterpretedRuleStore inner) where
     new = InterpretedRuleStore new
diff --git a/src/Data/CSS/Style/Selector/Specificity.hs b/src/Data/CSS/Style/Selector/Specificity.hs
--- a/src/Data/CSS/Style/Selector/Specificity.hs
+++ b/src/Data/CSS/Style/Selector/Specificity.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Sorts `StyleRule'`s by specificity.
+-- INTERNAL MODULE.
 module Data.CSS.Style.Selector.Specificity(
         OrderedRuleStore(..)
     ) where
@@ -27,6 +29,7 @@
 add :: Vec -> Vec -> Vec
 add (a, b, c) (x, y, z) = (a + x, b + y, c + z)
 
+-- | Sorts `StyleRule'`s by their selector specificity.
 data OrderedRuleStore inner = OrderedRuleStore inner Int
 
 instance RuleStore inner => RuleStore (OrderedRuleStore inner) where
diff --git a/src/Data/CSS/Syntax/Selector.hs b/src/Data/CSS/Syntax/Selector.hs
--- a/src/Data/CSS/Syntax/Selector.hs
+++ b/src/Data/CSS/Syntax/Selector.hs
@@ -1,3 +1,5 @@
+-- | Parses CSS selectors
+-- See `parseSelectors`
 module Data.CSS.Syntax.Selector(
         Selector(..), SimpleSelector(..), PropertyTest(..),
         parseSelectors
@@ -8,18 +10,31 @@
 
 import Data.Text.Internal (Text(..))
 
--- type Selector = [SimpleSelector]
-data Selector = Element [SimpleSelector] |
-    Child Selector [SimpleSelector] | Descendant Selector [SimpleSelector] |
-    Adjacent Selector [SimpleSelector] | Sibling Selector [SimpleSelector]
+-- | A CSS "selector" indicating which elements should be effected by CSS.
+data Selector = Element [SimpleSelector] -- ^ Selects a single element.
+    | Child Selector [SimpleSelector] -- ^ Represents "a > b" operator.
+    | Descendant Selector [SimpleSelector] -- ^ Represents "a b" operator.
+    | Adjacent Selector [SimpleSelector] -- ^ Represents "a + b" operator.
+    | Sibling Selector [SimpleSelector] -- ^ Represents "a ~ b" operator.
     deriving (Show, Eq)
-data SimpleSelector = Tag Text | Id Text | Class Text | Property Text PropertyTest |
-    Psuedoclass Text [Token]
+-- | An individual test comprising a CSS stylesheet.
+data SimpleSelector = Tag Text -- ^ Matches a tagname, e.g. "a"
+    | Id Text -- ^ Matches the "id" attribute, e.g. "#header"
+    | Class Text -- ^ Matches the "class" attribute, e.g. ".ad"
+    | Property Text PropertyTest -- ^ Matches a specified property
+    | Psuedoclass Text [Token] -- ^ Matches psuedoclasses provided by the caller (via a nameless property).
     deriving (Show, Eq)
-data PropertyTest = Exists | Equals Text | Suffix Text | Prefix Text | Substring Text |
-    Include Text | Dash Text
+-- | How should a property be matched.
+data PropertyTest = Exists -- ^ Matches whether an attribute actually exists, e.g. "[title]"
+    | Equals Text -- ^ Matches whether the attribute is exactly equal to the value, e.g. "="
+    | Suffix Text -- ^ Matches whether attribute ends with the given value, e.g. "$="
+    | Prefix Text -- ^ Matches whether attribute starts with the given value, e.g. "^="
+    | Substring Text -- ^ Matches whether the attribute contains the given value, e.g. "*="
+    | Include Text -- ^ Is one of the whitespace-seperated values the one specified? e.g. "~="
+    | Dash Text -- ^ Matches whitespace seperated values, or their "-"-seperated prefixes. e.g. "|="
     deriving (Show, Eq)
 
+-- | Parses a CSS selector.
 parseSelectors :: Parser [Selector]
 parseSelectors tokens = concatP (:) parseCompound parseSelectorsTail $ skipSpace tokens
 parseSelectorsTail :: Parser [Selector]
diff --git a/src/Data/CSS/Syntax/StyleSheet.hs b/src/Data/CSS/Syntax/StyleSheet.hs
--- a/src/Data/CSS/Syntax/StyleSheet.hs
+++ b/src/Data/CSS/Syntax/StyleSheet.hs
@@ -1,4 +1,6 @@
 {-# LANGUAGE OverloadedStrings #-}
+-- | Parses a CSS stylesheet
+-- See `StyleSheet` & `parseForURL`.
 module Data.CSS.Syntax.StyleSheet (
         parse, parse', parseForURL, TrivialStyleSheet(..),
         StyleSheet(..), skipAtRule, scanAtRule, scanBlock, skipSpace,
@@ -20,20 +22,28 @@
 --------
 ---- Output type class
 --------
+-- | Describes how to store, and to some extent parse, CSS stylesheets.
+-- These methods are used to construct the results from `parse`, etc.
 class StyleSheet s where
+    -- | Sets the stylesheet priority (useragent vs user vs author), optional.
     setPriority :: Int -> s -> s
     setPriority _ = id
+    -- | Stores a parsed selector+properties rule.
     addRule :: s -> StyleRule -> s
+    -- | Stores and parses an identified at-rule.
     addAtRule :: s -> Text -> [Token] -> (s, [Token])
     addAtRule self _ tokens = (self, skipAtRule tokens)
 
+-- | Stores the parsed selector*s*+proeprties rule.
 addRules :: StyleSheet ss => ss -> ([Selector], ([(Text, [Token])], Text)) -> ss
 addRules self (selector:selectors, val@(props, psuedoel)) = addRules self' (selectors, val)
     where self' = addRule self $ StyleRule selector props psuedoel
 addRules self ([], _) = self
 
+-- | The properties to set for elements matching the given selector.
 data StyleRule = StyleRule Selector [(Text, [Token])] Text deriving (Show, Eq)
 
+-- | Gathers StyleRules into a list, mainly for testing.
 data TrivialStyleSheet = TrivialStyleSheet [StyleRule] deriving (Show, Eq)
 instance StyleSheet TrivialStyleSheet where
     addRule (TrivialStyleSheet self) rule = TrivialStyleSheet $ rule:self
@@ -41,9 +51,11 @@
 --------
 ---- Basic parsing
 --------
+-- | Parse a CSS stylesheet
 parse :: StyleSheet s => s -> Text -> s
 parse stylesheet source = parse' stylesheet $ tokenize source
 
+-- | Parse a CSS stylesheet, resolving all URLs to absolute form.
 parseForURL :: StyleSheet s => s -> URI -> Text -> s
 parseForURL stylesheet base source = parse' stylesheet $ rewriteURLs $ tokenize source
     where
@@ -54,6 +66,7 @@
         rewriteURLs (tok:toks) = tok : rewriteURLs toks
         rewriteURLs [] = []
 
+-- | Parse a tokenized (via `css-syntax`) CSS stylesheet
 parse' :: StyleSheet t => t -> [Token] -> t
 -- Things to skip.
 parse' stylesheet (Whitespace:tokens) = parse' stylesheet tokens
@@ -71,6 +84,7 @@
 --------
 ---- Property parsing
 --------
+-- | Parse "{key: value; ...}" property values, with a psuedoelement.
 parseProperties :: Parser ([(Text, [Token])], Text)
 parseProperties (LeftCurlyBracket:tokens) = noPsuedoel $ parseProperties' tokens
 parseProperties (Whitespace:tokens) = parseProperties tokens
@@ -83,6 +97,7 @@
 noPsuedoel :: (x, y) -> ((x, Text), y)
 noPsuedoel (val, tokens) = ((val, ""), tokens)
 
+-- | Parse "key: value;"... property values, as per the HTML "style" property.
 parseProperties' :: Parser [(Text, [Token])]
 parseProperties' (Whitespace:tokens) = parseProperties' tokens
 parseProperties' (Ident name:tokens)
@@ -96,6 +111,7 @@
 --------
 ---- Skipping/Scanning utilities
 --------
+-- | Returns tokens before & after an at-rule value, terminated after a curly-bracketed block or a semicolon.
 scanAtRule :: Parser [Token]
 scanAtRule (Semicolon:tokens) = ([Semicolon], tokens)
 scanAtRule tokens@(LeftCurlyBracket:_) = scanInner tokens $ \rest -> ([], rest)
@@ -110,9 +126,11 @@
 
 scanAtRule tokens = capture scanAtRule tokens
 
+-- | Returns tokens after an at-rule, as per `scanAtRule`.
 skipAtRule :: [Token] -> [Token]
 skipAtRule tokens = snd $ scanAtRule tokens
 
+-- | Returns tokens before & after a semicolon.
 scanValue :: Parser [Token]
 scanValue (Semicolon:tokens) = ([], tokens)
 scanValue (Whitespace:tokens) = scanValue tokens
@@ -128,5 +146,6 @@
 
 scanValue tokens = capture scanValue tokens
 
+-- | Returns tokens after a semicolon.
 skipValue :: [Token] -> [Token]
 skipValue tokens = snd $ scanValue tokens
diff --git a/src/Data/CSS/Syntax/StylishUtil.hs b/src/Data/CSS/Syntax/StylishUtil.hs
--- a/src/Data/CSS/Syntax/StylishUtil.hs
+++ b/src/Data/CSS/Syntax/StylishUtil.hs
@@ -1,3 +1,4 @@
+-- | Utility parser combinators for parsing CSS stylesheets.
 module Data.CSS.Syntax.StylishUtil(
         concatP, capture, skipSpace,
         scanBlock, skipBlock, scanInner,
@@ -6,22 +7,28 @@
 
 import Data.CSS.Syntax.Tokens
 
+-- | A simple parser combinator type.
 type Parser x = [Token] -> (x, [Token])
+
+-- | Chains two parser combinators together.
 concatP :: (a -> b -> c) -> Parser a -> Parser b -> Parser c
 concatP join left right tokens = (join x y, remainder)
     where
         (x, tokens') = left tokens
         (y, remainder) = right tokens'
 
+-- | "captures" the token being parsed into the returned output.
 capture :: Parser [Token] -> Parser [Token]
 capture cb (token:tokens) = (token:captured, tokens')
    where (captured, tokens') = cb tokens
 capture _ [] = ([], [])
 
+-- | Removes preceding `Whitespace` tokens.
 skipSpace :: [Token] -> [Token]
 skipSpace (Whitespace:tokens) = skipSpace tokens
 skipSpace tokens = tokens
 
+-- | Returns tokens until the next unbalanced closing brace.
 scanBlock :: Parser [Token]
 -- TODO assert closing tags are correct
 --    But what should the error recovery be?
@@ -36,9 +43,11 @@
 
 scanBlock tokens = capture scanBlock tokens
 
+-- | Returns tokens after the next unbalanced closing brace.
 skipBlock :: [Token] -> [Token]
 skipBlock tokens = snd $ scanBlock tokens
 
+-- | Parses a block followed by the given combinator, returning the tokens the matched.
 scanInner :: [Token] -> Parser [Token] -> ([Token], [Token])
 scanInner (token:tokens) cb = concatP gather scanBlock cb tokens
     where gather x y = token : x ++ y
diff --git a/stylist.cabal b/stylist.cabal
--- a/stylist.cabal
+++ b/stylist.cabal
@@ -10,7 +10,7 @@
 -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             1.1.1.0
+version:             1.2.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            Apply CSS styles to a document tree.
@@ -66,7 +66,7 @@
   -- Other library packages from which modules are imported.
   build-depends:       base >=4.9 && <=4.12, css-syntax >=0.1 && <0.2, text,
                         unordered-containers >= 0.2 && <0.3, hashable,
-                        network-uri >= 2.6 && <2.7
+                        network-uri >= 2.6 && <2.7, async >= 2.1 && <2.3
   
   -- Directories containing source files.
   hs-source-dirs:      src
@@ -84,6 +84,6 @@
   other-modules:        Data.CSS.Syntax.StyleSheet, Data.CSS.Syntax.Selector, Data.CSS.Style
   build-depends:       base >=4.9 && <=4.12, css-syntax >=0.1 && <0.2, text,
                         unordered-containers >= 0.2 && <0.3, hashable,
-                        network-uri >= 2.6 && <2.7, hspec, QuickCheck,
+                        network-uri >= 2.6 && <2.7, async >= 2.1 && <2.3, hspec, QuickCheck,
                         scientific >= 0.3 && <1.0
   ghc-options: -Wall
