diff --git a/clay.cabal b/clay.cabal
--- a/clay.cabal
+++ b/clay.cabal
@@ -1,5 +1,5 @@
 Name:     clay
-Version:  0.12.2
+Version:  0.12.3
 Synopsis: CSS preprocessor as embedded Haskell.
 Description:
   Clay is a CSS preprocessor like LESS and Sass, but implemented as an embedded
@@ -43,6 +43,7 @@
     Clay.Border
     Clay.Box
     Clay.Color
+    Clay.Comments
     Clay.Common
     Clay.Dynamic
     Clay.Display
diff --git a/src/Clay.hs b/src/Clay.hs
--- a/src/Clay.hs
+++ b/src/Clay.hs
@@ -22,6 +22,10 @@
 
 , (-:)
 
+-- ** Comments
+-- $comments
+, commenting
+
 -- * The selector language.
 
 , Selector
@@ -69,8 +73,12 @@
 
 , fontFace
 
--- * Import other CSS files
+-- * !important
 
+, important
+
+-- * Import other CSS files
+
 , importUrl
 
 -- * Pseudo elements and classes.
@@ -138,6 +146,7 @@
 import Clay.Box
 import Clay.Color
 import Clay.Time
+import Clay.Comments (commenting)
 import Clay.Common
 import Clay.Display    hiding (table)
 import Clay.Dynamic
@@ -160,3 +169,19 @@
 -- Because a large part of the names export by "Clay.Media" clash with names
 -- export by other modules we don't re-export it here and recommend you to
 -- import the module qualified.
