diff --git a/.flowconfig b/.flowconfig
index 5f5dfd123..899a096e6 100644
--- a/.flowconfig
+++ b/.flowconfig
@@ -18,6 +18,5 @@ module.name_mapper='^types\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/types\1'
 module.name_mapper='^component\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/component\1'
 module.name_mapper='^page\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/page\1'
 module.name_mapper='^lbry\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/lbry\1'
-module.name_mapper='^modal\(.*\)$' -> '<PROJECT_ROOT>/src/renderer/modal\1'
 
 [strict]
diff --git a/flow-typed/react-modal.js b/flow-typed/react-modal.js
deleted file mode 100644
index 17766e9f0..000000000
--- a/flow-typed/react-modal.js
+++ /dev/null
@@ -1,3 +0,0 @@
-declare module 'react-modal' {
-  declare module.exports: any;
-}
diff --git a/package.json b/package.json
index 07d4e84fd..2e61b99cc 100644
--- a/package.json
+++ b/package.json
@@ -32,7 +32,6 @@
     "amplitude-js": "^4.0.0",
     "bluebird": "^3.5.1",
     "classnames": "^2.2.5",
-    "dom-scroll-into-view": "^1.2.1",
     "electron-dl": "^1.6.0",
     "formik": "^0.10.4",
     "from2": "^2.3.0",
diff --git a/src/renderer/component/app/view.jsx b/src/renderer/component/app/view.jsx
index 240db13e2..fb43b6574 100644
--- a/src/renderer/component/app/view.jsx
+++ b/src/renderer/component/app/view.jsx
@@ -1,4 +1,3 @@
-// @flow
 import React from 'react';
 import Router from 'component/router/index';
 import Header from 'component/header';
@@ -7,83 +6,61 @@ import ModalRouter from 'modal/modalRouter';
 import ReactModal from 'react-modal';
 import throttle from 'util/throttle';
 
