diff --git a/.gitignore b/.gitignore
index bc9103de..faf39252 100644
--- a/.gitignore
+++ b/.gitignore
@@ -5,3 +5,4 @@ npm-debug.log
 test/unit/coverage
 test/e2e/reports
 selenium-debug.log
+.idea/
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1d3cba05..c31d2d31 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -27,15 +27,20 @@ before_script:
 #  paths:
 #  - node_modules/
 
+stages:
+  - build
+  - test
+  - deploy
+
 test:
+  stage: test
   script:
-    - npm install -g yarn
     - yarn
     - npm run unit
 
 build:
+  stage: build
   script:
-    - npm install -g yarn
     - yarn
     - npm run build
   artifacts:
@@ -43,11 +48,11 @@ build:
     - dist/
 
 deploy:
+  stage: deploy
   environment: dev
   only:
     - develop
   script:
-    - npm install -g yarn
     - yarn
     - npm run build
     - scp -r dist/* pleroma@tenshi.heldscal.la:~/pleroma
diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js
index f4f6aebf..c3f52f57 100644
--- a/src/components/attachment/attachment.js
+++ b/src/components/attachment/attachment.js
@@ -29,7 +29,11 @@ const Attachment = {
       }
     },
     toggleHidden () {
-      this.showHidden = !this.showHidden
+      let img = document.createElement('img')
+      img.src = this.attachment.url
+      img.onload = () => {
+        this.showHidden = !this.showHidden
+      }
     }
   }
 }
diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue
index 9675e69f..a150ece3 100644
--- a/src/components/conversation/conversation.vue
+++ b/src/components/conversation/conversation.vue
@@ -1,6 +1,6 @@
 <template>
   <div class="timeline panel panel-default base00-background">
-    <div class="panel-heading base01-background base04">
+    <div class="panel-heading base01-background base04" style="justify-content:space-between;">
       Conversation
       <div v-if="collapsable">
         <small><a href="#" @click.prevent="$emit('toggleExpanded')">Collapse</a></small>
diff --git a/src/components/friends_timeline/friends_timeline.vue b/src/components/friends_timeline/friends_timeline.vue
index afe5cc89..3bf3b543 100644
--- a/src/components/friends_timeline/friends_timeline.vue
+++ b/src/components/friends_timeline/friends_timeline.vue
@@ -1,10 +1,5 @@
 <template>
-  <div class="timeline panel panel-default">
-    <div class="panel-heading base01-background base04">Friends Timeline</div>
-    <div class="panel-body">
-      <Timeline v-bind:timeline="timeline" v-bind:timeline-name="'friends'"/>
-    </div>
-  </div>
+  <Timeline :title="'Friends'" v-bind:timeline="timeline" v-bind:timeline-name="'friends'"/>
 </template>
 
 <script src="./friends_timeline.js"></script>
diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue
index c0ea4313..c0273bae 100644
--- a/src/components/login_form/login_form.vue
+++ b/src/components/login_form/login_form.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="login panel panel-default base00-background">
     <!-- Default panel contents -->
-    <div class="panel-heading base01-background">
+    <div class="panel-heading base01-background base04">
       Log in
     </div>
     <div class="panel-body">
diff --git a/src/components/mentions/mentions.vue b/src/components/mentions/mentions.vue
index 59f00241..7af402ce 100644
--- a/src/components/mentions/mentions.vue
+++ b/src/components/mentions/mentions.vue
@@ -1,10 +1,5 @@
 <template>
-  <div class="timeline panel panel-default">
-    <div class="panel-heading base01-background base04">Mentions</div>
-    <div class="panel-body">
-      <Timeline v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
-    </div>
-  </div>
+  <Timeline :title="'Mentions'" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
 </template>
 
 <script src="./mentions.js"></script>
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index 5da6d495..1378e730 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -9,16 +9,16 @@
     button {
       position: absolute;
       padding: 0.1em 0.3em 0.25em 0.3em;
-      right: 0.6em;
+      right: 0.7em;
     }
   }
 
-  .unseen {
-    border-left: 4px solid rgba(255, 48, 16, 0.65);
-  }
-
   .notification {
-    padding: 0.4em 0 0 0.7em;
+    // Will have to use pixels here to ensure consistent distance with
+    // pad alone and pad + border, browsers bad at rounding this with em,
+    // they love to give a 1 pixel ghost offset with 0.7em vs 0.3em + 0.4em,
+    // which does not happen with 10px vs 4px + 6px.
+    padding: 0.4em 0 0 10px;
     display: flex;
     border-bottom: 1px solid silver;
 
@@ -62,4 +62,9 @@
       border: none
     }
   }
+
+  .unseen {
+    border-left: 4px solid rgba(255, 48, 16, 0.65);
+    padding-left: 6px;
+  }
 }
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 41c274aa..180b86a1 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -3,7 +3,7 @@
     <div class="panel panel-default base00-background">
       <div class="panel-heading base01-background base04">
         Notifications ({{unseenCount}})
-        <button @click.prevent="markAsSeen" class="base05 base02-background">Read!</button>
+        <button @click.prevent="markAsSeen" class="base06 base02-background">Read!</button>
       </div>
       <div class="panel-body">
         <div v-for="notification in visibleNotifications" class="notification" :class='{"unseen": !notification.seen}'>
diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.vue b/src/components/public_and_external_timeline/public_and_external_timeline.vue
index bda51153..fd696938 100644
--- a/src/components/public_and_external_timeline/public_and_external_timeline.vue
+++ b/src/components/public_and_external_timeline/public_and_external_timeline.vue
@@ -1,10 +1,5 @@
 <template>
-  <div class="timeline panel panel-default">
-    <div class="panel-heading base01-background base04">THE WHOLE KNOWN NETWORK</div>
-    <div class="panel-body">
-      <Timeline v-bind:timeline="timeline" v-bind:timeline-name="'publicAndExternal'"/>
-    </div>
-  </div>
+  <Timeline :title="'THE WHOLE KNOWN NETWORK'"v-bind:timeline="timeline" v-bind:timeline-name="'publicAndExternal'"/>
 </template>
 
 <script src="./public_and_external_timeline.js"></script>
diff --git a/src/components/public_timeline/public_timeline.vue b/src/components/public_timeline/public_timeline.vue
index d05695b2..bd6a23ed 100644
--- a/src/components/public_timeline/public_timeline.vue
+++ b/src/components/public_timeline/public_timeline.vue
@@ -1,10 +1,5 @@
 <template>
-  <div class="timeline panel panel-default">
-    <div class="panel-heading base01-background base04">Public Timeline</div>
-    <div class="panel-body">
-      <Timeline v-bind:timeline="timeline" v-bind:timeline-name="'public'"/>
-    </div>
-  </div>
+  <Timeline :title="'Public Timeline'" v-bind:timeline="timeline" v-bind:timeline-name="'public'"/>
 </template>
 
 <script src="./public_timeline.js"></script>
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index addd0255..b4e80fe1 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -5,7 +5,8 @@ import StatusOrConversation from '../status_or_conversation/status_or_conversati
 const Timeline = {
   props: [
     'timeline',
-    'timelineName'
+    'timelineName',
+    'title'
   ],
   components: {
     Status,
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 078d954c..8a302e18 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -1,39 +1,62 @@
 <template>
-  <div class="timeline">
-    <a href="#" v-on:click.prevent='showNewStatuses()' v-if="timeline.newStatusCount > 0">
-      <div class="base00-background base05-border new-status-notification">
-        <p class="text-center" >
-          {{timeline.newStatusCount}} new statuses
-        </p>
+  <div class="timeline panel panel-default">
+    <div class="panel-heading base01-background base04">
+      <div class="title">
+        {{title}}
       </div>
-    </a>
-    <status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status"></status-or-conversation>
-    <a href="#" v-on:click.prevent='fetchOlderStatuses()' v-if="!timeline.loading">
-      <div class="base01-background base05-border new-status-notification">
-        <p class="text-center" >
-          Load older statuses.
-        </p>
+      <button @click.prevent="showNewStatuses" class="base06 base02-background" v-if="timeline.newStatusCount > 0">
+        Show new ({{timeline.newStatusCount}})
+      </button>
+      <button @click.prevent class="base04 base01-background no-press" v-if="!timeline.newStatusCount > 0">
+        Up-to-date
+      </button>
+    </div>
+    <div class="panel-body">
+      <div class="timeline">
+        <status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status"></status-or-conversation>
+        <a href="#" v-on:click.prevent='fetchOlderStatuses()' v-if="!timeline.loading">
+          <div class="base01-background base05-border new-status-notification text-center">Load older statuses.</div>
+        </a>
+          <div class="base01-background base05-border new-status-notification text-center" v-else>...</div>
       </div>
-    </a>
+    </div>
   </div>
 </template>
 <script src="./timeline.js"></script>
 
 <style lang="scss">
- .new-status-notification {
-   border-style: solid;
-   float: right;
-   border-width: 1px 1px 0px 1px;
-   border-radius: 5px 5px 0 0;
-   font-size: 1.1em;
-   margin-top: -2.08em;
-   margin-right: 0.8em;
-   max-width: 200px;
-   max-height: 2em;
 
-   p {
-     margin: 0px;
-     padding: 0.6em;
-   }
- }
+  .timeline .panel-heading {
+    position: relative;
+    display: flex;
+
+    .title {
+      white-space: nowrap;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      max-width: 70%;
+    }
+    button {
+      position: absolute;
+      right: 0.6em;
+      padding: 0.1em 0.3em 0.25em 0.3em;
+      min-width: 6em;
+    }
+    .no-press {
+      opacity: 0.8;
+      cursor: default;
+    }
+  }
+
+
+  .new-status-notification {
+    position:relative;
+    margin-top: -1px;
+    font-size: 1.1em;
+    border-width: 1px 0 0 0;
+    border-style: solid;
+    border-radius: 0 0 10px 10px;
+    padding: 10px;
+    z-index: 1;
+  }
 </style>
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index aa9a15e1..3fa34773 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -63,15 +63,13 @@
       headingStyle () {
         let rgb = this.$store.state.config.colors['base00'].match(/\d+/g)
         return {
-          backgroundColor: 'rgb(' + Math.floor(rgb[0] * 0.53) + ', ' +
-                                    Math.floor(rgb[1] * 0.56) + ', ' +
-                                    Math.floor(rgb[2] * 0.59) + ')',
+          backgroundColor: `rgb(${Math.floor(rgb[0] * 0.53)}, ${Math.floor(rgb[1] * 0.56)}, ${Math.floor(rgb[2] * 0.59)})`,
           backgroundImage: `url(${this.user.cover_photo})`
         }
       },
       bodyStyle () {
         return {
-          background: 'linear-gradient(to bottom, rgba(0, 0, 0, 0), ' + this.$store.state.config.colors['base00'] + ' 80%)'
+          background: `linear-gradient(to bottom, rgba(0, 0, 0, 0), ${this.$store.state.config.colors['base00']} 80%)`
         }
       },
       isOtherUser () {