+
+-- $comments
+--
+-- It is occasionally useful to output comments in the generated css.
+-- 'commenting' appends comments (surrounded by '@ /* @' and '@ */@') to the
+-- values of the supplied 'Css' as
+--
+-- > key: value /* comment */;
+--
+-- Placing the comments before the semicolon ensures they are obviously
+-- grouped with the preceding value when rendered compactly.
+--
+-- Note that /every/ generated line in the generated content will feature the
+-- comment. 
+--
+-- An empty comment generates '@/*  */@'.
diff --git a/src/Clay/Box.hs b/src/Clay/Box.hs
--- a/src/Clay/Box.hs
+++ b/src/Clay/Box.hs
@@ -3,7 +3,17 @@
 ( BoxType
 , paddingBox, borderBox, contentBox
 , boxSizing
+-- * @box-shadow@
+-- $box-shadow
 , boxShadow
+, shadow
+, shadowWithBlur
+, shadowWithSpread
+, bsInset
+, bsColor
+-- ** Deprecated
+-- $box-shadow-deprecated
+, boxShadow'
 , boxShadowWithSpread
 , boxShadows
 , insetBoxShadow
@@ -11,6 +21,7 @@
 where
 
 import Data.Monoid
+import Data.List.NonEmpty (NonEmpty)
 
 import Clay.Color
 import Clay.Common
@@ -37,17 +48,127 @@
 
 -------------------------------------------------------------------------------
 
-boxShadow :: Size a -> Size a -> Size a -> Color -> Css
-boxShadow x y w c = prefixed (browsers <> "box-shadow") (x ! y ! w ! c)
+-- $box-shadow
+--
+-- === Formal argument syntax
+--
+-- > none | <shadow>#
+-- > where 
+-- > <shadow> = inset? && <length>{2,4} && <color>?
+-- > 
+-- > where 
+-- > <color> = <rgb()> | <rgba()> | <hsl()> | <hsla()> | <hex-color> | <named-color> | currentcolor | <deprecated-system-color>
+-- > 
+-- > where 
+-- > <rgb()> = rgb( [ [ <percentage>{3} | <number>{3} ] [ / <alpha-value> ]? ] | [ [ <percentage>#{3} | <number>#{3} ] , <alpha-value>? ] )
+-- > <rgba()> = rgba( [ [ <percentage>{3} | <number>{3} ] [ / <alpha-value> ]? ] | [ [ <percentage>#{3} | <number>#{3} ] , <alpha-value>? ] )
+-- > <hsl()> = hsl( [ <hue> <percentage> <percentage> [ / <alpha-value> ]? ] | [ <hue>, <percentage>, <percentage>, <alpha-value>? ] )
+-- > <hsla()> = hsla( [ <hue> <percentage> <percentage> [ / <alpha-value> ]? ] | [ <hue>, <percentage>, <percentage>, <alpha-value>? ] )
+-- > 
+-- > where 
+-- > <alpha-value> = <number> | <percentage>
+-- > <hue> = <number> | <angle>
 
+newtype BoxShadow = BoxShadow Value
+  deriving (Val, Inherit, Initial, Unset, None, Other)
+
+-- | This function will usually take a singleton list, but requiring a (non-empty)
+-- list prevents accidentally applying the modifiers ('bsInset', 'bsColor')
+-- incorrectly.
+--
+-- 'pure' (from "Control.Applicative") creates a singleton list.
+--
+-- > boxShadow . pure $ none
+-- > boxShadow . pure $ shadow (px 1) (px 1)
+--
+-- Use with @{-# LANGUAGE OverloadedLists #-}@ for the simplest list syntax.
+--
+-- > boxShadow [none]
+-- > boxShadow [shadow (px 1) (px 1)]
+--
+-- This is recommended for supplying multiple 'BoxShadow' values.
+--
+-- > boxShadow [shadowWithBlur (em 2) (em 1), bsInset . bsColor red $ shadow (px 1) (px 2)]
+boxShadow :: NonEmpty BoxShadow -> Css
+boxShadow = prefixed (browsers <> "box-shadow") . value
+
+shadow
+  :: Size a -- ^ Horizontal offset
+  -> Size a -- ^ Vertical offset
+  -> BoxShadow
+shadow x y = BoxShadow . value $ (x ! y)
+
+shadowWithBlur
+  :: Size a -- ^ Horizontal offset
+  -> Size a -- ^ Vertical offset
+  -> Size a -- ^ Blur radius
+  -> BoxShadow
+shadowWithBlur x y w = BoxShadow . value $ (x ! y ! w)
+
+-- | While this function is the correct type to work with the 'sym', 'sym2'
+-- or 'sym3' functions, such applications are unlikely to be meaningful.
+shadowWithSpread
+  :: Size a -- ^ Horizontal offset
+  -> Size a -- ^ Vertical offset
+  -> Size a -- ^ Blur radius
+  -> Size a -- ^ Spread radius
+  -> BoxShadow
+shadowWithSpread x y blurRadius spreadRadius =
+    BoxShadow . value $ (x ! y ! blurRadius ! spreadRadius)
+
+-- | Adapt the provided @box-shadow@ with the @inset@ prefix.
+-- 
+-- > boxShadow . pure . bsInset
+bsInset :: BoxShadow -> BoxShadow
+bsInset (BoxShadow v) = BoxShadow . value $ ("inset" :: Value, v)
+
+-- | Supply a color to the provided @box-shadow@.
+bsColor :: Color -> BoxShadow -> BoxShadow
+bsColor c (BoxShadow v) = BoxShadow . value $ (v, c)
+infixr 9 `bsColor`
+
+-------------------------------------------------------------------------------
+
+-- $box-shadow-deprecated
+--
+-- The old implementation was both restrictive and slightly off-spec. It
+-- shall be discontinued in a future release. The 'boxShadow' name has already
+-- been taken, so the functionality that used to provide is now provided by
+-- 'boxShadow\''.
+
+-- | This is the drop-in replacement for the old 'boxShadow' function (< 0.13).
+-- It is possible to continue for now
+boxShadow' :: Size a -> Size a -> Size a -> Color -> Css
+boxShadow' x y w c = prefixed (browsers <> "box-shadow") (x ! y ! w ! c)
+{-# DEPRECATED boxShadow' "This function is only present for compatibility purposes and will be removed." #-}
+
+-- | Replace calls to this function as follows (using -XOverloadedLists)
+--
+-- > boxShadowWithSpread x y rb rs c
+--
+-- > boxShadow [c `bsColor` shadowWithSpread x y rb rs]
 boxShadowWithSpread :: Size a -> Size a -> Size a -> Size a -> Color -> Css
 boxShadowWithSpread x y blurRadius spreadRadius color =
     prefixed (browsers <> "box-shadow") (x ! y ! blurRadius ! spreadRadius ! color)
+{-# DEPRECATED boxShadowWithSpread "This function has been replaced with shadowWithSpread and bsColor and will be removed." #-}
 
+-- | Replace calls to this function as follows (using -XOverloadedLists)
+--
+-- > boxShadows [(x1, y1, rb1, c1), (x2, y2, rb2, c2)]
+--
+-- > boxShadow
+-- >   [ c1 `bsColor` shadowWithBlur x1 y1 rb1
+-- >   , c2 `bsColor` shadowWithBlur x2 y2 rb2
+-- >   ]
 boxShadows :: [(Size a, Size a, Size a, Color)] -> Css
 boxShadows = prefixed (browsers <> "box-shadow") . map (\(a, b, c, d) -> a ! b ! c ! d)
-
--------------------------------------------------------------------------------
+{-# DEPRECATED boxShadows "This function is replaced with boxShadow and will be removed." #-}
 
+-- | Replace calls to this function as follows (using -XOverloadedLists)
+--
+-- > insetBoxShadow s x y rb c
+--
+-- > boxShadow [bsInset $ c `bsColor` shadowWithBlur x y rb]
 insetBoxShadow :: Stroke -> Size a -> Size a -> Size a -> Color -> Css
 insetBoxShadow x y w c z = prefixed (browsers <> "box-shadow") (x ! y ! w ! c ! z)
+{-# DEPRECATED insetBoxShadow "This function has been replaced with shadowWithSpread, bsInset and bsColor and will be removed." #-}
diff --git a/src/Clay/Comments.hs b/src/Clay/Comments.hs
new file mode 100644
--- /dev/null
+++ b/src/Clay/Comments.hs
@@ -0,0 +1,30 @@
+{-# LANGUAGE ViewPatterns #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Clay.Comments where
+
+import Data.Monoid ((<>))
+import Data.Maybe (isNothing)
+import Data.List (partition)
+
+import Clay.Stylesheet
+
+-- | Annotate the supplied 'Css' with the supplied comment.
+-- Comments work with 'OverloadedStrings'. This will annotate every non-nested
+-- value.
+commenting :: CommentText -> Css -> Css
+commenting c css = foldMap (rule . addComment c) $ runS css
+infixl 3 `commenting`
+
+-- The last case indicates there may be something wrong in the typing, as
+-- it shouldn't be possible to comment a wrong rule. In practice, this implementation
+-- means only the directly applied property rule is affected, i.e. no nested
+-- rules. That could be changed by adding recursive cases.
+addComment :: CommentText -> Rule -> Rule
+addComment c (Property (PartitionComments xs (Just cs)) k v) = let c1 = Comment $ cs <> "; " <> c in
+  Property (c1 : xs) k v
+addComment c (Property ms k v  ) = Property (Comment c : ms) k v
+addComment _ r                   = r
+
+pattern PartitionComments :: [Modifier] -> Maybe CommentText -> [Modifier]
+pattern PartitionComments xs cs <- (fmap (foldMap _Comment) . partition (isNothing . _Comment) -> (xs, cs))
diff --git a/src/Clay/FontFace.hs b/src/Clay/FontFace.hs
--- a/src/Clay/FontFace.hs
+++ b/src/Clay/FontFace.hs
@@ -16,13 +16,20 @@
 
 -------------------------------------------------------------------------------
 
-data FontFaceFormat = WOFF | TrueType | OpenType | EmbeddedOpenType | SVG
+data FontFaceFormat
+  = WOFF
+  | WOFF2
+  | TrueType
+  | OpenType
+  | EmbeddedOpenType
+  | SVG
   deriving Show
 
 -- | name of format according to CSS specification
 formatName :: FontFaceFormat -> Text
 formatName format = case format of
   WOFF             -> "woff"
+  WOFF2            -> "woff2"
   TrueType         -> "truetype"
   OpenType         -> "opentype"
   EmbeddedOpenType -> "embedded-opentype"
diff --git a/src/Clay/Property.hs b/src/Clay/Property.hs
--- a/src/Clay/Property.hs
+++ b/src/Clay/Property.hs
@@ -5,6 +5,7 @@
 import Control.Monad.Writer
 import Data.Fixed (Fixed, HasResolution (resolution), showFixed)
 import Data.List (partition, sort)
+import Data.List.NonEmpty (NonEmpty, toList)
 import Data.Maybe
 import Data.String
 import Data.Text (Text, replace)
@@ -92,16 +93,19 @@
   value (Right a) = value a
 
 instance Val a => Val [a] where
-  value xs = intersperse "," (map value xs)
+  value xs = intercalate "," (map value xs)
 
-intersperse :: Monoid a => a -> [a] -> a
-intersperse _ []     = mempty
-intersperse s (x:xs) = foldl (\a b -> a <> s <> b) x xs
+instance Val a => Val (NonEmpty a) where
+  value = value . toList
 
+intercalate :: Monoid a => a -> [a] -> a
+intercalate _ []     = mempty
+intercalate s (x:xs) = foldl (\a b -> a <> s <> b) x xs
+
 -------------------------------------------------------------------------------
 
 noCommas :: Val a => [a] -> Value
-noCommas xs = intersperse " " (map value xs)
+noCommas xs = intercalate " " (map value xs)
 
 infixr !
 
diff --git a/src/Clay/Pseudo.hs b/src/Clay/Pseudo.hs
--- a/src/Clay/Pseudo.hs
+++ b/src/Clay/Pseudo.hs
@@ -3,8 +3,11 @@
 
 import Data.Text (Text)
 
+import Clay.Render (renderSelector)
 import Clay.Selector
 
+import qualified Data.Text.Lazy as Lazy
+
 -- List of specific pseudo classes, from:
 -- https://developer.mozilla.org/en-US/docs/CSS/Pseudo-classes
 
@@ -53,11 +56,13 @@
 target        = ":target"
 valid         = ":valid"
 
-lang, nthChild, nthLastChild, nthLastOfType, nthOfType, not :: Text -> Refinement
+lang, nthChild, nthLastChild, nthLastOfType, nthOfType :: Text -> Refinement
 
 lang          n = func "lang"             [n]
 nthChild      n = func "nth-child"        [n]
 nthLastChild  n = func "nth-last-child"   [n]
 nthLastOfType n = func "nth-last-of-type" [n]
 nthOfType     n = func "nth-of-type"      [n]
-not           n = func "not"              [n]
+
+not :: Selector -> Refinement
+not r = func "not" [Lazy.toStrict (renderSelector r)]
diff --git a/src/Clay/Render.hs b/src/Clay/Render.hs
--- a/src/Clay/Render.hs
+++ b/src/Clay/Render.hs
@@ -8,12 +8,12 @@
 , putCss
 , renderWith
 , renderSelector
+, withBanner
 )
 where
 
 import           Control.Applicative
 import           Control.Monad.Writer
-import           Data.Either
 import           Data.Foldable          (foldMap)
 import           Data.List              (sort)
 import           Data.Maybe
@@ -43,6 +43,7 @@
   , warn           :: Bool
   , align          :: Bool
   , banner         :: Bool
+  , comments       :: Bool
   }
 
 -- | Configuration to print to a pretty human readable CSS output.
@@ -58,6 +59,7 @@
   , warn           = True
   , align          = True
   , banner         = True
+  , comments       = True
   }
 
 -- | Configuration to print to a compacted unreadable CSS output.
@@ -73,6 +75,7 @@
   , warn           = False
   , align          = False
   , banner         = False
+  , comments       = False
   }
 
 -- | Configuration to print to a compacted unreadable CSS output for embedding inline with HTML.
@@ -88,6 +91,7 @@
   , warn           = False
   , align          = False
   , banner         = False
+  , comments       = False
   }
 
 -- | Render to CSS using the default configuration (`pretty`) and directly
@@ -121,10 +125,12 @@
 
 renderBanner :: Config -> Lazy.Text -> Lazy.Text
 renderBanner cfg
-  | banner cfg = (<> b)
+  | banner cfg = withBanner
   | otherwise  = id
-  where b = "\n/* Generated with Clay, http://fvisser.nl/clay */"
 
+withBanner :: Lazy.Text -> Lazy.Text
+withBanner = (<> "\n/* Generated with Clay, http://fvisser.nl/clay */")
+
 kframe :: Config -> Keyframes -> Builder
 kframe cfg (Keyframes ident xs) =
   foldMap
@@ -199,18 +205,18 @@
   , (\(a, b) -> rules  cfg (a : sel) b) `foldMap` mapMaybe nested  rs
   , (\(a, b) -> query  cfg  a   sel  b) `foldMap` mapMaybe queries rs
   ]
-  where property (Property k v) = Just (k, v)
-        property _              = Nothing
-        nested   (Nested a ns ) = Just (a, ns)
-        nested   _              = Nothing
-        queries  (Query q ns  ) = Just (q, ns)
-        queries  _              = Nothing
-        kframes  (Keyframe fs ) = Just fs;
-        kframes  _              = Nothing
-        faces    (Face ns     ) = Just ns
-        faces    _              = Nothing
-        imports  (Import i    ) = Just i
-        imports  _              = Nothing
+  where property (Property m k v) = Just (m, k, v)
+        property _                = Nothing
+        nested   (Nested a ns   ) = Just (a, ns)
+        nested   _                = Nothing
+        queries  (Query q ns    ) = Just (q, ns)
+        queries  _                = Nothing
+        kframes  (Keyframe fs   ) = Just fs;
+        kframes  _                = Nothing
+        faces    (Face ns       ) = Just ns
+        faces    _                = Nothing
+        imports  (Import i      ) = Just i
+        imports  _                = Nothing
 
 imp :: Config -> Text -> Builder
 imp cfg t =
@@ -220,8 +226,10 @@
     , ");"
     , newline cfg ]
 
+-- | A key-value pair with associated comment.
+type KeyVal = ([Modifier], Key (), Value)
 
-rule :: Config -> [App] -> [(Key (), Value)] -> Builder
+rule :: Config -> [App] -> [KeyVal] -> Builder
 rule _   _   []    = mempty
 rule cfg sel props =
   let xs = collect =<< props
@@ -245,36 +253,50 @@
     Pop        i -> merger (drop i (x:xs))
     Self       f -> case xs of [] -> star `with` f; _ -> merger xs `with` f
 
-collect :: (Key (), Value) -> [Either Text (Text, Text)]
-collect (Key ky, Value vl) =
-  case (ky, vl) of
+data Representation
+  = Warning Text
+  | KeyValRep [Modifier] Text Text
+  deriving (Show)
+
+keys :: [Representation] -> [Text]
+keys = mapMaybe f
+  where
+    f (KeyValRep _ k _) = Just k
+    f _                 = Nothing
+
+collect :: KeyVal -> [Representation]
+collect (ms, Key ky, Value vl) = case (ky, vl) of
     ( Plain    k  , Plain    v  ) -> [prop k v]
     ( Prefixed ks , Plain    v  ) -> flip map ks $ \(p, k) -> prop (p <> k) v
     ( Plain    k  , Prefixed vs ) -> flip map vs $ \(p, v) -> prop k (p <> v)
-    ( Prefixed ks , Prefixed vs ) -> flip map ks $ \(p, k) -> (Left (p <> k) `maybe` (prop (p <> k) . mappend p)) (lookup p vs)
-  where prop k v = Right (k, v)
+    ( Prefixed ks , Prefixed vs ) -> flip map ks $ \(p, k) -> (Warning (p <> k) `maybe` (prop (p <> k) . mappend p)) (lookup p vs)
+  where prop k v = KeyValRep ms k v
 
-properties :: Config -> [Either Text (Text, Text)] -> Builder
+properties :: Config -> [Representation] -> Builder
 properties cfg xs =
-  let width     = 1 + maximum (Text.length . fst <$> rights xs)
+  let width     = 1 + maximum (Text.length <$> keys xs)
       ind       = indentation cfg
       new       = newline cfg
       finalSemi = if finalSemicolon cfg then ";" else ""
-   in (<> new) $ (<> finalSemi) $ intersperse (";" <> new) $ flip map xs $ \p ->
+   in (<> new) $ (<> finalSemi) $ intercalate (";" <> new) $ flip map xs $ \p ->
         case p of
-          Left w -> if warn cfg
+          Warning w -> if warn cfg
                     then ind <> "/* no value for " <> fromText w <> " */" <> new
                     else mempty
-          Right (k, v) ->
+          KeyValRep ms k v ->
             let pad = if align cfg
                       then fromText (Text.replicate (width - Text.length k) " ")
                       else ""
-             in mconcat [ind, fromText k, pad, ":", sep cfg, fromText v]
+                imptant = maybe "" ((" " <>) . fromText) . foldMap _Important $ ms
+                comm = case (foldMap _Comment ms, comments cfg) of
+                  (Just c, True) -> " /* " <> fromText (unCommentText c) <> " */"
+                  _              -> mempty
+             in mconcat [ind, fromText k, pad, ":", sep cfg, fromText v, imptant, comm]
 
 selector :: Config -> Selector -> Builder
 selector Config { lbrace = "", rbrace = "" } = rec
   where rec _ = ""
-selector cfg = intersperse ("," <> newline cfg) . rec
+selector cfg = intercalate ("," <> newline cfg) . rec
   where rec (In (SelectorF (Refinement ft) p)) = (<> foldMap predicate (sort ft)) <$>
           case p of
             Star           -> if null ft then ["*"] else [""]
@@ -298,6 +320,6 @@
     AttrSpace    a v -> [ "[" , fromText a, "~='", fromText v, "']"                    ]
     AttrHyph     a v -> [ "[" , fromText a, "|='", fromText v, "']"                    ]
     Pseudo       a   -> [ ":" , fromText a                                             ]
-    PseudoFunc   a p -> [ ":" , fromText a, "(", intersperse "," (map fromText p), ")" ]
+    PseudoFunc   a p -> [ ":" , fromText a, "(", intercalate "," (map fromText p), ")" ]
     PseudoElem   a   -> [ "::", fromText a                                             ]
 
diff --git a/src/Clay/Selector.hs b/src/Clay/Selector.hs
--- a/src/Clay/Selector.hs
+++ b/src/Clay/Selector.hs
@@ -157,13 +157,13 @@
   deriving (Eq, Ord, Show)
 
 newtype Refinement = Refinement { unFilter :: [Predicate] }
-  deriving Show
+  deriving (Show, Monoid)
 
 instance IsString Refinement where
-  fromString = filterFromText . fromString
+  fromString = refinementFromText . fromString
 
-filterFromText :: Text -> Refinement
-filterFromText t = Refinement $
+refinementFromText :: Text -> Refinement
+refinementFromText t = Refinement $
   case Text.uncons t of
     Just ('#', s) -> [Id     s]
     Just ('.', s) -> [Class  s]
@@ -195,14 +195,14 @@
 type Selector = Fix SelectorF
 
 instance IsString (Fix SelectorF) where
-  fromString = text . fromString
+  fromString = selectorFromText . fromString
 
-text :: Text -> Selector
-text t = In $
+selectorFromText :: Text -> Selector
+selectorFromText t =
   case Text.uncons t of
-    Just ('#', s) -> SelectorF (Refinement [Id s]) Star
-    Just ('.', s) -> SelectorF (Refinement [Class s]) Star
-    _             -> SelectorF (Refinement []) (Elem t)
+    Just (c, _) | elem c ("#.:@" :: [Char])
+      -> with star (refinementFromText t)
+    _ -> In $ SelectorF (Refinement []) (Elem t)
 
 #if MIN_VERSION_base(4,9,0)
 instance Semigroup (Fix SelectorF) where
diff --git a/src/Clay/Stylesheet.hs b/src/Clay/Stylesheet.hs
--- a/src/Clay/Stylesheet.hs
+++ b/src/Clay/Stylesheet.hs
@@ -1,10 +1,15 @@
 {-# LANGUAGE GeneralizedNewtypeDeriving #-}
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE ViewPatterns #-}
 module Clay.Stylesheet where
 
 import Control.Applicative
 import Control.Arrow (second)
 import Control.Monad.Writer hiding (All)
+import Data.Maybe (isJust)
+import Data.Semigroup (Semigroup)
+import Data.String (IsString)
 import Data.Text (Text)
 
 import Clay.Selector hiding (Child)
@@ -25,6 +30,22 @@
 data Feature = Feature Text (Maybe Value)
   deriving Show
 
+newtype CommentText = CommentText { unCommentText :: Text }
+  deriving (Show, IsString, Semigroup, Monoid)
+
+data Modifier
+  = Important
+  | Comment CommentText
+  deriving (Show)
+
+_Important :: Modifier -> Maybe Text
+_Important Important   = Just "!important"
+_Important (Comment _) = Nothing
+
+_Comment :: Modifier -> Maybe CommentText
+_Comment (Comment c) = Just c
+_Comment Important   = Nothing
+
 -------------------------------------------------------------------------------
 
 data App
@@ -39,7 +60,7 @@
   deriving Show
 
 data Rule
-  = Property (Key ()) Value
+  = Property [Modifier] (Key ()) Value
   | Nested   App [Rule]
   | Query    MediaQuery [Rule]
   | Face     [Rule]
@@ -71,7 +92,7 @@
 -- words: can be converted to a `Value`.
 
 key :: Val a => Key a -> a -> Css
-key k v = rule $ Property (cast k) (value v)
+key k v = rule $ Property [] (cast k) (value v)
 
 -- | Add a new style property to the stylesheet with the specified `Key` and
 -- value, like `key` but use a `Prefixed` key.
@@ -161,3 +182,21 @@
 importUrl :: Text -> Css
 importUrl l = rule $ Import l
 
+-------------------------------------------------------------------------------
+
+-- | Indicate the supplied css should override css declarations that would
+-- otherwise take precedence.
+--
+-- Use sparingly.
+important :: Css -> Css
+important = foldMap (rule . addImportant) . runS
+
+-- The last case indicates there may be something wrong in the typing, as
+-- it shouldn't be possible to make a non-property important. In practice,
+-- this implementation means only the directly applied property rule is
+-- affected, i.e. no nested rules. That could be changed by adding recursive cases.
+addImportant :: Rule -> Rule
+addImportant (Property ms@(filter (isJust . _Important) -> (_:_)) k v) =
+  Property ms k v
+addImportant (Property ms k v  ) = Property (Important : ms) k v
+addImportant r                   = r
diff --git a/src/Clay/Text.hs b/src/Clay/Text.hs
--- a/src/Clay/Text.hs
+++ b/src/Clay/Text.hs
@@ -17,6 +17,7 @@
 , textShadow
 
 -- * Text-indent.
+-- $text-indent
 
 , TextIndent
 , textIndent
@@ -134,13 +135,37 @@
 
 -------------------------------------------------------------------------------
 
+-- $text-indent
+--
+-- Supply a length — optionally annotated with @each-line@ or @hanging@ or
+-- both, or a global value. It is possible to apply the same annotation
+-- multiple times, but it has no defined effect.
+--
+-- Note browser support is currently (March 2018) non-existent, but the
+-- Prince typesetting system supports the syntax.
+--
+-- === Formal argument syntax
+--
+-- > <length-percentage> && hanging? && each-line?
+-- > where
+-- > <length-percentage> = <length> | <percentage>
+
 newtype TextIndent = TextIndent Value
-  deriving (Val, Inherit, Other)
+  deriving (Val, Inherit, Initial, Unset, Other)
 
-eachLine, hanging :: TextIndent
+-- | An internal function that ensures each-line and hanging are processed
+-- correctly.
+tagTextIndent :: Value -> TextIndent -> TextIndent
+tagTextIndent v (TextIndent v0) = TextIndent . value $ (v0, v)
 
-eachLine = TextIndent "each-line"
-hanging  = TextIndent "hanging"
+-- | Annotate the supplied 'TextIndent' with @each-line@ or @hanging@ or
+-- both.
+--
+-- > eachLine . hanging . indent $ px 3 :: TextIndent
+eachLine, hanging :: TextIndent -> TextIndent
+
+eachLine = tagTextIndent "each-line"
+hanging  = tagTextIndent "hanging"
 
 indent :: Size a -> TextIndent
 indent = TextIndent . value
