diff --git a/CHANGES b/CHANGES
--- a/CHANGES
+++ b/CHANGES
@@ -2,8 +2,50 @@
 See also the hledger and project change logs.
 
 
-# 1.2 (2016/3/31)
+# 1.3 (2017/6/30)
 
+Deps: allow brick 0.19 (#575, Felix Yan, Simon Michael)
+
+The P key toggles pending mode.
+Also there is a temporary --status-toggles flag for testing different
+toggle styles, see `hledger-ui -h`. (#564)
+
+There is now less "warping" of selection when lists change:
+
+- When the selected account disappears, eg when toggling zero
+  accounts, the selection moves to the alphabetically preceding item,
+  instead of the first one.
+
+- When the selected transaction disappears, eg when toggling status
+  filters, the selection moves to the nearest transaction by date (and
+  if several have the same date, by journal order), instead of the
+  last one.
+
+In the accounts and register screens, you can now scroll down further
+so that the last item need not always be shown at the bottom of the
+screen.  Also we now try to center the selected item in the following
+situations:
+
+-   after moving to the end with Page down/End
+-   after toggling filters (status, real, historical..)
+-   on pressing the control-l key (should force a screen redraw, also)
+-   on entering the register screen from the accounts screen (there's a
+    known problem with this: it doesn't work the first time).
+
+Items near the top of the list can't be centered, as we don't scroll
+higher than the top of the list.
+
+Emacs movement keys are now supported, as well as VI keys.
+hjkl and CTRL-bfnp should work wherever unmodified arrow keys work.
+
+The register screen now shows transaction status marks.
+
+In the transaction screen, amounts are now better aligned, eg when
+there are posting status marks or virtual postings.
+
+
+# 1.2 (2017/3/31)
+
 Fix a pattern match failure when pressing E on the transaction screen (fixes #508)
 
 Accounts with ? in name had empty registers (fixes #498) (Bryan Richter)
@@ -20,6 +62,7 @@
 -   allow brick 0.16 (Joshua Chia)
 
 -   drop obsolete --no-elide flag
+
 
 # 1.1 (2016/12/31)
 
diff --git a/Hledger/UI/AccountsScreen.hs b/Hledger/UI/AccountsScreen.hs
--- a/Hledger/UI/AccountsScreen.hs
+++ b/Hledger/UI/AccountsScreen.hs
@@ -24,6 +24,7 @@
 import qualified Data.Vector as V
 import Graphics.Vty (Event(..),Key(..),Modifier(..))
 import Lens.Micro.Platform
+import Safe
 import System.Console.ANSI
 import System.FilePath (takeFileName)
 
@@ -54,19 +55,27 @@
   } =
   ui{aopts=uopts', aScreen=s & asList .~ newitems'}
    where
-    newitems = list AccountsList (V.fromList displayitems) 1
+    newitems = list AccountsList (V.fromList $ displayitems ++ blankitems) 1
 
-    -- keep the selection near the last selected account
-    -- (may need to move to the next leaf account when entering flat mode)
+    -- decide which account is selected:
+    -- if reset is true, the first account;
+    -- otherwise, the previously selected account if possible;
+    -- otherwise, the first account with the same prefix (eg first leaf account when entering flat mode);
+    -- otherwise, the alphabetically preceding account.
     newitems' = listMoveTo selidx newitems
       where
         selidx = case (reset, listSelectedElement $ _asList s) of
                    (True, _)               -> 0
                    (_, Nothing)            -> 0
-                   (_, Just (_,AccountsScreenItem{asItemAccountName=a})) -> fromMaybe (fromMaybe 0 mprefixmatch) mexactmatch
-                     where
-                       mexactmatch  = findIndex ((a ==)                      . asItemAccountName) displayitems
-                       mprefixmatch = findIndex ((a `isAccountNamePrefixOf`) . asItemAccountName) displayitems
+                   (_, Just (_,AccountsScreenItem{asItemAccountName=a})) -> 
+                     headDef 0 $ catMaybes [
+                       findIndex (a ==) as
+                      ,findIndex (a `isAccountNamePrefixOf`) as
+                      ,Just $ max 0 (length (filter (< a) as) - 1)
+                      ]
+                      where
+                        as = map asItemAccountName displayitems
+
     uopts' = uopts{cliopts_=copts{reportopts_=ropts'}}
     ropts' = ropts{accountlistmode_=if flat_ ropts then ALFlat else ALTree}
 
@@ -98,6 +107,13 @@
         Mixed amts = normaliseMixedAmountSquashPricesForDisplay $ stripPrices bal
         stripPrices (Mixed as) = Mixed $ map stripprice as where stripprice a = a{aprice=NoPrice}
     displayitems = map displayitem items
+    -- blanks added for scrolling control, cf RegisterScreen 
+    blankitems = replicate 100
+      AccountsScreenItem{asItemIndentLevel        = 0
+                        ,asItemAccountName        = ""
+                        ,asItemDisplayAccountName = ""
+                        ,asItemRenderedAmounts    = []
+                        }
 
 
 asInit _ _ _ = error "init function called with wrong screen type, should not happen"
@@ -109,7 +125,7 @@
                            ,aMode=mode
                            } =
   case mode of
-    Help       -> [helpDialog, maincontent]
+    Help       -> [helpDialog copts, maincontent]
     -- Minibuffer e -> [minibuffer e, maincontent]
     _          -> [maincontent]
   where
@@ -181,7 +197,7 @@
             mdepth = depth_ ropts
             togglefilters =
               case concat [
-                   uiShowClearedStatus $ clearedstatus_ ropts
+                   uiShowStatus copts $ statuses_ ropts
                   ,if real_ ropts then ["real"] else []
                   ] of
                 [] -> str ""
@@ -191,7 +207,8 @@
             cur = str (case _asList s ^. listSelectedL of
                         Nothing -> "-"
                         Just i -> show (i + 1))
-            total = str $ show $ V.length $ s ^. asList . listElementsL
+            total = str $ show $ V.length nonblanks 
+            nonblanks = V.takeWhile (not . T.null . asItemAccountName) $ s ^. asList . listElementsL
 
         bottomlabel = case mode of
                         Minibuffer ed -> minibuffer ed
@@ -255,9 +272,9 @@
   ,aMode=mode
   } ev = do
   d <- liftIO getCurrentDay
-  -- c <- getContext
-  -- let h = c^.availHeightL
-  --     moveSel n l = listMoveBy n l
+  let
+    nonblanks = V.takeWhile (not . T.null . asItemAccountName) $ _asList^.listElementsL
+    lastnonblankidx = max 0 (length nonblanks - 1)
 
   -- save the currently selected account, in case we leave this screen and lose the selection
   let
@@ -315,50 +332,70 @@
         VtyEvent (EvKey (KChar '_') []) -> continue $ regenerateScreens j d $ decDepth ui
         VtyEvent (EvKey (KChar c)   []) | c `elem` ['+','='] -> continue $ regenerateScreens j d $ incDepth ui
         VtyEvent (EvKey (KChar 't') [])    -> continue $ regenerateScreens j d $ setReportPeriod (DayPeriod d) ui