-type Props = {
-  alertError: (string | {}) => void,
-  recordScroll: number => void,
-  currentStackIndex: number,
-  currentPageAttributes: { path: string, scrollY: number },
-  pageTitle: ?string,
-};
-
-class App extends React.PureComponent<Props> {
+class App extends React.PureComponent {
   constructor() {
     super();
     this.mainContent = undefined;
-    (this: any).scrollListener = this.scrollListener.bind(this);
   }
 
   componentWillMount() {
     const { alertError } = this.props;
 
-    // TODO: create type for this object
-    // it lives in jsonrpc.js
-    document.addEventListener('unhandledError', (event: any) => {
+    document.addEventListener('unhandledError', event => {
       alertError(event.detail);
     });
   }
 
   componentDidMount() {
+    const { recordScroll } = this.props;
     const mainContent = document.getElementById('main-content');
     this.mainContent = mainContent;
 
-    if (this.mainContent) {
-      this.mainContent.addEventListener('scroll', throttle(this.scrollListener, 750));
-    }
+    const scrollListener = () => recordScroll(this.mainContent.scrollTop);
+
+    this.mainContent.addEventListener('scroll', throttle(scrollListener, 750));
 
     ReactModal.setAppElement('#window'); // fuck this
   }
 
-  componentWillReceiveProps(props: Props) {
-    const { pageTitle } = props;
-    this.setTitleFromProps(pageTitle);
+  componentWillUnmount() {
+    this.mainContent.removeEventListener('scroll', this.scrollListener);
   }
 
-  componentDidUpdate(prevProps: Props) {
+  componentWillReceiveProps(props) {
+    this.setTitleFromProps(props);
+  }
+
+  componentDidUpdate(prevProps) {
     const { currentStackIndex: prevStackIndex } = prevProps;
     const { currentStackIndex, currentPageAttributes } = this.props;
 
-    if (this.mainContent && currentStackIndex !== prevStackIndex) {
+    if (currentStackIndex !== prevStackIndex) {
       this.mainContent.scrollTop = currentPageAttributes.scrollY || 0;
     }
   }
 
-  componentWillUnmount() {
-    if (this.mainContent) {
-      // having issues with this
-      // $FlowFixMe
-      this.mainContent.removeEventListener('scroll');
-    }
+  setTitleFromProps(props) {
+    window.document.title = props.pageTitle || 'LBRY';
   }
 
-  setTitleFromProps = (title: ?string) => {
-    window.document.title = title || 'LBRY';
-  };
-
-  scrollListener() {
-    const { recordScroll } = this.props;
-    if (this.mainContent) {
-      recordScroll(this.mainContent.scrollTop);
-    }
-  }
-
-  mainContent: ?HTMLElement;
-
   render() {
     return (
       <div id="window">
         <Theme />
         <Header />
-        <Router />
+        <div id="main-content">
+          <Router />
+        </div>
         <ModalRouter />
       </div>
     );
diff --git a/src/renderer/component/cardMedia/view.jsx b/src/renderer/component/cardMedia/view.jsx
index 34feddccb..06f80f1d7 100644
--- a/src/renderer/component/cardMedia/view.jsx
+++ b/src/renderer/component/cardMedia/view.jsx
@@ -1,18 +1,48 @@
-// @flow
 import React from 'react';
 
-type Props = {
-  thumbnail: ?string, // externally sourced image
-};
+class CardMedia extends React.PureComponent {
+  static AUTO_THUMB_CLASSES = [
+    'purple',
+    'red',
+    'pink',
+    'indigo',
+    'blue',
+    'light-blue',
+    'cyan',
+    'teal',
+    'green',
+    'yellow',
+    'orange',
+  ];
+
+  componentWillMount() {
+    this.setState({
+      autoThumbClass:
+        CardMedia.AUTO_THUMB_CLASSES[
+          Math.floor(Math.random() * CardMedia.AUTO_THUMB_CLASSES.length)
+        ],
+    });
+  }
 
-class CardMedia extends React.PureComponent<Props> {
   render() {
-    const { thumbnail } = this.props;
+    const { title, thumbnail } = this.props;
+    const atClass = this.state.autoThumbClass;
+
     if (thumbnail) {
       return <div className="card__media" style={{ backgroundImage: `url('${thumbnail}')` }} />;
     }
 
-    return <div className="card__media card__media--autothumb">LBRY</div>;
+    return (
+      <div className={`card__media card__media--autothumb ${atClass}`}>
+        <div className="card__autothumb__text">
+          {title &&
+            title
+              .replace(/\s+/g, '')
+              .substring(0, Math.min(title.replace(' ', '').length, 5))
+              .toUpperCase()}
+        </div>
+      </div>
+    );
   }
 }
 
diff --git a/src/renderer/component/common.js b/src/renderer/component/common.js
index 687c6e9da..629d09f57 100644
--- a/src/renderer/component/common.js
+++ b/src/renderer/component/common.js
@@ -1,6 +1,3 @@
-// just disabling the linter because this file shouldn't even exist
-// will continue to move components over to /components/common/{comp} - sean
-/* eslint-disable */
 import React from 'react';
 import PropTypes from 'prop-types';
 import { formatCredits, formatFullPrice } from 'util/formatCredits';
@@ -173,4 +170,3 @@ export class Thumbnail extends React.PureComponent {
     );
   }
 }
-/* eslint-enable */
diff --git a/src/renderer/component/common/category-list.jsx b/src/renderer/component/common/category-list.jsx
deleted file mode 100644
index 1f01ea921..000000000
--- a/src/renderer/component/common/category-list.jsx
+++ /dev/null
@@ -1,255 +0,0 @@
-// @flow
-import React from 'react';
-import lbryuri from 'lbryuri';
-import ToolTip from 'component/common/tooltip';
-import FileCard from 'component/fileCard';
-import Button from 'component/link';
-
-type Props = {
-  category: string,
-  names: Array<string>,
-  categoryLink?: string,
-};
-
-type State = {
-  canScrollNext: boolean,
-  canScrollPrevious: boolean,
-};
-
-class CategoryList extends React.PureComponent<Props, State> {
-  constructor() {
-    super();
-
-    this.state = {
-      canScrollPrevious: false,
-      canScrollNext: false,
-    };
-
-    (this: any).handleScrollNext = this.handleScrollNext.bind(this);
-    (this: any).handleScrollPrevious = this.handleScrollPrevious.bind(this);
-    this.rowItems = undefined;
-  }
-
-  componentDidMount() {
-    const cardRow = this.rowItems;
-    if (cardRow) {
-      const cards = cardRow.getElementsByTagName('section');
-      const lastCard = cards[cards.length - 1];
-      const isCompletelyVisible = this.isCardVisible(lastCard);
-
-      if (!isCompletelyVisible) {
-        // not sure how we can avoid doing this
-        /* eslint-disable react/no-did-mount-set-state */
-        this.setState({
-          canScrollNext: true,
-        });
-        /* eslint-enable react/no-did-mount-set-state */
-      }
-    }
-  }
-
-  rowItems: ?HTMLDivElement;
-
-  handleScroll(cardRow: HTMLDivElement, scrollTarget: number) {
-    const cards = cardRow.getElementsByTagName('section');
-    const animationCallback = () => {
-      const firstCard = cards[0];
-      const lastCard = cards[cards.length - 1];
-      const firstCardVisible = this.isCardVisible(firstCard);
-      const lastCardVisible = this.isCardVisible(lastCard);
-      this.setState({
-        canScrollNext: !lastCardVisible,
-        canScrollPrevious: !firstCardVisible,
-      });
-    };
-
-    const currentScrollLeft = cardRow.scrollLeft;
-    const direction = currentScrollLeft > scrollTarget ? 'left' : 'right';
-    this.scrollCardsAnimated(cardRow, scrollTarget, direction, animationCallback);
-  }
-
-  scrollCardsAnimated = (
-    cardRow: HTMLDivElement,
-    scrollTarget: number,
-    direction: string,
-    callback: () => any
-  ) => {
-    let start;
-    const step = timestamp => {
-      if (!start) start = timestamp;
-
-      const currentLeftVal = cardRow.scrollLeft;
-
-      let newTarget;
-      let shouldContinue;
-      let progress = currentLeftVal;
-
-      if (direction === 'right') {
-        progress += timestamp - start;
-        newTarget = Math.min(progress, scrollTarget);
-        shouldContinue = newTarget < scrollTarget;
-      } else {
-        progress -= timestamp - start;
-        newTarget = Math.max(progress, scrollTarget);
-        shouldContinue = newTarget > scrollTarget;
-      }
-
-      cardRow.scrollLeft = newTarget; // eslint-disable-line no-param-reassign
-
-      if (shouldContinue) {
-        window.requestAnimationFrame(step);
-      } else {
-        callback();
-      }
-    };
-
-    window.requestAnimationFrame(step);
-  };
-
-  // check if a card is fully visible horizontally
-  isCardVisible = (section: HTMLElement) => {
-    const rect = section.getBoundingClientRect();
-    const isVisible = rect.left >= 0 && rect.right <= window.innerWidth;
-    return isVisible;
-  };
-
-  handleScrollNext() {
-    const cardRow = this.rowItems;
-    if (cardRow) {
-      const cards = cardRow.getElementsByTagName('section');
-
-      // loop over items until we find one that is on the screen
-      // continue searching until a card isn't fully visible, this is the new target
-      let firstFullVisibleCard;
-      let firstSemiVisibleCard;
-
-      for (let i = 0; i < cards.length; i += 1) {
-        const currentCardVisible = this.isCardVisible(cards[i]);
-
-        if (firstFullVisibleCard && !currentCardVisible) {
-          firstSemiVisibleCard = cards[i];
-          break;
-        } else if (currentCardVisible) {
-          [firstFullVisibleCard] = cards;
-        }
-      }
-
-      if (firstFullVisibleCard && firstSemiVisibleCard) {
-        const scrollTarget = firstSemiVisibleCard.offsetLeft - firstFullVisibleCard.offsetLeft;
-        this.handleScroll(cardRow, scrollTarget);
-      }
-    }
-  }
-
-  handleScrollPrevious() {
-    const cardRow = this.rowItems;
-    if (cardRow) {
-      const cards = cardRow.getElementsByTagName('section');
-
-      let hasFoundCard;
-      let numberOfCardsThatCanFit = 0;
-
-      // loop starting at the end until we find a visible card
-      // then count to find how many cards can fit on the screen
-      for (let i = cards.length - 1; i >= 0; i -= 1) {
-        const currentCard = cards[i];
-        const isCurrentCardVisible = this.isCardVisible(currentCard);
-
-        if (isCurrentCardVisible) {
-          if (!hasFoundCard) {
-            hasFoundCard = true;
-          }
-
-          numberOfCardsThatCanFit += 1;
-        } else if (hasFoundCard) {
-          // this card is off the screen to the left
-          // we know how many cards can fit on a screen
-          // find the new target and scroll
-          const firstCardOffsetLeft = cards[0].offsetLeft;
-          const cardIndexToScrollTo = i + 1 - numberOfCardsThatCanFit;
-          const newFirstCard = cards[cardIndexToScrollTo];
-
-          let scrollTarget;
-          if (newFirstCard) {
-            scrollTarget = newFirstCard.offsetLeft;
-          } else {
-            // more cards can fit on the screen than are currently hidden
-            // just scroll to the first card
-            scrollTarget = cards[0].offsetLeft;
-          }
-
-          scrollTarget -= firstCardOffsetLeft; // to play nice with the margins
-
-          this.handleScroll(cardRow, scrollTarget);
-          break;
-        }
-      }
-    }
-  }
-
-  render() {
-    const { category, names, categoryLink } = this.props;
-    const { canScrollNext, canScrollPrevious } = this.state;
-
-    // The lint was throwing an error saying we should use <button> instead of <a>
-    // We are using buttons, needs more exploration
-    return (
-      <div className="card-row">
-        <div className="card-row__header">
-          <div className="card-row__title">
-            <h3>
-              {categoryLink ? (
-                <Button
-                  className="button-text no-underline"
-                  label={category}
-                  navigate="/show"
-                  navigateParams={{ uri: categoryLink }}
-                />
-              ) : (
-                category
-              )}
-            </h3>
-            {category &&
-              category.match(/^community/i) && (
-                <ToolTip
-                  label={__("What's this?")}
-                  body={__(
-                    'Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!'
-                  )}
-                />
-              )}
-          </div>
-          <div>
-            <Button
-              inverse
-              circle
-              disabled={!canScrollPrevious}
-              onClick={this.handleScrollPrevious}
-              icon="chevron-left"
-            />
-            <Button
-              inverse
-              circle
-              disabled={!canScrollNext}
-              onClick={this.handleScrollNext}
-              icon="chevron-right"
-            />
-          </div>
-        </div>
-        <div
-          ref={ref => {
-            this.rowItems = ref;
-          }}
-          className="card-row__scrollhouse"
-        >
-          {names &&
-            names.map(name => (
-              <FileCard key={name} displayStyle="card" uri={lbryuri.normalize(name)} />
-            ))}
-        </div>
-      </div>
-    );
-  }
-}
-
-export default CategoryList;
diff --git a/src/renderer/component/common/icon.jsx b/src/renderer/component/common/icon.jsx
deleted file mode 100644
index 3e261d21b..000000000
--- a/src/renderer/component/common/icon.jsx
+++ /dev/null
@@ -1,43 +0,0 @@
-// @flow
-import React from 'react';
-import classnames from 'classnames';
-import * as icons from 'constants/icons';
-
-type Props = {
-  icon: string,
-  fixed?: boolean,
-  padded?: boolean,
-};
-
-class Icon extends React.PureComponent<Props> {
-  getIconTitle() {
-    const { icon } = this.props;
-
-    switch (icon) {
-      case icons.FEATURED:
-        return __('Watch this and earn rewards.');
-      case icons.LOCAL:
-        return __('You have a copy of this file.');
-      default:
-        return '';
-    }
-  }
-
-  render() {
-    const { icon, fixed, padded } = this.props;
-    const iconClassName = icon.startsWith('icon-') ? icon : `icon-${icon}`;
-    const title = this.getIconTitle();
-
-    const spanClassName = classnames(
-      {
-        'icon--fixed-width': fixed,
-        'icon--padded': padded,
-      },
-      iconClassName
-    );
-
-    return <span className={spanClassName} title={title} />;
-  }
-}
-
-export default Icon;
diff --git a/src/renderer/component/common/tooltip.jsx b/src/renderer/component/common/tooltip.jsx
deleted file mode 100644
index 942ac73be..000000000
--- a/src/renderer/component/common/tooltip.jsx
+++ /dev/null
@@ -1,57 +0,0 @@
-// @flow
-import React from 'react';
-import classnames from 'classnames';
-import Icon from 'component/common/icon';
-import Button from 'component/link';
-
-type Props = {
-  body: string,
-  label: string,
-};
-
-type State = {
-  showTooltip: boolean,
-};
-
-class ToolTip extends React.PureComponent<Props, State> {
-  constructor(props: Props) {
-    super(props);
-
-    this.state = {
-      showTooltip: false,
-    };
-
-    (this: any).handleClick = this.handleClick.bind(this);
-  }
-
-  handleClick() {
-    const { showTooltip } = this.state;
-
-    if (!showTooltip) {
-      document.addEventListener('click', this.handleClick);
-    } else {
-      document.removeEventListener('click', this.handleClick);
-    }
-
-    this.setState({
-      showTooltip: !showTooltip,
-    });
-  }
-
-  render() {
-    const { label, body } = this.props;
-    const { showTooltip } = this.state;
-
-    return (
-      <span className="tooltip">
-        <Button fakeLink className="help tooltip__link" onClick={this.handleClick}>
-          {label}
-          {showTooltip && <Icon icon="times" fixed />}
-        </Button>
-        <div className={classnames('tooltip__body', { hidden: !showTooltip })}>{body}</div>
-      </span>
-    );
-  }
-}
-
-export default ToolTip;
diff --git a/src/renderer/component/fileCard/view.jsx b/src/renderer/component/fileCard/view.jsx
index a3c8cc249..e38bf06c2 100644
--- a/src/renderer/component/fileCard/view.jsx
+++ b/src/renderer/component/fileCard/view.jsx
@@ -1,101 +1,111 @@
-// @flow
 import React from 'react';
-import lbryuri from 'lbryuri';
+import lbryuri from 'lbryuri.js';
 import CardMedia from 'component/cardMedia';
+import Link from 'component/link';
 import { TruncatedText } from 'component/common';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 import FilePrice from 'component/filePrice';
 import UriIndicator from 'component/uriIndicator';
 import NsfwOverlay from 'component/nsfwOverlay';
+import TruncatedMarkdown from 'component/truncatedMarkdown';
 import * as icons from 'constants/icons';
-import classnames from 'classnames';
 
-// TODO: iron these out
-type Props = {
-  isResolvingUri: boolean,
-  resolveUri: string => void,
-  uri: string,
-  claim: ?{ claim_id: string },
-  fileInfo: ?{},
-  metadata: ?{ nsfw: boolean, thumbnail: ?string },
-  navigate: (string, ?{}) => void,
-  rewardedContentClaimIds: Array<string>,
-  obscureNsfw: boolean,
-};
+class FileCard extends React.PureComponent {
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      hovered: false,
+    };
+  }
 
-class FileCard extends React.PureComponent<Props> {
   componentWillMount() {
     this.resolve(this.props);
   }
 
-  componentWillReceiveProps(nextProps: Props) {
+  componentWillReceiveProps(nextProps) {
     this.resolve(nextProps);
   }
 
-  resolve = (props: Props) => {
+  resolve(props) {
     const { isResolvingUri, resolveUri, claim, uri } = props;
 
     if (!isResolvingUri && claim === undefined && uri) {
       resolveUri(uri);
     }
-  };
+  }
+
+  handleMouseOver() {
+    this.setState({
+      hovered: true,
+    });
+  }
+
+  handleMouseOut() {
+    this.setState({
+      hovered: false,
+    });
+  }
 
   render() {
     const {
       claim,
       fileInfo,
       metadata,
+      isResolvingUri,
       navigate,
       rewardedContentClaimIds,
-      obscureNsfw,
     } = this.props;
+
     const uri = lbryuri.normalize(this.props.uri);
     const title = metadata && metadata.title ? metadata.title : uri;
     const thumbnail = metadata && metadata.thumbnail ? metadata.thumbnail : null;
-    const shouldObscureNsfw = obscureNsfw && metadata && metadata.nsfw;
+    const obscureNsfw = this.props.obscureNsfw && metadata && metadata.nsfw;
     const isRewardContent = claim && rewardedContentClaimIds.includes(claim.claim_id);
 
-    // Come back to this on other pages
-    // let description = '';
-    // if (isResolvingUri && !claim) {
-    //   description = __('Loading...');
-    // } else if (metadata && metadata.description) {
-    //   description = metadata.description;
-    // } else if (claim === null) {
-    //   description = __('This address contains no content.');
-    // }
+    let description = '';
+    if (isResolvingUri && !claim) {
+      description = __('Loading...');
+    } else if (metadata && metadata.description) {
+      description = metadata.description;
+    } else if (claim === null) {
+      description = __('This address contains no content.');
+    }
 
-    // We don't want to allow a click handler unless it's in focus
-    // I'll come back to this when I work on site-wide keyboard navigation
-    /* eslint-disable jsx-a11y/click-events-have-key-events */
     return (
       <section
-        tabIndex="0"
-        role="button"
-        onClick={() => navigate('/show', { uri })}
-        className={classnames('card card--small card__link', {
-          'card--obscured': shouldObscureNsfw,
-        })}
+        className={`card card--small card--link ${obscureNsfw ? 'card--obscured ' : ''}`}
+        onMouseEnter={this.handleMouseOver.bind(this)}
+        onMouseLeave={this.handleMouseOut.bind(this)}
       >
-        <CardMedia thumbnail={thumbnail} />
-
-        <div className="card__title-identity">
-          <div className="card__title--small">
-            <TruncatedText lines={3}>{title}</TruncatedText>
-          </div>
-
-          <div className="card__subtitle">
-            <UriIndicator uri={uri} link />
-            <div className="card--file-subtitle">
-              <FilePrice uri={uri} /> {isRewardContent && <Icon icon={icons.FEATURED} padded />}
-              {fileInfo && <Icon icon={icons.LOCAL} padded />}
+        <div className="card__inner">
+          <Link onClick={() => navigate('/show', { uri })} className="card__link">
+            <CardMedia title={title} thumbnail={thumbnail} />
+            <div className="card__title-identity">
+              <div className="card__title" title={title}>
+                <TruncatedText lines={1}>{title}</TruncatedText>
+              </div>
+              <div className="card__subtitle">
+                <span className="card__indicators card--file-subtitle">
+                  <FilePrice uri={uri} />{' '}
+                  {isRewardContent && <Icon icon={icons.FEATURED} leftPad />}{' '}
+                  {fileInfo && <Icon icon={icons.LOCAL} leftPad />}
+                </span>
+                <span className="card--file-subtitle">
+                  <UriIndicator uri={uri} link span smallCard />
+                </span>
+              </div>
             </div>
-          </div>
+          </Link>
+          {/* Test for nizuka's design: should we remove description?
+            <div className="card__content card__subtext card__subtext--two-lines">
+              <TruncatedMarkdown lines={2}>{description}</TruncatedMarkdown>
+            </div>
+            */}
         </div>
-        {obscureNsfw && <NsfwOverlay />}
+        {obscureNsfw && this.state.hovered && <NsfwOverlay />}
       </section>
     );
-    /* eslint-enable jsx-a11y/click-events-have-key-events */
   }
 }
 
diff --git a/src/renderer/component/fileDownloadLink/view.jsx b/src/renderer/component/fileDownloadLink/view.jsx
index 71cf39018..57818da51 100644
--- a/src/renderer/component/fileDownloadLink/view.jsx
+++ b/src/renderer/component/fileDownloadLink/view.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import { BusyMessage } from 'component/common';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 import Link from 'component/link';
 
 class FileDownloadLink extends React.PureComponent {
diff --git a/src/renderer/component/fileTile/view.jsx b/src/renderer/component/fileTile/view.jsx
index ae1901485..231cfc293 100644
--- a/src/renderer/component/fileTile/view.jsx
+++ b/src/renderer/component/fileTile/view.jsx
@@ -1,4 +1,3 @@
-/* eslint-disable */
 import React from 'react';
 import * as icons from 'constants/icons';
 import lbryuri from 'lbryuri.js';
@@ -6,7 +5,7 @@ import CardMedia from 'component/cardMedia';
 import { TruncatedText } from 'component/common.js';
 import FilePrice from 'component/filePrice';
 import NsfwOverlay from 'component/nsfwOverlay';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 
 class FileTile extends React.PureComponent {
   static SHOW_EMPTY_PUBLISH = 'publish';
@@ -134,4 +133,3 @@ class FileTile extends React.PureComponent {
 }
 
 export default FileTile;
-/* eslint-enable */
diff --git a/src/renderer/component/form.js b/src/renderer/component/form.js
index 889bec15a..c13619b1a 100644
--- a/src/renderer/component/form.js
+++ b/src/renderer/component/form.js
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 import FormField from 'component/formField';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 
 let formFieldCounter = 0;
 
diff --git a/src/renderer/component/header/view.jsx b/src/renderer/component/header/view.jsx
index f8fc83890..c1289c889 100644
--- a/src/renderer/component/header/view.jsx
+++ b/src/renderer/component/header/view.jsx
@@ -1,20 +1,8 @@
-// @flow
 import React from 'react';
-import Button from 'component/link';
+import Link from 'component/link';
 import WunderBar from 'component/wunderbar';
 
-type Props = {
-  balance: string,
-  back: any => void,
-  forward: any => void,
-  isBackDisabled: boolean,
-  isForwardDisabled: boolean,
-  isUpgradeAvailable: boolean,
-  navigate: any => void,
-  downloadUpgrade: any => void,
-};
-
-export const Header = (props: Props) => {
+export const Header = props => {
   const {
     balance,
     back,
@@ -27,58 +15,85 @@ export const Header = (props: Props) => {
   } = props;
   return (
     <header id="header">
-      <div className="header__actions-left">
-        <Button
-          alt
-          circle
+      <div className="header__item">
+        <Link
           onClick={back}
           disabled={isBackDisabled}
-          icon="arrow-left"
-          description={__('Navigate back')}
+          button="alt button--flat"
+          icon="icon-arrow-left"
+          title={__('Back')}
         />
-
-        <Button
-          alt
-          circle
+      </div>
+      <div className="header__item">
+        <Link
           onClick={forward}
           disabled={isForwardDisabled}
-          icon="arrow-right"
-          description={__('Navigate forward')}
+          button="alt button--flat"
+          icon="icon-arrow-right"
+          title={__('Forward')}
         />
-
-        <Button alt onClick={() => navigate('/discover')} icon="home" description={__('Home')} />
       </div>
-
-      <WunderBar />
-
-      <div className="header__actions-right">
-        <Button
-          inverse
+      <div className="header__item">
+        <Link
+          onClick={() => navigate('/discover')}
+          button="alt button--flat"
+          icon="icon-home"
+          title={__('Discover Content')}
+        />
+      </div>
+      <div className="header__item">
+        <Link
+          onClick={() => navigate('/subscriptions')}
+          button="alt button--flat"
+          icon="icon-at"
+          title={__('My Subscriptions')}
+        />
+      </div>
+      <div className="header__item header__item--wunderbar">
+        <WunderBar />
+      </div>
+      <div className="header__item">
+        <Link
           onClick={() => navigate('/wallet')}
-          icon="user"
-          label={isUpgradeAvailable ? `${balance} LBC` : `You have ${balance} LBC`}
-          description={__('Your wallet')}
+          button="text"
+          className="no-underline"
+          icon="icon-bank"
+          label={balance}
+          title={__('Wallet')}
         />
-
-        <Button
-          onClick={() => navigate('/publish')}
-          icon="cloud-upload"
-          label={isUpgradeAvailable ? '' : __('Publish')}
-          description={__('Publish content')}
-        />
-
-        <Button
-          alt
-          onClick={() => navigate('/settings')}
-          icon="gear"
-          description={__('Settings')}
-        />
-
-        <Button alt onClick={() => navigate('/help')} icon="question" description={__('Help')} />
-        {isUpgradeAvailable && (
-          <Button onClick={() => downloadUpgrade()} icon="arrow-up" label={__('Upgrade App')} />
-        )}
       </div>
+      <div className="header__item">
+        <Link
+          onClick={() => navigate('/publish')}
+          button="primary button--flat"
+          icon="icon-upload"
+          label={__('Publish')}
+        />
+      </div>
+      <div className="header__item">
+        <Link
+          onClick={() => navigate('/downloaded')}
+          button="alt button--flat"
+          icon="icon-folder"
+          title={__('Downloads and Publishes')}
+        />
+      </div>
+      <div className="header__item">
+        <Link
+          onClick={() => navigate('/settings')}
+          button="alt button--flat"
+          icon="icon-gear"
+          title={__('Settings')}
+        />
+      </div>
+      {isUpgradeAvailable && (
+        <Link
+          onClick={() => downloadUpgrade()}
+          button="primary button--flat"
+          icon="icon-arrow-up"
+          label={__('Upgrade App')}
+        />
+      )}
     </header>
   );
 };
diff --git a/src/renderer/component/icon/index.js b/src/renderer/component/icon/index.js
new file mode 100644
index 000000000..81d61e58b
--- /dev/null
+++ b/src/renderer/component/icon/index.js
@@ -0,0 +1,5 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import Icon from './view';
+
+export default connect(null, null)(Icon);
diff --git a/src/renderer/component/icon/view.jsx b/src/renderer/component/icon/view.jsx
new file mode 100644
index 000000000..795a1b241
--- /dev/null
+++ b/src/renderer/component/icon/view.jsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import * as icons from 'constants/icons';
+import classnames from 'classnames';
+
+export default class Icon extends React.PureComponent {
+  static propTypes = {
+    icon: PropTypes.string.isRequired,
+    fixed: PropTypes.bool,
+  };
+
+  static defaultProps = {
+    fixed: false,
+  };
+
+  getIconClass() {
+    const { icon } = this.props;
+
+    return icon.startsWith('icon-') ? icon : `icon-${icon}`;
+  }
+
+  getIconTitle() {
+    switch (this.props.icon) {
+      case icons.FEATURED:
+        return __('Watch this and earn rewards.');
+      case icons.LOCAL:
+        return __('You have a copy of this file.');
+      default:
+        return '';
+    }
+  }
+
+  render() {
+    const { icon, fixed, className, leftPad } = this.props;
+    const iconClass = this.getIconClass();
+    const title = this.getIconTitle();
+
+    const spanClassName = classnames(
+      'icon',
+      iconClass,
+      {
+        'icon-fixed-width': fixed,
+        'icon--left-pad': leftPad,
+      },
+      className
+    );
+
+    return <span className={spanClassName} title={title} />;
+  }
+}
diff --git a/src/renderer/component/inviteList/view.jsx b/src/renderer/component/inviteList/view.jsx
index 79b344e4e..c339cfd1b 100644
--- a/src/renderer/component/inviteList/view.jsx
+++ b/src/renderer/component/inviteList/view.jsx
@@ -1,5 +1,5 @@
 import React from 'react';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 import RewardLink from 'component/rewardLink';
 import rewards from 'rewards.js';
 
diff --git a/src/renderer/component/link/view.jsx b/src/renderer/component/link/view.jsx
index 41b103411..92451daff 100644
--- a/src/renderer/component/link/view.jsx
+++ b/src/renderer/component/link/view.jsx
@@ -1,99 +1,60 @@
-// @flow
-import * as React from 'react';
-import Icon from 'component/common/icon';
-import classnames from 'classnames';
+import React from 'react';
+import Icon from 'component/icon';
 
-type Props = {
-  onClick: ?(any) => any,
-  href: ?string,
-  title: ?string,
-  label: ?string,
-  icon: ?string,
-  iconRight: ?string,
-  disabled: ?boolean,
-  children: ?React.Node,
-  navigate: ?string,
-  // TODO: these (nav) should be a reusable type
-  doNavigate: (string, ?any) => void,
-  navigateParams: any,
-  className: ?string,
-  inverse: ?boolean,
-  circle: ?boolean,
-  alt: ?boolean,
-  flat: ?boolean,
-  fakeLink: ?boolean,
-  description: ?string,
-};
-
-const Button = (props: Props) => {
+const Link = props => {
   const {
-    onClick,
     href,
     title,
+    style,
     label,
     icon,
     iconRight,
+    button,
     disabled,
     children,
     navigate,
     navigateParams,
     doNavigate,
     className,
-    inverse,
-    alt,
-    circle,
-    flat,
-    fakeLink,
-    description,
-    ...otherProps
+    span,
   } = props;
 
-  const combinedClassName = classnames(
-    {
-      btn: !fakeLink,
-      'btn--link': fakeLink,
-      'btn--primary': !fakeLink && !alt,
-      'btn--alt': alt,
-      'btn--inverse': inverse,
-      'btn--disabled': disabled,
-      'btn--circle': circle,
-      'btn--flat': flat,
-    },
-    className
-  );
+  const combinedClassName =
+    (className || '') +
+    (!className && !button ? 'button-text' : '') + // Non-button links get the same look as text buttons
+    (button ? ` button-block button-${button} button-set-item` : '') +
+    (disabled ? ' disabled' : '');
 
-  const extendedOnClick =
-    !onClick && navigate
+  const onClick =
+    !props.onClick && navigate
       ? event => {
           event.stopPropagation();
           doNavigate(navigate, navigateParams || {});
         }
-      : onClick;
+      : props.onClick;
 
-  const content = (
-    <React.Fragment>
-      {icon && <Icon icon={icon} fixed />}
-      {label && <span className="btn__label">{label}</span>}
-      {children && children}
-      {iconRight && <Icon icon={iconRight} fixed />}
-    </React.Fragment>
-  );
+  let content;
+  if (children) {
+    content = children;
+  } else {
+    content = (
+      <span {...('button' in props ? { className: 'button__content' } : {})}>
+        {icon ? <Icon icon={icon} fixed /> : null}
+        {label ? <span className="link-label">{label}</span> : null}
+        {iconRight ? <Icon icon={iconRight} fixed /> : null}
+      </span>
+    );
+  }
 
-  return href ? (
-    <a className={combinedClassName} href={href} title={title}>
-      {content}
-    </a>
-  ) : (
-    <button
-      aria-label={description || label || title}
-      className={combinedClassName}
-      onClick={extendedOnClick}
-      disabled={disabled}
-      {...otherProps}
-    >
-      {content}
-    </button>
-  );
+  const linkProps = {
+    className: combinedClassName,
+    href: href || 'javascript:;',
+    title,
+    onClick,
+    style,
+  };
+
+  return span ? <span {...linkProps}>{content}</span> : <a {...linkProps}>{content}</a>;
 };
 
-export default Button;
+export default Link;
diff --git a/src/renderer/component/menu.js b/src/renderer/component/menu.js
index 5be125cd7..e070f8711 100644
--- a/src/renderer/component/menu.js
+++ b/src/renderer/component/menu.js
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 import Link from 'component/link';
 
 export class DropDownMenuItem extends React.PureComponent {
diff --git a/src/renderer/component/page/index.js b/src/renderer/component/page/index.js
deleted file mode 100644
index dbe9cc315..000000000
--- a/src/renderer/component/page/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-import { connect } from 'react-redux';
-import { selectPageTitle } from 'redux/selectors/navigation';
-import Page from './view';
-
-const select = state => ({
-  title: selectPageTitle(state),
-});
-
-export default connect(select, null)(Page);
diff --git a/src/renderer/component/page/view.jsx b/src/renderer/component/page/view.jsx
deleted file mode 100644
index 9d16b3e8f..000000000
--- a/src/renderer/component/page/view.jsx
+++ /dev/null
@@ -1,26 +0,0 @@
-// @flow
-import * as React from 'react';
-import classnames from 'classnames';
-import { BusyMessage } from 'component/common';
-
-type Props = {
-  children: React.Node,
-  title: ?string,
-  noPadding: ?boolean,
-  isLoading: ?boolean,
-};
-
-const Page = (props: Props) => {
-  const { children, title, noPadding, isLoading } = props;
-  return (
-    <main id="main-content">
-      <div className="page__header">
-        {title && <h1 className="page__title">{title}</h1>}
-        {isLoading && <BusyMessage message={__('Fetching content')} />}
-      </div>
-      <div className={classnames('main', { 'main--no-padding': noPadding })}>{children}</div>
-    </main>
-  );
-};
-
-export default Page;
diff --git a/src/renderer/component/tooltip.js b/src/renderer/component/tooltip.js
new file mode 100644
index 000000000..c81775614
--- /dev/null
+++ b/src/renderer/component/tooltip.js
@@ -0,0 +1,54 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export class ToolTip extends React.PureComponent {
+  static propTypes = {
+    body: PropTypes.string.isRequired,
+    label: PropTypes.string.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      showTooltip: false,
+    };
+  }
+
+  handleClick() {
+    this.setState({
+      showTooltip: !this.state.showTooltip,
+    });
+  }
+
+  handleTooltipMouseOut() {
+    this.setState({
+      showTooltip: false,
+    });
+  }
+
+  render() {
+    return (
+      <span className={`tooltip ${this.props.className || ''}`}>
+        <a
+          className="tooltip__link"
+          onClick={() => {
+            this.handleClick();
+          }}
+        >
+          {this.props.label}
+        </a>
+        <div
+          className={`tooltip__body ${this.state.showTooltip ? '' : ' hidden'}`}
+          onMouseOut={() => {
+            this.handleTooltipMouseOut();
+          }}
+        >
+          {this.props.body}
+        </div>
+      </span>
+    );
+  }
+}
+
+export default ToolTip;
diff --git a/src/renderer/component/uriIndicator/view.jsx b/src/renderer/component/uriIndicator/view.jsx
index 04a8c78a3..704769250 100644
--- a/src/renderer/component/uriIndicator/view.jsx
+++ b/src/renderer/component/uriIndicator/view.jsx
@@ -1,46 +1,35 @@
-// @flow
 import React from 'react';
-import { Icon } from 'component/common';
-import Button from 'component/link';
+import Icon from 'component/icon';
+import Link from 'component/link';
 import lbryuri from 'lbryuri';
 import classnames from 'classnames';
 
-type Props = {
-  isResolvingUri: boolean,
-  resolveUri: string => void,
-  claim: {
-    channel_name: string,
-    has_signature: boolean,
-    signature_is_valid: boolean,
-    value: {
-      publisherSignature: { certificateId: string },
-    },
-  },
-  uri: string,
-  link: ?boolean,
-};
-
-class UriIndicator extends React.PureComponent<Props> {
+class UriIndicator extends React.PureComponent {
   componentWillMount() {
     this.resolve(this.props);
   }
 
-  componentWillReceiveProps(nextProps: Props) {
+  componentWillReceiveProps(nextProps) {
     this.resolve(nextProps);
   }
 
-  resolve = (props: Props) => {
+  resolve(props) {
     const { isResolvingUri, resolveUri, claim, uri } = props;
 
     if (!isResolvingUri && claim === undefined && uri) {
       resolveUri(uri);
     }
-  };
+  }
 
   render() {
-    const { claim, link, isResolvingUri } = this.props;
+    const { claim, link, uri, isResolvingUri, smallCard, span } = this.props;
+
+    if (isResolvingUri && !claim) {
+      return <span className="empty">Validating...</span>;
+    }
+
     if (!claim) {
-      return <span className="empty">{isResolvingUri ? 'Validating...' : 'Unused'}</span>;
+      return <span className="empty">Unused</span>;
     }
 
     const {
@@ -49,17 +38,14 @@ class UriIndicator extends React.PureComponent<Props> {
       signature_is_valid: signatureIsValid,
       value,
     } = claim;
-
     const channelClaimId =
       value && value.publisherSignature && value.publisherSignature.certificateId;
 
     if (!hasSignature || !channelName) {
-      return <span>Anonymous</span>;
+      return <span className="empty">Anonymous</span>;
     }
 
-    let icon;
-    let channelLink;
-    let modifier;
+    let icon, channelLink, modifier;
 
     if (signatureIsValid) {
       modifier = 'valid';
@@ -73,6 +59,7 @@ class UriIndicator extends React.PureComponent<Props> {
       <span>
         <span
           className={classnames('channel-name', {
+            'channel-name--small': smallCard,
             'button-text no-underline': link,
           })}
         >
@@ -94,9 +81,14 @@ class UriIndicator extends React.PureComponent<Props> {
     }
 
     return (
-      <Button navigate="/show" navigateParams={{ uri: channelLink }} fakeLink>
+      <Link
+        navigate="/show"
+        navigateParams={{ uri: channelLink }}
+        className="no-underline"
+        span={span}
+      >
         {inner}
-      </Button>
+      </Link>
     );
   }
 }
diff --git a/src/renderer/component/wunderbar/index.js b/src/renderer/component/wunderbar/index.js
index 575676232..826ab4225 100644
--- a/src/renderer/component/wunderbar/index.js
+++ b/src/renderer/component/wunderbar/index.js
@@ -1,21 +1,19 @@
+import React from 'react';
 import { connect } from 'react-redux';
-import lbryuri from 'lbryuri';
-import { selectState as selectSearch, selectWunderBarAddress } from 'redux/selectors/search';
+import lbryuri from 'lbryuri.js';
+import { selectWunderBarAddress, selectWunderBarIcon } from 'redux/selectors/search';
 import { doNavigate } from 'redux/actions/navigation';
-import { updateSearchQuery, getSearchSuggestions } from 'redux/actions/search';
 import Wunderbar from './view';
 
 const select = state => ({
-  ...selectSearch(state),
   address: selectWunderBarAddress(state),
+  icon: selectWunderBarIcon(state),
 });
 
 const perform = dispatch => ({
   onSearch: query => dispatch(doNavigate('/search', { query })),
   onSubmit: (query, extraParams) =>
     dispatch(doNavigate('/show', { uri: lbryuri.normalize(query), ...extraParams })),
-  updateSearchQuery: query => dispatch(updateSearchQuery(query)),
-  getSearchSuggestions: query => dispatch(getSearchSuggestions(query)),
 });
 
 export default connect(select, perform)(Wunderbar);
diff --git a/src/renderer/component/wunderbar/internal/autocomplete.jsx b/src/renderer/component/wunderbar/internal/autocomplete.jsx
deleted file mode 100644
index 5c70c8f06..000000000
--- a/src/renderer/component/wunderbar/internal/autocomplete.jsx
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
-This is taken from https://github.com/reactjs/react-autocomplete
-
-We aren't using that component because (for now) there is no way to autohightlight
-the first item if it isn't an exact match from what is in the search bar.
-
-Our use case is:
-value in search bar: "hello"
-first suggestion: "lbry://hello"
-
-I changed the function maybeAutoCompleteText to check if the suggestion contains
-the search query anywhere, instead of the suggestion starting with it
-
-https://github.com/reactjs/react-autocomplete/issues/239
-*/
-/* eslint-disable */
-
-const React = require('react');
-const PropTypes = require('prop-types');
-const { findDOMNode } = require('react-dom');
-const scrollIntoView = require('dom-scroll-into-view');
-
-const IMPERATIVE_API = [
-  'blur',
-  'checkValidity',
-  'click',
-  'focus',
-  'select',
-  'setCustomValidity',
-  'setSelectionRange',
-  'setRangeText',
-];
-
-function getScrollOffset() {
-  return {
-    x:
-      window.pageXOffset !== undefined
-        ? window.pageXOffset
-        : (document.documentElement || document.body.parentNode || document.body).scrollLeft,
-    y:
-      window.pageYOffset !== undefined
-        ? window.pageYOffset
-        : (document.documentElement || document.body.parentNode || document.body).scrollTop,
-  };
-}
-
-export default class Autocomplete extends React.Component {
-  static propTypes = {
-    /**
-     * The items to display in the dropdown menu
-     */
-    items: PropTypes.array.isRequired,
-    /**
-     * The value to display in the input field
-     */
-    value: PropTypes.any,
-    /**
-     * Arguments: `event: Event, value: String`
-     *
-     * Invoked every time the user changes the input's value.
-     */
-    onChange: PropTypes.func,
-    /**
-     * Arguments: `value: String, item: Any`
-     *
-     * Invoked when the user selects an item from the dropdown menu.
-     */
-    onSelect: PropTypes.func,
-    /**
-     * Arguments: `item: Any, value: String`
-     *
-     * Invoked for each entry in `items` and its return value is used to
-     * determine whether or not it should be displayed in the dropdown menu.
-     * By default all items are always rendered.
-     */
-    shouldItemRender: PropTypes.func,
-    /**
-     * Arguments: `itemA: Any, itemB: Any, value: String`
-     *
-     * The function which is used to sort `items` before display.
-     */
-    sortItems: PropTypes.func,
-    /**
-     * Arguments: `item: Any`
-     *
-     * Used to read the display value from each entry in `items`.
-     */
-    getItemValue: PropTypes.func.isRequired,
-    /**
-     * Arguments: `item: Any, isHighlighted: Boolean, styles: Object`
-     *
-     * Invoked for each entry in `items` that also passes `shouldItemRender` to
-     * generate the render tree for each item in the dropdown menu. `styles` is
-     * an optional set of styles that can be applied to improve the look/feel
-     * of the items in the dropdown menu.
-     */
-    renderItem: PropTypes.func.isRequired,
-    /**
-     * Arguments: `items: Array<Any>, value: String, styles: Object`
-     *
-     * Invoked to generate the render tree for the dropdown menu. Ensure the
-     * returned tree includes every entry in `items` or else the highlight order
-     * and keyboard navigation logic will break. `styles` will contain
-     * { top, left, minWidth } which are the coordinates of the top-left corner
-     * and the width of the dropdown menu.
-     */
-    renderMenu: PropTypes.func,
-    /**
-     * Styles that are applied to the dropdown menu in the default `renderMenu`
-     * implementation. If you override `renderMenu` and you want to use
-     * `menuStyle` you must manually apply them (`this.props.menuStyle`).
-     */
-    menuStyle: PropTypes.object,
-    /**
-     * Arguments: `props: Object`
-     *
-     * Invoked to generate the input element. The `props` argument is the result
-     * of merging `props.inputProps` with a selection of props that are required
-     * both for functionality and accessibility. At the very least you need to
-     * apply `props.ref` and all `props.on<event>` event handlers. Failing to do
-     * this will cause `Autocomplete` to behave unexpectedly.
-     */
-    renderInput: PropTypes.func,
-    /**
-     * Props passed to `props.renderInput`. By default these props will be
-     * applied to the `<input />` element rendered by `Autocomplete`, unless you
-     * have specified a custom value for `props.renderInput`. Any properties
-     * supported by `HTMLInputElement` can be specified, apart from the
-     * following which are set by `Autocomplete`: value, autoComplete, role,
-     * aria-autocomplete. `inputProps` is commonly used for (but not limited to)
-     * placeholder, event handlers (onFocus, onBlur, etc.), autoFocus, etc..
-     */
-    inputProps: PropTypes.object,
-    /**
-     * Props that are applied to the element which wraps the `<input />` and
-     * dropdown menu elements rendered by `Autocomplete`.
-     */
-    wrapperProps: PropTypes.object,
-    /**
-     * This is a shorthand for `wrapperProps={{ style: <your styles> }}`.
-     * Note that `wrapperStyle` is applied before `wrapperProps`, so the latter
-     * will win if it contains a `style` entry.
-     */
-    wrapperStyle: PropTypes.object,
-    /**
-     * Whether or not to automatically highlight the top match in the dropdown
-     * menu.
-     */
-    autoHighlight: PropTypes.bool,
-    /**
-     * Whether or not to automatically select the highlighted item when the
-     * `<input>` loses focus.
-     */
-    selectOnBlur: PropTypes.bool,
-    /**
-     * Arguments: `isOpen: Boolean`
-     *
-     * Invoked every time the dropdown menu's visibility changes (i.e. every
-     * time it is displayed/hidden).
-     */
-    onMenuVisibilityChange: PropTypes.func,
-    /**
-     * Used to override the internal logic which displays/hides the dropdown
-     * menu. This is useful if you want to force a certain state based on your
-     * UX/business logic. Use it together with `onMenuVisibilityChange` for
-     * fine-grained control over the dropdown menu dynamics.
-     */
-    open: PropTypes.bool,
-    debug: PropTypes.bool,
-  };
-
-  static defaultProps = {
-    value: '',
-    wrapperProps: {},
-    wrapperStyle: {
-      display: 'inline-block',
-    },
-    inputProps: {},
-    renderInput(props) {
-      return <input {...props} />;
-    },
-    onChange() {},
-    onSelect() {},
-    renderMenu(items, value, style) {
-      return <div style={{ ...style, ...this.menuStyle }} children={items} />;
-    },
-    menuStyle: {
-      borderRadius: '3px',
-      boxShadow: '0 2px 12px rgba(0, 0, 0, 0.1)',
-      background: 'rgba(255, 255, 255, 0.9)',
-      padding: '2px 0',
-      fontSize: '90%',
-      position: 'fixed',
-      overflow: 'auto',
-      maxHeight: '50%', // TODO: don't cheat, let it flow to the bottom,
-    },
-    autoHighlight: true,
-    selectOnBlur: false,
-    onMenuVisibilityChange() {},
-  };
-
-  constructor(props) {
-    super(props);
-    this.state = {
-      isOpen: false,
-      highlightedIndex: null,
-    };
-    this._debugStates = [];
-    this.ensureHighlightedIndex = this.ensureHighlightedIndex.bind(this);
-    this.exposeAPI = this.exposeAPI.bind(this);
-    this.handleInputFocus = this.handleInputFocus.bind(this);
-    this.handleInputBlur = this.handleInputBlur.bind(this);
-    this.handleChange = this.handleChange.bind(this);
-    this.handleKeyDown = this.handleKeyDown.bind(this);
-    this.handleInputClick = this.handleInputClick.bind(this);
-    this.maybeAutoCompleteText = this.maybeAutoCompleteText.bind(this);
-  }
-
-  componentWillMount() {
-    // this.refs is frozen, so we need to assign a new object to it
-    this.refs = {};
-    this._ignoreBlur = false;
-    this._ignoreFocus = false;
-    this._scrollOffset = null;
-    this._scrollTimer = null;
-  }
-
-  componentWillUnmount() {
-    clearTimeout(this._scrollTimer);
-    this._scrollTimer = null;
-  }
-
-  componentWillReceiveProps(nextProps) {
-    if (this.state.highlightedIndex !== null) {
-      this.setState(this.ensureHighlightedIndex);
-    }
-    if (
-      nextProps.autoHighlight &&
-      (this.props.value !== nextProps.value || this.state.highlightedIndex === null)
-    ) {
-      this.setState(this.maybeAutoCompleteText);
-    }
-  }
-
-  componentDidMount() {
-    if (this.isOpen()) {
-      this.setMenuPositions();
-    }
-  }
-
-  componentDidUpdate(prevProps, prevState) {
-    if (
-      (this.state.isOpen && !prevState.isOpen) ||
-      ('open' in this.props && this.props.open && !prevProps.open)
-    )
-      this.setMenuPositions();
-
-    this.maybeScrollItemIntoView();
-    if (prevState.isOpen !== this.state.isOpen) {
-      this.props.onMenuVisibilityChange(this.state.isOpen);
-    }
-  }
-
-  exposeAPI(el) {
-    this.refs.input = el;
-    IMPERATIVE_API.forEach(ev => (this[ev] = el && el[ev] && el[ev].bind(el)));
-  }
-
-  maybeScrollItemIntoView() {
-    if (this.isOpen() && this.state.highlightedIndex !== null) {
-      const itemNode = this.refs[`item-${this.state.highlightedIndex}`];
-      const menuNode = this.refs.menu;
-      scrollIntoView(findDOMNode(itemNode), findDOMNode(menuNode), {
-        onlyScrollIfNeeded: true,
-      });
-    }
-  }
-
-  handleKeyDown(event) {
-    if (Autocomplete.keyDownHandlers[event.key])
-      Autocomplete.keyDownHandlers[event.key].call(this, event);
-    else if (!this.isOpen()) {
-      this.setState({
-        isOpen: true,
-      });
-    }
-  }
-
-  handleChange(event) {
-    this.props.onChange(event, event.target.value);
-  }
-
-  static keyDownHandlers = {
-    ArrowDown(event) {
-      event.preventDefault();
-      const itemsLength = this.getFilteredItems(this.props).length;
-      if (!itemsLength) return;
-      const { highlightedIndex } = this.state;
-      const index =
-        highlightedIndex === null || highlightedIndex === itemsLength - 1
-          ? 0
-          : highlightedIndex + 1;
-      this.setState({
-        highlightedIndex: index,
-        isOpen: true,
-      });
-    },
-
-    ArrowUp(event) {
-      event.preventDefault();
-      const itemsLength = this.getFilteredItems(this.props).length;
-      if (!itemsLength) return;
-      const { highlightedIndex } = this.state;
-      const index =
-        highlightedIndex === 0 || highlightedIndex === null
-          ? itemsLength - 1
-          : highlightedIndex - 1;
-      this.setState({
-        highlightedIndex: index,
-        isOpen: true,
-      });
-    },
-
-    Enter(event) {
-      // Key code 229 is used for selecting items from character selectors (Pinyin, Kana, etc)
-      if (event.keyCode !== 13) return;
-      if (!this.isOpen()) {
-        // menu is closed so there is no selection to accept -> do nothing
-      } else if (this.state.highlightedIndex == null) {
-        // input has focus but no menu item is selected + enter is hit -> close the menu, highlight whatever's in input
-        this.setState(
-          {
-            isOpen: false,
-          },
-          () => {
-            this.refs.input.select();
-          }
-        );
-      } else {
-        // text entered + menu item has been highlighted + enter is hit -> update value to that of selected menu item, close the menu
-        event.preventDefault();
-        const item = this.getFilteredItems(this.props)[this.state.highlightedIndex];
-        const value = this.props.getItemValue(item);
-        this.setState(
-          {
-            isOpen: false,
-            highlightedIndex: null,
-          },
-          () => {
-            // this.refs.input.focus() // TODO: file issue
-            this.refs.input.setSelectionRange(value.length, value.length);
-            this.props.onSelect(value, item);
-          }
-        );
-      }
-    },
-
-    Escape() {
-      // In case the user is currently hovering over the menu
-      this.setIgnoreBlur(false);
-      this.setState({
-        highlightedIndex: null,
-        isOpen: false,
-      });
-    },
-
-    Tab() {
-      // In case the user is currently hovering over the menu
-      this.setIgnoreBlur(false);
-    },
-  };
-
-  getFilteredItems(props) {
-    let items = props.items;
-
-    if (props.shouldItemRender) {
-      items = items.filter(item => props.shouldItemRender(item, props.value));
-    }
-
-    if (props.sortItems) {
-      items.sort((a, b) => props.sortItems(a, b, props.value));
-    }
-
-    return items;
-  }
-
-  maybeAutoCompleteText(state, props) {
-    const { highlightedIndex } = state;
-    const { value, getItemValue } = props;
-    const index = highlightedIndex === null ? 0 : highlightedIndex;
-    const matchedItem = this.getFilteredItems(props)[index];
-    if (value !== '' && matchedItem) {
-      const itemValue = getItemValue(matchedItem);
-      const itemValueDoesMatch =
-        itemValue.toLowerCase().indexOf(
-          value.toLowerCase()
-          // below line is the the only thing that is changed from the real component
-        ) !== -1;
-      if (itemValueDoesMatch) {
-        return { highlightedIndex: index };
-      }
-    }
-    return { highlightedIndex: null };
-  }
-
-  ensureHighlightedIndex(state, props) {
-    if (state.highlightedIndex >= this.getFilteredItems(props).length) {
-      return { highlightedIndex: null };
-    }
-  }
-
-  setMenuPositions() {
-    const node = this.refs.input;
-    const rect = node.getBoundingClientRect();
-    const computedStyle = global.window.getComputedStyle(node);
-    const marginBottom = parseInt(computedStyle.marginBottom, 10) || 0;
-    const marginLeft = parseInt(computedStyle.marginLeft, 10) || 0;
-    const marginRight = parseInt(computedStyle.marginRight, 10) || 0;
-    this.setState({
-      menuTop: rect.bottom + marginBottom,
-      menuLeft: rect.left + marginLeft,
-      menuWidth: rect.width + marginLeft + marginRight,
-    });
-  }
-
-  highlightItemFromMouse(index) {
-    this.setState({ highlightedIndex: index });
-  }
-
-  selectItemFromMouse(item) {
-    const value = this.props.getItemValue(item);
-    // The menu will de-render before a mouseLeave event
-    // happens. Clear the flag to release control over focus
-    this.setIgnoreBlur(false);
-    this.setState(
-      {
-        isOpen: false,
-        highlightedIndex: null,
-      },
-      () => {
-        this.props.onSelect(value, item);
-      }
-    );
-  }
-
-  setIgnoreBlur(ignore) {
-    this._ignoreBlur = ignore;
-  }
-
-  renderMenu() {
-    const items = this.getFilteredItems(this.props).map((item, index) => {
-      const element = this.props.renderItem(item, this.state.highlightedIndex === index, {
-        cursor: 'default',
-      });
-      return React.cloneElement(element, {
-        onMouseEnter: () => this.highlightItemFromMouse(index),
-        onClick: () => this.selectItemFromMouse(item),
-        ref: e => (this.refs[`item-${index}`] = e),
-      });
-    });
-    const style = {
-      left: this.state.menuLeft,
-      top: this.state.menuTop,
-      minWidth: this.state.menuWidth,
-    };
-    const menu = this.props.renderMenu(items, this.props.value, style);
-    return React.cloneElement(menu, {
-      ref: e => (this.refs.menu = e),
-      // Ignore blur to prevent menu from de-rendering before we can process click
-      onMouseEnter: () => this.setIgnoreBlur(true),
-      onMouseLeave: () => this.setIgnoreBlur(false),
-    });
-  }
-
-  handleInputBlur(event) {
-    if (this._ignoreBlur) {
-      this._ignoreFocus = true;
-      this._scrollOffset = getScrollOffset();
-      this.refs.input.focus();
-      return;
-    }
-    let setStateCallback;
-    const { highlightedIndex } = this.state;
-    if (this.props.selectOnBlur && highlightedIndex !== null) {
-      const items = this.getFilteredItems(this.props);
-      const item = items[highlightedIndex];
-      const value = this.props.getItemValue(item);
-      setStateCallback = () => this.props.onSelect(value, item);
-    }
-    this.setState(
-      {
-        isOpen: false,
-        highlightedIndex: null,
-      },
-      setStateCallback
-    );
-    const { onBlur } = this.props.inputProps;
-    if (onBlur) {
-      onBlur(event);
-    }
-  }
-
-  handleInputFocus(event) {
-    if (this._ignoreFocus) {
-      this._ignoreFocus = false;
-      const { x, y } = this._scrollOffset;
-      this._scrollOffset = null;
-      // Focus will cause the browser to scroll the <input> into view.
-      // This can cause the mouse coords to change, which in turn
-      // could cause a new highlight to happen, cancelling the click
-      // event (when selecting with the mouse)
-      window.scrollTo(x, y);
-      // Some browsers wait until all focus event handlers have been
-      // processed before scrolling the <input> into view, so let's
-      // scroll again on the next tick to ensure we're back to where
-      // the user was before focus was lost. We could do the deferred
-      // scroll only, but that causes a jarring split second jump in
-      // some browsers that scroll before the focus event handlers
-      // are triggered.
-      clearTimeout(this._scrollTimer);
-      this._scrollTimer = setTimeout(() => {
-        this._scrollTimer = null;
-        window.scrollTo(x, y);
-      }, 0);
-      return;
-    }
-    this.setState({ isOpen: true });
-    const { onFocus } = this.props.inputProps;
-    if (onFocus) {
-      onFocus(event);
-    }
-  }
-
-  isInputFocused() {
-    const el = this.refs.input;
-    return el.ownerDocument && el === el.ownerDocument.activeElement;
-  }
-
-  handleInputClick() {
-    // Input will not be focused if it's disabled
-    if (this.isInputFocused() && !this.isOpen()) this.setState({ isOpen: true });
-  }
-
-  composeEventHandlers(internal, external) {
-    return external
-      ? e => {
-          internal(e);
-          external(e);
-        }
-      : internal;
-  }
-
-  isOpen() {
-    return 'open' in this.props ? this.props.open : this.state.isOpen;
-  }
-
-  render() {
-    if (this.props.debug) {
-      // you don't like it, you love it
-      this._debugStates.push({
-        id: this._debugStates.length,
-        state: this.state,
-      });
-    }
-
-    const { inputProps, items } = this.props;
-
-    const open = this.isOpen();
-    return (
-      <div style={{ ...this.props.wrapperStyle }} {...this.props.wrapperProps}>
-        {this.props.renderInput({
-          ...inputProps,
-          role: 'combobox',
-          'aria-autocomplete': 'list',
-          'aria-expanded': open,
-          autoComplete: 'off',
-          ref: this.exposeAPI,
-          onFocus: this.handleInputFocus,
-          onBlur: this.handleInputBlur,
-          onChange: this.handleChange,
-          onKeyDown: this.composeEventHandlers(this.handleKeyDown, inputProps.onKeyDown),
-          onClick: this.composeEventHandlers(this.handleInputClick, inputProps.onClick),
-          value: this.props.value,
-        })}
-        {open && !!items.length && this.renderMenu()}
-        {this.props.debug && (
-          <pre style={{ marginLeft: 300 }}>
-            {JSON.stringify(
-              this._debugStates.slice(
-                Math.max(0, this._debugStates.length - 5),
-                this._debugStates.length
-              ),
-              null,
-              2
-            )}
-          </pre>
-        )}
-      </div>
-    );
-  }
-}
diff --git a/src/renderer/component/wunderbar/view.jsx b/src/renderer/component/wunderbar/view.jsx
index 27fdd5e17..f332a11ec 100644
--- a/src/renderer/component/wunderbar/view.jsx
+++ b/src/renderer/component/wunderbar/view.jsx
@@ -1,116 +1,166 @@
-// @flow
 import React from 'react';
-import lbryuri from 'lbryuri';
-import classnames from 'classnames';
-import Autocomplete from './internal/autocomplete';
+import PropTypes from 'prop-types';
+import lbryuri from 'lbryuri.js';
+import Icon from 'component/icon';
+import { parseQueryParams } from 'util/query_params';
 
-type Props = {
-  updateSearchQuery: string => void,
-  getSearchSuggestions: string => void,
-  onSearch: string => void,
-  onSubmit: string => void,
-  searchQuery: ?string,
-  isActive: boolean,
-  address: ?string,
-  suggestions: Array<string>,
-};
+class WunderBar extends React.PureComponent {
+  static TYPING_TIMEOUT = 800;
 
-class WunderBar extends React.PureComponent<Props> {
-  constructor() {
-    super();
-    (this: any).handleSubmit = this.handleSubmit.bind(this);
-    (this: any).handleChange = this.handleChange.bind(this);
-    (this: any).focus = this.focus.bind(this);
-    this.input = undefined;
+  static propTypes = {
+    onSearch: PropTypes.func.isRequired,
+    onSubmit: PropTypes.func.isRequired,
+  };
+
+  constructor(props) {
+    super(props);
+    this._userTypingTimer = null;
+    this._isSearchDispatchPending = false;
+    this._input = null;
+    this._stateBeforeSearch = null;
+    this._resetOnNextBlur = true;
+    this.onChange = this.onChange.bind(this);
+    this.onFocus = this.onFocus.bind(this);
+    this.onBlur = this.onBlur.bind(this);
+    this.onKeyPress = this.onKeyPress.bind(this);
+    this.onReceiveRef = this.onReceiveRef.bind(this);
+    this.state = {
+      address: this.props.address,
+      icon: this.props.icon,
+    };
   }
 
-  input: ?HTMLInputElement;
-
-  handleChange(e: SyntheticInputEvent<*>) {
-    const { updateSearchQuery, getSearchSuggestions } = this.props;
-    const { value } = e.target;
-
-    updateSearchQuery(value);
-    getSearchSuggestions(value);
-  }
-
-  focus() {
-    const { input } = this;
-    if (input) {
-      input.focus();
+  componentWillUnmount() {
+    if (this.userTypingTimer) {
+      clearTimeout(this._userTypingTimer);
     }
   }
 
-  handleSubmit(value: string) {
-    if (!value) {
-      return;
+  onChange(event) {
+    if (this._userTypingTimer) {
+      clearTimeout(this._userTypingTimer);
     }
 
-    const { onSubmit, onSearch } = this.props;
+    this.setState({ address: event.target.value });
 
-    // if they choose the "search for {value}" in the suggestions
-    // it will contain the {query}?search
-    const choseDoSuggestedSearch = value.endsWith('?search');
+    this._isSearchDispatchPending = true;
 
-    let searchValue = value;
-    if (choseDoSuggestedSearch) {
-      searchValue = value.slice(0, -7); // trim off ?search
+    const searchQuery = event.target.value;
+
+    this._userTypingTimer = setTimeout(() => {
+      const hasQuery = searchQuery.length === 0;
+      this._resetOnNextBlur = hasQuery;
+      this._isSearchDispatchPending = false;
+      if (searchQuery) {
+        this.props.onSearch(searchQuery.trim());
+      }
+    }, WunderBar.TYPING_TIMEOUT); // 800ms delay, tweak for faster/slower
+  }
+
+  componentWillReceiveProps(nextProps) {
+    if (
+      nextProps.viewingPage !== this.props.viewingPage ||
+      nextProps.address != this.props.address
+    ) {
+      this.setState({ address: nextProps.address, icon: nextProps.icon });
     }
+  }
 
-    if (this.input) {
-      this.input.blur();
-    }
+  onFocus() {
+    this._stateBeforeSearch = this.state;
+    const newState = {
+      icon: 'icon-search',
+      isActive: true,
+    };
 
-    try {
-      const uri = lbryuri.normalize(value);
-      onSubmit(uri);
-    } catch (e) {
-      // search query isn't a valid uri
-      onSearch(searchValue);
+    this._focusPending = true;
+    // below is hacking, improved when we have proper routing
+    if (!this.state.address.startsWith('lbry://') && this.state.icon !== 'icon-search') {
+      // onFocus, if they are not on an exact URL or a search page, clear the bar
+      newState.address = '';
     }
+    this.setState(newState);
+  }
+
+  onBlur() {
+    if (this._isSearchDispatchPending) {
+      setTimeout(() => {
+        this.onBlur();
+      }, WunderBar.TYPING_TIMEOUT + 1);
+    } else {
+      const commonState = { isActive: false };
+      if (this._resetOnNextBlur) {
+        this.setState(Object.assign({}, this._stateBeforeSearch, commonState));
+        this._input.value = this.state.address;
+      } else {
+        this._resetOnNextBlur = true;
+        this._stateBeforeSearch = this.state;
+        this.setState(commonState);
+      }
+    }
+  }
+
+  componentDidUpdate() {
+    if (this._input) {
+      const start = this._input.selectionStart,
+        end = this._input.selectionEnd;
+
+      this._input.value = this.state.address; // this causes cursor to go to end of input
+
+      this._input.setSelectionRange(start, end);
+
+      if (this._focusPending) {
+        this._input.select();
+        this._focusPending = false;
+      }
+    }
+  }
+
+  onKeyPress(event) {
+    if (event.charCode == 13 && this._input.value) {
+      let uri = null,
+        method = 'onSubmit',
+        extraParams = {};
+
+      this._resetOnNextBlur = false;
+      clearTimeout(this._userTypingTimer);
+
+      const parts = this._input.value.trim().split('?');
+      const value = parts.shift();
+      if (parts.length > 0) extraParams = parseQueryParams(parts.join(''));
+
+      try {
+        uri = lbryuri.normalize(value);
+        this.setState({ value: uri });
+      } catch (error) {
+        // then it's not a valid URL, so let's search
+        uri = value;
+        method = 'onSearch';
+      }
+
+      this.props[method](uri, extraParams);
+      this._input.blur();
+    }
+  }
+
+  onReceiveRef(ref) {
+    this._input = ref;
   }
 
   render() {
-    const { searchQuery, isActive, address, suggestions } = this.props;
-
-    // if we are on the file/channel page
-    // use the address in the history stack
-    const wunderbarValue = isActive ? searchQuery : searchQuery || address;
-
     return (
-      <div
-        className={classnames('header__wunderbar', {
-          'header__wunderbar--active': isActive,
-        })}
-      >
-        <Autocomplete
-          autoHighlight
-          ref={ref => {
-            this.input = ref;
-          }}
-          wrapperStyle={{ flex: 1, minHeight: 0 }}
-          value={wunderbarValue}
-          items={suggestions}
-          getItemValue={item => item.value}
-          onChange={this.handleChange}
-          onSelect={this.handleSubmit}
-          renderInput={props => (
-            <input
-              {...props}
-              className="wunderbar__input"
-              placeholder="Search for videos, music, games and more"
-            />
-          )}
-          renderItem={(item, isHighlighted) => (
-            <div
-              key={item.value}
-              className={classnames('wunderbar__suggestion', {
-                'wunderbar__active-suggestion': isHighlighted,
-              })}
-            >
-              {item.label}
-            </div>
-          )}
+      <div className={`wunderbar${this.state.isActive ? ' wunderbar--active' : ''}`}>
+        {this.state.icon ? <Icon fixed icon={this.state.icon} /> : ''}
+        <input
+          className="wunderbar__input"
+          type="search"
+          ref={this.onReceiveRef}
+          onFocus={this.onFocus}
+          onBlur={this.onBlur}
+          onChange={this.onChange}
+          onKeyPress={this.onKeyPress}
+          value={this.state.address}
+          placeholder={__('Find videos, music, games, and more')}
         />
       </div>
     );
diff --git a/src/renderer/constants/action_types.js b/src/renderer/constants/action_types.js
index 9a8c57c7f..3c828f5cb 100644
--- a/src/renderer/constants/action_types.js
+++ b/src/renderer/constants/action_types.js
@@ -88,13 +88,9 @@ export const FETCH_AVAILABILITY_COMPLETED = 'FETCH_AVAILABILITY_COMPLETED';
 export const FILE_DELETE = 'FILE_DELETE';
 
 // Search
-export const SEARCH_START = 'SEARCH_START';
-export const SEARCH_SUCCESS = 'SEARCH_SUCCESS';
-export const SEARCH_FAIL = 'SEARCH_FAIL';
-export const UPDATE_SEARCH_QUERY = 'UPDATE_SEARCH_QUERY';
-export const SEARCH_SUGGESTIONS_START = 'SEARCH_SUGGESTIONS_START';
-export const GET_SEARCH_SUGGESTIONS_SUCCESS = 'GET_SEARCH_SUGGESTIONS_SUCCESS';
-export const GET_SEARCH_SUGGESTIONS_FAIL = 'GET_SEARCH_SUGGESTIONS_FAIL';
+export const SEARCH_STARTED = 'SEARCH_STARTED';
+export const SEARCH_COMPLETED = 'SEARCH_COMPLETED';
+export const SEARCH_CANCELLED = 'SEARCH_CANCELLED';
 
 // Settings
 export const DAEMON_SETTINGS_RECEIVED = 'DAEMON_SETTINGS_RECEIVED';
diff --git a/flow-typed/reselect.js b/src/renderer/flow-typed/reselect.js
similarity index 100%
rename from flow-typed/reselect.js
rename to src/renderer/flow-typed/reselect.js
diff --git a/src/renderer/index.js b/src/renderer/index.js
index ad2db3927..fd6dcc1f7 100644
--- a/src/renderer/index.js
+++ b/src/renderer/index.js
@@ -31,7 +31,7 @@ ipcRenderer.on('open-uri-requested', (event, uri, newSession) => {
       try {
         verification = JSON.parse(atob(uri.substring(15)));
       } catch (error) {
-        console.log(error); // eslint-disable-line no-console
+        console.log(error);
       }
       if (verification.token && verification.recaptcha) {
         app.store.dispatch(doConditionalAuthNavigate(newSession));
@@ -112,10 +112,10 @@ const init = () => {
 
           ReactDOM.render(
             <Provider store={store}>
-              <React.Fragment>
+              <div>
                 <App />
                 <SnackBar />
-              </React.Fragment>
+              </div>
             </Provider>,
             document.getElementById('app')
           );
diff --git a/src/renderer/page/channel/view.jsx b/src/renderer/page/channel/view.jsx
index 7ce61b182..f32a9f938 100644
--- a/src/renderer/page/channel/view.jsx
+++ b/src/renderer/page/channel/view.jsx
@@ -1,4 +1,3 @@
-/* eslint-disable */
 import React from 'react';
 import lbryuri from 'lbryuri';
 import { BusyMessage } from 'component/common';
@@ -6,7 +5,6 @@ import FileTile from 'component/fileTile';
 import ReactPaginate from 'react-paginate';
 import Link from 'component/link';
 import SubscribeButton from 'component/subscribeButton';
-import Page from 'component/page';
 
 class ChannelPage extends React.PureComponent {
   componentDidMount() {
@@ -72,7 +70,7 @@ class ChannelPage extends React.PureComponent {
     }
 
     return (
-      <Page>
+      <div>
         <section className="card">
           <div className="card__inner">
             <div className="card__title-identity">
@@ -109,10 +107,9 @@ class ChannelPage extends React.PureComponent {
               containerClassName="pagination"
             />
           )}
-      </Page>
+      </div>
     );
   }
 }
 
 export default ChannelPage;
-/* eslint-enable */
diff --git a/src/renderer/page/discover/view.jsx b/src/renderer/page/discover/view.jsx
index 28adf330c..52b841bab 100644
--- a/src/renderer/page/discover/view.jsx
+++ b/src/renderer/page/discover/view.jsx
@@ -1,37 +1,259 @@
-// @flow
 import React from 'react';
-import Page from 'component/page';
-import CategoryList from 'component/common/category-list';
+import ReactDOM from 'react-dom';
+import lbryuri from 'lbryuri';
+import FileCard from 'component/fileCard';
+import { BusyMessage } from 'component/common.js';
+import Icon from 'component/icon';
+import ToolTip from 'component/tooltip.js';
+import SubHeader from 'component/subHeader';
+import classnames from 'classnames';
+import Link from 'component/link';
 
-type Props = {
-  fetchFeaturedUris: () => void,
-  fetchingFeaturedUris: boolean,
-  featuredUris: {},
-};
+// This should be in a separate file
+export class FeaturedCategory extends React.PureComponent {
+  constructor() {
+    super();
 
-class DiscoverPage extends React.PureComponent<Props> {
+    this.state = {
+      numItems: undefined,
+      canScrollPrevious: false,
+      canScrollNext: false,
+    };
+  }
+
+  componentWillMount() {
+    this.setState({
+      numItems: this.props.names.length,
+    });
+  }
+
+  componentDidMount() {
+    const cardRow = ReactDOM.findDOMNode(this.refs.rowitems);
+    const cards = cardRow.getElementsByTagName('section');
+
+    // check if the last card is visible
+    const lastCard = cards[cards.length - 1];
+    const isCompletelyVisible = this.isCardVisible(lastCard, cardRow, false);
+
+    if (!isCompletelyVisible) {
+      this.setState({
+        canScrollNext: true,
+      });
+    }
+  }
+
+  handleScrollPrevious() {
+    const cardRow = ReactDOM.findDOMNode(this.refs.rowitems);
+    if (cardRow.scrollLeft > 0) {
+      // check the visible cards
+      const cards = cardRow.getElementsByTagName('section');
+      let firstVisibleCard = null;
+      let firstVisibleIdx = -1;
+      for (let i = 0; i < cards.length; i++) {
+        if (this.isCardVisible(cards[i], cardRow, false)) {
+          firstVisibleCard = cards[i];
+          firstVisibleIdx = i;
+          break;
+        }
+      }
+
+      const numDisplayed = this.numDisplayedCards(cardRow);
+      const scrollToIdx = firstVisibleIdx - numDisplayed;
+      const animationCallback = () => {
+        this.setState({
+          canScrollPrevious: cardRow.scrollLeft !== 0,
+          canScrollNext: true,
+        });
+      };
+      this.scrollCardItemsLeftAnimated(
+        cardRow,
+        scrollToIdx < 0 ? 0 : cards[scrollToIdx].offsetLeft,
+        100,
+        animationCallback
+      );
+    }
+  }
+
+  handleScrollNext() {
+    const cardRow = ReactDOM.findDOMNode(this.refs.rowitems);
+
+    // check the visible cards
+    const cards = cardRow.getElementsByTagName('section');
+    let lastVisibleCard = null;
+    let lastVisibleIdx = -1;
+    for (let i = 0; i < cards.length; i++) {
+      if (this.isCardVisible(cards[i], cardRow, true)) {
+        lastVisibleCard = cards[i];
+        lastVisibleIdx = i;
+      }
+    }
+
+    if (lastVisibleCard) {
+      const numDisplayed = this.numDisplayedCards(cardRow);
+      const animationCallback = () => {
+        // update last visible index after scroll
+        for (let i = 0; i < cards.length; i++) {
+          if (this.isCardVisible(cards[i], cardRow, true)) {
+            lastVisibleIdx = i;
+          }
+        }
+
+        this.setState({ canScrollPrevious: true });
+        if (lastVisibleIdx === cards.length - 1) {
+          this.setState({ canScrollNext: false });
+        }
+      };
+
+      this.scrollCardItemsLeftAnimated(
+        cardRow,
+        Math.min(lastVisibleCard.offsetLeft, cardRow.scrollWidth - cardRow.clientWidth),
+        100,
+        animationCallback
+      );
+    }
+  }
+
+  scrollCardItemsLeftAnimated(cardRow, target, duration, callback) {
+    if (!duration || duration <= diff) {
+      cardRow.scrollLeft = target;
+      if (callback) {
+        callback();
+      }
+      return;
+    }
+
+    const component = this;
+    const diff = target - cardRow.scrollLeft;
+    const tick = diff / duration * 10;
+    setTimeout(() => {
+      cardRow.scrollLeft += tick;
+      if (cardRow.scrollLeft === target) {
+        if (callback) {
+          callback();
+        }
+        return;
+      }
+      component.scrollCardItemsLeftAnimated(cardRow, target, duration - 10, callback);
+    }, 10);
+  }
+
+  isCardVisible(section, cardRow, partialVisibility) {
+    // check if a card is fully or partialy visible in its parent
+    const cardRowWidth = cardRow.offsetWidth;
+    const cardRowLeft = cardRow.scrollLeft;
+    const cardRowEnd = cardRowLeft + cardRow.offsetWidth;
+    const sectionLeft = section.offsetLeft - cardRowLeft;
+    const sectionEnd = sectionLeft + section.offsetWidth;
+
+    return (
+      (sectionLeft >= 0 && sectionEnd <= cardRowWidth) ||
+      (((sectionLeft < 0 && sectionEnd > 0) || (sectionLeft > 0 && sectionLeft <= cardRowWidth)) &&
+        partialVisibility)
+    );
+  }
+
+  numDisplayedCards(cardRow) {
+    const cards = cardRow.getElementsByTagName('section');
+    const cardRowWidth = cardRow.offsetWidth;
+    // get the width of the first card and then calculate
+    const cardWidth = cards.length > 0 ? cards[0].offsetWidth : 0;
+
+    if (cardWidth > 0) {
+      return Math.ceil(cardRowWidth / cardWidth);
+    }
+
+    // return a default value of 1 card displayed if the card width couldn't be determined
+    return 1;
+  }
+
+  render() {
+    const { category, names, categoryLink } = this.props;
+
+    return (
+      <div className="card-row card-row--small">
+        <h3 className="card-row__header">
+          {categoryLink ? (
+            <Link
+              className="button-text no-underline"
+              label={category}
+              navigate="/show"
+              navigateParams={{ uri: categoryLink }}
+            />
+          ) : (
+            category
+          )}
+
+          {category &&
+            category.match(/^community/i) && (
+              <ToolTip
+                label={__("What's this?")}
+                body={__(
+                  'Community Content is a public space where anyone can share content with the rest of the LBRY community. Bid on the names "one," "two," "three," "four" and "five" to put your content here!'
+                )}
+                className="tooltip--header"
+              />
+            )}
+        </h3>
+        <div className="card-row__scrollhouse">
+          {this.state.canScrollPrevious && (
+            <div className="card-row__nav card-row__nav--left">
+              <a className="card-row__scroll-button" onClick={this.handleScrollPrevious.bind(this)}>
+                <Icon icon="icon-chevron-left" />
+              </a>
+            </div>
+          )}
+          {this.state.canScrollNext && (
+            <div className="card-row__nav card-row__nav--right">
+              <a className="card-row__scroll-button" onClick={this.handleScrollNext.bind(this)}>
+                <Icon icon="icon-chevron-right" />
+              </a>
+            </div>
+          )}
+          <div ref="rowitems" className="card-row__items">
+            {names &&
+              names.map(name => (
+                <FileCard key={name} displayStyle="card" uri={lbryuri.normalize(name)} />
+              ))}
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
+
+class DiscoverPage extends React.PureComponent {
   componentWillMount() {
     this.props.fetchFeaturedUris();
   }
 
   render() {
     const { featuredUris, fetchingFeaturedUris } = this.props;
-    const hasContent = typeof featuredUris === 'object' && Object.keys(featuredUris).length;
-    const failedToLoad = !fetchingFeaturedUris && !hasContent;
+    const hasContent = typeof featuredUris === 'object' && Object.keys(featuredUris).length,
+      failedToLoad = !fetchingFeaturedUris && !hasContent;
 
     return (
-      <Page noPadding isLoading={!hasContent && fetchingFeaturedUris}>
+      <main
+        className={classnames('main main--no-margin', {
+          reloading: hasContent && fetchingFeaturedUris,
+        })}
+      >
+        <SubHeader fullWidth smallMargin />
+        {!hasContent && fetchingFeaturedUris && <BusyMessage message={__('Fetching content')} />}
         {hasContent &&
           Object.keys(featuredUris).map(
             category =>
               featuredUris[category].length ? (
-                <CategoryList key={category} category={category} names={featuredUris[category]} />
+                <FeaturedCategory
+                  key={category}
+                  category={category}
+                  names={featuredUris[category]}
+                />
               ) : (
                 ''
               )
           )}
         {failedToLoad && <div className="empty">{__('Failed to load landing content.')}</div>}
-      </Page>
+      </main>
     );
   }
 }
diff --git a/src/renderer/page/file/view.jsx b/src/renderer/page/file/view.jsx
index d9a224c84..fb8f741c8 100644
--- a/src/renderer/page/file/view.jsx
+++ b/src/renderer/page/file/view.jsx
@@ -1,4 +1,3 @@
-/* eslint-disable */
 import React from 'react';
 import lbry from 'lbry';
 import lbryuri from 'lbryuri';
@@ -7,13 +6,12 @@ import { Thumbnail } from 'component/common';
 import FilePrice from 'component/filePrice';
 import FileDetails from 'component/fileDetails';
 import UriIndicator from 'component/uriIndicator';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 import WalletSendTip from 'component/walletSendTip';
 import DateTime from 'component/dateTime';
 import * as icons from 'constants/icons';
 import Link from 'component/link';
 import SubscribeButton from 'component/subscribeButton';
-import Page from 'component/page';
 
 class FilePage extends React.PureComponent {
   componentDidMount() {
@@ -71,52 +69,49 @@ class FilePage extends React.PureComponent {
     }
 
     return (
-      <Page>
-        <section className={`card ${obscureNsfw ? 'card--obscured ' : ''}`}>
-          <div className="show-page-media">
-            {isPlayable ? (
-              <Video className="video-embedded" uri={uri} />
-            ) : metadata && metadata.thumbnail ? (
-              <Thumbnail src={metadata.thumbnail} />
-            ) : (
-              <Thumbnail />
-            )}
-          </div>
-          <div className="card__inner">
-            {(!tab || tab === 'details') && (
-              <div>
-                {' '}
-                <div className="card__title-identity">
-                  {!fileInfo || fileInfo.written_bytes <= 0 ? (
-                    <span style={{ float: 'right' }}>
-                      <FilePrice uri={lbryuri.normalize(uri)} />
-                      {isRewardContent && (
-                        <span>
-                          {' '}
-                          <Icon icon={icons.FEATURED} />
-                        </span>
-                      )}
-                    </span>
-                  ) : null}
-                  <h1>{title}</h1>
-                  <div className="card__subtitle card--file-subtitle">
-                    <UriIndicator uri={uri} link />
-                    <span className="card__publish-date">
-                      Published on <DateTime block={height} show={DateTime.SHOW_DATE} />
-                    </span>
-                  </div>
+      <section className={`card ${obscureNsfw ? 'card--obscured ' : ''}`}>
+        <div className="show-page-media">
+          {isPlayable ? (
+            <Video className="video-embedded" uri={uri} />
+          ) : metadata && metadata.thumbnail ? (
+            <Thumbnail src={metadata.thumbnail} />
+          ) : (
+            <Thumbnail />
+          )}
+        </div>
+        <div className="card__inner">
+          {(!tab || tab === 'details') && (
+            <div>
+              {' '}
+              <div className="card__title-identity">
+                {!fileInfo || fileInfo.written_bytes <= 0 ? (
+                  <span style={{ float: 'right' }}>
+                    <FilePrice uri={lbryuri.normalize(uri)} />
+                    {isRewardContent && (
+                      <span>
+                        {' '}
+                        <Icon icon={icons.FEATURED} />
+                      </span>
+                    )}
+                  </span>
+                ) : null}
+                <h1>{title}</h1>
+                <div className="card__subtitle card--file-subtitle">
+                  <UriIndicator uri={uri} link />
+                  <span className="card__publish-date">
+                    Published on <DateTime block={height} show={DateTime.SHOW_DATE} />
+                  </span>
                 </div>
-                <SubscribeButton uri={subscriptionUri} channelName={channelName} />
-                <FileDetails uri={uri} />
               </div>
-            )}
-            {tab === 'tip' && <WalletSendTip claim_id={claim.claim_id} uri={uri} />}
-          </div>
-        </section>
-      </Page>
+              <SubscribeButton uri={subscriptionUri} channelName={channelName} />
+              <FileDetails uri={uri} />
+            </div>
+          )}
+          {tab === 'tip' && <WalletSendTip claim_id={claim.claim_id} uri={uri} />}
+        </div>
+      </section>
     );
   }
 }
 
 export default FilePage;
-/* eslint-enable */
diff --git a/src/renderer/page/help/view.jsx b/src/renderer/page/help/view.jsx
index c2590fd81..bb22e6fe5 100644
--- a/src/renderer/page/help/view.jsx
+++ b/src/renderer/page/help/view.jsx
@@ -4,7 +4,7 @@ import lbry from 'lbry.js';
 import Link from 'component/link';
 import SubHeader from 'component/subHeader';
 import { BusyMessage } from 'component/common';
-import Icon from 'component/common/icon';
+import Icon from 'component/icon';
 
 class HelpPage extends React.PureComponent {
   constructor(props) {
diff --git a/src/renderer/page/search/view.jsx b/src/renderer/page/search/view.jsx
index c3cd0cc7e..48aed6fce 100644
--- a/src/renderer/page/search/view.jsx
+++ b/src/renderer/page/search/view.jsx
@@ -1,21 +1,15 @@
-// @flow
 import React from 'react';
 import lbryuri from 'lbryuri';
 import FileTile from 'component/fileTile';
 import FileListSearch from 'component/fileListSearch';
-import ToolTip from 'component/common/tooltip';
-import Page from 'component/page';
+import { ToolTip } from 'component/tooltip.js';
 
-type Props = {
-  query: ?string,
-};
-
-class SearchPage extends React.PureComponent<Props> {
+class SearchPage extends React.PureComponent {
   render() {
     const { query } = this.props;
 
     return (
-      <Page>
+      <main className="main--single-column">
         {lbryuri.isValid(query) ? (
           <section className="section-spaced">
             <h3 className="card-row__header">
@@ -42,7 +36,7 @@ class SearchPage extends React.PureComponent<Props> {
           </h3>
           <FileListSearch query={query} />
         </section>
-      </Page>
+      </main>
     );
   }
 }
diff --git a/src/renderer/page/show/view.jsx b/src/renderer/page/show/view.jsx
index 60a1fd06f..ebb45da30 100644
--- a/src/renderer/page/show/view.jsx
+++ b/src/renderer/page/show/view.jsx
@@ -1,24 +1,17 @@
-/* eslint-disable */
 import React from 'react';
+import lbryuri from 'lbryuri';
 import { BusyMessage } from 'component/common';
 import ChannelPage from 'page/channel';
 import FilePage from 'page/file';
 
-type Props = {
-  isResolvingUri: boolean,
-  resolveUri: string => void,
-  uri: string,
-  claim: { name: string },
-};
-
-class ShowPage extends React.PureComponent<Props> {
+class ShowPage extends React.PureComponent {
   componentWillMount() {
     const { isResolvingUri, resolveUri, uri } = this.props;
 
     if (!isResolvingUri) resolveUri(uri);
   }
 
-  componentWillReceiveProps(nextProps: Props) {
+  componentWillReceiveProps(nextProps) {
     const { isResolvingUri, resolveUri, claim, uri } = nextProps;
 
     if (!isResolvingUri && claim === undefined && uri) {
@@ -54,9 +47,8 @@ class ShowPage extends React.PureComponent<Props> {
       innerContent = <FilePage uri={uri} />;
     }
 
-    return innerContent;
+    return <main className="main--single-column">{innerContent}</main>;
   }
 }
 
 export default ShowPage;
-/* eslint-enable */
diff --git a/src/renderer/page/subscriptions/view.jsx b/src/renderer/page/subscriptions/view.jsx
index 3c4e6e61a..3e09748a5 100644
--- a/src/renderer/page/subscriptions/view.jsx
+++ b/src/renderer/page/subscriptions/view.jsx
@@ -1,8 +1,8 @@
 // @flow
 import React from 'react';
 import SubHeader from 'component/subHeader';
-import { BusyMessage } from 'component/common';
-import CategoryList from 'component/common/category-list';
+import { BusyMessage } from 'component/common.js';
+import { FeaturedCategory } from 'page/discover/view';
 import type { Subscription } from 'redux/reducers/subscriptions';
 
 type SavedSubscriptions = Array<Subscription>;
@@ -83,7 +83,7 @@ export default class extends React.PureComponent<Props> {
                 }
 
                 return (
-                  <CategoryList
+                  <FeaturedCategory
                     key={subscription.channelName}
                     categoryLink={subscription.uri}
                     category={subscription.channelName}
diff --git a/src/renderer/redux/actions/search.js b/src/renderer/redux/actions/search.js
index d5294b54c..277b5cbe4 100644
--- a/src/renderer/redux/actions/search.js
+++ b/src/renderer/redux/actions/search.js
@@ -5,119 +5,63 @@ import { doNavigate } from 'redux/actions/navigation';
 import { selectCurrentPage } from 'redux/selectors/navigation';
 import batchActions from 'util/batchActions';
 
-// TODO: this should be in a util
-const handleSearchApiResponse = searchResponse =>
-  searchResponse.status === 200
-    ? Promise.resolve(searchResponse.json())
-    : Promise.reject(new Error(searchResponse.statusText));
+// eslint-disable-next-line import/prefer-default-export
+export function doSearch(rawQuery) {
+  return (dispatch, getState) => {
+    const state = getState();
+    const page = selectCurrentPage(state);
 
-export const doSearch = rawQuery => (dispatch, getState) => {
-  const state = getState();
-  const page = selectCurrentPage(state);
+    const query = rawQuery.replace(/^lbry:\/\//i, '');
 
-  const query = rawQuery.replace(/^lbry:\/\//i, '');
-
-  if (!query) {
-    dispatch({
-      type: ACTIONS.SEARCH_FAIL,
-    });
-    return;
-  }
-
-  dispatch({
-    type: ACTIONS.SEARCH_START,
-    data: { query },
-  });
-
-  if (page !== 'search') {
-    dispatch(doNavigate('search', { query }));
-  } else {
-    fetch(`https://lighthouse.lbry.io/search?s=${query}`)
-      .then(handleSearchApiResponse)
-      .then(data => {
-        const uris = [];
-        const actions = [];
-
-        data.forEach(result => {
-          const uri = Lbryuri.build({
-            name: result.name,
-            claimId: result.claimId,
-          });
-          actions.push(doResolveUri(uri));
-          uris.push(uri);
-        });
-
-        actions.push({
-          type: ACTIONS.SEARCH_SUCCESS,
-          data: {
-            query,
-            uris,
-          },
-        });
-        dispatch(batchActions(...actions));
-      })
-      .catch(() => {
-        dispatch({
-          type: ACTIONS.SEARCH_FAIL,
-        });
-      });
-  }
-};
-
-export const updateSearchQuery = searchQuery => ({
-  type: ACTIONS.UPDATE_SEARCH_QUERY,
-  data: { searchQuery },
-});
-
-export const getSearchSuggestions = value => dispatch => {
-  dispatch({ type: ACTIONS.SEARCH_SUGGESTIONS_START });
-  if (!value) {
-    dispatch({
-      type: ACTIONS.GET_SEARCH_SUGGESTIONS_SUCCESS,
-      data: [],
-    });
-    return;
-  }
-
-  // This should probably be more robust
-  let searchValue = value;
-  if (searchValue.startsWith('lbry://')) {
-    searchValue = searchValue.slice(7);
-  }
-
-  // need to handle spaces in the query?
-  fetch(`https://lighthouse.lbry.io/autocomplete?s=${searchValue}`)
-    .then(handleSearchApiResponse)
-    .then(suggestions => {
-      const formattedSuggestions = suggestions.slice(0, 5).map(suggestion => ({
-        label: suggestion,
-        value: suggestion,
-      }));
-
-      // Should we add lbry://{query} as the first result?
-      // If it's not a valid uri, then add a "search for {query}" result
-      const searchLabel = `Search for "${value}"`;
-      try {
-        const uri = Lbryuri.normalize(value);
-        formattedSuggestions.unshift(
-          { label: uri, value: uri },
-          { label: searchLabel, value: `${value}?search` }
-        );
-      } catch (e) {
-        if (value) {
-          formattedSuggestions.unshift({ label: searchLabel, value });
-        }
-      }
-
-      return dispatch({
-        type: ACTIONS.GET_SEARCH_SUGGESTIONS_SUCCESS,
-        data: formattedSuggestions,
-      });
-    })
-    .catch(err =>
+    if (!query) {
       dispatch({
-        type: ACTIONS.GET_SEARCH_SUGGESTIONS_FAIL,
-        data: err,
-      })
-    );
-};
+        type: ACTIONS.SEARCH_CANCELLED,
+      });
+      return;
+    }
+
+    dispatch({
+      type: ACTIONS.SEARCH_STARTED,
+      data: { query },
+    });
+
+    if (page !== 'search') {
+      dispatch(doNavigate('search', { query }));
+    } else {
+      fetch(`https://lighthouse.lbry.io/search?s=${query}`)
+        .then(
+          response =>
+            response.status === 200
+              ? Promise.resolve(response.json())
+              : Promise.reject(new Error(response.statusText))
+        )
+        .then(data => {
+          const uris = [];
+          const actions = [];
+
+          data.forEach(result => {
+            const uri = Lbryuri.build({
+              name: result.name,
+              claimId: result.claimId,
+            });
+            actions.push(doResolveUri(uri));
+            uris.push(uri);
+          });
+
+          actions.push({
+            type: ACTIONS.SEARCH_COMPLETED,
+            data: {
+              query,
+              uris,
+            },
+          });
+          dispatch(batchActions(...actions));
+        })
+        .catch(() => {
+          dispatch({
+            type: ACTIONS.SEARCH_CANCELLED,
+          });
+        });
+    }
+  };
+}
diff --git a/src/renderer/redux/reducers/search.js b/src/renderer/redux/reducers/search.js
index 3a8330b93..b3a0754e4 100644
--- a/src/renderer/redux/reducers/search.js
+++ b/src/renderer/redux/reducers/search.js
@@ -1,75 +1,32 @@
-// @flow
 import * as ACTIONS from 'constants/action_types';
-import { handleActions } from 'util/redux-utils';
-
-type SearchState = {
-  isActive: boolean,
-  searchQuery: string,
-  searchingForSuggestions: boolean,
-  suggestions: Array<string>,
-  urisByQuery: {},
-};
 
+const reducers = {};
 const defaultState = {
-  isActive: false,
-  searchQuery: '', // needs to be an empty string for input focusing
-  searchingForSuggestions: false,
-  suggestions: [],
   urisByQuery: {},
+  searching: false,
 };
 
-export default handleActions(
-  {
-    [ACTIONS.SEARCH_START]: (state: SearchState): SearchState => ({
-      ...state,
-      searching: true,
-    }),
-    [ACTIONS.SEARCH_SUCCESS]: (state: SearchState, action): SearchState => {
-      const { query, uris } = action.data;
+reducers[ACTIONS.SEARCH_STARTED] = state =>
+  Object.assign({}, state, {
+    searching: true,
+  });
 
-      return {
-        ...state,
-        searching: false,
-        urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris }),
-      };
-    },
+reducers[ACTIONS.SEARCH_COMPLETED] = (state, action) => {
+  const { query, uris } = action.data;
 
-    [ACTIONS.SEARCH_FAIL]: (state: SearchState): SearchState => ({
-      ...state,
-      searching: false,
-    }),
+  return Object.assign({}, state, {
+    searching: false,
+    urisByQuery: Object.assign({}, state.urisByQuery, { [query]: uris }),
+  });
+};
 
-    [ACTIONS.UPDATE_SEARCH_QUERY]: (state: SearchState, action): SearchState => ({
-      ...state,
-      searchQuery: action.data.searchQuery,
-      suggestions: [],
-      isActive: true,
-    }),
+reducers[ACTIONS.SEARCH_CANCELLED] = state =>
+  Object.assign({}, state, {
+    searching: false,
+  });
 
-    [ACTIONS.SEARCH_SUGGESTIONS_START]: (state: SearchState): SearchState => ({
-      ...state,
-      searchingForSuggestions: true,
-      suggestions: [],
-    }),
-    [ACTIONS.GET_SEARCH_SUGGESTIONS_SUCCESS]: (state: SearchState, action): SearchState => ({
-      ...state,
-      searchingForSuggestions: false,
-      suggestions: action.data,
-    }),
-    [ACTIONS.GET_SEARCH_SUGGESTIONS_FAIL]: (state: SearchState): SearchState => ({
-      ...state,
-      searchingForSuggestions: false,
-      // error, TODO: figure this out on the search page
-    }),
-
-    // clear the searchQuery on back/forward
-    // it may be populated by the page title for search/file pages
-    // if going home, it should be blank
-    [ACTIONS.HISTORY_NAVIGATE]: (state: SearchState): SearchState => ({
-      ...state,
-      searchQuery: '',
-      isActive: false,
-    }),
-  },
-  defaultState
-);
+export default function reducer(state = defaultState, action) {
+  const handler = reducers[action.type];
+  if (handler) return handler(state, action);
+  return state;
+}
diff --git a/src/renderer/redux/selectors/navigation.js b/src/renderer/redux/selectors/navigation.js
index 014a0b988..dc0b507a1 100644
--- a/src/renderer/redux/selectors/navigation.js
+++ b/src/renderer/redux/selectors/navigation.js
@@ -68,6 +68,30 @@ export const selectPageTitle = createSelector(
   selectCurrentParams,
   (page, params) => {
     switch (page) {
+      case 'settings':
+        return __('Settings');
+      case 'report':
+        return __('Report');
+      case 'wallet':
+        return __('Wallet');
+      case 'send':
+        return __('Send or Receive LBRY Credits');
+      case 'getcredits':
+        return __('Get LBRY Credits');
+      case 'backup':
+        return __('Backup Your Wallet');
+      case 'rewards':
+        return __('Rewards');
+      case 'invite':
+        return __('Invites');
+      case 'start':
+        return __('Start');
+      case 'publish':
+        return params.id ? __('Edit') : __('Publish');
+      case 'help':
+        return __('Help');
+      case 'developer':
+        return __('Developer');
       case 'show': {
         const parts = [Lbryuri.normalize(params.uri)];
         // If the params has any keys other than "uri"
@@ -76,14 +100,21 @@ export const selectPageTitle = createSelector(
         }
         return parts.join('?');
       }
+      case 'downloaded':
+        return __('Downloads & Purchases');
+      case 'published':
+        return __('Publications');
+      case 'search':
+        return params.query ? __('Search results for %s', params.query) : __('Search');
+      case 'subscriptions':
+        return __('Your Subscriptions');
       case 'discover':
-        return __('Discover');
       case false:
       case null:
       case '':
         return '';
       default:
-        return '';
+        return page[0].toUpperCase() + (page.length > 0 ? page.substr(1) : '');
     }
   }
 );
diff --git a/src/renderer/redux/selectors/search.js b/src/renderer/redux/selectors/search.js
index 8eb6c95c0..4e49f47d8 100644
--- a/src/renderer/redux/selectors/search.js
+++ b/src/renderer/redux/selectors/search.js
@@ -28,15 +28,52 @@ export const selectWunderBarAddress = createSelector(
   selectCurrentPage,
   selectPageTitle,
   selectSearchQuery,
-  (page, title, query) => {
-    // only populate the wunderbar address if we are on the file/channel pages
-    // or show the search query
-    if (page === 'show') {
-      return title;
-    } else if (page === 'search') {
-      return query;
-    }
+  (page, title, query) => (page !== 'search' ? title : query || title)
+);
 
-    return '';
+export const selectWunderBarIcon = createSelector(
+  selectCurrentPage,
+  selectCurrentParams,
+  (page, params) => {
+    switch (page) {
+      case 'auth':
+        return 'icon-user';
+      case 'settings':
+        return 'icon-gear';
+      case 'help':
+        return 'icon-question';
+      case 'report':
+        return 'icon-file';
+      case 'downloaded':
+        return 'icon-folder';
+      case 'published':
+        return 'icon-folder';
+      case 'history':
+        return 'icon-history';
+      case 'send':
+        return 'icon-send';
+      case 'rewards':
+        return 'icon-rocket';
+      case 'invite':
+        return 'icon-envelope-open';
+      case 'getcredits':
+        return 'icon-shopping-cart';
+      case 'wallet':
+      case 'backup':
+        return 'icon-bank';
+      case 'show':
+        return 'icon-file';
+      case 'publish':
+        return params.id ? __('icon-pencil') : __('icon-upload');
+      case 'developer':
+        return 'icon-code';
+      case 'discover':
+      case 'search':
+        return 'icon-search';
+      case 'subscriptions':
+        return 'icon-th-list';
+      default:
+        return 'icon-file';
+    }
   }
 );
diff --git a/src/renderer/scss/_gui.scss b/src/renderer/scss/_gui.scss
index db1eedf76..92b82d146 100644
--- a/src/renderer/scss/_gui.scss
+++ b/src/renderer/scss/_gui.scss
@@ -1,30 +1,4 @@
-// Generic html styles used accross the App
-// component specific styling should go in the component scss file
-
-// The actual fonts used will change ex: medium vs regular
-@font-face {
-  font-family: 'Metropolis';
-  font-weight: normal;
-  font-style: normal;
-  text-rendering: optimizeLegibility;
-  src: url('../../../static/font/metropolis/Metropolis-Medium.woff2') format('woff2');
-}
-
-@font-face {
-  font-family: 'Metropolis';
-  font-weight: 600;
-  font-style: normal;
-  text-rendering: optimizeLegibility;
-  src: url('../../../static/font/metropolis/Metropolis-SemiBold.woff2') format('woff2');
-}
-
-@font-face {
-  font-family: 'Metropolis';
-  font-weight: 800;
-  font-style: normal;
-  text-rendering: optimizeLegibility;
-  src: url('../../../static/font/metropolis/Metropolis-ExtraBold.woff2') format('woff2');
-}
+@import url(https://fonts.googleapis.com/css?family=Roboto:400,400i,500,500i,700);
 
 html {
   height: 100%;
@@ -33,20 +7,84 @@ html {
 
 body {
   color: var(--text-color);
-  font-family: 'Metropolis', sans-serif;
+  font-family: 'Roboto', sans-serif;
   line-height: var(--font-line-height);
-  height: 100%;
-  overflow: hidden;
 }
 
-h1,
-h2,
-h3,
-h4,
-h5 {
+/* Custom text selection */
+*::selection {
+  background: var(--text-selection-bg);
+  color: var(--text-selection-color);
+}
+
+#window {
+  min-height: 100vh;
+  background: var(--window-bg);
+}
+
+.credit-amount--indicator {
+  font-weight: 500;
+  color: var(--color-money);
+}
+.credit-amount--fee {
+  font-size: 0.9em;
+  color: var(--color-meta-light);
+}
+
+.credit-amount--bold {
   font-weight: 700;
 }
 
+#main-content {
+  margin: auto;
+  display: flex;
+  flex-direction: column;
+  overflow: overlay;
+  padding: $spacing-vertical;
+  position: absolute;
+  top: var(--header-height);
+  bottom: 0;
+  left: 4px;
+  right: 4px;
+  main {
+    margin-left: auto;
+    margin-right: auto;
+    max-width: 100%;
+  }
+  main.main--single-column {
+    width: $width-page-constrained;
+  }
+
+  main.main--no-margin {
+    margin-left: 0;
+    margin-right: 0;
+  }
+}
+
+.reloading {
+  &:before {
+    $width: 30px;
+    position: absolute;
+    background: url('../../../static/img/busy.gif') no-repeat center center;
+    width: $width;
+    height: $spacing-vertical;
+    content: '';
+    left: 50%;
+    margin-left: -1 / 2 * $width;
+    display: inline-block;
+  }
+}
+
+.icon-fixed-width {
+  /* This borrowed is from a component of Font Awesome we're not using, maybe add it? */
+  width: (18em / 14);
+  text-align: center;
+}
+
+.icon--left-pad {
+  padding-left: 3px;
+}
+
 h2 {
   font-size: 1.75em;
 }
@@ -62,13 +100,11 @@ h4 {
 h5 {
   font-size: 1.1em;
 }
-
 sup,
 sub {
   vertical-align: baseline;
   position: relative;
 }
-
 sup {
   top: -0.4em;
 }
@@ -81,67 +117,11 @@ code {
   background-color: var(--color-bg-alt);
 }
 
-// Without this buttons don't have the Metropolis font
-button {
-  font-family: inherit;
-}
-
-#window {
-  height: 100%;
-  overflow: hidden;
-}
-
-#main-content {
-  height: 100%;
-  overflow-y: auto;
-  position: absolute;
-  left: 0px;
-  right: 0px;
-  // don't use {bottom/top} here
-  // they cause flashes of un-rendered content when scrolling
-  margin-top: var(--header-height);
-  // TODO: fix this scrollbar extends beyond screen at the bottom
-  padding-bottom: var(--header-height);
-  background-color: var(--color-bg);
-}
-
-.main {
-  padding: 0 $spacing-vertical * 2/3;
-}
-
-.main--no-padding {
-  padding-left: 0;
-  padding-right: 0;
-}
-
-.page__header {
-  padding: $spacing-vertical * 2/3;
-  padding-bottom: 0;
-}
-
-.page__title {
-  font-weight: 800;
-  font-size: 3em;
-}
-
-/* Custom text selection */
-*::selection {
-  background: var(--text-selection-bg);
-  color: var(--text-selection-color);
-}
-
-.credit-amount--indicator {
-  font-weight: 500;
-  color: var(--color-money);
-}
-
-.credit-amount--fee {
-  font-size: 0.9em;
-  color: var(--color-meta-light);
-}
-
-.credit-amount--bold {
-  font-weight: 700;
+p {
+  margin-bottom: 0.8em;
+  &:last-child {
+    margin-bottom: 0;
+  }
 }
 
 .hidden {
@@ -212,3 +192,7 @@ button {
 section.section-spaced {
   margin-bottom: $spacing-vertical;
 }
+
+.text-center {
+  text-align: center;
+}
diff --git a/src/renderer/scss/_icons.scss b/src/renderer/scss/_icons.scss
index 7797614a8..c589a1ac5 100644
--- a/src/renderer/scss/_icons.scss
+++ b/src/renderer/scss/_icons.scss
@@ -27,16 +27,6 @@
   transform: translate(0, 0);
 }
 
-.icon--fixed-width {
-  /* This borrowed is from a component of Font Awesome we're not using, maybe add it? */
-  width: (18em / 14);
-  text-align: center;
-}
-
-.icon--padded {
-  padding: 0 3px;
-}
-
 /* Adjustments for icon size and alignment */
 .icon-rocket {
   color: orangered;
diff --git a/src/renderer/scss/_vars.scss b/src/renderer/scss/_vars.scss
index d93fd2217..15436a5b1 100644
--- a/src/renderer/scss/_vars.scss
+++ b/src/renderer/scss/_vars.scss
@@ -6,8 +6,6 @@ $width-page-constrained: 800px;
 $text-color: #000;
 
 :root {
-  --spacing-vertical: 24px;
-
   /* Colors */
   --color-brand: #155b4a;
   --color-primary: #155b4a;
@@ -23,8 +21,7 @@ $text-color: #000;
   --color-download: rgba(0, 0, 0, 0.75);
   --color-canvas: #f5f5f5;
   --color-bg: #ffffff;
-  --color-bg-alt: #f6f6f6;
-  --color-placeholder: #ececec;
+  --color-bg-alt: #d9d9d9;
 
   /* Misc */
   --content-max-width: 1000px;
@@ -37,7 +34,7 @@ $text-color: #000;
   --font-size-subtext-multiple: 0.82;
 
   /* Shadows */
-  --box-shadow-layer: 0px 1px 3px 0px rgba(0, 0, 0, 0.2);
+  --box-shadow-layer: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
   --box-shadow-focus: 2px 4px 4px 0 rgba(0, 0, 0, 0.14), 2px 5px 3px -2px rgba(0, 0, 0, 0.2),
     2px 3px 7px 0 rgba(0, 0, 0, 0.12);
 
@@ -53,6 +50,9 @@ $text-color: #000;
   --text-selection-bg: rgba(saturate(lighten(#155b4a, 20%), 20%), 1); // temp color
   --text-selection-color: #fff;
 
+  /* Window */
+  --window-bg: var(--color-canvas);
+
   /* Form */
   --form-label-color: rgba(0, 0, 0, 0.54);
 
@@ -80,23 +80,21 @@ $text-color: #000;
   --select-bg: var(--color-bg-alt);
   --select-color: var(--text-color);
 
-  //TODO: determine proper button variables;
   /* Button */
-  --btn-primary-color: #fff;
-  --button-alt-color: var(--text-color);
-  --btn-primary-bg: var(--color-primary);
-  --btn-alt-bg: red;
-  --btn-radius: 10px;
-  // below needed?
-  --btn-padding: $spacing-vertical * 2/3;
-  --btn-height: $spacing-vertical * 1.5;
-  --btn-intra-margin: $spacing-vertical;
+  --button-bg: var(--color-bg-alt);
+  --button-color: #fff;
+  --button-primary-bg: var(--color-primary);
+  --button-primary-color: #fff;
+  --button-padding: $spacing-vertical * 2/3;
+  --button-height: $spacing-vertical * 1.5;
+  --button-intra-margin: $spacing-vertical;
+  --button-radius: 3px;
 
   /* Header */
   --header-bg: var(--color-bg);
   --header-color: #666;
   --header-active-color: rgba(0, 0, 0, 0.85);
-  --header-height: 65px;
+  --header-height: $spacing-vertical * 2.5;
   --header-button-bg: transparent; //var(--button-bg);
   --header-button-hover-bg: rgba(100, 100, 100, 0.15);
 
@@ -144,6 +142,7 @@ $text-color: #000;
   --tooltip-width: 300px;
   --tooltip-bg: var(--color-bg);
   --tooltip-color: var(--text-color);
+  --tooltip-border: 1px solid #aaa;
 
   /* Scrollbar */
   --scrollbar-radius: 10px;
diff --git a/src/renderer/scss/component/_button.scss b/src/renderer/scss/component/_button.scss
index dfb8e0513..576ca4c33 100644
--- a/src/renderer/scss/component/_button.scss
+++ b/src/renderer/scss/component/_button.scss
@@ -1,78 +1,89 @@
-/*
-TODO:
-Determine [disabled] or .disabled
-Add <a> support (probably just get rid of button prefix)
-*/
+@import '../mixin/link.scss';
 
-button {
-  border: none;
-  text-decoration: none;
-  cursor: pointer;
+$button-focus-shift: 12%;
+
+.button-set-item {
   position: relative;
-}
+  display: inline-block;
 
-button:disabled.btn--disabled {
-  cursor: default;
-  background-color: transparent;
-}
-
-button.btn {
-  padding: 10px;
-  margin: 0 5px;
-  border-radius: var(--btn-radius);
-  color: var(--btn-primary-color);
-  background-color: var(--btn-primary-bg);
-
-  &:hover:not(.btn--disabled) {
-    box-shadow: var(--box-shadow-layer);
+  + .button-set-item {
+    margin-left: var(--button-intra-margin);
   }
 }
 
-button.btn.btn--alt {
-  color: var(--btn-alt-color);
-  background-color: #efefef;
-
-  &:hover {
-    color: #111;
+.button-block,
+.faux-button-block {
+  display: inline-block;
+  height: var(--button-height);
+  line-height: var(--button-height);
+  text-decoration: none;
+  border: 0 none;
+  text-align: center;
+  border-radius: var(--button-radius);
+  text-transform: uppercase;
+  .icon {
+    top: 0em;
   }
-
-  &:active {
-    background-color: #cdcdcd;
+  .icon:first-child {
+    padding-right: 5px;
   }
+  .icon:last-child {
+    padding-left: 5px;
+  }
+  .icon:only-child {
+    padding-left: 0;
+    padding-right: 0;
+  }
+}
+.button-block {
+  cursor: pointer;
+  font-weight: 500;
+  font-size: 14px;
+  user-select: none;
+  transition: background var(--animation-duration) var(--animation-style);
+}
 
-  &:disabled {
-    color: var(--color-help);
-    background-color: transparent;
+.button__content {
+  margin: 0 var(--button-padding);
+  display: flex;
+  .link-label {
+    text-decoration: none !important;
   }
 }
 
-button.btn.btn--circle {
-  border-radius: 50%;
-  transition: all 0.2s;
+.button-primary {
+  color: var(--button-primary-color);
+  background-color: var(--button-primary-bg);
+  box-shadow: var(--box-shadow-layer);
 
-  &:hover:not([disabled]) {
-    border-radius: var(--btn-radius);
+  &:focus {
+    //color: var(--button-primary-active-color);
+    //background-color:color: var(--button-primary-active-bg);
+    //box-shadow: $box-shadow-focus;
   }
 }
-
-button.btn.btn--inverse {
-  box-shadow: none;
-  background-color: transparent;
-  color: var(--btn-primary-bg);
+.button-alt {
+  background-color: var(--button-bg);
+  box-shadow: var(--box-shadow-layer);
 }
 
-button.btn--link {
-  padding: 0;
-  margin: 0;
-  background-color: inherit;
-  font-size: 0.9em;
-  color: var(--btn-primary-bg); // this should be a different color
+.button-text {
+  @include text-link();
+  display: inline-block;
 
-  &:hover {
-    border-bottom: 1px solid;
+  .button__content {
+    margin: 0 var(--text-link-padding);
   }
 }
-
-.btn__label {
-  padding: 0 5px;
+.button-text-help {
+  @include text-link(var(--text-help-color));
+  font-size: 0.8em;
+}
+.button--flat {
+  box-shadow: none !important;
+}
+
+.button--submit {
+  font-family: inherit;
+  line-height: 0;
 }
diff --git a/src/renderer/scss/component/_card.scss b/src/renderer/scss/component/_card.scss
index 3315b8f31..cef50a1fb 100644
--- a/src/renderer/scss/component/_card.scss
+++ b/src/renderer/scss/component/_card.scss
@@ -2,19 +2,194 @@
   margin-left: auto;
   margin-right: auto;
   max-width: var(--card-max-width);
+  background: var(--card-bg);
+  box-shadow: var(--box-shadow-layer);
   border-radius: var(--card-radius);
+  margin-bottom: var(--card-margin);
   overflow: auto;
   user-select: text;
-  display: flex;
+
+  //below added to prevent scrollbar on long titles when show page loads, would prefer a cleaner CSS solution
+  overflow-x: hidden;
+}
+.card--obscured {
+  position: relative;
+}
+.card--obscured .card__inner {
+  filter: blur(var(--nsfw-blur-intensity));
+}
+.card__title-primary,
+.card__title-identity,
+.card__content,
+.card__subtext,
+.card__actions {
+  padding: 0 var(--card-padding);
 }
 
-.card--placeholder {
-  background-color: black;
+.card--small {
+  .card__title-primary,
+  .card__title-identity,
+  .card__actions,
+  .card__content,
+  .card__subtext {
+    padding: 0 calc(var(--card-padding) / 2);
+  }
+}
+.card__title-primary {
+  margin-top: var(--card-margin);
+  margin-bottom: var(--card-margin);
+}
+.card__title-primary .meta {
+  white-space: nowrap;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+.card__title-identity {
+  margin: 16px 0;
+}
+.card__actions {
+  margin-top: var(--card-margin);
+  margin-bottom: var(--card-margin);
+  user-select: none;
+}
+.card__actions--bottom {
+  margin-top: $spacing-vertical * 1/3;
+  margin-bottom: $spacing-vertical * 1/3;
+  border-top: var(--divider);
+}
+.card__actions--form-submit {
+  margin-top: $spacing-vertical;
+  margin-bottom: var(--card-margin);
+}
+.card__action--right {
+  float: right;
+}
+.card__content {
+  margin-top: var(--card-margin);
+  margin-bottom: var(--card-margin);
+  table:not(:last-child) {
+    margin-bottom: var(--card-margin);
+  }
+}
+
+.card__actions--only-vertical {
+  margin-left: 0;
+  margin-right: 0;
+  padding-left: 0;
+  padding-right: 0;
+}
+
+.card__content--extra-vertical-space {
+  margin: $spacing-vertical 0;
+}
+
+$font-size-subtext-multiple: 0.82;
+.card__subtext {
+  color: var(--color-meta-light);
+  font-size: calc(var(--font-size-subtext-multiple) * 1em);
+  margin-top: $spacing-vertical * 1/3;
+  margin-bottom: $spacing-vertical * 1/3;
+}
+.card__subtext--allow-newlines {
+  white-space: pre-wrap;
+}
+.card__subtext--two-lines {
+  height: calc(
+    var(--font-size) * var(--font-size-subtext-multiple) * var(--font-line-height) * 2
+  ); /*this is so one line text still has the proper height*/
+}
+.card-overlay {
+  position: absolute;
+  left: 0px;
+  right: 0px;
+  top: 0px;
+  bottom: 0px;
+  padding: 20px;
+  background-color: var(--color-dark-overlay);
+  color: #fff;
+  display: flex;
+  align-items: center;
+  font-weight: 600;
+}
+
+.card__link {
+  display: block;
+  cursor: pointer;
+}
+.card--link {
+  transition: transform 0.2s var(--animation-style);
+}
+.card--link:hover {
+  position: relative;
+  z-index: 1;
+  box-shadow: var(--box-shadow-focus);
+  transform: scale(var(--card-link-scaling)) translateX(var(--card-hover-translate));
+  transform-origin: 50% 50%;
+  overflow-x: visible;
+  overflow-y: visible;
+}
+.card--link:hover ~ .card--link {
+  transform: translateX(calc(var(--card-hover-translate) * 2));
+}
+
+.card__media {
+  background-size: cover;
+  background-repeat: no-repeat;
+  background-position: 50% 50%;
+}
+
+.card__media--autothumb {
+  position: relative;
+}
+.card__media--autothumb.purple {
+  background-color: #9c27b0;
+}
+.card__media--autothumb.red {
+  background-color: #e53935;
+}
+.card__media--autothumb.pink {
+  background-color: #e91e63;
+}
+.card__media--autothumb.indigo {
+  background-color: #3f51b5;
+}
+.card__media--autothumb.blue {
+  background-color: #2196f3;
+}
+.card__media--autothumb.light-blue {
+  background-color: #039be5;
+}
+.card__media--autothumb.cyan {
+  background-color: #00acc1;
+}
+.card__media--autothumb.teal {
+  background-color: #009688;
+}
+.card__media--autothumb.green {
+  background-color: #43a047;
+}
+.card__media--autothumb.yellow {
+  background-color: #ffeb3b;
+}
+.card__media--autothumb.orange {
+  background-color: #ffa726;
+}
+
+.card__media--autothumb .card__autothumb__text {
+  font-size: 2em;
+  width: 100%;
+  color: #ffffff;
+  text-align: center;
+  position: absolute;
+  top: 36%;
+}
+
+.card__indicators {
+  float: right;
 }
 
 .card--small {
   width: var(--card-small-width);
-  min-height: var(--card-small-width);
   overflow-x: hidden;
   white-space: normal;
 }
@@ -22,237 +197,126 @@
   height: calc(var(--card-small-width) * 9 / 16);
 }
 
-.card__link {
-  cursor: pointer;
-
-  // TODO: hover animations
-  // :hover {
-  //
-  // }
-}
-
-.card__media {
-  background-size: cover;
-  background-repeat: no-repeat;
-  background-position: 50% 50%;
-  background-color: var(--color-placeholder);
-}
-
-.card__media--autothumb {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-}
-
-.card__title-identity {
-  margin-top: $spacing-vertical * 1/3;
-}
-
-// TODO: regular .card__title for show page
-.card__title--small {
-  font-weight: 600;
-  font-size: 0.9em;
+.card--form {
+  width: calc(var(--input-width) + var(--card-padding) * 2);
 }
 
 .card__subtitle {
   color: var(--color-help);
   font-size: 0.85em;
-  padding-top: $spacing-vertical * 1/3;
+  line-height: calc(var(--font-line-height) * 1 / 0.85);
 }
 
-// .card__title-primary .meta {
-//   white-space: nowrap;
-//   overflow: hidden;
-//   text-overflow: ellipsis;
-// }
-//
+.card--file-subtitle {
+  display: flex;
+}
 
-//
-// .card__actions {
-//   margin-top: var(--card-margin);
-//   margin-bottom: var(--card-margin);
-//   user-select: none;
-// }
-//
-// .card__actions--bottom {
-//   margin-top: $spacing-vertical * 1/3;
-//   margin-bottom: $spacing-vertical * 1/3;
-//   border-top: var(--divider);
-// }
-//
-// .card__actions--form-submit {
-//   margin-top: $spacing-vertical;
-//   margin-bottom: var(--card-margin);
-// }
-//
-// .card__action--right {
-//   float: right;
-// }
-//
-// .card__content {
-//   margin-top: var(--card-margin);
-//   margin-bottom: var(--card-margin);
-//   table:not(:last-child) {
-//     margin-bottom: var(--card-margin);
-//   }
-// }
-//
-// .card__actions--only-vertical {
-//   margin-left: 0;
-//   margin-right: 0;
-//   padding-left: 0;
-//   padding-right: 0;
-// }
-//
-// .card__content--extra-vertical-space {
-//   margin: $spacing-vertical 0;
-// }
-//
-// $font-size-subtext-multiple: 0.82;
-// .card__subtext {
-//   color: var(--color-meta-light);
-//   font-size: calc(var(--font-size-subtext-multiple) * 1em);
-//   margin-top: $spacing-vertical * 1/3;
-//   margin-bottom: $spacing-vertical * 1/3;
-// }
-// .card__subtext--allow-newlines {
-//   white-space: pre-wrap;
-// }
-// .card__subtext--two-lines {
-//   height: calc(
-//     var(--font-size) * var(--font-size-subtext-multiple) * var(--font-line-height) * 2
-//   ); /*this is so one line text still has the proper height*/
-// }
-// .card-overlay {
-//   position: absolute;
-//   left: 0px;
-//   right: 0px;
-//   top: 0px;
-//   bottom: 0px;
-//   padding: 20px;
-//   background-color: var(--color-dark-overlay);
-//   color: #fff;
-//   display: flex;
-//   align-items: center;
-//   font-weight: 600;
-// }
-//
-//
-// .card__media--autothumb {
-//   position: relative;
-// }
-// .card__media--autothumb.purple {
-//   background-color: #9c27b0;
-// }
-// .card__media--autothumb.red {
-//   background-color: #e53935;
-// }
-// .card__media--autothumb.pink {
-//   background-color: #e91e63;
-// }
-// .card__media--autothumb.indigo {
-//   background-color: #3f51b5;
-// }
-// .card__media--autothumb.blue {
-//   background-color: #2196f3;
-// }
-// .card__media--autothumb.light-blue {
-//   background-color: #039be5;
-// }
-// .card__media--autothumb.cyan {
-//   background-color: #00acc1;
-// }
-// .card__media--autothumb.teal {
-//   background-color: #009688;
-// }
-// .card__media--autothumb.green {
-//   background-color: #43a047;
-// }
-// .card__media--autothumb.yellow {
-//   background-color: #ffeb3b;
-// }
-// .card__media--autothumb.orange {
-//   background-color: #ffa726;
-// }
-//
-// .card__media--autothumb .card__autothumb__text {
-//   font-size: 2em;
-//   width: 100%;
-//   color: #ffffff;
-//   text-align: center;
-//   position: absolute;
-//   top: 36%;
-// }
-//
-// .card--form {
-//   width: calc(var(--input-width) + var(--card-padding) * 2);
-// }
-//
+// this is too specific
+// it should be a helper class
+// ex. ".m-padding-left"
+// will come back to this during the redesign - sean
+.card__publish-date {
+  padding-left: 20px;
+}
 
-//
-// .card-series-submit {
-//   margin-left: auto;
-//   margin-right: auto;
-//   max-width: var(--card-max-width);
-//   padding: $spacing-vertical / 2;
-// }
+.card-series-submit {
+  margin-left: auto;
+  margin-right: auto;
+  max-width: var(--card-max-width);
+  padding: $spacing-vertical / 2;
+}
 
-/*
- .card-row is used on the discover page
- It is a list of cards that extend past the right edge of the screen
- There are left/right arrows to scroll the cards and view hidden content
-*/
 .card-row {
+  + .card-row {
+    margin-top: $spacing-vertical * 1/3;
+  }
+}
+
+.card-row__placeholder {
+  padding-bottom: $spacing-vertical;
+}
+
+$padding-top-card-hover-hack: 20px;
+$padding-right-card-hover-hack: 30px;
+
+.card-row__items {
+  width: 100%;
+  overflow: hidden;
+
+  /*hacky way to give space for hover */
+  padding-top: $padding-top-card-hover-hack;
+  margin-top: -1 * $padding-top-card-hover-hack;
+  padding-right: $padding-right-card-hover-hack;
+  margin-right: -1 * $padding-right-card-hover-hack;
+  > .card {
+    vertical-align: top;
+    display: inline-block;
+  }
+  > .card + .card {
+    margin-left: 16px;
+  }
+}
+
+.card-row--small {
   overflow: hidden;
   white-space: nowrap;
   width: 100%;
   min-width: var(--card-small-width);
-  padding-top: $spacing-vertical;
+  margin-right: $spacing-vertical;
 }
-
 .card-row__header {
-  display: flex;
-  flex-direction: row;
-  justify-content: space-between;
-  // specific padding-left styling is needed here
-  // this needs to be used on a page with noPadding
-  // doing so allows the content to scroll to the edge of the screen
-  padding-left: $spacing-vertical * 2/3;
-}
-
-.card-row__title {
-  display: flex;
-  align-items: center;
+  margin-bottom: 16px;
 }
 
 .card-row__scrollhouse {
-  padding-top: $spacing-vertical * 2/3;
-  overflow: hidden;
+  position: relative;
+  /*hacky way to give space for hover */
+  padding-right: $padding-right-card-hover-hack;
+}
 
-  .card {
-    display: inline-block;
-    vertical-align: top;
-    margin-left: $spacing-vertical * 2/3;
-  }
+.card-row__nav {
+  position: absolute;
+  padding: 0 var(--card-margin);
+  height: 100%;
+  top: calc($padding-top-card-hover-hack - var(--card-margin));
+}
+.card-row__nav .card-row__scroll-button {
+  background: var(--card-bg);
+  color: var(--color-help);
+  box-shadow: var(--box-shadow-layer);
+  padding: $spacing-vertical $spacing-vertical / 2;
+  position: absolute;
+  cursor: pointer;
+  left: 0;
+  top: 36%;
+  z-index: 2;
+  opacity: 0.8;
+  transition: transform 0.2s var(--animation-style);
 
-  .card:last-of-type {
-    padding-right: $spacing-vertical * 2/3;
+  &:hover {
+    opacity: 1;
+    transform: scale(calc(var(--card-link-scaling) * 1.1));
   }
 }
+.card-row__nav--left {
+  left: 0;
+}
+.card-row__nav--right {
+  right: 0;
+}
 
 /*
 if we keep doing things like this, we should add a real grid system, but I'm going to be a selective dick about it - Jeremy
  */
-//TODO: css grid
-// .card-grid {
-//   $margin-card-grid: $spacing-vertical * 2/3;
-//   display: flex;
-//   flex-wrap: wrap;
-//   > .card {
-//     width: $width-page-constrained / 2 - $margin-card-grid / 2;
-//     flex-grow: 1;
-//   }
-//   > .card:nth-of-type(2n - 1):not(:last-child) {
-//     margin-right: $margin-card-grid;
-//   }
-// }
+.card-grid {
+  $margin-card-grid: $spacing-vertical * 2/3;
+  display: flex;
+  flex-wrap: wrap;
+  > .card {
+    width: $width-page-constrained / 2 - $margin-card-grid / 2;
+    flex-grow: 1;
+  }
+  > .card:nth-of-type(2n - 1):not(:last-child) {
+    margin-right: $margin-card-grid;
+  }
+}
diff --git a/src/renderer/scss/component/_channel-indicator.scss b/src/renderer/scss/component/_channel-indicator.scss
index 2291cc933..7c437780c 100644
--- a/src/renderer/scss/component/_channel-indicator.scss
+++ b/src/renderer/scss/component/_channel-indicator.scss
@@ -5,6 +5,12 @@
   text-overflow: ellipsis;
 }
 
+// this shouldn't know about the card width
+// will come back to this for the redesign - sean
+.channel-name--small {
+  width: calc(var(--card-small-width) * 2 / 3);
+}
+
 .channel-indicator__icon--invalid {
   color: var(--color-error);
 }
diff --git a/src/renderer/scss/component/_header.scss b/src/renderer/scss/component/_header.scss
index ca07bcc13..a8967d0eb 100644
--- a/src/renderer/scss/component/_header.scss
+++ b/src/renderer/scss/component/_header.scss
@@ -1,60 +1,64 @@
 #header {
+  color: var(--header-color);
+  background: var(--header-bg);
   display: flex;
   align-items: center;
+  justify-content: space-around;
   position: fixed;
+  box-shadow: var(--box-shadow-layer);
   top: 0;
   left: 0;
   width: 100%;
-  height: var(--header-height);
   z-index: 3;
+  padding: $spacing-vertical / 2;
   box-sizing: border-box;
-  color: var(--header-color);
-  background-color: var(--header-bg);
 }
-
-.header__actions-left {
-  display: flex;
-  padding: 0 5px;
-}
-
-.header__actions-right {
-  margin-left: auto;
-}
-
-.header__wunderbar {
-  flex: 1;
-  max-width: 325px;
-  min-width: 175px;
-  overflow: hidden;
-  white-space: nowrap;
-  text-overflow: ellipsis;
-  height: 100%;
-  display: flex;
-  align-items: center;
-  padding: 10px 5px;
-  cursor: text;
-}
-
-.wunderbar__input {
-  height: 50%;
-  width: 100%;
-  color: var(--search-color);
-  padding: 10px;
-  background-color: #f3f3f3;
-  border-radius: 10px;
-  font-size: 0.9em;
-
-  &:focus {
-    // TODO: focus style
+.header__item {
+  padding-left: $spacing-vertical / 4;
+  padding-right: $spacing-vertical / 4;
+  .button-alt {
+    background: var(--header-button-bg) !important;
+    font-size: 1em;
+  }
+  .button-alt:hover {
+    background: var(--header-button-hover-bg) !important;
   }
 }
 
-.wunderbar__suggestion {
-  padding: 5px;
-  background-color: var(--header-bg);
-  cursor: pointer;
+.header__item--wunderbar {
+  flex-grow: 1;
 }
 
-.wunderbar__active-suggestion {
-  background-color: #a3ffb0;
+.wunderbar {
+  position: relative;
+  .icon {
+    position: absolute;
+    left: 10px;
+    top: $spacing-vertical / 2 - 4px; //hacked
+  }
+}
+
+.wunderbar--active .icon-search {
+  color: var(--color-primary);
+}
+
+// below styles should be inside the common input styling
+// will come back to this with the redesign - sean
+.wunderbar__input {
+  background: var(--search-bg);
+  width: 100%;
+  color: var(--search-color);
+  height: $spacing-vertical * 1.5;
+  line-height: $spacing-vertical * 1.5;
+  padding-left: 38px;
+  padding-right: 5px;
+  border-radius: 2px;
+  border: var(--search-border);
+  transition: box-shadow var(--transition-duration) var(--transition-type);
+  &:focus {
+    background: var(--search-active-bg);
+    color: var(--search-active-color);
+    box-shadow: var(--search-active-shadow);
+    border-color: var(--color-primary);
+  }
 }
diff --git a/src/renderer/scss/component/_tooltip.scss b/src/renderer/scss/component/_tooltip.scss
index 1448fd590..d017996c1 100644
--- a/src/renderer/scss/component/_tooltip.scss
+++ b/src/renderer/scss/component/_tooltip.scss
@@ -2,7 +2,10 @@
 
 .tooltip {
   position: relative;
-  padding: 0 $spacing-vertical / 3;
+}
+
+.tooltip__link {
+  @include text-link();
 }
 
 .tooltip__body {
@@ -14,15 +17,16 @@
   box-sizing: border-box;
   padding: $spacing-vertical / 2;
   width: var(--tooltip-width);
+  border: var(--tooltip-border);
   color: var(--tooltip-color);
   background-color: var(--tooltip-bg);
   font-size: calc(var(--font-size) * 7/8);
   line-height: var(--font-line-height);
   box-shadow: var(--box-shadow-layer);
-  border-radius: var(--card-radius);
 }
 
-.tooltip__link {
+.tooltip--header .tooltip__link {
+  @include text-link(#aaa);
   font-size: calc(var(--font-size) * 3/4);
   margin-left: var(--button-padding);
   vertical-align: middle;
diff --git a/static/font/metropolis/Metropolis-BlackItalic.woff2 b/static/font/metropolis/Metropolis-BlackItalic.woff2
deleted file mode 100755
index 942bf6452..000000000
Binary files a/static/font/metropolis/Metropolis-BlackItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-Bold.woff2 b/static/font/metropolis/Metropolis-Bold.woff2
deleted file mode 100755
index 54bb59f65..000000000
Binary files a/static/font/metropolis/Metropolis-Bold.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-BoldItalic.woff2 b/static/font/metropolis/Metropolis-BoldItalic.woff2
deleted file mode 100755
index dbb3f0425..000000000
Binary files a/static/font/metropolis/Metropolis-BoldItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-ExtraBold.woff2 b/static/font/metropolis/Metropolis-ExtraBold.woff2
deleted file mode 100755
index d3ce18b1d..000000000
Binary files a/static/font/metropolis/Metropolis-ExtraBold.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-ExtraBoldItalic.woff2 b/static/font/metropolis/Metropolis-ExtraBoldItalic.woff2
deleted file mode 100755
index 21d8ab53e..000000000
Binary files a/static/font/metropolis/Metropolis-ExtraBoldItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-ExtraLight.woff2 b/static/font/metropolis/Metropolis-ExtraLight.woff2
deleted file mode 100755
index 993d8c421..000000000
Binary files a/static/font/metropolis/Metropolis-ExtraLight.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-ExtraLightItalic.woff2 b/static/font/metropolis/Metropolis-ExtraLightItalic.woff2
deleted file mode 100755
index deffa671b..000000000
Binary files a/static/font/metropolis/Metropolis-ExtraLightItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-Light.woff2 b/static/font/metropolis/Metropolis-Light.woff2
deleted file mode 100755
index 3b20f0723..000000000
Binary files a/static/font/metropolis/Metropolis-Light.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-LightItalic.woff2 b/static/font/metropolis/Metropolis-LightItalic.woff2
deleted file mode 100755
index f3c0e4095..000000000
Binary files a/static/font/metropolis/Metropolis-LightItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-Medium.woff2 b/static/font/metropolis/Metropolis-Medium.woff2
deleted file mode 100755
index d5aabb6e9..000000000
Binary files a/static/font/metropolis/Metropolis-Medium.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-MediumItalic.woff2 b/static/font/metropolis/Metropolis-MediumItalic.woff2
deleted file mode 100755
index 506fb07b1..000000000
Binary files a/static/font/metropolis/Metropolis-MediumItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-Regular.woff2 b/static/font/metropolis/Metropolis-Regular.woff2
deleted file mode 100755
index 40417bff0..000000000
Binary files a/static/font/metropolis/Metropolis-Regular.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-RegularItalic.woff2 b/static/font/metropolis/Metropolis-RegularItalic.woff2
deleted file mode 100755
index 956e0adb8..000000000
Binary files a/static/font/metropolis/Metropolis-RegularItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-SemiBold.woff2 b/static/font/metropolis/Metropolis-SemiBold.woff2
deleted file mode 100755
index 2ad1a7e00..000000000
Binary files a/static/font/metropolis/Metropolis-SemiBold.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-SemiBoldItalic.woff2 b/static/font/metropolis/Metropolis-SemiBoldItalic.woff2
deleted file mode 100755
index 94df7d35e..000000000
Binary files a/static/font/metropolis/Metropolis-SemiBoldItalic.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-Thin.woff2 b/static/font/metropolis/Metropolis-Thin.woff2
deleted file mode 100755
index 0c370707f..000000000
Binary files a/static/font/metropolis/Metropolis-Thin.woff2 and /dev/null differ
diff --git a/static/font/metropolis/Metropolis-ThinItalic.woff2 b/static/font/metropolis/Metropolis-ThinItalic.woff2
deleted file mode 100755
index 85491c2e2..000000000
Binary files a/static/font/metropolis/Metropolis-ThinItalic.woff2 and /dev/null differ
diff --git a/yarn.lock b/yarn.lock
index 02f395c04..35e76177e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2661,10 +2661,6 @@ dom-converter@~0.1:
   dependencies:
     utila "~0.3"
 
-dom-scroll-into-view@^1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-1.2.1.tgz#e8f36732dd089b0201a88d7815dc3f88e6d66c7e"
-
 dom-serializer@0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"