-        VtyEvent (EvKey (KChar 'H') []) -> continue $ regenerateScreens j d $ toggleHistorical ui
-        VtyEvent (EvKey (KChar 'F') []) -> continue $ regenerateScreens j d $ toggleFlat ui
-        VtyEvent (EvKey (KChar 'Z') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleEmpty ui)
-        VtyEvent (EvKey (KChar 'C') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleCleared ui)
-        VtyEvent (EvKey (KChar 'U') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleUncleared ui)
-        VtyEvent (EvKey (KChar 'R') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleReal ui)
+
+        -- display mode/query toggles
+        VtyEvent (EvKey (KChar 'H') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleHistorical ui
+        VtyEvent (EvKey (KChar 'F') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleFlat ui
+        VtyEvent (EvKey (KChar 'Z') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleEmpty ui
+        VtyEvent (EvKey (KChar 'R') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleReal ui
+        VtyEvent (EvKey (KChar 'U') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui
+        VtyEvent (EvKey (KChar 'P') []) -> asCenterAndContinue $ regenerateScreens j d $ togglePending ui
+        VtyEvent (EvKey (KChar 'C') []) -> asCenterAndContinue $ regenerateScreens j d $ toggleCleared ui
+
         VtyEvent (EvKey (KDown)     [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui
         VtyEvent (EvKey (KUp)       [MShift]) -> continue $ regenerateScreens j d $ growReportPeriod d ui
         VtyEvent (EvKey (KRight)    [MShift]) -> continue $ regenerateScreens j d $ nextReportPeriod journalspan ui
         VtyEvent (EvKey (KLeft)     [MShift]) -> continue $ regenerateScreens j d $ previousReportPeriod journalspan ui
         VtyEvent (EvKey (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer ui
         VtyEvent (EvKey k           []) | k `elem` [KBS, KDel] -> (continue $ regenerateScreens j d $ resetFilter ui)
-        VtyEvent (EvKey k           []) | k `elem` [KLeft, KChar 'h']  -> continue $ popScreen ui
-        VtyEvent (EvKey k           []) | k `elem` [KRight, KChar 'l'] -> scrollTopRegister >> continue (screenEnter d scr ui)
+        VtyEvent e | e `elem` moveLeftEvents -> continue $ popScreen ui
+        VtyEvent (EvKey (KChar 'l') [MCtrl]) -> scrollSelectionToMiddle _asList >> invalidateCache >> continue ui
+
+        -- enter register screen for selected account (if there is one), 
+        -- centering its selected transaction if possible
+        VtyEvent e | e `elem` moveRightEvents 
+                   , not $ isBlankElement $ listSelectedElement _asList->
+          -- TODO center selection after entering register screen; neither of these works till second time entering; easy strictifications didn't help 
+          rsCenterAndContinue $  
+          -- flip rsHandle (VtyEvent (EvKey (KChar 'l') [MCtrl])) $
+            screenEnter d regscr ui 
           where
-            scr = rsSetAccount selacct isdepthclipped registerScreen
+            regscr = rsSetAccount selacct isdepthclipped registerScreen
             isdepthclipped = case getDepth ui of
                                 Just d  -> accountNameLevel selacct >= d
                                 Nothing -> False
 
+        -- prevent moving down over blank padding items;
+        -- instead scroll down by one, until maximally scrolled - shows the end has been reached
+        VtyEvent (EvKey (KDown)     []) | isBlankElement mnextelement -> do
+          vScrollBy (viewportScroll $ _asList^.listNameL) 1 
+          continue ui
+          where 
+            mnextelement = listSelectedElement $ listMoveDown _asList
+
+        -- if page down or end leads to a blank padding item, stop at last non-blank
+        VtyEvent e@(EvKey k           []) | k `elem` [KPageDown, KEnd] -> do
+          list <- handleListEvent e _asList
+          if isBlankElement $ listSelectedElement list
+          then do
+            let list' = listMoveTo lastnonblankidx list
+            scrollSelectionToMiddle list'
+            continue ui{aScreen=scr{_asList=list'}}
+          else
+            continue ui{aScreen=scr{_asList=list}}
+          
         -- fall through to the list's event handler (handles up/down)
-        VtyEvent ev ->
-              do
-                let ev' = case ev of
-                            EvKey (KChar 'k') [] -> EvKey (KUp) []
-                            EvKey (KChar 'j') [] -> EvKey (KDown) []
-                            _                    -> ev
-                newitems <- handleListEvent ev' _asList
-                continue $ ui{aScreen=scr & asList .~ newitems
-                                          & asSelectedAccount .~ selacct
-                                          }
-                -- continue =<< handleEventLensed ui someLens ev
+        VtyEvent ev -> do
+          newitems <- handleListEvent (normaliseMovementKeys ev) _asList
+          continue $ ui{aScreen=scr & asList .~ newitems
+                                    & asSelectedAccount .~ selacct
+                                    }
+
         AppEvent _        -> continue ui
         MouseDown _ _ _ _ -> continue ui
         MouseUp _ _ _     -> continue ui
 
   where
-    -- Encourage a more stable scroll position when toggling list items.
-    -- We scroll to the top, and the viewport will automatically
-    -- scroll down just far enough to reveal the selection, which
-    -- usually leaves it at bottom of screen).
-    -- XXX better: scroll so selection is in middle of screen ?
-    scrollTop         = vScrollToBeginning $ viewportScroll AccountsViewport
-    scrollTopRegister = vScrollToBeginning $ viewportScroll RegisterViewport
     journalspan = journalDateSpan False j
 
 asHandle _ _ = error "event handler called with wrong screen type, should not happen"
@@ -366,3 +403,8 @@
 asSetSelectedAccount a s@AccountsScreen{} = s & asSelectedAccount .~ a
 asSetSelectedAccount _ s = s
 
+isBlankElement mel = ((asItemAccountName . snd) <$> mel) == Just "" 
+
+asCenterAndContinue ui = do
+  scrollSelectionToMiddle $ _asList $ aScreen ui
+  continue ui
diff --git a/Hledger/UI/ErrorScreen.hs b/Hledger/UI/ErrorScreen.hs
--- a/Hledger/UI/ErrorScreen.hs
+++ b/Hledger/UI/ErrorScreen.hs
@@ -39,11 +39,11 @@
 esInit _ _ _ = error "init function called with wrong screen type, should not happen"
 
 esDraw :: UIState -> [Widget Name]
-esDraw UIState{ --aopts=UIOpts{cliopts_=copts@CliOpts{}}
-               aScreen=ErrorScreen{..}
+esDraw UIState{aopts=UIOpts{cliopts_=copts@CliOpts{}}
+              ,aScreen=ErrorScreen{..}
               ,aMode=mode} =
   case mode of
-    Help       -> [helpDialog, maincontent]
+    Help       -> [helpDialog copts, maincontent]
     -- Minibuffer e -> [minibuffer e, maincontent]
     _          -> [maincontent]
   where
diff --git a/Hledger/UI/RegisterScreen.hs b/Hledger/UI/RegisterScreen.hs
--- a/Hledger/UI/RegisterScreen.hs
+++ b/Hledger/UI/RegisterScreen.hs
@@ -4,11 +4,12 @@
 
 module Hledger.UI.RegisterScreen
  (registerScreen
+ ,rsHandle
  ,rsSetAccount
+ ,rsCenterAndContinue
  )
 where
 
-import Lens.Micro.Platform ((^.))
 import Control.Monad
 import Control.Monad.IO.Class (liftIO)
 import Data.List
@@ -16,13 +17,15 @@
 import Data.Monoid
 import Data.Maybe
 import qualified Data.Text as T
-import Data.Time.Calendar (Day)
+import Data.Time.Calendar
 import qualified Data.Vector as V
 import Graphics.Vty (Event(..),Key(..),Modifier(..))
 import Brick
 import Brick.Widgets.List
 import Brick.Widgets.Edit
 import Brick.Widgets.Border (borderAttr)
+import Lens.Micro.Platform
+import Safe
 import System.Console.ANSI
 
 
@@ -76,6 +79,7 @@
       where
         displayitem (t, _, _issplit, otheracctsstr, change, bal) =
           RegisterScreenItem{rsItemDate          = showDate $ transactionRegisterDate q thisacctq t
+                            ,rsItemStatus        = tstatus t
                             ,rsItemDescription   = T.unpack $ tdescription t
                             ,rsItemOtherAccounts = case splitOn ", " otheracctsstr of
                                                      [s] -> s
@@ -85,20 +89,41 @@
                             ,rsItemBalanceAmount = showMixedAmountOneLineWithoutPrice bal
                             ,rsItemTransaction   = t
                             }
-
+    -- blank items are added to allow more control of scroll position; we won't allow movement over these
+    blankitems = replicate 100  -- 100 ought to be enough for anyone
+          RegisterScreenItem{rsItemDate          = ""
+                            ,rsItemStatus        = Unmarked
+                            ,rsItemDescription   = ""
+                            ,rsItemOtherAccounts = ""
+                            ,rsItemChangeAmount  = ""
+                            ,rsItemBalanceAmount = ""
+                            ,rsItemTransaction   = nulltransaction
+                            }
     -- build the List
-    newitems = list RegisterList (V.fromList displayitems) 1
+    newitems = list RegisterList (V.fromList $ displayitems ++ blankitems) 1
 
-    -- keep the selection on the previously selected transaction if possible,
-    -- (eg after toggling nonzero mode), otherwise select the last element.
+    -- decide which transaction is selected:
+    -- if reset is true, the last (latest) transaction;
+    -- otherwise, the previously selected transaction if possible;
+    -- otherwise, the transaction nearest in date to it;
+    -- or if there's several with the same date, the nearest in journal order;
+    -- otherwise, the last (latest) transaction. 
     newitems' = listMoveTo newselidx newitems
       where
-        newselidx = case (reset, listSelectedElement rsList) of
-                      (True, _)    -> endidx
-                      (_, Nothing) -> endidx
-                      (_, Just (_,RegisterScreenItem{rsItemTransaction=Transaction{tindex=ti}}))
-                                   -> fromMaybe endidx $ findIndex ((==ti) . tindex . rsItemTransaction) displayitems
-        endidx = length displayitems
+        newselidx = 
+          case (reset, listSelectedElement rsList) of
+            (True, _)    -> endidx
+            (_, Nothing) -> endidx
+            (_, Just (_, RegisterScreenItem{rsItemTransaction=Transaction{tindex=prevselidx, tdate=prevseld}})) ->
+              headDef endidx $ catMaybes [
+                 findIndex ((==prevselidx) . tindex . rsItemTransaction) displayitems
+                ,findIndex ((==nearestidbydatethenid) . Just . tindex . rsItemTransaction) displayitems
+                ]
+              where
+                nearestidbydatethenid = third3 <$> (headMay $ sort
+                  [(abs $ diffDays (tdate t) prevseld, abs (tindex t - prevselidx), tindex t) | t <- ts])
+                ts = map rsItemTransaction displayitems
+        endidx = length displayitems - 1
 
 rsInit _ _ _ = error "init function called with wrong screen type, should not happen"
 
@@ -108,7 +133,7 @@
                             ,aMode=mode
                             } =
   case mode of
-    Help       -> [helpDialog, maincontent]
+    Help       -> [helpDialog copts, maincontent]
     -- Minibuffer e -> [minibuffer e, maincontent]
     _          -> [maincontent]
   where
@@ -127,7 +152,7 @@
         -- columns and whitespace.  If they don't get all they need,
         -- allocate it to them proportionally to their maximum widths.
         whitespacewidth = 10 -- inter-column whitespace, fixed width
-        minnonamtcolswidth = datewidth + 2 + 2 -- date column plus at least 2 for desc and accts
+        minnonamtcolswidth = datewidth + 1 + 2 + 2 -- date column plus at least 1 for status and 2 for desc and accts
         maxamtswidth = max 0 (totalwidth - minnonamtcolswidth - whitespacewidth)
         maxchangewidthseen = maximum' $ map (strWidth . rsItemChangeAmount) displayitems
         maxbalwidthseen = maximum' $ map (strWidth . rsItemBalanceAmount) displayitems
@@ -140,7 +165,7 @@
         -- maxdescacctswidth = totalwidth - (whitespacewidth - 4) - changewidth - balwidth
         maxdescacctswidth =
           -- trace (show (totalwidth, datewidth, changewidth, balwidth, whitespacewidth)) $
-          max 0 (totalwidth - datewidth - changewidth - balwidth - whitespacewidth)
+          max 0 (totalwidth - datewidth - 1 - changewidth - balwidth - whitespacewidth)
         -- allocating proportionally.
         -- descwidth' = maximum' $ map (strWidth . second6) displayitems
         -- acctswidth' = maximum' $ map (strWidth . third6) displayitems
@@ -178,7 +203,7 @@
           where
             togglefilters =
               case concat [
-                   uiShowClearedStatus $ clearedstatus_ ropts
+                   uiShowStatus copts $ statuses_ ropts
                   ,if real_ ropts then ["real"] else []
                   ,if empty_ ropts then [] else ["nonzero"]
                   ] of
@@ -187,7 +212,8 @@
             cur = str $ case rsList ^. listSelectedL of
                          Nothing -> "-"
                          Just i -> show (i + 1)
-            total = str $ show $ length displayitems
+            total = str $ show $ length nonblanks
+            nonblanks = V.takeWhile (not . null . rsItemDate) $ rsList^.listElementsL
 
             -- query = query_ $ reportopts_ $ cliopts_ opts
 
@@ -220,7 +246,9 @@
   Widget Greedy Fixed $ do
     render $
       str (fitString (Just datewidth) (Just datewidth) True True rsItemDate) <+>
-      str "  " <+>
+      str " " <+>
+      str (fitString (Just 1) (Just 1) True True (show rsItemStatus)) <+>
+      str " " <+>
       str (fitString (Just descwidth) (Just descwidth) True True rsItemDescription) <+>
       str "  " <+>
       str (fitString (Just acctswidth) (Just acctswidth) True True rsItemOtherAccounts) <+>
@@ -244,7 +272,11 @@
   ,aMode=mode
   } ev = do
   d <- liftIO getCurrentDay
-
+  let 
+    journalspan = journalDateSpan False j
+    nonblanks = V.takeWhile (not . null . rsItemDate) $ rsList^.listElementsL
+    lastnonblankidx = max 0 (length nonblanks - 1)
+  
   case mode of
     Minibuffer ed ->
       case ev of
@@ -285,24 +317,31 @@
                           rsItemTransaction=Transaction{tsourcepos=GenericSourcePos f l c}}) -> (Just (l, Just c),f)
                         Just (_, RegisterScreenItem{
                           rsItemTransaction=Transaction{tsourcepos=JournalSourcePos f (l,_)}}) -> (Just (l, Nothing),f)
-        VtyEvent (EvKey (KChar 'H') []) -> continue $ regenerateScreens j d $ toggleHistorical ui
-        VtyEvent (EvKey (KChar 'F') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleFlat ui)
-        VtyEvent (EvKey (KChar 'Z') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleEmpty ui)
-        VtyEvent (EvKey (KChar 'C') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleCleared ui)
-        VtyEvent (EvKey (KChar 'U') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleUncleared ui)
-        VtyEvent (EvKey (KChar 'R') []) -> scrollTop >> (continue $ regenerateScreens j d $ toggleReal ui)
-        VtyEvent (EvKey (KChar '/') []) -> (continue $ regenerateScreens j d $ showMinibuffer ui)
+
+        -- display mode/query toggles
+        VtyEvent (EvKey (KChar 'H') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleHistorical ui
+        VtyEvent (EvKey (KChar 'F') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleFlat ui
+        VtyEvent (EvKey (KChar 'Z') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleEmpty ui
+        VtyEvent (EvKey (KChar 'R') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleReal ui
+        VtyEvent (EvKey (KChar 'U') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleUnmarked ui
+        VtyEvent (EvKey (KChar 'P') []) -> rsCenterAndContinue $ regenerateScreens j d $ togglePending ui
+        VtyEvent (EvKey (KChar 'C') []) -> rsCenterAndContinue $ regenerateScreens j d $ toggleCleared ui
+
+        VtyEvent (EvKey (KChar '/') []) -> continue $ regenerateScreens j d $ showMinibuffer ui
         VtyEvent (EvKey (KDown)     [MShift]) -> continue $ regenerateScreens j d $ shrinkReportPeriod d ui
         VtyEvent (EvKey (KUp)       [MShift]) -> continue $ regenerateScreens j d $ growReportPeriod d ui
         VtyEvent (EvKey (KRight)    [MShift]) -> continue $ regenerateScreens j d $ nextReportPeriod journalspan ui
         VtyEvent (EvKey (KLeft)     [MShift]) -> continue $ regenerateScreens j d $ previousReportPeriod journalspan ui
         VtyEvent (EvKey k           []) | k `elem` [KBS, KDel] -> (continue $ regenerateScreens j d $ resetFilter ui)
-        VtyEvent (EvKey k           []) | k `elem` [KLeft, KChar 'h']  -> continue $ popScreen ui
-        VtyEvent (EvKey k           []) | k `elem` [KRight, KChar 'l'] -> do
+        VtyEvent e | e `elem` moveLeftEvents  -> continue $ popScreen ui
+        VtyEvent (EvKey (KChar 'l') [MCtrl]) -> scrollSelectionToMiddle rsList >> invalidateCache >> continue ui
+
+        -- enter transaction screen for selected transaction
+        VtyEvent e | e `elem` moveRightEvents -> do
           case listSelectedElement rsList of
             Just (_, RegisterScreenItem{rsItemTransaction=t}) ->
               let
-                ts = map rsItemTransaction $ V.toList $ listElements rsList
+                ts = map rsItemTransaction $ V.toList $ nonblanks
                 numberedts = zip [1..] ts
                 i = fromIntegral $ maybe 0 (+1) $ elemIndex t ts -- XXX
               in
@@ -310,21 +349,40 @@
                                                           ,tsTransactions=numberedts
                                                           ,tsAccount=rsAccount} ui
             Nothing -> continue ui
-        -- fall through to the list's event handler (handles [pg]up/down)
+
+        -- prevent moving down over blank padding items;
+        -- instead scroll down by one, until maximally scrolled - shows the end has been reached
+        VtyEvent e | e `elem` moveDownEvents, isBlankElement mnextelement -> do
+          vScrollBy (viewportScroll $ rsList^.listNameL) 1 
+          continue ui
+          where 
+            mnextelement = listSelectedElement $ listMoveDown rsList
+
+        -- if page down or end leads to a blank padding item, stop at last non-blank
+        VtyEvent e@(EvKey k           []) | k `elem` [KPageDown, KEnd] -> do
+          list <- handleListEvent e rsList
+          if isBlankElement $ listSelectedElement list
+          then do
+            let list' = listMoveTo lastnonblankidx list
+            scrollSelectionToMiddle list'
+            continue ui{aScreen=s{rsList=list'}}
+          else
+            continue ui{aScreen=s{rsList=list}}
+          
+        -- fall through to the list's event handler (handles other [pg]up/down events)
         VtyEvent ev -> do
-                let ev' = case ev of
-                            EvKey (KChar 'k') [] -> EvKey (KUp) []
-                            EvKey (KChar 'j') [] -> EvKey (KDown) []
-                            _                    -> ev
-                newitems <- handleListEvent ev' rsList
-                continue ui{aScreen=s{rsList=newitems}}
-                -- continue =<< handleEventLensed ui someLens ev
+          let ev' = normaliseMovementKeys ev
+          newitems <- handleListEvent ev' rsList
+          continue ui{aScreen=s{rsList=newitems}}
+
         AppEvent _        -> continue ui
         MouseDown _ _ _ _ -> continue ui
         MouseUp _ _ _     -> continue ui
-      where
-        -- Encourage a more stable scroll position when toggling list items (cf AccountsScreen.hs)
-        scrollTop = vScrollToBeginning $ viewportScroll RegisterViewport
-        journalspan = journalDateSpan False j
 
 rsHandle _ _ = error "event handler called with wrong screen type, should not happen"
+
+isBlankElement mel = ((rsItemDate . snd) <$> mel) == Just "" 
+
+rsCenterAndContinue ui = do
+  scrollSelectionToMiddle $ rsList $ aScreen ui
+  continue ui
diff --git a/Hledger/UI/TransactionScreen.hs b/Hledger/UI/TransactionScreen.hs
--- a/Hledger/UI/TransactionScreen.hs
+++ b/Hledger/UI/TransactionScreen.hs
@@ -53,7 +53,7 @@
                                   ,tsAccount=acct}
                               ,aMode=mode} =
   case mode of
-    Help       -> [helpDialog, maincontent]
+    Help       -> [helpDialog copts, maincontent]
     -- Minibuffer e -> [minibuffer e, maincontent]
     _          -> [maincontent]
   where
@@ -78,7 +78,7 @@
           where
             togglefilters =
               case concat [
-                   uiShowClearedStatus $ clearedstatus_ ropts
+                   uiShowStatus copts $ statuses_ ropts
                   ,if real_ ropts then ["real"] else []
                   ,if empty_ ropts then [] else ["nonzero"]
                   ] of
@@ -168,9 +168,9 @@
         -- EvKey (KChar 'E') [] -> continue $ regenerateScreens j d $ stToggleEmpty ui
         -- EvKey (KChar 'C') [] -> continue $ regenerateScreens j d $ stToggleCleared ui
         -- EvKey (KChar 'R') [] -> continue $ regenerateScreens j d $ stToggleReal ui
-        VtyEvent (EvKey k           []) | k `elem` [KUp, KChar 'k']   -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(iprev,tprev)}}
-        VtyEvent (EvKey k           []) | k `elem` [KDown, KChar 'j'] -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(inext,tnext)}}
-        VtyEvent (EvKey k           []) | k `elem` [KLeft, KChar 'h'] -> continue ui''
+        VtyEvent e | e `elem` moveUpEvents   -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(iprev,tprev)}}
+        VtyEvent e | e `elem` moveDownEvents -> continue $ regenerateScreens j d ui{aScreen=s{tsTransaction=(inext,tnext)}}
+        VtyEvent e | e `elem` moveLeftEvents -> continue ui''
           where
             ui'@UIState{aScreen=scr} = popScreen ui
             ui'' = ui'{aScreen=rsSelect (fromIntegral i) scr}
diff --git a/Hledger/UI/UIOptions.hs b/Hledger/UI/UIOptions.hs
--- a/Hledger/UI/UIOptions.hs
+++ b/Hledger/UI/UIOptions.hs
@@ -39,6 +39,15 @@
   -- ,flagReq ["drop"] (\s opts -> Right $ setopt "drop" s opts) "N" "with --flat, omit this many leading account name components"
   -- ,flagReq  ["format"] (\s opts -> Right $ setopt "format" s opts) "FORMATSTR" "use this custom line format"
   -- ,flagNone ["no-elide"] (\opts -> setboolopt "no-elide" opts) "don't compress empty parent accounts on one line"
+  ,flagReq  ["status-toggles"] (\s opts -> Right $ setopt "status-toggles" s opts) "N"
+    (intercalate "\n"
+      ["choose how status toggles work:"
+      ," 1 UPC toggles X/all"
+      ," 2 UPC cycles X/not-X/all"
+      ," 3 UPC toggles each X"
+--      ," 4 upc sets X, UPC sets not-X"
+--      ," 5 upc toggles X, UPC toggles not-X"
+      ])
  ]
 
 --uimode :: Mode [([Char], [Char])]
diff --git a/Hledger/UI/UIState.hs b/Hledger/UI/UIState.hs
--- a/Hledger/UI/UIState.hs
+++ b/Hledger/UI/UIState.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {- | UIState operations. -}
 
 {-# LANGUAGE OverloadedStrings #-}
@@ -6,7 +7,9 @@
 module Hledger.UI.UIState
 where
 
+#if !MIN_VERSION_brick(0,19,0)
 import Brick
+#endif
 import Brick.Widgets.Edit
 import Data.List
 import Data.Text.Zipper (gotoEOL)
@@ -17,30 +20,87 @@
 import Hledger.UI.UITypes
 import Hledger.UI.UIOptions
 
--- | Toggle between showing only cleared items or all items.
-toggleCleared :: UIState -> UIState
-toggleCleared ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
-  ui{aopts=uopts{cliopts_=copts{reportopts_=toggleCleared ropts}}}
-  where
-    toggleCleared ropts@ReportOpts{clearedstatus_=Just Cleared} = ropts{clearedstatus_=Nothing}
-    toggleCleared ropts = ropts{clearedstatus_=Just Cleared}
+-- | Toggle between showing only unmarked items or all items.
+toggleUnmarked :: UIState -> UIState
+toggleUnmarked ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
+  ui{aopts=uopts{cliopts_=copts{reportopts_=reportOptsToggleStatusSomehow Unmarked copts ropts}}}
 
 -- | Toggle between showing only pending items or all items.
 togglePending :: UIState -> UIState
 togglePending ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
-  ui{aopts=uopts{cliopts_=copts{reportopts_=togglePending ropts}}}
-  where
-    togglePending ropts@ReportOpts{clearedstatus_=Just Pending} = ropts{clearedstatus_=Nothing}
-    togglePending ropts = ropts{clearedstatus_=Just Pending}
+  ui{aopts=uopts{cliopts_=copts{reportopts_=reportOptsToggleStatusSomehow Pending copts ropts}}}
 
--- | Toggle between showing only uncleared items or all items.
-toggleUncleared :: UIState -> UIState
-toggleUncleared ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
-  ui{aopts=uopts{cliopts_=copts{reportopts_=toggleUncleared ropts}}}
+-- | Toggle between showing only cleared items or all items.
+toggleCleared :: UIState -> UIState
+toggleCleared ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
+  ui{aopts=uopts{cliopts_=copts{reportopts_=reportOptsToggleStatusSomehow Cleared copts ropts}}}
+
+-- TODO testing different status toggle styles 
+
+-- | Generate zero or more indicators of the status filters currently active, 
+-- which will be shown comma-separated as part of the indicators list.
+uiShowStatus :: CliOpts -> [Status] -> [String]
+uiShowStatus copts ss =
+  case style of
+    -- in style 2, instead of "Y, Z" show "not X" 
+    Just 2 | length ss == numstatuses-1 
+      -> map (("not "++). showstatus) $ sort $ complement ss  -- should be just one
+    _ -> map showstatus $ sort ss
   where
-    toggleUncleared ropts@ReportOpts{clearedstatus_=Just Uncleared} = ropts{clearedstatus_=Nothing}
-    toggleUncleared ropts = ropts{clearedstatus_=Just Uncleared}
+    numstatuses = length [minBound..maxBound::Status]
+    style = maybeintopt "status-toggles" $ rawopts_ copts
+    showstatus Cleared  = "cleared"
+    showstatus Pending  = "pending"
+    showstatus Unmarked = "unmarked"
 
+reportOptsToggleStatusSomehow :: Status -> CliOpts -> ReportOpts -> ReportOpts
+reportOptsToggleStatusSomehow s copts ropts =
+  case maybeintopt "status-toggles" $ rawopts_ copts of 
+     Just 2 -> reportOptsToggleStatus2 s ropts
+     Just 3 -> reportOptsToggleStatus3 s ropts
+--     Just 4 -> reportOptsToggleStatus4 s ropts
+--     Just 5 -> reportOptsToggleStatus5 s ropts
+     _      -> reportOptsToggleStatus1 s ropts
+
+-- 1 UPC toggles only X/all
+reportOptsToggleStatus1 s ropts@ReportOpts{statuses_=ss}
+  | ss == [s]  = ropts{statuses_=[]}
+  | otherwise = ropts{statuses_=[s]}
+
+-- 2 UPC cycles X/not-X/all
+-- repeatedly pressing X cycles:
+-- [] U [u]
+-- [u] U [pc]
+-- [pc] U []
+-- pressing Y after first or second step starts new cycle:
+-- [u] P [p]
+-- [pc] P [p]
+reportOptsToggleStatus2 s ropts@ReportOpts{statuses_=ss}
+  | ss == [s]            = ropts{statuses_=complement [s]}
+  | ss == complement [s] = ropts{statuses_=[]}
+  | otherwise            = ropts{statuses_=[s]}  -- XXX assume only three values 
+
+-- 3 UPC toggles each X
+reportOptsToggleStatus3 s ropts@ReportOpts{statuses_=ss}
+  | s `elem` ss = ropts{statuses_=filter (/= s) ss}
+  | otherwise   = ropts{statuses_=simplifyStatuses (s:ss)}
+
+-- 4 upc sets X, UPC sets not-X
+--reportOptsToggleStatus4 s ropts@ReportOpts{statuses_=ss}
+--  | s `elem` ss = ropts{statuses_=filter (/= s) ss}
+--  | otherwise   = ropts{statuses_=simplifyStatuses (s:ss)}
+--
+-- 5 upc toggles X, UPC toggles not-X
+--reportOptsToggleStatus5 s ropts@ReportOpts{statuses_=ss}
+--  | s `elem` ss = ropts{statuses_=filter (/= s) ss}
+--  | otherwise   = ropts{statuses_=simplifyStatuses (s:ss)}
+
+-- | Given a list of unique enum values, list the other possible values of that enum.
+complement :: (Bounded a, Enum a, Eq a) => [a] -> [a]
+complement = ([minBound..maxBound] \\)
+
+--
+
 -- | Toggle between showing all and showing only nonempty (more precisely, nonzero) items.
 toggleEmpty :: UIState -> UIState
 toggleEmpty ui@UIState{aopts=uopts@UIOpts{cliopts_=copts@CliOpts{reportopts_=ropts}}} =
@@ -125,7 +185,7 @@
   ui{aopts=uopts{cliopts_=copts{reportopts_=ropts{
      accountlistmode_=ALTree
     ,empty_=True
-    ,clearedstatus_=Nothing
+    ,statuses_=[]
     ,real_=False
     ,query_=""
     --,period_=PeriodAll
@@ -178,7 +238,11 @@
 showMinibuffer :: UIState -> UIState
 showMinibuffer ui = setMode (Minibuffer e) ui
   where
+#if MIN_VERSION_brick(0,19,0)
+    e = applyEdit gotoEOL $ editor MinibufferEditor (Just 1) oldq
+#else
     e = applyEdit gotoEOL $ editor MinibufferEditor (str . unlines) (Just 1) oldq
+#endif
     oldq = query_ $ reportopts_ $ cliopts_ $ aopts ui
 
 -- | Close the minibuffer, discarding any edit in progress.
diff --git a/Hledger/UI/UITypes.hs b/Hledger/UI/UITypes.hs
--- a/Hledger/UI/UITypes.hs
+++ b/Hledger/UI/UITypes.hs
@@ -142,6 +142,7 @@
 -- | An item in the register screen's list of transactions in the current account.
 data RegisterScreenItem = RegisterScreenItem {
    rsItemDate           :: String           -- ^ date
+  ,rsItemStatus         :: Status           -- ^ transaction status
   ,rsItemDescription    :: String           -- ^ description
   ,rsItemOtherAccounts  :: String           -- ^ other accounts
   ,rsItemChangeAmount   :: String           -- ^ the change to the current account from this transaction
diff --git a/Hledger/UI/UIUtils.hs b/Hledger/UI/UIUtils.hs
--- a/Hledger/UI/UIUtils.hs
+++ b/Hledger/UI/UIUtils.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP #-}
 {- | Rendering & misc. helpers. -}
 
 {-# LANGUAGE OverloadedStrings #-}
@@ -11,13 +12,16 @@
 -- import Brick.Widgets.Center
 import Brick.Widgets.Dialog
 import Brick.Widgets.Edit
+import Brick.Widgets.List
 import Data.List
+import Data.Maybe
 import Data.Monoid
-import Graphics.Vty (Event(..),Key(..),Color,Attr,currentAttr)
+import Graphics.Vty (Event(..),Key(..),Modifier(..),Color,Attr,currentAttr)
 import Lens.Micro.Platform
 import System.Process
 
-import Hledger
+import Hledger hiding (Color)
+import Hledger.Cli (CliOpts(rawopts_))
 import Hledger.UI.UITypes
 import Hledger.UI.UIState
 
@@ -28,16 +32,9 @@
 
 -- ui
 
-uiShowClearedStatus mc =
- case mc of
-   Just Cleared   -> ["cleared"]
-   Just Pending   -> ["pending"]
-   Just Uncleared -> ["uncleared"]
-   Nothing        -> []
-
 -- | Draw the help dialog, called when help mode is active.
-helpDialog :: Widget Name
-helpDialog =
+helpDialog :: CliOpts -> Widget Name
+helpDialog copts =
   Widget Fixed Fixed $ do
     c <- getContext
     render $
@@ -48,10 +45,11 @@
               padLeftRight 1 $
                 vBox [
                    str "NAVIGATION"
-                  ,renderKey ("UP/DOWN/k/j/PGUP/PGDN/HOME/END", "")
+                  ,renderKey ("UP/DOWN/PGUP/PGDN/HOME/END", "")
                   ,str "  move selection"
-                  ,renderKey ("RIGHT/l", "more detail")
-                  ,renderKey ("LEFT/h", "previous screen")
+                  ,renderKey ("RIGHT", "more detail")
+                  ,renderKey ("LEFT", "previous screen")
+                  ,str "  (or vi/emacs movement keys)"
                   ,renderKey ("ESC", "cancel / reset to top")
                   ,str " "
                   ,str "MISC"
@@ -59,8 +57,9 @@
                   ,renderKey ("a", "add transaction (hledger add)")
                   ,renderKey ("A", "add transaction (hledger-iadd)")
                   ,renderKey ("E", "open editor")
-                  ,renderKey ("g", "reload data")
                   ,renderKey ("I", "toggle balance assertions")
+                  ,renderKey ("g", "reload data")
+                  ,renderKey ("CTRL-l", "redraw & recenter")
                   ,renderKey ("q", "quit")
                   ,str " "
                   ,str "MANUAL"
@@ -77,8 +76,21 @@
                   ,renderKey ("t", "set report period to today")
                   ,str " "
                   ,renderKey ("/", "set a filter query")
-                  ,renderKey ("C", "toggle cleared/all")
-                  ,renderKey ("U", "toggle uncleared/all")
+                  ,renderKey ("U", 
+                    ["toggle unmarked/all"
+                    ,"cycle unmarked/not unmarked/all"
+                    ,"toggle unmarked filter"
+                    ] !! (statusstyle-1))
+                  ,renderKey ("P",
+                    ["toggle pending/all"
+                    ,"cycle pending/not pending/all"
+                    ,"toggle pending filter"
+                    ] !! (statusstyle-1))
+                  ,renderKey ("C",
+                    ["toggle cleared/all"
+                    ,"cycle cleared/not cleared/all"
+                    ,"toggle cleared filter"
+                    ] !! (statusstyle-1))
                   ,renderKey ("R", "toggle real/all")
                   ,renderKey ("Z", "toggle nonzero/all")
                   ,renderKey ("DEL/BS", "remove filters")
@@ -109,12 +121,13 @@
           ]
   where
     renderKey (key,desc) = withAttr (borderAttr <> "keys") (str key) <+> str " " <+> str desc
+    statusstyle = min 3 $ fromMaybe 1 $ maybeintopt "status-toggles" $ rawopts_ copts 
 
 -- | Event handler used when help mode is active.
 helpHandle :: UIState -> BrickEvent Name AppEvent -> EventM Name (Next UIState)
 helpHandle ui ev =
   case ev of
-    VtyEvent (EvKey k []) | k `elem` [KEsc, KLeft, KChar 'h', KChar '?'] -> continue $ setMode Normal ui
+    VtyEvent e | e `elem` (moveLeftEvents ++ [EvKey KEsc [], EvKey (KChar '?') []]) -> continue $ setMode Normal ui
     VtyEvent (EvKey (KChar 't') []) -> suspendAndResume $ runHelp >> return ui'
     VtyEvent (EvKey (KChar 'm') []) -> suspendAndResume $ runMan  >> return ui'
     VtyEvent (EvKey (KChar 'i') []) -> suspendAndResume $ runInfo >> return ui'
@@ -127,7 +140,11 @@
 minibuffer ed =
   forceAttr (borderAttr <> "minibuffer") $
   hBox $
+#if MIN_VERSION_brick(0,19,0)
+  [txt "filter: ", renderEditor (str . unlines) True ed]
+#else
   [txt "filter: ", renderEditor True ed]
+#endif
 
 -- | Wrap a widget in the default hledger-ui screen layout.
 defaultLayout :: Widget Name -> Widget Name -> Widget Name -> Widget Name
@@ -246,3 +263,44 @@
 withBorderAttr :: Attr -> Widget Name -> Widget Name
 withBorderAttr attr = updateAttrMap (applyAttrMappings [(borderAttr, attr)])
 
+-- | Like brick's continue, but first run some action to modify brick's state.
+-- This action does not affect the app state, but might eg adjust a widget's scroll position.
+continueWith :: EventM n () -> ui -> EventM n (Next ui)
+continueWith brickaction ui = brickaction >> continue ui
+
+-- | Scroll a list's viewport so that the selected item is centered in the
+-- middle of the display area.
+scrollToTop :: List Name e -> EventM Name ()
+scrollToTop list = do
+  let vpname = list^.listNameL
+  setTop (viewportScroll vpname) 0 
+
+-- | Scroll a list's viewport so that the selected item is centered in the
+-- middle of the display area.
+scrollSelectionToMiddle :: List Name e -> EventM Name ()
+scrollSelectionToMiddle list = do
+  let mselectedrow = list^.listSelectedL 
+      vpname = list^.listNameL
+  mvp <- lookupViewport vpname
+  case (mselectedrow, mvp) of
+    (Just selectedrow, Just vp) -> do
+      let
+        itemheight   = dbg4 "itemheight" $ list^.listItemHeightL
+        vpheight     = dbg4 "vpheight" $ vp^.vpSize._2
+        itemsperpage = dbg4 "itemsperpage" $ vpheight `div` itemheight
+        toprow       = dbg4 "toprow" $ max 0 (selectedrow - (itemsperpage `div` 2)) -- assuming ViewportScroll's row offset is measured in list items not screen rows
+      setTop (viewportScroll vpname) toprow 
+    _ -> return ()
+
+--                 arrow keys       vi keys               emacs keys
+moveUpEvents    = [EvKey KUp []   , EvKey (KChar 'k') [], EvKey (KChar 'p') [MCtrl]]
+moveDownEvents  = [EvKey KDown [] , EvKey (KChar 'j') [], EvKey (KChar 'n') [MCtrl]]
+moveLeftEvents  = [EvKey KLeft [] , EvKey (KChar 'h') [], EvKey (KChar 'b') [MCtrl]]
+moveRightEvents = [EvKey KRight [], EvKey (KChar 'l') [], EvKey (KChar 'f') [MCtrl]]
+
+normaliseMovementKeys ev
+  | ev `elem` moveUpEvents    = EvKey KUp []
+  | ev `elem` moveDownEvents  = EvKey KDown []
+  | ev `elem` moveLeftEvents  = EvKey KLeft []
+  | ev `elem` moveRightEvents = EvKey KRight []
+  | otherwise = ev
diff --git a/doc/hledger-ui.1 b/doc/hledger-ui.1
--- a/doc/hledger-ui.1
+++ b/doc/hledger-ui.1
@@ -1,5 +1,5 @@
 
-.TH "hledger\-ui" "1" "March 2017" "hledger\-ui 1.2" "hledger User Manuals"
+.TH "hledger\-ui" "1" "June 2017" "hledger\-ui 1.3" "hledger User Manuals"
 
 
 
@@ -146,18 +146,18 @@
 .RS
 .RE
 .TP
-.B \f[C]\-C\ \-\-cleared\f[]
-include only cleared postings/txns
+.B \f[C]\-U\ \-\-unmarked\f[]
+include only unmarked postings/txns (can combine with \-P or \-C)
 .RS
 .RE
 .TP
-.B \f[C]\-\-pending\f[]
+.B \f[C]\-P\ \-\-pending\f[]
 include only pending postings/txns
 .RS
 .RE
 .TP
-.B \f[C]\-U\ \-\-uncleared\f[]
-include only uncleared (and pending) postings/txns
+.B \f[C]\-C\ \-\-cleared\f[]
+include only cleared postings/txns
 .RS
 .RE
 .TP
@@ -232,8 +232,9 @@
 deeper, \f[C]left\f[] returns to the previous screen,
 \f[C]up\f[]/\f[C]down\f[]/\f[C]page\ up\f[]/\f[C]page\ down\f[]/\f[C]home\f[]/\f[C]end\f[]
 move up and down through lists.
-Vi\-style \f[C]h\f[]/\f[C]j\f[]/\f[C]k\f[]/\f[C]l\f[] movement keys are
-also supported.
+Vi\-style (\f[C]h\f[]/\f[C]j\f[]/\f[C]k\f[]/\f[C]l\f[]) and Emacs\-style
+(\f[C]CTRL\-p\f[]/\f[C]CTRL\-n\f[]/\f[C]CTRL\-f\f[]/\f[C]CTRL\-b\f[])
+movement keys are also supported.
 A tip: movement speed is limited by your keyboard repeat rate, to move
 faster you may want to adjust it.
 (If you\[aq]re on a mac, the Karabiner app is one way to do that.)
@@ -255,13 +256,17 @@
 While editing the query, you can use CTRL\-a/e/d/k, BS, cursor keys;
 press \f[C]ENTER\f[] to set it, or \f[C]ESCAPE\f[]to cancel.
 There are also keys for quickly adjusting some common filters like
-account depth and cleared/uncleared (see below).
+account depth and transaction status (see below).
 \f[C]BACKSPACE\f[] or \f[C]DELETE\f[] removes all filters, showing all
 transactions.
 .PP
 \f[C]ESCAPE\f[] removes all filters and jumps back to the top screen.
 Or, it cancels a minibuffer edit or help dialog in progress.
 .PP
+\f[C]CTRL\-l\f[] redraws the screen and centers the selection if
+possible (selections near the top won\[aq]t be centered, since we
+don\[aq]t scroll above the top).
+.PP
 \f[C]g\f[] reloads from the data file(s) and updates the current screen
 and any previous screens.
 (With large files, this could cause a noticeable pause.)
@@ -322,10 +327,13 @@
 they show the change in balance during the report period.
 They are more useful eg when viewing a time log.
 .PP
-\f[C]C\f[] toggles cleared mode, in which uncleared transactions and
-postings are not shown.
-\f[C]U\f[] toggles uncleared mode, in which only uncleared
-transactions/postings are shown.
+\f[C]U\f[] toggles filtering by unmarked status, including or excluding
+unmarked postings in the balances.
+Similarly, \f[C]P\f[] toggles pending postings, and \f[C]C\f[] toggles
+cleared postings.
+(By default, balances include all postings; if you activate one or two
+status filters, only those postings are included; and if you activate
+all three, the filter is removed.)
 .PP
 \f[C]R\f[] toggles real mode, in which virtual postings are ignored.
 .PP
@@ -367,10 +375,13 @@
 for the period balance shown on the accounts screen.
 As on the accounts screen, this can be toggled with \f[C]F\f[].
 .PP
-\f[C]C\f[] toggles cleared mode, in which uncleared transactions and
-postings are not shown.
-\f[C]U\f[] toggles uncleared mode, in which only uncleared
-transactions/postings are shown.
+\f[C]U\f[] toggles filtering by unmarked status, showing or hiding
+unmarked transactions.
+Similarly, \f[C]P\f[] toggles pending transactions, and \f[C]C\f[]
+toggles cleared transactions.
+(By default, transactions with all statuses are shown; if you activate
+one or two status filters, only those transactions are shown; and if you
+activate all three, the filter is removed.)q
 .PP
 \f[C]R\f[] toggles real mode, in which virtual postings are ignored.
 .PP
diff --git a/doc/hledger-ui.1.info b/doc/hledger-ui.1.info
--- a/doc/hledger-ui.1.info
+++ b/doc/hledger-ui.1.info
@@ -3,7 +3,7 @@
 
 File: hledger-ui.1.info,  Node: Top,  Next: OPTIONS,  Up: (dir)
 
-hledger-ui(1) hledger-ui 1.2
+hledger-ui(1) hledger-ui 1.3
 ****************************
 
 hledger-ui is hledger's curses-style interface, providing an efficient
@@ -104,15 +104,15 @@
 '--date2'
 
      show, and match with -b/-e/-p/date:, secondary dates instead
-'-C --cleared'
+'-U --unmarked'
 
-     include only cleared postings/txns
-'--pending'
+     include only unmarked postings/txns (can combine with -P or -C)
+'-P --pending'
 
      include only pending postings/txns
-'-U --uncleared'
+'-C --cleared'
 
-     include only uncleared (and pending) postings/txns
+     include only cleared postings/txns
 '-R --real'
 
      include only non-virtual postings
@@ -167,10 +167,10 @@
    The cursor keys navigate: 'right' (or 'enter') goes deeper, 'left'
 returns to the previous screen, 'up'/'down'/'page up'/'page
 down'/'home'/'end' move up and down through lists.  Vi-style
-'h'/'j'/'k'/'l' movement keys are also supported.  A tip: movement speed
-is limited by your keyboard repeat rate, to move faster you may want to
-adjust it.  (If you're on a mac, the Karabiner app is one way to do
-that.)
+('h'/'j'/'k'/'l') and Emacs-style ('CTRL-p'/'CTRL-n'/'CTRL-f'/'CTRL-b')
+movement keys are also supported.  A tip: movement speed is limited by
+your keyboard repeat rate, to move faster you may want to adjust it.
+(If you're on a mac, the Karabiner app is one way to do that.)
 
    With shift pressed, the cursor keys adjust the report period,
 limiting the transactions to be shown (by default, all are shown).
@@ -186,13 +186,17 @@
 using the same query terms as in hledger and hledger-web.  While editing
 the query, you can use CTRL-a/e/d/k, BS, cursor keys; press 'ENTER' to
 set it, or 'ESCAPE'to cancel.  There are also keys for quickly adjusting
-some common filters like account depth and cleared/uncleared (see
+some common filters like account depth and transaction status (see
 below).  'BACKSPACE' or 'DELETE' removes all filters, showing all
 transactions.
 
    'ESCAPE' removes all filters and jumps back to the top screen.  Or,
 it cancels a minibuffer edit or help dialog in progress.
 
+   'CTRL-l' redraws the screen and centers the selection if possible
+(selections near the top won't be centered, since we don't scroll above
+the top).
+
    'g' reloads from the data file(s) and updates the current screen and
 any previous screens.  (With large files, this could cause a noticeable
 pause.)
@@ -260,9 +264,12 @@
 before the report start date, so they show the change in balance during
 the report period.  They are more useful eg when viewing a time log.
 
-   'C' toggles cleared mode, in which uncleared transactions and
-postings are not shown.  'U' toggles uncleared mode, in which only
-uncleared transactions/postings are shown.
+   'U' toggles filtering by unmarked status, including or excluding
+unmarked postings in the balances.  Similarly, 'P' toggles pending
+postings, and 'C' toggles cleared postings.  (By default, balances
+include all postings; if you activate one or two status filters, only
+those postings are included; and if you activate all three, the filter
+is removed.)
 
    'R' toggles real mode, in which virtual postings are ignored.
 
@@ -304,9 +311,12 @@
 responsible for the period balance shown on the accounts screen.  As on
 the accounts screen, this can be toggled with 'F'.
 
-   'C' toggles cleared mode, in which uncleared transactions and
-postings are not shown.  'U' toggles uncleared mode, in which only
-uncleared transactions/postings are shown.
+   'U' toggles filtering by unmarked status, showing or hiding unmarked
+transactions.  Similarly, 'P' toggles pending transactions, and 'C'
+toggles cleared transactions.  (By default, transactions with all
+statuses are shown; if you activate one or two status filters, only
+those transactions are shown; and if you activate all three, the filter
+is removed.)q
 
    'R' toggles real mode, in which virtual postings are ignored.
 
@@ -357,17 +367,17 @@
 Node: Top73
 Node: OPTIONS825
 Ref: #options924
-Node: KEYS3650
-Ref: #keys3747
-Node: SCREENS6335
-Ref: #screens6422
-Node: Accounts screen6512
-Ref: #accounts-screen6642
-Node: Register screen8691
-Ref: #register-screen8848
-Node: Transaction screen10737
-Ref: #transaction-screen10897
-Node: Error screen11767
-Ref: #error-screen11891
+Node: KEYS3665
+Ref: #keys3762
+Node: SCREENS6558
+Ref: #screens6645
+Node: Accounts screen6735
+Ref: #accounts-screen6865
+Node: Register screen9095
+Ref: #register-screen9252
+Node: Transaction screen11326
+Ref: #transaction-screen11486
+Node: Error screen12356
+Ref: #error-screen12480
 
 End Tag Table
diff --git a/doc/hledger-ui.1.txt b/doc/hledger-ui.1.txt
--- a/doc/hledger-ui.1.txt
+++ b/doc/hledger-ui.1.txt
@@ -101,14 +101,14 @@
        --date2
               show, and match with -b/-e/-p/date:, secondary dates instead
 
-       -C --cleared
-              include only cleared postings/txns
+       -U --unmarked
+              include only unmarked postings/txns (can combine with -P or -C)
 
-       --pending
+       -P --pending
               include only pending postings/txns
 
-       -U --uncleared
-              include only uncleared (and pending) postings/txns
+       -C --cleared
+              include only cleared postings/txns
 
        -R --real
               include only non-virtual postings
@@ -151,45 +151,50 @@
 
        The cursor keys navigate: right (or enter) goes deeper, left returns to
        the previous screen,  up/down/page up/page down/home/end  move  up  and
-       down through lists.  Vi-style h/j/k/l movement keys are also supported.
-       A tip: movement speed is limited by your keyboard repeat rate, to  move
-       faster  you  may want to adjust it.  (If you're on a mac, the Karabiner
-       app is one way to do that.)
+       down    through    lists.     Vi-style    (h/j/k/l)   and   Emacs-style
+       (CTRL-p/CTRL-n/CTRL-f/CTRL-b) movement keys are also supported.  A tip:
+       movement  speed is limited by your keyboard repeat rate, to move faster
+       you may want to adjust it.  (If you're on a mac, the Karabiner  app  is
+       one way to do that.)
 
-       With shift pressed, the cursor keys adjust the report period,  limiting
-       the   transactions   to   be   shown   (by  default,  all  are  shown).
-       shift-down/up steps downward and upward through these  standard  report
+       With  shift pressed, the cursor keys adjust the report period, limiting
+       the  transactions  to  be  shown   (by   default,   all   are   shown).
+       shift-down/up  steps  downward and upward through these standard report
        period   durations:   year,   quarter,   month,   week,   day.    Then,
-       shift-left/right moves to the previous/next period.  t sets the  report
-       period  to  today.   With  the --watch option, when viewing a "current"
-       period (the current day, week, month, quarter,  or  year),  the  period
-       will  move automatically to track the current date.  To set a non-stan-
+       shift-left/right  moves to the previous/next period.  t sets the report
+       period to today.  With the --watch option,  when  viewing  a  "current"
+       period  (the  current  day,  week, month, quarter, or year), the period
+       will move automatically to track the current date.  To set a  non-stan-
        dard period, you can use / and a date: query.
 
-       / lets you set a general filter query limiting the  data  shown,  using
-       the  same query terms as in hledger and hledger-web.  While editing the
-       query, you can use CTRL-a/e/d/k, BS, cursor keys; press  ENTER  to  set
+       /  lets  you  set a general filter query limiting the data shown, using
+       the same query terms as in hledger and hledger-web.  While editing  the
+       query,  you  can  use CTRL-a/e/d/k, BS, cursor keys; press ENTER to set
        it, or ESCAPEto cancel.  There are also keys for quickly adjusting some
-       common filters like account depth and  cleared/uncleared  (see  below).
+       common  filters  like account depth and transaction status (see below).
        BACKSPACE or DELETE removes all filters, showing all transactions.
 
-       ESCAPE  removes  all  filters and jumps back to the top screen.  Or, it
+       ESCAPE removes all filters and jumps back to the top  screen.   Or,  it
        cancels a minibuffer edit or help dialog in progress.
 
-       g reloads from the data file(s) and updates the current screen and  any
-       previous  screens.   (With  large  files, this could cause a noticeable
+       CTRL-l redraws the screen and centers the selection if possible (selec-
+       tions near the top won't be centered, since we don't scroll  above  the
+       top).
+
+       g  reloads from the data file(s) and updates the current screen and any
+       previous screens.  (With large files, this  could  cause  a  noticeable
        pause.)
 
-       I toggles balance assertion  checking.   Disabling  balance  assertions
+       I  toggles  balance  assertion  checking.  Disabling balance assertions
        temporarily can be useful for troubleshooting.
 
-       a  runs  command-line  hledger's  add  command, and reloads the updated
+       a runs command-line hledger's add  command,  and  reloads  the  updated
        file.  This allows some basic data entry.
 
-       E  runs  $HLEDGER_UI_EDITOR,  or   $EDITOR,   or   a   default   (emac-
+       E   runs   $HLEDGER_UI_EDITOR,   or   $EDITOR,   or  a  default  (emac-
        sclient -a "" -nw) on the journal file.  With some editors (emacs, vi),
-       the cursor will be positioned at the current transaction  when  invoked
-       from  the  register  and transaction screens, and at the error location
+       the  cursor  will be positioned at the current transaction when invoked
+       from the register and transaction screens, and at  the  error  location
        (if possible) when invoked from the error screen.
 
        q quits the application.
@@ -198,42 +203,44 @@
 
 SCREENS
    Accounts screen
-       This is normally the first screen displayed.   It  lists  accounts  and
-       their  balances,  like hledger's balance command.  By default, it shows
-       all accounts and their latest ending balances (including  the  balances
-       of  subaccounts).  if you specify a query on the command line, it shows
+       This  is  normally  the  first screen displayed.  It lists accounts and
+       their balances, like hledger's balance command.  By default,  it  shows
+       all  accounts  and their latest ending balances (including the balances
+       of subaccounts).  if you specify a query on the command line, it  shows
        just the matched accounts and the balances from matched transactions.
 
-       Account names are normally indented to show the hierarchy (tree  mode).
+       Account  names are normally indented to show the hierarchy (tree mode).
        To see less detail, set a depth limit by pressing a number key, 1 to 9.
        0 shows even less detail, collapsing all accounts to a single total.  -
-       and  +  (or  =)  decrease  and increase the depth limit.  To remove the
-       depth limit, set it higher than the maximum  account  depth,  or  press
+       and + (or =) decrease and increase the  depth  limit.   To  remove  the
+       depth  limit,  set  it  higher than the maximum account depth, or press
        ESCAPE.
 
-       F  toggles  flat mode, in which accounts are shown as a flat list, with
-       their full names.  In this mode, account balances exclude  subaccounts,
-       except  for accounts at the depth limit (as with hledger's balance com-
+       F toggles flat mode, in which accounts are shown as a flat  list,  with
+       their  full names.  In this mode, account balances exclude subaccounts,
+       except for accounts at the depth limit (as with hledger's balance  com-
        mand).
 
        H toggles between showing historical balances or period balances.  His-
-       torical  balances  (the  default) are ending balances at the end of the
-       report period, taking into account all transactions  before  that  date
-       (filtered  by  the  filter query if any), including transactions before
-       the start of the report period.  In other  words,  historical  balances
-       are  what  you  would  see on a bank statement for that account (unless
-       disturbed by a filter  query).   Period  balances  ignore  transactions
+       torical balances (the default) are ending balances at the  end  of  the
+       report  period,  taking  into account all transactions before that date
+       (filtered by the filter query if any),  including  transactions  before
+       the  start  of  the report period.  In other words, historical balances
+       are what you would see on a bank statement  for  that  account  (unless
+       disturbed  by  a  filter  query).   Period balances ignore transactions
        before the report start date, so they show the change in balance during
        the report period.  They are more useful eg when viewing a time log.
 
-       C toggles cleared mode, in which uncleared  transactions  and  postings
-       are  not  shown.   U  toggles  uncleared  mode, in which only uncleared
-       transactions/postings are shown.
+       U toggles filtering by unmarked status, including or excluding unmarked
+       postings in the balances.  Similarly, P toggles pending postings, and C
+       toggles  cleared postings.  (By default, balances include all postings;
+       if you activate one or two status  filters,  only  those  postings  are
+       included; and if you activate all three, the filter is removed.)
 
        R toggles real mode, in which virtual postings are ignored.
 
-       Z toggles nonzero mode, in which only accounts  with  nonzero  balances
-       are  shown (hledger-ui shows zero items by default, unlike command-line
+       Z  toggles  nonzero  mode, in which only accounts with nonzero balances
+       are shown (hledger-ui shows zero items by default, unlike  command-line
        hledger).
 
        Press right or enter to view an account's transactions register.
@@ -242,32 +249,35 @@
        This screen shows the transactions affecting a particular account, like
        a check register.  Each line represents one transaction and shows:
 
-       o the  other  account(s)  involved, in abbreviated form.  (If there are
-         both real and virtual postings, it shows only the  accounts  affected
+       o the other account(s) involved, in abbreviated form.   (If  there  are
+         both  real  and virtual postings, it shows only the accounts affected
          by real postings.)
 
-       o the  overall change to the current account's balance; positive for an
+       o the overall change to the current account's balance; positive for  an
          inflow to this account, negative for an outflow.
 
        o the running historical total or period total for the current account,
-         after  the  transaction.  This can be toggled with H.  Similar to the
-         accounts screen, the historical total  is  affected  by  transactions
-         (filtered  by  the  filter query) before the report start date, while
+         after the transaction.  This can be toggled with H.  Similar  to  the
+         accounts  screen,  the  historical  total is affected by transactions
+         (filtered by the filter query) before the report  start  date,  while
          the period total is not.  If the historical total is not disturbed by
-         a  filter  query, it will be the running historical balance you would
+         a filter query, it will be the running historical balance  you  would
          see on a bank register for the current account.
 
-       If the accounts screen was in  tree  mode,  the  register  screen  will
+       If  the  accounts  screen  was  in  tree mode, the register screen will
        include transactions from both the current account and its subaccounts.
-       If the accounts screen  was  in  flat  mode,  and  a  non-depth-clipped
-       account  was  selected,  the  register screen will exclude transactions
+       If  the  accounts  screen  was  in  flat  mode, and a non-depth-clipped
+       account was selected, the register  screen  will  exclude  transactions
        from subaccounts.  In other words, the register always shows the trans-
-       actions  responsible  for  the  period  balance  shown  on the accounts
+       actions responsible for  the  period  balance  shown  on  the  accounts
        screen.  As on the accounts screen, this can be toggled with F.
 
-       C toggles cleared mode, in which uncleared  transactions  and  postings
-       are  not  shown.   U  toggles  uncleared  mode, in which only uncleared
-       transactions/postings are shown.
+       U  toggles  filtering  by  unmarked  status, showing or hiding unmarked
+       transactions.  Similarly, P toggles pending transactions, and C toggles
+       cleared  transactions.  (By default, transactions with all statuses are
+       shown; if you activate one or two status filters, only  those  transac-
+       tions  are  shown;  and  if  you  activate  all  three,  the  filter is
+       removed.)q
 
        R toggles real mode, in which virtual postings are ignored.
 
@@ -359,4 +369,4 @@
 
 
 
-hledger-ui 1.2                    March 2017                     hledger-ui(1)
+hledger-ui 1.3                     June 2017                     hledger-ui(1)
diff --git a/hledger-ui.cabal b/hledger-ui.cabal
--- a/hledger-ui.cabal
+++ b/hledger-ui.cabal
@@ -3,7 +3,7 @@
 -- see: https://github.com/sol/hpack
 
 name:           hledger-ui
-version:        1.2
+version:        1.3
 synopsis:       Curses-style user interface for the hledger accounting tool
 description:    This is hledger's curses-style interface.
                 It is simpler and more convenient for browsing data than the command-line interface,
@@ -55,10 +55,10 @@
   hs-source-dirs:
       ./.
   ghc-options: -Wall -fno-warn-unused-do-bind -fno-warn-name-shadowing -fno-warn-missing-signatures -fno-warn-type-defaults -fno-warn-orphans
-  cpp-options: -DVERSION="1.2"
+  cpp-options: -DVERSION="1.3"
   build-depends:
-      hledger >= 1.2 && < 1.3
-    , hledger-lib >= 1.2 && < 1.3
+      hledger >= 1.3
+    , hledger-lib >= 1.3
     , ansi-terminal >= 0.6.2.3 && < 0.7
     , async
     , base >= 4.8 && < 5
@@ -72,7 +72,7 @@
     , HUnit
     , microlens >= 0.4 && < 0.5
     , microlens-platform >= 0.2.3.1 && < 0.4
-    , megaparsec >=5.0 && < 5.3
+    , megaparsec >=5.0 && < 5.4
     , pretty-show >=1.6.4
     , process >= 1.2
     , safe >= 0.2
@@ -85,7 +85,7 @@
     buildable: False
   else
     build-depends:
-        brick >= 0.12 && < 0.18
+        brick >= 0.12 && < 0.20
       , vty >= 5.5 && < 5.16
   if flag(threaded)
     ghc-options: -threaded
