diff --git a/package.json b/package.json
index 2aea1af8..60e5ca02 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
   "dependencies": {
     "babel-plugin-add-module-exports": "^0.2.1",
     "babel-plugin-lodash": "^3.2.11",
+    "chromatism": "^3.0.0",
     "diff": "^3.0.1",
     "karma-mocha-reporter": "^2.2.1",
     "localforage": "^1.5.0",
@@ -30,6 +31,7 @@
     "vue-router": "^3.0.1",
     "vue-template-compiler": "^2.3.4",
     "vue-timeago": "^3.1.2",
+    "vuelidate": "^0.7.4",
     "vuex": "^3.0.1",
     "whatwg-fetch": "^2.0.3"
   },
diff --git a/src/App.js b/src/App.js
index 3bfd307f..89aed01d 100644
--- a/src/App.js
+++ b/src/App.js
@@ -59,7 +59,12 @@ export default {
       })
     },
     logo () { return this.$store.state.instance.logo },
-    style () { return { 'background-image': `url(${this.background})` } },
+    style () {
+      return {
+        '--body-background-image': `url(${this.background})`,
+        'background-image': `url(${this.background})`
+      }
+    },
     sitename () { return this.$store.state.instance.name },
     chat () { return this.$store.state.chat.channel.state === 'joined' },
     suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
diff --git a/src/App.scss b/src/App.scss
index 056a235e..5355d899 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -34,10 +34,11 @@ h4 {
 
 body {
   font-family: sans-serif;
+  font-family: var(--interfaceFont, sans-serif);
   font-size: 14px;
   margin: 0;
-  color: $fallback--fg;
-  color: var(--fg, $fallback--fg);
+  color: $fallback--text;
+  color: var(--text, $fallback--text);
   max-width: 100vw;
   overflow-x: hidden;
 }
@@ -50,19 +51,24 @@ a {
 
 button {
   user-select: none;
-  color: $fallback--fg;
-  color: var(--fg, $fallback--fg);
-  background-color: $fallback--btn;
-  background-color: var(--btn, $fallback--btn);
+  color: $fallback--text;
+  color: var(--btnText, $fallback--text);
+  background-color: $fallback--fg;
+  background-color: var(--btn, $fallback--fg);
   border: none;
   border-radius: $fallback--btnRadius;
   border-radius: var(--btnRadius, $fallback--btnRadius);
   cursor: pointer;
-  border-top: 1px solid rgba(255, 255, 255, 0.2);
-  border-bottom: 1px solid rgba(0, 0, 0, 0.2);
-  box-shadow: 0px 0px 2px black;
+  box-shadow: 0px 0px 2px 0px rgba(0, 0, 0, 1), 0px 1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px -1px 0px 0px rgba(0, 0, 0, 0.2) inset;
+  box-shadow: var(--buttonShadow);
   font-size: 14px;
   font-family: sans-serif;
+  font-family: var(--interfaceFont, sans-serif);
+
+  i[class*=icon-] {
+    color: $fallback--text;
+    color: var(--btnText, $fallback--text);
+  }
 
   &::-moz-focus-inner {
     border: none;
@@ -70,11 +76,12 @@ button {
 
   &:hover {
     box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3);
+    box-shadow: var(--buttonHoverShadow);
   }
 
   &:active {
-    border-bottom: 1px solid rgba(255, 255, 255, 0.2);
-    border-top: 1px solid rgba(0, 0, 0, 0.2);
+    box-shadow: 0px 0px 4px 0px rgba(255, 255, 255, 0.3), 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
+    box-shadow: var(--buttonPressedShadow);
   }
 
   &:disabled {
@@ -99,32 +106,37 @@ input, textarea, .select {
   border: none;
   border-radius: $fallback--inputRadius;
   border-radius: var(--inputRadius, $fallback--inputRadius);
-  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
-  border-top: 1px solid rgba(0, 0, 0, 0.2);
-  box-shadow: 0px 0px 2px black inset;
-  background-color: $fallback--input;
-  background-color: var(--input, $fallback--input);
-  color: $fallback--lightFg;
-  color: var(--lightFg, $fallback--lightFg);
+  box-shadow: 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px 0px 2px 0px rgba(0, 0, 0, 1) inset;
+  box-shadow: var(--inputShadow);
+  background-color: $fallback--fg;
+  background-color: var(--input, $fallback--fg);
+  color: $fallback--lightText;
+  color: var(--inputText, $fallback--lightText);
   font-family: sans-serif;
+  font-family: var(--inputFont, sans-serif);
   font-size: 14px;
-  padding: 8px 7px;
+  padding: 8px .5em;
   box-sizing: border-box;
   display: inline-block;
   position: relative;
-  height: 29px;
+  height: 28px;
   line-height: 16px;
   hyphens: none;
 
+  &:disabled, &[disabled=disabled] {
+    cursor: not-allowed;
+    opacity: 0.5;
+  }
+
   .icon-down-open {
     position: absolute;
     top: 0;
     bottom: 0;
     right: 5px;
     height: 100%;
-    color: $fallback--fg;
-    color: var(--fg, $fallback--fg);
-    line-height: 29px;
+    color: $fallback--text;
+    color: var(--text, $fallback--text);
+    line-height: 28px;
     z-index: 0;
     pointer-events: none;
   }
@@ -135,22 +147,33 @@ input, textarea, .select {
     appearance: none;
     background: transparent;
     border: none;
+    color: $fallback--text;
+    color: var(--text, $fallback--text);
     margin: 0;
-    color: $fallback--fg;
-    color: var(--fg, $fallback--fg);
-    padding: 4px 2em 3px 3px;
+    padding: 0 2em 0 .2em;
+    font-family: sans-serif;
+    font-family: var(--inputFont, sans-serif);
+    font-size: 14px;
     width: 100%;
     z-index: 1;
-    height: 29px;
+    height: 28px;
     line-height: 16px;
   }
 
+  &[type=range] {
+    background: none;
+    border: none;
+    margin: 0;
+    box-shadow: none;
+    flex: 1;
+  }
+
   &[type=radio],
   &[type=checkbox] {
     display: none;
     &:checked + label::before {
-      color: $fallback--fg;
-      color: var(--fg, $fallback--fg);
+      color: $fallback--text;
+      color: var(--text, $fallback--text);
     }
     &:disabled,
     {
@@ -166,14 +189,13 @@ input, textarea, .select {
       transition: color 200ms;
       width: 1.1em;
       height: 1.1em;
-      border-radius: $fallback--checkBoxRadius;
-      border-radius: var(--checkBoxRadius, $fallback--checkBoxRadius);
-      border-bottom: 1px solid rgba(255, 255, 255, 0.2);
-      border-top: 1px solid rgba(0, 0, 0, 0.2);
+      border-radius: $fallback--checkboxRadius;
+      border-radius: var(--checkboxRadius, $fallback--checkboxRadius);
       box-shadow: 0px 0px 2px black inset;
+      box-shadow: var(--inputShadow);
       margin-right: .5em;
-      background-color: $fallback--input;
-      background-color: var(--input, $fallback--input);
+      background-color: $fallback--fg;
+      background-color: var(--input, $fallback--fg);
       vertical-align: top;
       text-align: center;
       line-height: 1.1em;
@@ -187,8 +209,8 @@ input, textarea, .select {
 }
 
 option {
-  color: $fallback--fg;
-  color: var(--fg, $fallback--fg);
+  color: $fallback--text;
+  color: var(--text, $fallback--text);
   background-color: $fallback--bg;
   background-color: var(--bg, $fallback--bg);
 }
@@ -254,7 +276,7 @@ nav {
       mask-position: center;
       mask-size: contain;
       background-color: $fallback--fg;
-      background-color: var(--fg, $fallback--fg);
+      background-color: var(--topBarText, $fallback--fg);
       position: absolute;
       top: 0;
       bottom: 0;
@@ -279,9 +301,9 @@ nav {
     margin: auto;
     height: 50px;
 
-    a i {
+    a, a i {
       color: $fallback--link;
-      color: var(--link, $fallback--link);
+      color: var(--topBarLink, $fallback--link);
     }
   }
 }
@@ -304,15 +326,33 @@ main-router {
 
 .panel {
   display: flex;
+  position: relative;
+
   flex-direction: column;
   margin: 0.5em;
 
   background-color: $fallback--bg;
   background-color: var(--bg, $fallback--bg);
 
-  border-radius: $fallback--panelRadius;
-  border-radius: var(--panelRadius, $fallback--panelRadius);
-  box-shadow: 1px 1px 4px rgba(0,0,0,.6);
+  &::after, & {
+    border-radius: $fallback--panelRadius;
+    border-radius: var(--panelRadius, $fallback--panelRadius);
+  }
+
+  &::after {
+    content: '';
+    position: absolute;
+
+    top: 0;
+    bottom: 0;
+    left: 0;
+    right: 0;
+
+    pointer-events: none;
+
+    box-shadow: 1px 1px 4px rgba(0,0,0,.6);
+    box-shadow: var(--panelShadow);
+  }
 }
 
 .panel-body:empty::before {
@@ -330,15 +370,23 @@ main-router {
   padding: .6em .6em;
   text-align: left;
   line-height: 28px;
-  background-color: $fallback--btn;
-  background-color: var(--btn, $fallback--btn);
+  color: var(--panelText);
+  background-color: $fallback--fg;
+  background-color: var(--panel, $fallback--fg);
   align-items: baseline;
+  box-shadow: var(--panelHeaderShadow);
 
   .title {
     flex: 1 0 auto;
     font-size: 1.3em;
   }
 
+  .faint {
+    background-color: transparent;
+    color: $fallback--faint;
+    color: var(--panelFaint, $fallback--faint);
+  }
+
   .alert {
     white-space: nowrap;
     text-overflow: ellipsis;
@@ -359,6 +407,11 @@ main-router {
     min-width: 1px;
     align-self: stretch;
   }
+
+  a {
+    color: $fallback--link;
+    color: var(--panelLink, $fallback--link)
+  }
 }
 
 .panel-heading.stub {
@@ -369,6 +422,11 @@ main-router {
 .panel-footer {
   border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
   border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
+
+  a {
+    color: $fallback--link;
+    color: var(--panelLink, $fallback--link)
+  }
 }
 
 .panel-body > p {
@@ -387,11 +445,13 @@ main-router {
 
 nav {
   z-index: 1000;
-  background-color: $fallback--btn;
-  background-color: var(--btn, $fallback--btn);
+  color: var(--topBarText);
+  background-color: $fallback--fg;
+  background-color: var(--topBar, $fallback--fg);
   color: $fallback--faint;
   color: var(--faint, $fallback--faint);
   box-shadow: 0px 0px 4px rgba(0,0,0,.6);
+  box-shadow: var(--topBarShadow);
 }
 
 .fade-enter-active, .fade-leave-active {
@@ -465,20 +525,46 @@ nav {
     flex-grow: 0;
   }
 }
+.badge {
+  display: inline-block;
+  border-radius: 99px;
+  min-width: 22px;
+  max-width: 22px;
+  min-height: 22px;
+  max-height: 22px;
+  font-size: 15px;
+  line-height: 22px;
+  text-align: center;
+  vertical-align: middle;
+  white-space: nowrap;
+  padding: 0;
+
+  &.badge-notification {
+    background-color: $fallback--cRed;
+    background-color: var(--badgeNotification, $fallback--cRed);
+    color: white;
+    color: var(--badgeNotificationText, white);
+  }
+}
 
 .alert {
   margin: 0.35em;
   padding: 0.25em;
   border-radius: $fallback--tooltipRadius;
   border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-  color: $fallback--faint;
-  color: var(--faint, $fallback--faint);
   min-height: 28px;
   line-height: 28px;
 
   &.error {
-    background-color: $fallback--cAlertRed;
-    background-color: var(--cAlertRed, $fallback--cAlertRed);
+    background-color: $fallback--alertError;
+    background-color: var(--alertError, $fallback--alertError);
+    color: $fallback--text;
+    color: var(--alertErrorText, $fallback--text);
+
+    .panel-heading & {
+      color: $fallback--text;
+      color: var(--alertErrorPanelText, $fallback--text);
+    }
   }
 }
 
@@ -516,8 +602,8 @@ nav {
   cursor: pointer;
 
   .selected {
-    color: $fallback--lightFg;
-    color: var(--lightFg, $fallback--lightFg);
+    color: $fallback--lightText;
+    color: var(--lightText, $fallback--lightText);
   }
 
   .text-format {
diff --git a/src/App.vue b/src/App.vue
index 9d66b9d4..16cd08d4 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -30,7 +30,7 @@
               <instance-specific-panel v-if="showInstanceSpecificPanel"></instance-specific-panel>
               <features-panel v-if="!currentUser"></features-panel>
               <who-to-follow-panel v-if="currentUser && suggestionsEnabled"></who-to-follow-panel>
-              <notifications v-if="currentUser"></notifications>
+              <notifications :activatePanel="activatePanel" v-if="currentUser"></notifications>
             </div>
           </div>
         </div>
diff --git a/src/_variables.scss b/src/_variables.scss
index b5222a6a..150e4fb5 100644
--- a/src/_variables.scss
+++ b/src/_variables.scss
@@ -3,24 +3,23 @@ $main-background: white;
 $darkened-background: whitesmoke;
 
 $fallback--bg: #121a24;
-$fallback--btn: #182230;
-$fallback--input: #182230;
+$fallback--fg: #182230;
 $fallback--faint: rgba(185, 185, 186, .5);
-$fallback--fg: #b9b9ba;
+$fallback--text: #b9b9ba;
 $fallback--link: #d8a070;
 $fallback--icon: #666;
 $fallback--lightBg: rgb(21, 30, 42);
-$fallback--lightFg: #b9b9ba;
+$fallback--lightText: #b9b9ba;
 $fallback--border: #222;
 $fallback--cRed: #ff0000;
 $fallback--cBlue: #0095ff;
 $fallback--cGreen: #0fa00f;
 $fallback--cOrange: orange;
 
-$fallback--cAlertRed: rgba(211,16,20,.5);
+$fallback--alertError: rgba(211,16,20,.5);
 
 $fallback--panelRadius: 10px;
-$fallback--checkBoxRadius: 2px;
+$fallback--checkboxRadius: 2px;
 $fallback--btnRadius: 4px;
 $fallback--inputRadius: 4px;
 $fallback--tooltipRadius: 5px;
diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js
index 41730720..16114c30 100644
--- a/src/components/attachment/attachment.js
+++ b/src/components/attachment/attachment.js
@@ -13,6 +13,7 @@ const Attachment = {
     return {
       nsfwImage,
       hideNsfwLocal: this.$store.state.config.hideNsfw,
+      preloadImage: this.$store.state.config.preloadImage,
       loopVideo: this.$store.state.config.loopVideo,
       showHidden: false,
       loading: false,
@@ -46,7 +47,7 @@ const Attachment = {
       }
     },
     toggleHidden () {
-      if (this.img) {
+      if (this.img && !this.preloadImage) {
         if (this.img.onload) {
           this.img.onload()
         } else {
diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue
index 40e2cf1b..5eaa0d1d 100644
--- a/src/components/attachment/attachment.vue
+++ b/src/components/attachment/attachment.vue
@@ -9,8 +9,7 @@
     <div class="hider" v-if="nsfw && hideNsfwLocal && !hidden">
       <a href="#" @click.prevent="toggleHidden()">Hide</a>
     </div>
-
-    <a v-if="type === 'image' && !hidden" class="image-attachment" :href="attachment.url" target="_blank" :title="attachment.description">
+    <a v-if="type === 'image' && (!hidden || preloadImage)" class="image-attachment" :class="{'hidden': hidden && preloadImage}" :href="attachment.url" target="_blank" :title="attachment.description">
       <StillImage :class="{'small': isSmall}" referrerpolicy="no-referrer" :mimetype="attachment.mimetype" :src="attachment.large_thumb_url || attachment.url"/>
     </a>
 
@@ -161,6 +160,10 @@
     display: flex;
     flex: 1;
 
+    &.hidden {
+      display: none;
+    }
+
     .still-image {
       width: 100%;
       height: 100%;
diff --git a/src/components/chat_panel/chat_panel.vue b/src/components/chat_panel/chat_panel.vue
index 30070d3e..f174319a 100644
--- a/src/components/chat_panel/chat_panel.vue
+++ b/src/components/chat_panel/chat_panel.vue
@@ -55,8 +55,8 @@
 .chat-heading {
   cursor: pointer;
   .icon-comment-empty {
-    color: $fallback--fg;
-    color: var(--fg, $fallback--fg);
+    color: $fallback--text;
+    color: var(--text, $fallback--text);
   }
 }
 
diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue
new file mode 100644
index 00000000..34eec248
--- /dev/null
+++ b/src/components/color_input/color_input.vue
@@ -0,0 +1,53 @@
+<template>
+<div class="color-control style-control" :class="{ disabled: !present || disabled }">
+  <label :for="name" class="label">
+    {{label}}
+  </label>
+  <input
+    v-if="typeof fallback !== 'undefined'"
+    class="opt exlcude-disabled"
+    :id="name + '-o'"
+    type="checkbox"
+    :checked="present"
+    @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)">
+  <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
+  <input
+    :id="name"
+    class="color-input"
+    type="color"
+    :value="value || fallback"
+    :disabled="!present || disabled"
+    @input="$emit('input', $event.target.value)"
+    >
+  <input
+    :id="name + '-t'"
+    class="text-input"
+    type="text"
+    :value="value || fallback"
+    :disabled="!present || disabled"
+    @input="$emit('input', $event.target.value)"
+    >
+</div>
+</template>
+
+<script>
+export default {
+  props: [
+    'name', 'label', 'value', 'fallback', 'disabled'
+  ],
+  computed: {
+    present () {
+      return typeof this.value !== 'undefined'
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.color-control {
+  input.text-input {
+    max-width: 7em;
+    flex: 1;
+  }
+}
+</style>
diff --git a/src/components/contrast_ratio/contrast_ratio.vue b/src/components/contrast_ratio/contrast_ratio.vue
new file mode 100644
index 00000000..bd971d00
--- /dev/null
+++ b/src/components/contrast_ratio/contrast_ratio.vue
@@ -0,0 +1,69 @@
+<template>
+<span  v-if="contrast" class="contrast-ratio">
+  <span :title="hint" class="rating">
+    <span v-if="contrast.aaa">
+      <i class="icon-thumbs-up-alt"/>
+    </span>
+    <span v-if="!contrast.aaa && contrast.aa">
+      <i class="icon-adjust"/>
+    </span>
+    <span v-if="!contrast.aaa && !contrast.aa">
+      <i class="icon-attention"/>
+    </span>
+  </span>
+  <span class="rating" v-if="contrast && large" :title="hint_18pt">
+    <span v-if="contrast.laaa">
+      <i class="icon-thumbs-up-alt"/>
+    </span>
+    <span v-if="!contrast.laaa && contrast.laa">
+      <i class="icon-adjust"/>
+    </span>
+    <span v-if="!contrast.laaa && !contrast.laa">
+      <i class="icon-attention"/>
+    </span>
+  </span>
+</span>
+</template>
+
+<script>
+export default {
+  props: [
+    'large', 'contrast'
+  ],
+  computed: {
+    hint () {
+      const levelVal = this.contrast.aaa ? 'aaa' : (this.contrast.aa ? 'aa' : 'bad')
+      const level = this.$t(`settings.style.common.contrast.level.${levelVal}`)
+      const context = this.$t('settings.style.common.contrast.context.text')
+      const ratio = this.contrast.text
+      return this.$t('settings.style.common.contrast.hint', { level, context, ratio })
+    },
+    hint_18pt () {
+      const levelVal = this.contrast.laaa ? 'aaa' : (this.contrast.laa ? 'aa' : 'bad')
+      const level = this.$t(`settings.style.common.contrast.level.${levelVal}`)
+      const context = this.$t('settings.style.common.contrast.context.18pt')
+      const ratio = this.contrast.text
+      return this.$t('settings.style.common.contrast.hint', { level, context, ratio })
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.contrast-ratio {
+  display: flex;
+  justify-content: flex-end;
+
+  margin-top: -4px;
+  margin-bottom: 5px;
+
+  .label {
+    margin-right: 1em;
+  }
+
+  .rating {
+    display: inline-block;
+    text-align: center;
+  }
+}
+</style>
diff --git a/src/components/delete_button/delete_button.vue b/src/components/delete_button/delete_button.vue
index d13547e2..b458b0dc 100644
--- a/src/components/delete_button/delete_button.vue
+++ b/src/components/delete_button/delete_button.vue
@@ -14,8 +14,8 @@
 .icon-cancel,.delete-status {
   cursor: pointer;
   &:hover {
-    color: var(--cRed, $fallback--cRed);
     color: $fallback--cRed;
+    color: var(--cRed, $fallback--cRed);
   }
 }
 </style>
diff --git a/src/components/export_import/export_import.vue b/src/components/export_import/export_import.vue
new file mode 100644
index 00000000..451a2668
--- /dev/null
+++ b/src/components/export_import/export_import.vue
@@ -0,0 +1,87 @@
+<template>
+<div class="import-export-container">
+  <slot name="before"/>
+  <button class="btn" @click="exportData">{{ exportLabel }}</button>
+  <button class="btn" @click="importData">{{ importLabel }}</button>
+  <slot name="afterButtons"/>
+  <p v-if="importFailed" class="alert error">{{ importFailedText }}</p>
+  <slot name="afterError"/>
+</div>
+</template>
+
+<script>
+export default {
+  props: [
+    'exportObject',
+    'importLabel',
+    'exportLabel',
+    'importFailedText',
+    'validator',
+    'onImport',
+    'onImportFailure'
+  ],
+  data () {
+    return {
+      importFailed: false
+    }
+  },
+  methods: {
+    exportData () {
+      const stringified = JSON.stringify(this.exportObject) // Pretty-print and indent with 2 spaces
+
+      // Create an invisible link with a data url and simulate a click
+      const e = document.createElement('a')
+      e.setAttribute('download', 'pleroma_theme.json')
+      e.setAttribute('href', 'data:application/json;base64,' + window.btoa(stringified))
+      e.style.display = 'none'
+
+      document.body.appendChild(e)
+      e.click()
+      document.body.removeChild(e)
+    },
+    importData () {
+      this.importFailed = false
+      const filePicker = document.createElement('input')
+      filePicker.setAttribute('type', 'file')
+      filePicker.setAttribute('accept', '.json')
+
+      filePicker.addEventListener('change', event => {
+        if (event.target.files[0]) {
+          // eslint-disable-next-line no-undef
+          const reader = new FileReader()
+          reader.onload = ({target}) => {
+            try {
+              const parsed = JSON.parse(target.result)
+              const valid = this.validator(parsed)
+              if (valid) {
+                this.onImport(parsed)
+              } else {
+                this.importFailed = true
+                // this.onImportFailure(valid)
+              }
+            } catch (e) {
+              // This will happen both if there is a JSON syntax error or the theme is missing components
+              this.importFailed = true
+              // this.onImportFailure(e)
+            }
+          }
+          reader.readAsText(event.target.files[0])
+        }
+      })
+
+      document.body.appendChild(filePicker)
+      filePicker.click()
+      document.body.removeChild(filePicker)
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+.import-export-container {
+  display: flex;
+  flex-wrap: wrap;
+  align-items: baseline;
+  justify-content: center;
+}
+</style>
diff --git a/src/components/font_control/font_control.js b/src/components/font_control/font_control.js
new file mode 100644
index 00000000..8e2b0e45
--- /dev/null
+++ b/src/components/font_control/font_control.js
@@ -0,0 +1,58 @@
+import { set } from 'vue'
+
+export default {
+  props: [
+    'name', 'label', 'value', 'fallback', 'options', 'no-inherit'
+  ],
+  data () {
+    return {
+      lValue: this.value,
+      availableOptions: [
+        this.noInherit ? '' : 'inherit',
+        'custom',
+        ...(this.options || []),
+        'serif',
+        'monospace',
+        'sans-serif'
+      ].filter(_ => _)
+    }
+  },
+  beforeUpdate () {
+    this.lValue = this.value
+  },
+  computed: {
+    present () {
+      return typeof this.lValue !== 'undefined'
+    },
+    dValue () {
+      return this.lValue || this.fallback || {}
+    },
+    family: {
+      get () {
+        return this.dValue.family
+      },
+      set (v) {
+        set(this.lValue, 'family', v)
+        this.$emit('input', this.lValue)
+      }
+    },
+    isCustom () {
+      return this.preset === 'custom'
+    },
+    preset: {
+      get () {
+        if (this.family === 'serif' ||
+            this.family === 'sans-serif' ||
+            this.family === 'monospace' ||
+            this.family === 'inherit') {
+          return this.family
+        } else {
+          return 'custom'
+        }
+      },
+      set (v) {
+        this.family = v === 'custom' ? '' : v
+      }
+    }
+  }
+}
diff --git a/src/components/font_control/font_control.vue b/src/components/font_control/font_control.vue
new file mode 100644
index 00000000..ed36b280
--- /dev/null
+++ b/src/components/font_control/font_control.vue
@@ -0,0 +1,54 @@
+<template>
+<div class="font-control style-control" :class="{ custom: isCustom }">
+  <label :for="preset === 'custom' ? name : name + '-font-switcher'" class="label">
+    {{label}}
+  </label>
+  <input
+    v-if="typeof fallback !== 'undefined'"
+    class="opt exlcude-disabled"
+    type="checkbox"
+    :id="name + '-o'"
+    :checked="present"
+    @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)">
+  <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
+  <label :for="name + '-font-switcher'" class="select" :disabled="!present">
+    <select
+      :disabled="!present"
+      v-model="preset"
+      class="font-switcher"
+      :id="name + '-font-switcher'">
+      <option v-for="option in availableOptions" :value="option">
+        {{ option === 'custom' ? $t('settings.style.fonts.custom') : option }}
+      </option>
+    </select>
+    <i class="icon-down-open"/>
+  </label>
+  <input
+    v-if="isCustom"
+    class="custom-font"
+    type="text"
+    :id="name"
+    v-model="family">
+</div>
+</template>
+
+<script src="./font_control.js" ></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+.font-control {
+  input.custom-font {
+    min-width: 10em;
+  }
+  &.custom {
+    .select {
+      border-top-right-radius: 0;
+      border-bottom-right-radius: 0;
+    }
+    .custom-font {
+      border-top-left-radius: 0;
+      border-bottom-left-radius: 0;
+    }
+  }
+}
+</style>
diff --git a/src/components/instance_specific_panel/instance_specific_panel.js b/src/components/instance_specific_panel/instance_specific_panel.js
index 09e3d055..9bb5e945 100644
--- a/src/components/instance_specific_panel/instance_specific_panel.js
+++ b/src/components/instance_specific_panel/instance_specific_panel.js
@@ -2,6 +2,9 @@ const InstanceSpecificPanel = {
   computed: {
     instanceSpecificPanelContent () {
       return this.$store.state.instance.instanceSpecificPanelContent
+    },
+    show () {
+      return !this.$store.state.config.hideISP
     }
   }
 }
diff --git a/src/components/instance_specific_panel/instance_specific_panel.vue b/src/components/instance_specific_panel/instance_specific_panel.vue
index ca8e00c0..a7b74667 100644
--- a/src/components/instance_specific_panel/instance_specific_panel.vue
+++ b/src/components/instance_specific_panel/instance_specific_panel.vue
@@ -1,5 +1,5 @@
 <template>
-  <div class="instance-specific-panel">
+  <div v-if="show" class="instance-specific-panel">
     <div class="panel panel-default">
       <div class="panel-body">
         <div v-html="instanceSpecificPanelContent">
diff --git a/src/components/interface_language_switcher/interface_language_switcher.vue b/src/components/interface_language_switcher/interface_language_switcher.vue
index 4b541888..3f58af2c 100644
--- a/src/components/interface_language_switcher/interface_language_switcher.vue
+++ b/src/components/interface_language_switcher/interface_language_switcher.vue
@@ -1,5 +1,8 @@
 <template>
   <div>
+    <label for="interface-language-switcher">
+      {{ $t('settings.interfaceLanguage') }}
+    </label>
     <label for="interface-language-switcher" class='select'>
       <select id="interface-language-switcher" v-model="language">
         <option v-for="(langCode, i) in languageCodes" :value="langCode">
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index c786f2cc..345fe3ee 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -6,11 +6,13 @@ import { highlightClass, highlightStyle } from '../../services/user_highlighter/
 const Notification = {
   data () {
     return {
-      userExpanded: false
+      userExpanded: false,
+      betterShadow: this.$store.state.interface.browserSupport.cssFilter
     }
   },
   props: [
-    'notification'
+    'notification',
+    'activatePanel'
   ],
   components: {
     Status, StillImage, UserCardContent
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 13a5c0aa..e84ce0b6 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -1,8 +1,8 @@
 <template>
-  <status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status>
+  <status :activatePanel="activatePanel" v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status>
   <div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]"v-else>
     <a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded">
-      <StillImage class='avatar-compact' :src="notification.action.user.profile_image_url_original"/>
+      <StillImage class='avatar-compact' :class="{'better-shadow': betterShadow}" :src="notification.action.user.profile_image_url_original"/>
     </a>
     <div class='notification-right'>
       <div class="usercard notification-usercard" v-if="userExpanded">
@@ -25,13 +25,13 @@
             <small>{{$t('notifications.followed_you')}}</small>
           </span>
         </div>
-        <small class="timeago"><router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small>
+        <small class="timeago"><router-link @click.native="activatePanel('timeline')" v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small>
       </span>
       <div class="follow-text" v-if="notification.type === 'follow'">
-        <router-link :to="{ name: 'user-profile', params: { id: notification.action.user.id } }">@{{notification.action.user.screen_name}}</router-link>
+        <router-link @click.native="activatePanel('timeline')" :to="{ name: 'user-profile', params: { id: notification.action.user.id } }">@{{notification.action.user.screen_name}}</router-link>
       </div>
       <template v-else>
-        <status v-if="notification.status"  class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status>
+        <status :activatePanel="activatePanel" v-if="notification.status"  class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status>
         <div class="broken-favorite" v-else>
           {{$t('notifications.broken_favorite')}}
         </div>
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 945ffd1f..4b7a591d 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -4,6 +4,7 @@ import notificationsFetcher from '../../services/notifications_fetcher/notificat
 import { sortBy, filter } from 'lodash'
 
 const Notifications = {
+  props: [ 'activatePanel' ],
   created () {
     const store = this.$store
     const credentials = store.state.users.currentUser.credentials
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index a137ccd5..a6468e01 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -4,31 +4,28 @@
   // a bit of a hack to allow scrolling below notifications
   padding-bottom: 15em;
 
-  .unseen-count {
-    display: inline-block;
-    background-color: $fallback--cRed;
-    background-color: var(--cRed, $fallback--cRed);
-    text-shadow: 0px 0px 3px rgba(0, 0, 0, 0.5);
-    border-radius: 99px;
-    min-width: 22px;
-    max-width: 22px;
-    min-height: 22px;
-    max-height: 22px;
-    color: white;
-    font-size: 15px;
-    line-height: 22px;
-    text-align: center;
-    vertical-align: middle
-  }
-
   .loadmore-error {
-    color: $fallback--fg;
-    color: var(--fg, $fallback--fg);
+    color: $fallback--text;
+    color: var(--text, $fallback--text);
   }
 
-  .unseen {
-    box-shadow: inset 4px 0 0 var(--cRed, $fallback--cRed);
-    padding-left: 0;
+  .notification {
+    position: relative;
+
+    .notification-overlay {
+      position: absolute;
+      top: 0;
+      right: 0;
+      left: 0;
+      bottom: 0;
+      pointer-events: none;
+    }
+
+    &.unseen {
+      .notification-overlay {
+        background-image: linear-gradient(135deg, var(--badgeNotification, $fallback--cRed) 4px, transparent 10px)
+      }
+    }
   }
 }
 
@@ -42,21 +39,27 @@
   .broken-favorite {
     border-radius: $fallback--tooltipRadius;
     border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-    color: $fallback--faint;
-    color: var(--faint, $fallback--faint);
-    background-color: $fallback--cAlertRed;
-    background-color: var(--cAlertRed, $fallback--cAlertRed);
+    color: $fallback--text;
+    color: var(--alertErrorText, $fallback--text);
+    background-color: $fallback--alertError;
+    background-color: var(--alertError, $fallback--alertError);
     padding: 2px .5em
   }
 
   .avatar-compact {
     width: 32px;
     height: 32px;
+    box-shadow: var(--avatarStatusShadow);
     border-radius: $fallback--avatarAltRadius;
     border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
     overflow: hidden;
     line-height: 0;
 
+    &.better-shadow {
+      box-shadow: var(--avatarStatusShadowInset);
+      filter: var(--avatarStatusShadowFilter)
+    }
+
     &.animated::before {
       display: none;
     }
@@ -90,6 +93,9 @@
         padding: 0.25em 0;
         color: $fallback--faint;
         color: var(--faint, $fallback--faint);
+        a {
+          color: var(--faintLink);
+        }
       }
       padding: 0;
       .media-body {
diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue
index 7a4322f9..bef48567 100644
--- a/src/components/notifications/notifications.vue
+++ b/src/components/notifications/notifications.vue
@@ -4,7 +4,7 @@
       <div class="panel-heading">
         <div class="title">
           {{$t('notifications.notifications')}}
-          <span class="unseen-count" v-if="unseenCount">{{unseenCount}}</span>
+          <span class="badge badge-notification unseen-count" v-if="unseenCount">{{unseenCount}}</span>
         </div>
         <div @click.prevent class="loadmore-error alert error" v-if="error">
           {{$t('timeline.error_fetching')}}
@@ -13,7 +13,8 @@
       </div>
       <div class="panel-body">
         <div v-for="notification in visibleNotifications" :key="notification.action.id" class="notification" :class='{"unseen": !notification.seen}'>
-          <notification :notification="notification"></notification>
+          <div class="notification-overlay"></div>
+          <notification :activatePanel="activatePanel" :notification="notification"></notification>
         </div>
       </div>
       <div class="panel-footer">
diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue
new file mode 100644
index 00000000..3926915b
--- /dev/null
+++ b/src/components/opacity_input/opacity_input.vue
@@ -0,0 +1,38 @@
+<template>
+<div class="opacity-control style-control" :class="{ disabled: !present || disabled }">
+  <label :for="name" class="label">
+    {{$t('settings.style.common.opacity')}}
+  </label>
+  <input
+    v-if="typeof fallback !== 'undefined'"
+    class="opt exclude-disabled"
+    :id="name + '-o'"
+    type="checkbox"
+    :checked="present"
+    @input="$emit('input', !present ? fallback : undefined)">
+  <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
+  <input
+    :id="name"
+    class="input-number"
+    type="number"
+    :value="value || fallback"
+    :disabled="!present || disabled"
+    @input="$emit('input', $event.target.value)"
+    max="1"
+    min="0"
+    step=".05">
+</div>
+</template>
+
+<script>
+export default {
+  props: [
+    'name', 'value', 'fallback', 'disabled'
+  ],
+  computed: {
+    present () {
+      return typeof this.value !== 'undefined'
+    }
+  }
+}
+</script>
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 789243cf..f9252f73 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -46,7 +46,7 @@ const PostStatusForm = {
       statusText = buildMentionsString({ user: this.repliedUser, attentions: this.attentions }, currentUser)
     }
 
-    const scope = (this.copyMessageScope && this.$store.state.config.copyScope || this.copyMessageScope === 'direct')
+    const scope = (this.copyMessageScope && this.$store.state.config.scopeCopy || this.copyMessageScope === 'direct')
           ? this.copyMessageScope
           : this.$store.state.users.currentUser.default_scope
 
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index e4c46b9a..fcf5c873 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -153,8 +153,8 @@
       padding-bottom: 0;
       margin-left: $fallback--attachmentRadius;
       margin-left: var(--attachmentRadius, $fallback--attachmentRadius);
-      background-color: $fallback--btn;
-      background-color: var(--btn, $fallback--btn);
+      background-color: $fallback--fg;
+      background-color: var(--btn, $fallback--fg);
       border-bottom-left-radius: 0;
       border-bottom-right-radius: 0;
     }
@@ -258,11 +258,13 @@
     position: absolute;
     z-index: 1;
     box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
+    // this doesn't match original but i don't care, making it uniform.
+    box-shadow: var(--popupShadow);
     min-width: 75%;
     background: $fallback--bg;
     background: var(--bg, $fallback--bg);
-    color: $fallback--lightFg;
-    color: var(--lightFg, $fallback--lightFg);
+    color: $fallback--lightText;
+    color: var(--lightText, $fallback--lightText);
   }
 
   .autocomplete {
@@ -291,8 +293,8 @@
     }
 
     &.highlighted {
-      background-color: $fallback--btn;
-      background-color: var(--btn, $fallback--btn);
+      background-color: $fallback--fg;
+      background-color: var(--lightBg, $fallback--fg);
     }
   }
 }
diff --git a/src/components/range_input/range_input.vue b/src/components/range_input/range_input.vue
new file mode 100644
index 00000000..3e50664b
--- /dev/null
+++ b/src/components/range_input/range_input.vue
@@ -0,0 +1,48 @@
+<template>
+<div class="range-control style-control" :class="{ disabled: !present || disabled }">
+  <label :for="name" class="label">
+    {{label}}
+  </label>
+  <input
+    v-if="typeof fallback !== 'undefined'"
+    class="opt exclude-disabled"
+    :id="name + '-o'"
+    type="checkbox"
+    :checked="present"
+    @input="$emit('input', !present ? fallback : undefined)">
+  <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
+  <input
+    :id="name"
+    class="input-number"
+    type="range"
+    :value="value || fallback"
+    :disabled="!present || disabled"
+    @input="$emit('input', $event.target.value)"
+    :max="max || hardMax || 100"
+    :min="min || hardMin || 0"
+    :step="step || 1">
+  <input
+    :id="name"
+    class="input-number"
+    type="number"
+    :value="value || fallback"
+    :disabled="!present || disabled"
+    @input="$emit('input', $event.target.value)"
+    :max="hardMax"
+    :min="hardMin"
+    :step="step || 1">
+</div>
+</template>
+
+<script>
+export default {
+  props: [
+    'name', 'value', 'fallback', 'disabled', 'label', 'max', 'min', 'step', 'hardMin', 'hardMax'
+  ],
+  computed: {
+    present () {
+      return typeof this.value !== 'undefined'
+    }
+  }
+}
+</script>
diff --git a/src/components/registration/registration.js b/src/components/registration/registration.js
index f7f8a720..e5ead8bc 100644
--- a/src/components/registration/registration.js
+++ b/src/components/registration/registration.js
@@ -1,57 +1,61 @@
-import oauthApi from '../../services/new_api/oauth.js'
+import { validationMixin } from 'vuelidate'
+import { required, sameAs } from 'vuelidate/lib/validators'
+import { mapActions, mapState } from 'vuex'
 
 const registration = {
+  mixins: [validationMixin],
   data: () => ({
-    user: {},
-    error: false,
-    registering: false
-  }),
-  created () {
-    if ((!this.$store.state.instance.registrationOpen && !this.token) || !!this.$store.state.users.currentUser) {
-      this.$router.push('/main/all')
+    user: {
+      email: '',
+      fullname: '',
+      username: '',
+      password: '',
+      confirm: ''
     }
-    // Seems like this doesn't work at first page open for some reason
-    if (this.$store.state.instance.registrationOpen && this.token) {
-      this.$router.push('/registration')
+  }),
+  validations: {
+    user: {
+      email: { required },
+      username: { required },
+      fullname: { required },
+      password: { required },
+      confirm: {
+        required,
+        sameAsPassword: sameAs('password')
+      }
+    }
+  },
+  created () {
+    if ((!this.registrationOpen && !this.token) || this.signedIn) {
+      this.$router.push('/main/all')
     }
   },
   computed: {
-    termsofservice () { return this.$store.state.instance.tos },
-    token () { return this.$route.params.token }
+    token () { return this.$route.params.token },
+    ...mapState({
+      registrationOpen: (state) => state.instance.registrationOpen,
+      signedIn: (state) => !!state.users.currentUser,
+      isPending: (state) => state.users.signUpPending,
+      serverValidationErrors: (state) => state.users.signUpErrors,
+      termsOfService: (state) => state.instance.tos
+    })
   },
   methods: {
-    submit () {
-      this.registering = true
+    ...mapActions(['signUp']),
+    async submit () {
       this.user.nickname = this.user.username
       this.user.token = this.token
-      this.$store.state.api.backendInteractor.register(this.user).then(
-        (response) => {
-          if (response.ok) {
-            const data = {
-              oauth: this.$store.state.oauth,
-              instance: this.$store.state.instance.server
-            }
-            oauthApi.getOrCreateApp(data).then((app) => {
-              oauthApi.getTokenWithCredentials(
-                {
-                  app,
-                  instance: data.instance,
-                  username: this.user.username,
-                  password: this.user.password})
-                .then((result) => {
-                  this.$store.commit('setToken', result.access_token)
-                  this.$store.dispatch('loginUser', result.access_token)
-                  this.$router.push('/main/friends')
-                })
-            })
-          } else {
-            this.registering = false
-            response.json().then((data) => {
-              this.error = data.error
-            })
-          }
+
+      this.$v.$touch()
+
+      if (!this.$v.$invalid) {
+        try {
+          await this.signUp(this.user)
+          this.$router.push('/main/friends')
+        } catch (error) {
+          console.warn('Registration failed: ' + error)
         }
-      )
+      }
     }
   }
 }
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index 087cab6b..8cb1392b 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -7,50 +7,90 @@
       <form v-on:submit.prevent='submit(user)' class='registration-form'>
         <div class='container'>
           <div class='text-fields'>
-            <div class='form-group'>
-              <label for='username'>{{$t('login.username')}}</label>
-              <input :disabled="registering" v-model='user.username' class='form-control' id='username' placeholder='e.g. lain'>
+            <div class='form-group' :class="{ 'form-group--error': $v.user.username.$error }">
+              <label class='form--label' for='sign-up-username'>{{$t('login.username')}}</label>
+              <input :disabled="isPending" v-model.trim='$v.user.username.$model' class='form-control' id='sign-up-username' placeholder='e.g. lain'>
             </div>
-            <div class='form-group'>
-              <label for='fullname'>{{$t('registration.fullname')}}</label>
-              <input :disabled="registering" v-model='user.fullname' class='form-control' id='fullname' placeholder='e.g. Lain Iwakura'>
+            <div class="form-error" v-if="$v.user.username.$dirty">
+              <ul>
+                <li v-if="!$v.user.username.required">
+                  <span>{{$t('registration.validations.username_required')}}</span>
+                </li>
+              </ul>
             </div>
-            <div class='form-group'>
-              <label for='email'>{{$t('registration.email')}}</label>
-              <input :disabled="registering" v-model='user.email' class='form-control' id='email' type="email">
+
+            <div class='form-group' :class="{ 'form-group--error': $v.user.fullname.$error }">
+              <label class='form--label' for='sign-up-fullname'>{{$t('registration.fullname')}}</label>
+              <input :disabled="isPending" v-model.trim='$v.user.fullname.$model' class='form-control' id='sign-up-fullname' placeholder='e.g. Lain Iwakura'>
             </div>
-            <div class='form-group'>
-              <label for='bio'>{{$t('registration.bio')}}</label>
-              <input :disabled="registering" v-model='user.bio' class='form-control' id='bio'>
+            <div class="form-error" v-if="$v.user.fullname.$dirty">
+              <ul>
+                <li v-if="!$v.user.fullname.required">
+                  <span>{{$t('registration.validations.fullname_required')}}</span>
+                </li>
+              </ul>
             </div>
-            <div class='form-group'>
-              <label for='password'>{{$t('login.password')}}</label>
-              <input :disabled="registering" v-model='user.password' class='form-control' id='password' type='password'>
+
+            <div class='form-group' :class="{ 'form-group--error': $v.user.email.$error }">
+              <label class='form--label' for='email'>{{$t('registration.email')}}</label>
+              <input :disabled="isPending" v-model='$v.user.email.$model' class='form-control' id='email' type="email">
             </div>
-            <div class='form-group'>
-              <label for='password_confirmation'>{{$t('registration.password_confirm')}}</label>
-              <input :disabled="registering" v-model='user.confirm' class='form-control' id='password_confirmation' type='password'>
+            <div class="form-error" v-if="$v.user.email.$dirty">
+              <ul>
+                <li v-if="!$v.user.email.required">
+                  <span>{{$t('registration.validations.email_required')}}</span>
+                </li>
+              </ul>
             </div>
-            <!--
+
             <div class='form-group'>
-              <label for='captcha'>Captcha</label>
-              <img src='/qvittersimplesecurity/captcha.jpg' alt='captcha' class='captcha'>
-              <input :disabled="registering" v-model='user.captcha' placeholder='Enter captcha' type='test' class='form-control' id='captcha'>
+              <label class='form--label' for='bio'>{{$t('registration.bio')}}</label>
+              <input :disabled="isPending" v-model='user.bio' class='form-control' id='bio'>
             </div>
-            -->
+
+            <div class='form-group' :class="{ 'form-group--error': $v.user.password.$error }">
+              <label class='form--label' for='sign-up-password'>{{$t('login.password')}}</label>
+              <input :disabled="isPending" v-model='user.password' class='form-control' id='sign-up-password' type='password'>
+            </div>
+            <div class="form-error" v-if="$v.user.password.$dirty">
+              <ul>
+                <li v-if="!$v.user.password.required">
+                  <span>{{$t('registration.validations.password_required')}}</span>
+                </li>
+              </ul>
+            </div>
+
+            <div class='form-group' :class="{ 'form-group--error': $v.user.confirm.$error }">
+              <label class='form--label' for='sign-up-password-confirmation'>{{$t('registration.password_confirm')}}</label>
+              <input :disabled="isPending" v-model='user.confirm' class='form-control' id='sign-up-password-confirmation' type='password'>
+            </div>
+            <div class="form-error" v-if="$v.user.confirm.$dirty">
+              <ul>
+                <li v-if="!$v.user.confirm.required">
+                  <span>{{$t('registration.validations.password_confirmation_required')}}</span>
+                </li>
+                <li v-if="!$v.user.confirm.sameAsPassword">
+                  <span>{{$t('registration.validations.password_confirmation_match')}}</span>
+                </li>
+              </ul>
+            </div>
+
             <div class='form-group' v-if='token' >
               <label for='token'>{{$t('registration.token')}}</label>
               <input disabled='true' v-model='token' class='form-control' id='token' type='text'>
             </div>
             <div class='form-group'>
-              <button :disabled="registering" type='submit' class='btn btn-default'>{{$t('general.submit')}}</button>
+              <button :disabled="isPending" type='submit' class='btn btn-default'>{{$t('general.submit')}}</button>
             </div>
           </div>
-          <div class='terms-of-service' v-html="termsofservice">
+
+          <div class='terms-of-service' v-html="termsOfService">
           </div>
         </div>
-        <div v-if="error" class='form-group'>
-          <div class='alert error'>{{error}}</div>
+        <div v-if="serverValidationErrors.length" class='form-group'>
+          <div class='alert error'>
+            <span v-for="error in serverValidationErrors">{{error}}</span>
+          </div>
         </div>
       </form>
     </div>
@@ -60,6 +100,7 @@
 <script src="./registration.js"></script>
 <style lang="scss">
 @import '../../_variables.scss';
+$validations-cRed: #f04124;
 
 .registration-form {
   display: flex;
@@ -89,6 +130,55 @@
     flex-direction: column;
     padding: 0.3em 0.0em 0.3em;
     line-height:24px;
+    margin-bottom: 1em;
+  }
+
+  @keyframes shakeError {
+    0% {
+      transform: translateX(0); }
+    15% {
+      transform: translateX(0.375rem); }
+    30% {
+      transform: translateX(-0.375rem); }
+    45% {
+      transform: translateX(0.375rem); }
+    60% {
+      transform: translateX(-0.375rem); }
+    75% {
+      transform: translateX(0.375rem); }
+    90% {
+      transform: translateX(-0.375rem); }
+    100% {
+      transform: translateX(0); } }
+
+  .form-group--error {
+    animation-name: shakeError;
+    animation-duration: .6s;
+    animation-timing-function: ease-in-out;
+  }
+
+  .form-group--error .form--label {
+    color: $validations-cRed;
+    color: var(--cRed, $validations-cRed);
+  }
+
+  .form-error {
+    margin-top: -0.7em;
+    text-align: left;
+
+    span {
+      font-size: 12px;
+    }
+  }
+
+  .form-error ul {
+    list-style: none;
+    padding: 0 0 0 5px;
+    margin-top: 0;
+
+    li::before {
+      content: "• ";
+    }
   }
 
   form textarea {
@@ -102,8 +192,6 @@
   }
 
   .btn {
-    //align-self: flex-start;
-    //width: 10em;
     margin-top: 0.6em;
     height: 28px;
   }
diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js
index ca8543d1..681ccda8 100644
--- a/src/components/settings/settings.js
+++ b/src/components/settings/settings.js
@@ -13,6 +13,8 @@ const settings = {
       hideAttachmentsLocal: user.hideAttachments,
       hideAttachmentsInConvLocal: user.hideAttachmentsInConv,
       hideNsfwLocal: user.hideNsfw,
+      hideISPLocal: user.hideISP,
+      preloadImage: user.preloadImage,
       hidePostStatsLocal: typeof user.hidePostStats === 'undefined'
         ? instance.hidePostStats
         : user.hidePostStats,
@@ -84,6 +86,12 @@ const settings = {
     hideNsfwLocal (value) {
       this.$store.dispatch('setOption', { name: 'hideNsfw', value })
     },
+    preloadImage (value) {
+      this.$store.dispatch('setOption', { name: 'preloadImage', value })
+    },
+    hideISPLocal (value) {
+      this.$store.dispatch('setOption', { name: 'hideISP', value })
+    },
     'notificationVisibilityLocal.likes' (value) {
       this.$store.dispatch('setOption', { name: 'notificationVisibility', value: this.$store.state.config.notificationVisibility })
     },
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index 871735fe..3f920de5 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -14,15 +14,24 @@
         <div @click.prevent class="alert transparent" v-if="!currentSaveStateNotice.error">
           {{ $t('settings.saving_ok') }}
         </div>
-    </template>
+      </template>
     </transition>
   </div>
   <div class="panel-body">
+<keep-alive>
     <tab-switcher>
       <div :label="$t('settings.general')" >
         <div class="setting-item">
-          <h2>{{ $t('settings.interfaceLanguage') }}</h2>
-          <interface-language-switcher />
+          <h2>{{ $t('settings.interface') }}</h2>
+          <ul class="setting-list">
+            <li>
+              <interface-language-switcher />
+            </li>
+            <li>
+              <input type="checkbox" id="hideISP" v-model="hideISPLocal">
+              <label for="hideISP">{{$t('settings.hide_isp')}}</label>
+            </li>
+          </ul>
         </div>
         <div class="setting-item">
           <h2>{{$t('nav.timeline')}}</h2>
@@ -109,6 +118,12 @@
               <input type="checkbox" id="hideNsfw" v-model="hideNsfwLocal">
               <label for="hideNsfw">{{$t('settings.nsfw_clickthrough')}}</label>
             </li>
+            <ul class="setting-list suboptions" >
+              <li>
+                <input :disabled="!hideAttachmentsInConvLocal" type="checkbox" id="preloadImage" v-model="preloadImage">
+                <label for="preloadImage">{{$t('settings.preload_images')}}</label>
+              </li>
+            </ul>
             <li>
               <input type="checkbox" id="stopGifs" v-model="stopGifs">
               <label for="stopGifs">{{$t('settings.stop_gifs')}}</label>
@@ -211,6 +226,7 @@
       </div>
 
     </tab-switcher>
+</keep-alive>
   </div>
 </div>
 </template>
@@ -222,7 +238,7 @@
 @import '../../_variables.scss';
 
 .setting-item {
-  border-bottom: 2px solid var(--btn, $fallback--btn);
+  border-bottom: 2px solid var(--fg, $fallback--fg);
   margin: 1em 1em 1.4em;
   padding-bottom: 1.4em;
 
@@ -271,12 +287,8 @@
 
   .btn {
     min-height: 28px;
-  }
-
-  .submit {
-    margin-top: 1em;
-    min-height: 30px;
-    width: 10em;
+    min-width: 10em;
+    padding: 0 2em;
   }
 }
 .select-multiple {
diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js
new file mode 100644
index 00000000..44e4a22f
--- /dev/null
+++ b/src/components/shadow_control/shadow_control.js
@@ -0,0 +1,87 @@
+import ColorInput from '../color_input/color_input.vue'
+import OpacityInput from '../opacity_input/opacity_input.vue'
+import { getCssShadow } from '../../services/style_setter/style_setter.js'
+import { hex2rgb } from '../../services/color_convert/color_convert.js'
+
+export default {
+  // 'Value' and 'Fallback' can be undefined, but if they are
+  // initially vue won't detect it when they become something else
+  // therefore i'm using "ready" which should be passed as true when
+  // data becomes available
+  props: [
+    'value', 'fallback', 'ready'
+  ],
+  data () {
+    return {
+      selectedId: 0,
+      // TODO there are some bugs regarding display of array (it's not getting updated when deleting for some reason)
+      cValue: this.value || this.fallback || []
+    }
+  },
+  components: {
+    ColorInput,
+    OpacityInput
+  },
+  methods: {
+    add () {
+      this.cValue.push(Object.assign({}, this.selected))
+      this.selectedId = this.cValue.length - 1
+    },
+    del () {
+      this.cValue.splice(this.selectedId, 1)
+      this.selectedId = this.cValue.length === 0 ? undefined : this.selectedId - 1
+    },
+    moveUp () {
+      const movable = this.cValue.splice(this.selectedId, 1)[0]
+      this.cValue.splice(this.selectedId - 1, 0, movable)
+      this.selectedId -= 1
+    },
+    moveDn () {
+      const movable = this.cValue.splice(this.selectedId, 1)[0]
+      this.cValue.splice(this.selectedId + 1, 0, movable)
+      this.selectedId += 1
+    }
+  },
+  beforeUpdate () {
+    this.cValue = this.value || this.fallback
+  },
+  computed: {
+    selected () {
+      if (this.ready && this.cValue.length > 0) {
+        return this.cValue[this.selectedId]
+      } else {
+        return {
+          x: 0,
+          y: 0,
+          blur: 0,
+          spread: 0,
+          inset: false,
+          color: '#000000',
+          alpha: 1
+        }
+      }
+    },
+    moveUpValid () {
+      return this.ready && this.selectedId > 0
+    },
+    moveDnValid () {
+      return this.ready && this.selectedId < this.cValue.length - 1
+    },
+    present () {
+      return this.ready &&
+        typeof this.cValue[this.selectedId] !== 'undefined' &&
+        !this.usingFallback
+    },
+    usingFallback () {
+      return typeof this.value === 'undefined'
+    },
+    rgb () {
+      return hex2rgb(this.selected.color)
+    },
+    style () {
+      return this.ready ? {
+        boxShadow: getCssShadow(this.cValue)
+      } : {}
+    }
+  }
+}
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
new file mode 100644
index 00000000..744925d4
--- /dev/null
+++ b/src/components/shadow_control/shadow_control.vue
@@ -0,0 +1,243 @@
+<template>
+<div class="shadow-control" :class="{ disabled: !present }">
+  <div class="shadow-preview-container">
+    <div :disabled="!present" class="y-shift-control">
+      <input
+        v-model="selected.y"
+        :disabled="!present"
+        class="input-number"
+        type="number">
+      <div class="wrap">
+        <input
+          v-model="selected.y"
+          :disabled="!present"
+          class="input-range"
+          type="range"
+          max="20"
+          min="-20">
+      </div>
+    </div>
+    <div class="preview-window">
+      <div class="preview-block" :style="style"></div>
+    </div>
+    <div :disabled="!present" class="x-shift-control">
+      <input
+        v-model="selected.x"
+        :disabled="!present"
+        class="input-number"
+        type="number">
+      <div class="wrap">
+        <input
+          v-model="selected.x"
+          :disabled="!present"
+          class="input-range"
+          type="range"
+          max="20"
+          min="-20">
+      </div>
+    </div>
+  </div>
+
+  <div class="shadow-tweak">
+    <div :disabled="usingFallback" class="id-control style-control">
+      <label for="shadow-switcher" class="select" :disabled="!ready || usingFallback">
+        <select
+          v-model="selectedId" class="shadow-switcher"
+          :disabled="!ready || usingFallback"
+          id="shadow-switcher">
+          <option v-for="(shadow, index) in cValue" :value="index">
+            {{$t('settings.style.shadows.shadow_id', { value: index })}}
+          </option>
+        </select>
+        <i class="icon-down-open"/>
+      </label>
+      <button class="btn btn-default" :disabled="!ready || !present" @click="del">
+        <i class="icon-cancel"/>
+      </button>
+      <button class="btn btn-default" :disabled="!moveUpValid" @click="moveUp">
+        <i class="icon-up-open"/>
+      </button>
+      <button class="btn btn-default" :disabled="!moveDnValid" @click="moveDn">
+        <i class="icon-down-open"/>
+      </button>
+      <button class="btn btn-default" :disabled="usingFallback" @click="add">
+        <i class="icon-plus"/>
+      </button>
+    </div>
+    <div :disabled="!present" class="inset-control style-control">
+      <label for="inset" class="label">
+        {{$t('settings.style.shadows.inset')}}
+      </label>
+      <input
+        v-model="selected.inset"
+        :disabled="!present"
+        name="inset"
+        id="inset"
+        class="input-inset"
+        type="checkbox">
+      <label class="checkbox-label" for="inset"></label>
+    </div>
+    <div :disabled="!present" class="blur-control style-control">
+      <label for="spread" class="label">
+        {{$t('settings.style.shadows.blur')}}
+      </label>
+      <input
+        v-model="selected.blur"
+        :disabled="!present"
+        name="blur"
+        id="blur"
+        class="input-range"
+        type="range"
+        max="20"
+        min="0">
+      <input
+        v-model="selected.blur"
+        :disabled="!present"
+        class="input-number"
+        type="number"
+        min="0">
+    </div>
+    <div :disabled="!present" class="spread-control style-control">
+      <label for="spread" class="label">
+        {{$t('settings.style.shadows.spread')}}
+      </label>
+      <input
+        v-model="selected.spread"
+        :disabled="!present"
+        name="spread"
+        id="spread"
+        class="input-range"
+        type="range"
+        max="20"
+        min="-20">
+      <input
+        v-model="selected.spread"
+        :disabled="!present"
+        class="input-number"
+        type="number">
+    </div>
+    <ColorInput
+      v-model="selected.color"
+      :disabled="!present"
+      :label="$t('settings.style.common.color')"
+      name="shadow"/>
+    <OpacityInput
+      v-model="selected.alpha"
+      :disabled="!present"/>
+    <p>
+      {{$t('settings.style.shadows.hint')}}
+    </p>
+  </div>
+</div>
+</template>
+
+<script src="./shadow_control.js" ></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+.shadow-control {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+  margin-bottom: 1em;
+
+  .shadow-preview-container,
+  .shadow-tweak {
+    margin: 5px 6px 0 0;
+  }
+  .shadow-preview-container {
+    flex: 0;
+    display: flex;
+    flex-wrap: wrap;
+
+    $side: 15em;
+
+    input[type=number] {
+      width: 5em;
+      min-width: 2em;
+    }
+    .x-shift-control,
+    .y-shift-control {
+      display: flex;
+      flex: 0;
+
+      &[disabled=disabled] *{
+        opacity: .5
+      }
+
+    }
+
+    .x-shift-control {
+      align-items: flex-start;
+    }
+
+    .x-shift-control .wrap,
+    input[type=range] {
+      margin: 0;
+      width: $side;
+      height: 2em;
+    }
+    .y-shift-control {
+      flex-direction: column;
+      align-items: flex-end;
+      .wrap {
+        width: 2em;
+        height: $side;
+      }
+      input[type=range] {
+        transform-origin: 1em 1em;
+        transform: rotate(90deg);
+      }
+    }
+    .preview-window {
+      flex: 1;
+      background-color: #999999;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background-image:
+      linear-gradient(45deg, #666666 25%, transparent 25%),
+      linear-gradient(-45deg, #666666 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #666666 75%),
+      linear-gradient(-45deg, transparent 75%, #666666 75%);
+      background-size: 20px 20px;
+      background-position:0 0, 0 10px, 10px -10px, -10px 0;
+
+      border-radius: $fallback--inputRadius;
+      border-radius: var(--inputRadius, $fallback--inputRadius);
+
+      .preview-block {
+        width: 33%;
+        height: 33%;
+        background-color: $fallback--bg;
+        background-color: var(--bg, $fallback--bg);
+        border-radius: $fallback--panelRadius;
+        border-radius: var(--panelRadius, $fallback--panelRadius);
+      }
+    }
+  }
+
+  .shadow-tweak {
+    flex: 1;
+    min-width: 280px;
+
+    .id-control {
+      align-items: stretch;
+      .select, .btn {
+        min-width: 1px;
+        margin-right: 5px;
+      }
+      .btn {
+        padding: 0 .4em;
+        margin: 0 .1em;
+      }
+      .select {
+        flex: 1;
+        select {
+          align-self: initial;
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index ad6f4184..9a63d047 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -20,7 +20,8 @@ const Status = {
     'replies',
     'noReplyLinks',
     'noHeading',
-    'inlineExpanded'
+    'inlineExpanded',
+    'activatePanel'
   ],
   data () {
     return {
@@ -33,7 +34,8 @@ const Status = {
       showingTall: false,
       expandingSubject: typeof this.$store.state.config.collapseMessageWithSubject === 'undefined'
         ? !this.$store.state.instance.collapseMessageWithSubject
-        : !this.$store.state.config.collapseMessageWithSubject
+        : !this.$store.state.config.collapseMessageWithSubject,
+      betterShadow: this.$store.state.interface.browserSupport.cssFilter
     }
   },
   computed: {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 984884ff..96709084 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -2,14 +2,14 @@
   <div class="status-el" v-if="!hideReply && !deleted" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]">
     <template v-if="muted && !noReplyLinks">
       <div class="media status container muted">
-        <small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small>
+        <small><router-link @click.native="activatePanel('timeline')" :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small>
         <small class="muteWords">{{muteWordHits.join(', ')}}</small>
         <a href="#" class="unmute" @click.prevent="toggleMute"><i class="icon-eye-off"></i></a>
       </div>
     </template>
     <template v-else>
       <div v-if="retweet && !noHeading" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info">
-        <StillImage v-if="retweet" class='avatar' :src="statusoid.user.profile_image_url_original"/>
+        <StillImage v-if="retweet" class='avatar' :class='{ "better-shadow": betterShadow }' :src="statusoid.user.profile_image_url_original"/>
         <div class="media-body faint">
           <a v-if="retweeterHtml" :href="statusoid.user.statusnet_profile_url" class="user-name" :title="'@'+statusoid.user.screen_name" v-html="retweeterHtml"></a>
           <a v-else :href="statusoid.user.statusnet_profile_url" class="user-name" :title="'@'+statusoid.user.screen_name">{{retweeter}}</a>
@@ -21,7 +21,7 @@
       <div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet }]" :style="[ userStyle ]" class="media status">
         <div v-if="!noHeading" class="media-left">
           <a :href="status.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded">
-            <StillImage class='avatar' :class="{'avatar-compact': compact}"  :src="status.user.profile_image_url_original"/>
+            <StillImage class='avatar' :class="{'avatar-compact': compact, 'better-shadow': betterShadow}"  :src="status.user.profile_image_url_original"/>
           </a>
         </div>
         <div class="status-body">
@@ -34,10 +34,10 @@
                 <h4 class="user-name" v-if="status.user.name_html" v-html="status.user.name_html"></h4>
                 <h4 class="user-name" v-else>{{status.user.name}}</h4>
                 <span class="links">
-                  <router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link>
+                  <router-link @click.native="activatePanel('timeline')" :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link>
                   <span v-if="status.in_reply_to_screen_name" class="faint reply-info">
                     <i class="icon-right-open"></i>
-                    <router-link :to="{ name: 'user-profile', params: { id: status.in_reply_to_user_id } }">
+                    <router-link @click.native="activatePanel('timeline')" :to="{ name: 'user-profile', params: { id: status.in_reply_to_user_id } }">
                       {{status.in_reply_to_screen_name}}
                     </router-link>
                   </span>
@@ -54,7 +54,7 @@
               </h4>
             </div>
             <div class="media-heading-right">
-              <router-link class="timeago" :to="{ name: 'conversation', params: { id: status.id } }">
+              <router-link @click.native="activatePanel('timeline')" :to="{ name: 'conversation', params: { id: status.id } }">
                 <timeago :since="status.created_at" :auto-update="60"></timeago>
               </router-link>
               <div class="visibility-icon" v-if="status.visibility">
@@ -73,7 +73,7 @@
           </div>
 
           <div v-if="showPreview" class="status-preview-container">
-            <status class="status-preview" v-if="preview" :noReplyLinks="true" :statusoid="preview" :compact=true></status>
+            <status :activatePanel="activatePanel" class="status-preview" v-if="preview" :noReplyLinks="true" :statusoid="preview" :compact=true></status>
             <div class="status-preview status-preview-loading" v-else>
               <i class="icon-spin4 animate-spin"></i>
             </div>
@@ -146,6 +146,7 @@
   border-radius: $fallback--tooltipRadius;
   border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
   box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
+  box-shadow: var(--popupShadow);
   margin-top: 0.25em;
   margin-left: 0.5em;
   z-index: 50;
@@ -284,8 +285,8 @@
       margin-left: 0.2em;
     }
     a:hover i {
-      color: $fallback--fg;
-      color: var(--fg, $fallback--fg);
+      color: $fallback--text;
+      color: var(--text, $fallback--text);
     }
   }
 
@@ -323,6 +324,8 @@
 
   .status-content {
     margin-right: 0.5em;
+    font-family: var(--postFont, sans-serif);
+
     img, video {
       max-width: 100%;
       max-height: 400px;
@@ -339,6 +342,10 @@
       overflow: auto;
     }
 
+    code, samp, kbd, var, pre {
+      font-family: var(--postCodeFont, monospace);
+    }
+
     p {
       margin: 0;
       margin-top: 0.2em;
@@ -457,18 +464,30 @@
 .status .avatar-compact {
   width: 32px;
   height: 32px;
+  box-shadow: var(--avatarStatusShadow);
   border-radius: $fallback--avatarAltRadius;
   border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
+
+  &.better-shadow {
+    box-shadow: var(--avatarStatusShadowInset);
+    filter: var(--avatarStatusShadowFilter)
+  }
 }
 
 .avatar {
   width: 48px;
   height: 48px;
+  box-shadow: var(--avatarStatusShadow);
   border-radius: $fallback--avatarRadius;
   border-radius: var(--avatarRadius, $fallback--avatarRadius);
   overflow: hidden;
   position: relative;
 
+  &.better-shadow {
+    box-shadow: var(--avatarStatusShadowInset);
+    filter: var(--avatarStatusShadowFilter)
+  }
+
   img {
     width: 100%;
     height: 100%;
@@ -532,6 +551,7 @@ a.unmute {
   .status-el:last-child {
     border-bottom-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;;
     border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
+    border-bottom: none;
   }
 }
 
diff --git a/src/components/style_switcher/preview.vue b/src/components/style_switcher/preview.vue
new file mode 100644
index 00000000..09a136e9
--- /dev/null
+++ b/src/components/style_switcher/preview.vue
@@ -0,0 +1,78 @@
+<template>
+<div class="panel dummy">
+  <div class="panel-heading">
+    <div class="title">
+      {{$t('settings.style.preview.header')}}
+      <span class="badge badge-notification">
+        99
+      </span>
+    </div>
+    <span class="faint">
+      {{$t('settings.style.preview.header_faint')}}
+    </span>
+    <span class="alert error">
+      {{$t('settings.style.preview.error')}}
+    </span>
+    <button class="btn">
+      {{$t('settings.style.preview.button')}}
+    </button>
+  </div>
+  <div class="panel-body theme-preview-content">
+    <div class="post">
+      <div class="avatar">
+        ( ͡° ͜ʖ ͡°)
+      </div>
+      <div class="content">
+        <h4>
+          {{$t('settings.style.preview.content')}}
+        </h4>
+
+        <i18n path="settings.style.preview.text">
+          <code style="font-family: var(--postCodeFont)">
+            {{$t('settings.style.preview.mono')}}
+          </code>
+          <a style="color: var(--link)">
+            {{$t('settings.style.preview.link')}}
+          </a>
+        </i18n>
+
+        <div class="icons">
+          <i style="color: var(--cBlue)" class="icon-reply"/>
+          <i style="color: var(--cGreen)" class="icon-retweet"/>
+          <i style="color: var(--cOrange)" class="icon-star"/>
+          <i style="color: var(--cRed)" class="icon-cancel"/>
+        </div>
+      </div>
+    </div>
+
+    <div class="after-post">
+      <div class="avatar-alt">
+        :^)
+      </div>
+      <div class="content">
+        <i18n path="settings.style.preview.fine_print" tag="span" class="faint">
+          <a style="color: var(--faintLink)">
+            {{$t('settings.style.preview.faint_link')}}
+          </a>
+        </i18n>
+      </div>
+    </div>
+    <div class="separator"></div>
+
+    <span class="alert error">
+      {{$t('settings.style.preview.error')}}
+    </span>
+    <input :value="$t('settings.style.preview.input')" type="text">
+
+    <div class="actions">
+      <span class="checkbox">
+        <input checked="very yes" type="checkbox" id="preview_checkbox">
+        <label for="preview_checkbox">{{$t('settings.style.preview.checkbox')}}</label>
+      </span>
+      <button class="btn">
+        {{$t('settings.style.preview.button')}}
+      </button>
+    </div>
+  </div>
+</div>
+</template>
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 95c15b49..6a4e1cba 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,21 +1,101 @@
-import { rgbstr2hex } from '../../services/color_convert/color_convert.js'
+import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
+import { set, delete as del } from 'vue'
+import { generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js'
+import ColorInput from '../color_input/color_input.vue'
+import RangeInput from '../range_input/range_input.vue'
+import OpacityInput from '../opacity_input/opacity_input.vue'
+import ShadowControl from '../shadow_control/shadow_control.vue'
+import FontControl from '../font_control/font_control.vue'
+import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
+import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
+import Preview from './preview.vue'
+import ExportImport from '../export_import/export_import.vue'
+
+// List of color values used in v1
+const v1OnlyNames = [
+  'bg',
+  'fg',
+  'text',
+  'link',
+  'cRed',
+  'cGreen',
+  'cBlue',
+  'cOrange'
+].map(_ => _ + 'ColorLocal')
 
 export default {
   data () {
     return {
       availableStyles: [],
       selected: this.$store.state.config.theme,
-      invalidThemeImported: false,
-      bgColorLocal: '',
-      btnColorLocal: '',
+
+      previewShadows: {},
+      previewColors: {},
+      previewRadii: {},
+      previewFonts: {},
+
+      shadowsInvalid: true,
+      colorsInvalid: true,
+      radiiInvalid: true,
+
+      keepColor: false,
+      keepShadows: false,
+      keepOpacity: false,
+      keepRoundness: false,
+      keepFonts: false,
+
       textColorLocal: '',
       linkColorLocal: '',
-      redColorLocal: '',
-      blueColorLocal: '',
-      greenColorLocal: '',
-      orangeColorLocal: '',
+
+      bgColorLocal: '',
+      bgOpacityLocal: undefined,
+
+      fgColorLocal: '',
+      fgTextColorLocal: undefined,
+      fgLinkColorLocal: undefined,
+
+      btnColorLocal: undefined,
+      btnTextColorLocal: undefined,
+      btnOpacityLocal: undefined,
+
+      inputColorLocal: undefined,
+      inputTextColorLocal: undefined,
+      inputOpacityLocal: undefined,
+
+      panelColorLocal: undefined,
+      panelTextColorLocal: undefined,
+      panelLinkColorLocal: undefined,
+      panelFaintColorLocal: undefined,
+      panelOpacityLocal: undefined,
+
+      topBarColorLocal: undefined,
+      topBarTextColorLocal: undefined,
+      topBarLinkColorLocal: undefined,
+
+      alertErrorColorLocal: undefined,
+
+      badgeOpacityLocal: undefined,
+      badgeNotificationColorLocal: undefined,
+
+      borderColorLocal: undefined,
+      borderOpacityLocal: undefined,
+
+      faintColorLocal: undefined,
+      faintOpacityLocal: undefined,
+      faintLinkColorLocal: undefined,
+
+      cRedColorLocal: '',
+      cBlueColorLocal: '',
+      cGreenColorLocal: '',
+      cOrangeColorLocal: '',
+
+      shadowSelected: undefined,
+      shadowsLocal: {},
+      fontsLocal: {},
+
       btnRadiusLocal: '',
       inputRadiusLocal: '',
+      checkboxRadiusLocal: '',
       panelRadiusLocal: '',
       avatarRadiusLocal: '',
       avatarAltRadiusLocal: '',
@@ -26,144 +106,470 @@ export default {
   created () {
     const self = this
 
-    window.fetch('/static/styles.json')
-      .then((data) => data.json())
-      .then((themes) => {
-        self.availableStyles = themes
-      })
+    getThemes().then((themesComplete) => {
+      self.availableStyles = themesComplete
+    })
   },
   mounted () {
-    this.normalizeLocalState(this.$store.state.config.colors, this.$store.state.config.radii)
+    this.normalizeLocalState(this.$store.state.config.customTheme)
+    if (typeof this.shadowSelected === 'undefined') {
+      this.shadowSelected = this.shadowsAvailable[0]
+    }
   },
-  methods: {
-    exportCurrentTheme () {
-      const stringified = JSON.stringify({
-        // To separate from other random JSON files and possible future theme formats
-        _pleroma_theme_version: 1,
-        colors: this.$store.state.config.colors,
-        radii: this.$store.state.config.radii
-      }, null, 2) // Pretty-print and indent with 2 spaces
-
-      // Create an invisible link with a data url and simulate a click
-      const e = document.createElement('a')
-      e.setAttribute('download', 'pleroma_theme.json')
-      e.setAttribute('href', 'data:application/json;base64,' + window.btoa(stringified))
-      e.style.display = 'none'
-
-      document.body.appendChild(e)
-      e.click()
-      document.body.removeChild(e)
+  computed: {
+    selectedVersion () {
+      return Array.isArray(this.selected) ? 1 : 2
     },
+    currentColors () {
+      return {
+        bg: this.bgColorLocal,
+        text: this.textColorLocal,
+        link: this.linkColorLocal,
 
-    importTheme () {
-      this.invalidThemeImported = false
-      const filePicker = document.createElement('input')
-      filePicker.setAttribute('type', 'file')
-      filePicker.setAttribute('accept', '.json')
+        fg: this.fgColorLocal,
+        fgText: this.fgTextColorLocal,
+        fgLink: this.fgLinkColorLocal,
 
-      filePicker.addEventListener('change', event => {
-        if (event.target.files[0]) {
-          // eslint-disable-next-line no-undef
-          const reader = new FileReader()
-          reader.onload = ({target}) => {
-            try {
-              const parsed = JSON.parse(target.result)
-              if (parsed._pleroma_theme_version === 1) {
-                this.normalizeLocalState(parsed.colors, parsed.radii)
-              } else {
-                // A theme from the future, spooky
-                this.invalidThemeImported = true
-              }
-            } catch (e) {
-              // This will happen both if there is a JSON syntax error or the theme is missing components
-              this.invalidThemeImported = true
-            }
-          }
-          reader.readAsText(event.target.files[0])
-        }
+        panel: this.panelColorLocal,
+        panelText: this.panelTextColorLocal,
+        panelLink: this.panelLinkColorLocal,
+        panelFaint: this.panelFaintColorLocal,
+
+        input: this.inputColorLocal,
+        inputText: this.inputTextColorLocal,
+
+        topBar: this.topBarColorLocal,
+        topBarText: this.topBarTextColorLocal,
+        topBarLink: this.topBarLinkColorLocal,
+
+        btn: this.btnColorLocal,
+        btnText: this.btnTextColorLocal,
+
+        alertError: this.alertErrorColorLocal,
+        badgeNotification: this.badgeNotificationColorLocal,
+
+        faint: this.faintColorLocal,
+        faintLink: this.faintLinkColorLocal,
+        border: this.borderColorLocal,
+
+        cRed: this.cRedColorLocal,
+        cBlue: this.cBlueColorLocal,
+        cGreen: this.cGreenColorLocal,
+        cOrange: this.cOrangeColorLocal
+      }
+    },
+    currentOpacity () {
+      return {
+        bg: this.bgOpacityLocal,
+        btn: this.btnOpacityLocal,
+        input: this.inputOpacityLocal,
+        panel: this.panelOpacityLocal,
+        topBar: this.topBarOpacityLocal,
+        border: this.borderOpacityLocal,
+        faint: this.faintOpacityLocal
+      }
+    },
+    currentRadii () {
+      return {
+        btn: this.btnRadiusLocal,
+        input: this.inputRadiusLocal,
+        checkbox: this.checkboxRadiusLocal,
+        panel: this.panelRadiusLocal,
+        avatar: this.avatarRadiusLocal,
+        avatarAlt: this.avatarAltRadiusLocal,
+        tooltip: this.tooltipRadiusLocal,
+        attachment: this.attachmentRadiusLocal
+      }
+    },
+    preview () {
+      return composePreset(this.previewColors, this.previewRadii, this.previewShadows, this.previewFonts)
+    },
+    previewTheme () {
+      if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {}, fonts: {} }
+      return this.preview.theme
+    },
+    // This needs optimization maybe
+    previewContrast () {
+      if (!this.previewTheme.colors.bg) return {}
+      const colors = this.previewTheme.colors
+      const opacity = this.previewTheme.opacity
+      if (!colors.bg) return {}
+      const hints = (ratio) => ({
+        text: ratio.toPrecision(3) + ':1',
+        // AA level, AAA level
+        aa: ratio >= 4.5,
+        aaa: ratio >= 7,
+        // same but for 18pt+ texts
+        laa: ratio >= 3,
+        laaa: ratio >= 4.5
       })
 
-      document.body.appendChild(filePicker)
-      filePicker.click()
-      document.body.removeChild(filePicker)
-    },
+      // fgsfds :DDDD
+      const fgs = {
+        text: hex2rgb(colors.text),
+        panelText: hex2rgb(colors.panelText),
+        panelLink: hex2rgb(colors.panelLink),
+        btnText: hex2rgb(colors.btnText),
+        topBarText: hex2rgb(colors.topBarText),
+        inputText: hex2rgb(colors.inputText),
 
+        link: hex2rgb(colors.link),
+        topBarLink: hex2rgb(colors.topBarLink),
+
+        red: hex2rgb(colors.cRed),
+        green: hex2rgb(colors.cGreen),
+        blue: hex2rgb(colors.cBlue),
+        orange: hex2rgb(colors.cOrange)
+      }
+
+      const bgs = {
+        bg: hex2rgb(colors.bg),
+        btn: hex2rgb(colors.btn),
+        panel: hex2rgb(colors.panel),
+        topBar: hex2rgb(colors.topBar),
+        input: hex2rgb(colors.input),
+        alertError: hex2rgb(colors.alertError),
+        badgeNotification: hex2rgb(colors.badgeNotification)
+      }
+
+      /* This is a bit confusing because "bottom layer" used is text color
+       * This is done to get worst case scenario when background below transparent
+       * layer matches text color, making it harder to read the lower alpha is.
+       */
+      const ratios = {
+        bgText: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.text), fgs.text),
+        bgLink: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.link), fgs.link),
+        bgRed: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.red), fgs.red),
+        bgGreen: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.green), fgs.green),
+        bgBlue: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.blue), fgs.blue),
+        bgOrange: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.orange), fgs.orange),
+
+        tintText: getContrastRatio(alphaBlend(bgs.bg, 0.5, fgs.panelText), fgs.text),
+
+        panelText: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText),
+        panelLink: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelLink), fgs.panelLink),
+
+        btnText: getContrastRatio(alphaBlend(bgs.btn, opacity.btn, fgs.btnText), fgs.btnText),
+
+        inputText: getContrastRatio(alphaBlend(bgs.input, opacity.input, fgs.inputText), fgs.inputText),
+
+        topBarText: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarText), fgs.topBarText),
+        topBarLink: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarLink), fgs.topBarLink)
+      }
+
+      return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
+    },
+    previewRules () {
+      if (!this.preview.rules) return ''
+      return [
+        ...Object.values(this.preview.rules),
+        'color: var(--text)',
+        'font-family: var(--interfaceFont, sans-serif)'
+      ].join(';')
+    },
+    shadowsAvailable () {
+      return Object.keys(this.previewTheme.shadows).sort()
+    },
+    currentShadowOverriden: {
+      get () {
+        return !!this.currentShadow
+      },
+      set (val) {
+        if (val) {
+          set(this.shadowsLocal, this.shadowSelected, this.currentShadowFallback.map(_ => Object.assign({}, _)))
+        } else {
+          del(this.shadowsLocal, this.shadowSelected)
+        }
+      }
+    },
+    currentShadowFallback () {
+      return this.previewTheme.shadows[this.shadowSelected]
+    },
+    currentShadow: {
+      get () {
+        return this.shadowsLocal[this.shadowSelected]
+      },
+      set (v) {
+        set(this.shadowsLocal, this.shadowSelected, v)
+      }
+    },
+    themeValid () {
+      return !this.shadowsInvalid && !this.colorsInvalid && !this.radiiInvalid
+    },
+    exportedTheme () {
+      const saveEverything = (
+        !this.keepFonts &&
+        !this.keepShadows &&
+        !this.keepOpacity &&
+        !this.keepRoundness &&
+        !this.keepColor
+      )
+
+      const theme = {}
+
+      if (this.keepFonts || saveEverything) {
+        theme.fonts = this.fontsLocal
+      }
+      if (this.keepShadows || saveEverything) {
+        theme.shadows = this.shadowsLocal
+      }
+      if (this.keepOpacity || saveEverything) {
+        theme.opacity = this.currentOpacity
+      }
+      if (this.keepColor || saveEverything) {
+        theme.colors = this.currentColors
+      }
+      if (this.keepRoundness || saveEverything) {
+        theme.radii = this.currentRadii
+      }
+
+      return {
+        // To separate from other random JSON files and possible future theme formats
+        _pleroma_theme_version: 2, theme
+      }
+    }
+  },
+  components: {
+    ColorInput,
+    OpacityInput,
+    RangeInput,
+    ContrastRatio,
+    ShadowControl,
+    FontControl,
+    TabSwitcher,
+    Preview,
+    ExportImport
+  },
+  methods: {
     setCustomTheme () {
-      if (!this.bgColorLocal && !this.btnColorLocal && !this.linkColorLocal) {
-        // reset to picked themes
-      }
-
-      const rgb = (hex) => {
-        const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
-        return result ? {
-          r: parseInt(result[1], 16),
-          g: parseInt(result[2], 16),
-          b: parseInt(result[3], 16)
-        } : null
-      }
-      const bgRgb = rgb(this.bgColorLocal)
-      const btnRgb = rgb(this.btnColorLocal)
-      const textRgb = rgb(this.textColorLocal)
-      const linkRgb = rgb(this.linkColorLocal)
-
-      const redRgb = rgb(this.redColorLocal)
-      const blueRgb = rgb(this.blueColorLocal)
-      const greenRgb = rgb(this.greenColorLocal)
-      const orangeRgb = rgb(this.orangeColorLocal)
-
-      if (bgRgb && btnRgb && linkRgb) {
-        this.$store.dispatch('setOption', {
-          name: 'customTheme',
-          value: {
-            fg: btnRgb,
-            bg: bgRgb,
-            text: textRgb,
-            link: linkRgb,
-            cRed: redRgb,
-            cBlue: blueRgb,
-            cGreen: greenRgb,
-            cOrange: orangeRgb,
-            btnRadius: this.btnRadiusLocal,
-            inputRadius: this.inputRadiusLocal,
-            panelRadius: this.panelRadiusLocal,
-            avatarRadius: this.avatarRadiusLocal,
-            avatarAltRadius: this.avatarAltRadiusLocal,
-            tooltipRadius: this.tooltipRadiusLocal,
-            attachmentRadius: this.attachmentRadiusLocal
-          }})
+      this.$store.dispatch('setOption', {
+        name: 'customTheme',
+        value: {
+          shadows: this.shadowsLocal,
+          fonts: this.fontsLocal,
+          opacity: this.currentOpacity,
+          colors: this.currentColors,
+          radii: this.currentRadii
+        }
+      })
+    },
+    onImport (parsed) {
+      if (parsed._pleroma_theme_version === 1) {
+        this.normalizeLocalState(parsed, 1)
+      } else if (parsed._pleroma_theme_version === 2) {
+        this.normalizeLocalState(parsed.theme, 2)
       }
     },
+    importValidator (parsed) {
+      const version = parsed._pleroma_theme_version
+      return version >= 1 || version <= 2
+    },
+    clearAll () {
+      const state = this.$store.state.config.customTheme
+      const version = state.colors ? 2 : 'l1'
+      this.normalizeLocalState(this.$store.state.config.customTheme, version)
+    },
 
-    normalizeLocalState (colors, radii) {
-      this.bgColorLocal = rgbstr2hex(colors.bg)
-      this.btnColorLocal = rgbstr2hex(colors.btn)
-      this.textColorLocal = rgbstr2hex(colors.fg)
-      this.linkColorLocal = rgbstr2hex(colors.link)
+    // Clears all the extra stuff when loading V1 theme
+    clearV1 () {
+      Object.keys(this.$data)
+        .filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal'))
+        .filter(_ => !v1OnlyNames.includes(_))
+        .forEach(key => {
+          set(this.$data, key, undefined)
+        })
+    },
 
-      this.redColorLocal = rgbstr2hex(colors.cRed)
-      this.blueColorLocal = rgbstr2hex(colors.cBlue)
-      this.greenColorLocal = rgbstr2hex(colors.cGreen)
-      this.orangeColorLocal = rgbstr2hex(colors.cOrange)
+    clearRoundness () {
+      Object.keys(this.$data)
+        .filter(_ => _.endsWith('RadiusLocal'))
+        .forEach(key => {
+          set(this.$data, key, undefined)
+        })
+    },
 
-      this.btnRadiusLocal = radii.btnRadius || 4
-      this.inputRadiusLocal = radii.inputRadius || 4
-      this.panelRadiusLocal = radii.panelRadius || 10
-      this.avatarRadiusLocal = radii.avatarRadius || 5
-      this.avatarAltRadiusLocal = radii.avatarAltRadius || 50
-      this.tooltipRadiusLocal = radii.tooltipRadius || 2
-      this.attachmentRadiusLocal = radii.attachmentRadius || 5
+    clearOpacity () {
+      Object.keys(this.$data)
+        .filter(_ => _.endsWith('OpacityLocal'))
+        .forEach(key => {
+          set(this.$data, key, undefined)
+        })
+    },
+
+    clearShadows () {
+      this.shadowsLocal = {}
+    },
+
+    clearFonts () {
+      this.fontsLocal = {}
+    },
+
+    /**
+     * This applies stored theme data onto form. Supports three versions of data:
+     * v2 (version = 2) - newer version of themes.
+     * v1 (version = 1) - older version of themes (import from file)
+     * v1l (version = l1) - older version of theme (load from local storage)
+     * v1 and v1l differ because of way themes were stored/exported.
+     * @param {Object} input - input data
+     * @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type
+     */
+    normalizeLocalState (input, version = 0) {
+      const colors = input.colors || input
+      const radii = input.radii || input
+      const opacity = input.opacity
+      const shadows = input.shadows || {}
+      const fonts = input.fonts || {}
+
+      if (version === 0) {
+        if (input.version) version = input.version
+        // Old v1 naming: fg is text, btn is foreground
+        if (typeof colors.text === 'undefined' && typeof colors.fg !== 'undefined') {
+          version = 1
+        }
+        // New v2 naming: text is text, fg is foreground
+        if (typeof colors.text !== 'undefined' && typeof colors.fg !== 'undefined') {
+          version = 2
+        }
+      }
+
+      // Stuff that differs between V1 and V2
+      if (version === 1) {
+        this.fgColorLocal = rgb2hex(colors.btn)
+        this.textColorLocal = rgb2hex(colors.fg)
+      }
+
+      if (!this.keepColor) {
+        this.clearV1()
+        const keys = new Set(version !== 1 ? Object.keys(colors) : [])
+        if (version === 1 || version === 'l1') {
+          keys
+            .add('bg')
+            .add('link')
+            .add('cRed')
+            .add('cBlue')
+            .add('cGreen')
+            .add('cOrange')
+        }
+
+        keys.forEach(key => {
+          this[key + 'ColorLocal'] = rgb2hex(colors[key])
+        })
+      }
+
+      if (!this.keepRoundness) {
+        this.clearRoundness()
+        Object.entries(radii).forEach(([k, v]) => {
+          // 'Radius' is kept mostly for v1->v2 localstorage transition
+          const key = k.endsWith('Radius') ? k.split('Radius')[0] : k
+          this[key + 'RadiusLocal'] = v
+        })
+      }
+
+      if (!this.keepShadows) {
+        this.clearShadows()
+        this.shadowsLocal = shadows
+        this.shadowSelected = this.shadowsAvailable[0]
+      }
+
+      if (!this.keepFonts) {
+        this.clearFonts()
+        this.fontsLocal = fonts
+      }
+
+      if (opacity && !this.keepOpacity) {
+        this.clearOpacity()
+        Object.entries(opacity).forEach(([k, v]) => {
+          if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
+          this[k + 'OpacityLocal'] = v
+        })
+      }
     }
   },
   watch: {
+    currentRadii () {
+      try {
+        this.previewRadii = generateRadii({ radii: this.currentRadii })
+        this.radiiInvalid = false
+      } catch (e) {
+        this.radiiInvalid = true
+        console.warn(e)
+      }
+    },
+    shadowsLocal: {
+      handler () {
+        try {
+          this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
+          this.shadowsInvalid = false
+        } catch (e) {
+          this.shadowsInvalid = true
+          console.warn(e)
+        }
+      },
+      deep: true
+    },
+    fontsLocal: {
+      handler () {
+        try {
+          this.previewFonts = generateFonts({ fonts: this.fontsLocal })
+          this.fontsInvalid = false
+        } catch (e) {
+          this.fontsInvalid = true
+          console.warn(e)
+        }
+      },
+      deep: true
+    },
+    currentColors () {
+      try {
+        this.previewColors = generateColors({
+          opacity: this.currentOpacity,
+          colors: this.currentColors
+        })
+        this.colorsInvalid = false
+      } catch (e) {
+        this.colorsInvalid = true
+        console.warn(e)
+      }
+    },
+    currentOpacity () {
+      try {
+        this.previewColors = generateColors({
+          opacity: this.currentOpacity,
+          colors: this.currentColors
+        })
+      } catch (e) {
+        console.warn(e)
+      }
+    },
     selected () {
-      this.bgColorLocal = this.selected[1]
-      this.btnColorLocal = this.selected[2]
-      this.textColorLocal = this.selected[3]
-      this.linkColorLocal = this.selected[4]
-      this.redColorLocal = this.selected[5]
-      this.greenColorLocal = this.selected[6]
-      this.blueColorLocal = this.selected[7]
-      this.orangeColorLocal = this.selected[8]
+      if (this.selectedVersion === 1) {
+        if (!this.keepRoundness) {
+          this.clearRoundness()
+        }
+
+        if (!this.keepShadows) {
+          this.clearShadows()
+        }
+
+        if (!this.keepOpacity) {
+          this.clearOpacity()
+        }
+
+        if (!this.keepColor) {
+          this.clearV1()
+
+          this.bgColorLocal = this.selected[1]
+          this.fgColorLocal = this.selected[2]
+          this.textColorLocal = this.selected[3]
+          this.linkColorLocal = this.selected[4]
+          this.cRedColorLocal = this.selected[5]
+          this.cGreenColorLocal = this.selected[6]
+          this.cBlueColorLocal = this.selected[7]
+          this.cOrangeColorLocal = this.selected[8]
+        }
+      } else if (this.selectedVersion >= 2) {
+        this.normalizeLocalState(this.selected.theme, 2)
+      }
     }
   }
 }
diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss
new file mode 100644
index 00000000..135c113a
--- /dev/null
+++ b/src/components/style_switcher/style_switcher.scss
@@ -0,0 +1,335 @@
+@import '../../_variables.scss';
+.style-switcher {
+  .preset-switcher {
+    margin-right: 1em;
+  }
+
+  .style-control {
+    display: flex;
+    align-items: baseline;
+    margin-bottom: 5px;
+
+    .label {
+      flex: 1;
+    }
+
+    &.disabled {
+      input, select {
+        &:not(.exclude-disabled) {
+          opacity: .5
+        }
+      }
+    }
+
+    input, select {
+      min-width: 3em;
+      margin: 0;
+      flex: 0;
+
+      &[type=color] {
+        padding: 1px;
+        cursor: pointer;
+        height: 29px;
+        min-width: 2em;
+        border: none;
+        align-self: stretch;
+      }
+
+      &[type=number] {
+        min-width: 5em;
+      }
+
+      &[type=range] {
+        flex: 1;
+        min-width: 3em;
+      }
+
+      &[type=checkbox] + label {
+        margin: 6px 0;
+      }
+
+      &:not([type=number]):not([type=text]) {
+        align-self: flex-start;
+      }
+    }
+  }
+
+  .tab-switcher {
+    margin: 0 -1em;
+  }
+
+  .reset-container {
+    flex-wrap: wrap;
+  }
+
+  .fonts-container,
+  .reset-container,
+  .apply-container,
+  .radius-container,
+  .color-container,
+  {
+    display: flex;
+  }
+
+  .fonts-container,
+  .radius-container {
+    flex-direction: column;
+  }
+
+  .color-container{
+    > h4 {
+      width: 99%;
+    }
+    flex-wrap: wrap;
+    justify-content: space-between;
+  }
+
+  .fonts-container,
+  .color-container,
+  .shadow-container,
+  .radius-container,
+  .presets-container {
+    margin: 1em 1em 0;
+  }
+
+  .tab-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: baseline;
+    width: 100%;
+    min-height: 30px;
+
+    .btn {
+      min-width: 1px;
+      flex: 0 auto;
+      padding: 0 1em;
+    }
+
+    p {
+      flex: 1;
+      margin: 0;
+      margin-right: .5em;
+    }
+
+    margin-bottom: 1em;
+  }
+
+  .shadow-selector {
+    .override {
+      flex: 1;
+      margin-left: .5em;
+    }
+    .select-container {
+      margin-top: -4px;
+      margin-bottom: -3px;
+    }
+  }
+
+  .save-load,
+  .save-load-options {
+    display: flex;
+    justify-content: center;
+    align-items: baseline;
+    flex-wrap: wrap;
+
+    .presets,
+    .import-export {
+      margin-bottom: .5em;
+    }
+
+    .import-export {
+      display: flex;
+    }
+
+    .override {
+      margin-left: .5em;
+    }
+  }
+
+  .save-load-options {
+    flex-wrap: wrap;
+    margin-top: .5em;
+    justify-content: center;
+    .keep-option {
+      margin: 0 .5em .5em;
+      min-width: 25%;
+    }
+  }
+
+  .preview-container {
+    border-top: 1px dashed;
+    border-bottom: 1px dashed;
+    border-color: $fallback--border;
+    border-color: var(--border, $fallback--border);
+    margin: 1em -1em 0;
+    padding: 1em;
+    background: var(--body-background-image);
+    background-size: cover;
+    background-position: 50% 50%;
+
+    .dummy {
+      .post {
+        font-family: var(--postFont);
+        display: flex;
+
+        .content {
+          flex: 1;
+
+          h4 {
+            margin-bottom: .25em;
+          }
+
+          .icons {
+            margin-top: .5em;
+            display: flex;
+
+            i {
+              margin-right: 1em;
+            }
+          }
+        }
+      }
+
+      .after-post {
+        margin-top: 1em;
+        display: flex;
+        align-items: center;
+      }
+
+      .avatar, .avatar-alt{
+        background: linear-gradient(135deg, #b8e1fc 0%,#a9d2f3 10%,#90bae4 25%,#90bcea 37%,#90bff0 50%,#6ba8e5 51%,#a2daf5 83%,#bdf3fd 100%);
+        color: black;
+        font-family: sans-serif;
+        text-align: center;
+        margin-right: 1em;
+      }
+
+      .avatar-alt {
+        flex: 0 auto;
+        margin-left: 28px;
+        font-size: 12px;
+        min-width: 20px;
+        min-height: 20px;
+        line-height: 20px;
+        border-radius: $fallback--avatarAltRadius;
+        border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
+      }
+
+      .avatar {
+        flex: 0 auto;
+        width: 48px;
+        height: 48px;
+        font-size: 14px;
+        line-height: 48px;
+      }
+
+      .actions {
+        display: flex;
+        align-items: baseline;
+
+        .checkbox {
+          display: inline-flex;
+          align-items: baseline;
+          margin-right: 1em;
+          flex: 1;
+        }
+      }
+
+      .separator {
+        margin: 1em;
+        border-bottom: 1px solid;
+        border-color: $fallback--border;
+        border-color: var(--border, $fallback--border);
+      }
+
+      .panel-heading {
+        .badge, .alert, .btn, .faint {
+          margin-left: 1em;
+          white-space: nowrap;
+        }
+        .faint {
+          text-overflow: ellipsis;
+          min-width: 2em;
+          overflow-x: hidden;
+        }
+        .flex-spacer {
+          flex: 1;
+        }
+      }
+      .btn {
+        margin-left: 0;
+        padding: 0 1em;
+        min-width: 3em;
+        min-height: 30px;
+      }
+    }
+  }
+
+  .apply-container {
+    justify-content: center;
+  }
+
+  .radius-item,
+  .color-item {
+    min-width: 20em;
+    margin: 5px 6px 0 0;
+    display:flex;
+    flex-direction: column;
+    flex: 1 1 0;
+
+    &.wide {
+      min-width: 60%
+    }
+
+    &:not(.wide):nth-child(2n+1) {
+      margin-right: 7px;
+
+    }
+
+    .color, .opacity {
+      display:flex;
+      align-items: baseline;
+    }
+  }
+
+  .radius-item {
+    flex-basis: auto;
+  }
+
+  .theme-radius-rn,
+  .theme-color-cl {
+    border: 0;
+    box-shadow: none;
+    background: transparent;
+    color: var(--faint, $fallback--faint);
+    align-self: stretch;
+  }
+
+  .theme-color-cl,
+  .theme-radius-in,
+  .theme-color-in {
+    margin-left: 4px;
+  }
+
+  .theme-radius-in {
+    min-width: 1em;
+  }
+
+  .theme-radius-in {
+    max-width: 7em;
+    flex: 1;
+  }
+
+  .theme-radius-lb{
+    max-width: 50em;
+  }
+
+  .theme-preview-content {
+    padding: 20px;
+  }
+
+  .btn {
+    margin-left: .25em;
+    margin-right: .25em;
+  }
+}
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 72a338bd..84963c81 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -1,300 +1,276 @@
 <template>
-<div>
+<div class="style-switcher">
   <div class="presets-container">
-    <div>
-      {{$t('settings.presets')}}
-      <label for="style-switcher" class='select'>
-        <select id="style-switcher" v-model="selected" class="style-switcher">
-          <option v-for="style in availableStyles"
-                  :value="style"
-                  :style="{
-                          backgroundColor: style[1],
-                          color: style[3]
-                          }">
-            {{style[0]}}
-          </option>
-        </select>
-        <i class="icon-down-open"/>
-      </label>
+    <div class="save-load">
+      <export-import
+        :exportObject='exportedTheme'
+        :exportLabel='$t("settings.export_theme")'
+        :importLabel='$t("settings.import_theme")'
+        :importFailedText='$t("settings.invalid_theme_imported")'
+        :onImport='onImport'
+        :validator='importValidator'>
+        <template slot="before">
+          <div class="presets">
+            {{$t('settings.presets')}}
+            <label for="preset-switcher" class='select'>
+              <select id="preset-switcher" v-model="selected" class="preset-switcher">
+                <option v-for="style in availableStyles"
+                        :value="style"
+                        :style="{
+                                backgroundColor: style[1] || style.theme.colors.bg,
+                                color: style[3] || style.theme.colors.text
+                                }">
+                  {{style[0] || style.name}}
+                </option>
+              </select>
+              <i class="icon-down-open"/>
+            </label>
+          </div>
+        </template>
+      </export-import>
     </div>
-    <div class="import-export">
-      <button class="btn" @click="exportCurrentTheme">{{ $t('settings.export_theme') }}</button>
-      <button class="btn" @click="importTheme">{{ $t('settings.import_theme') }}</button>
-      <p v-if="invalidThemeImported" class="import-warning">{{ $t('settings.invalid_theme_imported') }}</p>
+    <div class="save-load-options">
+      <span class="keep-option">
+        <input
+          id="keep-color"
+          type="checkbox"
+          v-model="keepColor">
+        <label for="keep-color">{{$t('settings.style.switcher.keep_color')}}</label>
+      </span>
+      <span class="keep-option">
+        <input
+          id="keep-shadows"
+          type="checkbox"
+          v-model="keepShadows">
+        <label for="keep-shadows">{{$t('settings.style.switcher.keep_shadows')}}</label>
+      </span>
+      <span class="keep-option">
+        <input
+          id="keep-opacity"
+          type="checkbox"
+          v-model="keepOpacity">
+        <label for="keep-opacity">{{$t('settings.style.switcher.keep_opacity')}}</label>
+      </span>
+      <span class="keep-option">
+        <input
+          id="keep-roundness"
+          type="checkbox"
+          v-model="keepRoundness">
+        <label for="keep-roundness">{{$t('settings.style.switcher.keep_roundness')}}</label>
+      </span>
+      <span class="keep-option">
+        <input
+          id="keep-fonts"
+          type="checkbox"
+          v-model="keepFonts">
+        <label for="keep-fonts">{{$t('settings.style.switcher.keep_fonts')}}</label>
+      </span>
+      <p>{{$t('settings.style.switcher.save_load_hint')}}</p>
     </div>
   </div>
 
   <div class="preview-container">
-    <div :style="{
-                 '--btnRadius': btnRadiusLocal + 'px',
-                 '--inputRadius': inputRadiusLocal + 'px',
-                 '--panelRadius': panelRadiusLocal + 'px',
-                 '--avatarRadius': avatarRadiusLocal + 'px',
-                 '--avatarAltRadius': avatarAltRadiusLocal + 'px',
-                 '--tooltipRadius': tooltipRadiusLocal + 'px',
-                 '--attachmentRadius': attachmentRadiusLocal + 'px'
-                 }">
-      <div class="panel dummy">
-        <div class="panel-heading" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Preview</div>
-        <div class="panel-body theme-preview-content" :style="{ 'background-color': bgColorLocal, 'color': textColorLocal }">
-          <div class="avatar" :style="{
-                                      'border-radius': avatarRadiusLocal + 'px'
-                                      }">
-            ( ͡° ͜ʖ ͡°)
-          </div>
-          <h4>Content</h4>
-          <br>
-          A bunch of more content and
-          <a :style="{ color: linkColorLocal }">a nice lil' link</a>
-          <i :style="{ color: blueColorLocal }" class="icon-reply"/>
-          <i :style="{ color: greenColorLocal }" class="icon-retweet"/>
-          <i :style="{ color: redColorLocal }" class="icon-cancel"/>
-          <i :style="{ color: orangeColorLocal }" class="icon-star"/>
-          <br>
-          <button class="btn" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Button</button>
+    <preview :style="previewRules"/>
+  </div>
+
+  <keep-alive>
+    <tab-switcher key="style-tweak">
+      <div :label="$t('settings.style.common_colors._tab_label')" class="color-container">
+        <div class="tab-header">
+          <p>{{$t('settings.theme_help')}}</p>
+          <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
+          <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
+        </div>
+        <p>{{$t('settings.theme_help_v2_1')}}</p>
+        <h4>{{ $t('settings.style.common_colors.main') }}</h4>
+        <div class="color-item">
+          <ColorInput name="bgColor" v-model="bgColorLocal" :label="$t('settings.background')"/>
+          <OpacityInput name="bgOpacity" v-model="bgOpacityLocal" :fallback="previewTheme.opacity.bg || 1"/>
+          <ColorInput name="textColor" v-model="textColorLocal" :label="$t('settings.text')"/>
+          <ContrastRatio :contrast="previewContrast.bgText"/>
+          <ColorInput name="linkColor" v-model="linkColorLocal" :label="$t('settings.links')"/>
+          <ContrastRatio :contrast="previewContrast.bgLink"/>
+        </div>
+        <div class="color-item">
+          <ColorInput name="fgColor" v-model="fgColorLocal" :label="$t('settings.foreground')"/>
+          <ColorInput name="fgTextColor" v-model="fgTextColorLocal" :label="$t('settings.text')" :fallback="previewTheme.colors.fgText"/>
+          <ColorInput name="fgLinkColor" v-model="fgLinkColorLocal" :label="$t('settings.links')" :fallback="previewTheme.colors.fgLink"/>
+          <p>{{ $t('settings.style.common_colors.foreground_hint') }}</p>
+        </div>
+        <h4>{{ $t('settings.style.common_colors.rgbo') }}</h4>
+        <div class="color-item">
+          <ColorInput name="cRedColor" v-model="cRedColorLocal" :label="$t('settings.cRed')"/>
+          <ContrastRatio :contrast="previewContrast.bgRed"/>
+          <ColorInput name="cBlueColor" v-model="cBlueColorLocal" :label="$t('settings.cBlue')"/>
+          <ContrastRatio :contrast="previewContrast.bgBlue"/>
+        </div>
+        <div class="color-item">
+          <ColorInput name="cGreenColor" v-model="cGreenColorLocal" :label="$t('settings.cGreen')"/>
+          <ContrastRatio :contrast="previewContrast.bgGreen"/>
+          <ColorInput name="cOrangeColor" v-model="cOrangeColorLocal" :label="$t('settings.cOrange')"/>
+          <ContrastRatio :contrast="previewContrast.bgOrange"/>
+        </div>
+        <p>{{$t('settings.theme_help_v2_2')}}</p>
+      </div>
+
+      <div :label="$t('settings.style.advanced_colors._tab_label')" class="color-container">
+        <div class="tab-header">
+          <p>{{$t('settings.theme_help')}}</p>
+          <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
+          <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
+          <ColorInput name="alertError" v-model="alertErrorColorLocal" :label="$t('settings.style.advanced_colors.alert_error')" :fallback="previewTheme.colors.alertError"/>
+          <ContrastRatio :contrast="previewContrast.alertError"/>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
+          <ColorInput name="badgeNotification" v-model="badgeNotificationColorLocal" :label="$t('settings.style.advanced_colors.badge_notification')" :fallback="previewTheme.colors.badgeNotification"/>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.panel_header') }}</h4>
+          <ColorInput name="panelColor" v-model="panelColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
+          <OpacityInput name="panelOpacity" v-model="panelOpacityLocal" :fallback="previewTheme.opacity.panel || 1"/>
+          <ColorInput name="panelTextColor" v-model="panelTextColorLocal" :fallback="previewTheme.colors.panelText" :label="$t('settings.text')"/>
+          <ContrastRatio :contrast="previewContrast.panelText" large="1"/>
+          <ColorInput name="panelLinkColor" v-model="panelLinkColorLocal" :fallback="previewTheme.colors.panelLink" :label="$t('settings.links')"/>
+          <ContrastRatio :contrast="previewContrast.panelLink" large="1"/>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.top_bar') }}</h4>
+          <ColorInput name="topBarColor" v-model="topBarColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
+          <ColorInput name="topBarTextColor" v-model="topBarTextColorLocal" :fallback="previewTheme.colors.topBarText" :label="$t('settings.text')"/>
+          <ContrastRatio :contrast="previewContrast.topBarText"/>
+          <ColorInput name="topBarLinkColor" v-model="topBarLinkColorLocal" :fallback="previewTheme.colors.topBarLink" :label="$t('settings.links')"/>
+          <ContrastRatio :contrast="previewContrast.topBarLink"/>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.inputs') }}</h4>
+          <ColorInput name="inputColor" v-model="inputColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
+          <OpacityInput name="inputOpacity" v-model="inputOpacityLocal" :fallback="previewTheme.opacity.input || 1"/>
+          <ColorInput name="inputTextColor" v-model="inputTextColorLocal" :fallback="previewTheme.colors.inputText" :label="$t('settings.text')"/>
+          <ContrastRatio :contrast="previewContrast.inputText"/>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.buttons') }}</h4>
+          <ColorInput name="btnColor" v-model="btnColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
+          <OpacityInput name="btnOpacity" v-model="btnOpacityLocal" :fallback="previewTheme.opacity.btn || 1"/>
+          <ColorInput name="btnTextColor" v-model="btnTextColorLocal" :fallback="previewTheme.colors.btnText" :label="$t('settings.text')"/>
+          <ContrastRatio :contrast="previewContrast.btnText"/>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.borders') }}</h4>
+          <ColorInput name="borderColor" v-model="borderColorLocal" :fallback="previewTheme.colors.border" :label="$t('settings.style.common.color')"/>
+          <OpacityInput name="borderOpacity" v-model="borderOpacityLocal" :fallback="previewTheme.opacity.border || 1"/>
+        </div>
+        <div class="color-item">
+          <h4>{{ $t('settings.style.advanced_colors.faint_text') }}</h4>
+          <ColorInput name="faintColor" v-model="faintColorLocal" :fallback="previewTheme.colors.faint || 1" :label="$t('settings.text')"/>
+          <ColorInput name="faintLinkColor" v-model="faintLinkColorLocal" :fallback="previewTheme.colors.faintLink" :label="$t('settings.links')"/>
+          <ColorInput name="panelFaintColor" v-model="panelFaintColorLocal" :fallback="previewTheme.colors.panelFaint" :label="$t('settings.style.advanced_colors.panel_header')"/>
+          <OpacityInput name="faintOpacity" v-model="faintOpacityLocal" :fallback="previewTheme.opacity.faint || 0.5"/>
         </div>
       </div>
-    </div>
-  </div>
 
-  <div class="color-container">
-    <p>{{$t('settings.theme_help')}}</p>
-    <div class="color-item">
-      <label for="bgcolor" class="theme-color-lb">{{$t('settings.background')}}</label>
-      <input id="bgcolor" class="theme-color-cl" type="color" v-model="bgColorLocal">
-      <input id="bgcolor-t" class="theme-color-in" type="text" v-model="bgColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="fgcolor" class="theme-color-lb">{{$t('settings.foreground')}}</label>
-      <input id="fgcolor" class="theme-color-cl" type="color" v-model="btnColorLocal">
-      <input id="fgcolor-t" class="theme-color-in" type="text" v-model="btnColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="textcolor" class="theme-color-lb">{{$t('settings.text')}}</label>
-      <input id="textcolor" class="theme-color-cl" type="color" v-model="textColorLocal">
-      <input id="textcolor-t" class="theme-color-in" type="text" v-model="textColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="linkcolor" class="theme-color-lb">{{$t('settings.links')}}</label>
-      <input id="linkcolor" class="theme-color-cl" type="color" v-model="linkColorLocal">
-      <input id="linkcolor-t" class="theme-color-in" type="text" v-model="linkColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="redcolor" class="theme-color-lb">{{$t('settings.cRed')}}</label>
-      <input id="redcolor" class="theme-color-cl" type="color" v-model="redColorLocal">
-      <input id="redcolor-t" class="theme-color-in" type="text" v-model="redColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="bluecolor" class="theme-color-lb">{{$t('settings.cBlue')}}</label>
-      <input id="bluecolor" class="theme-color-cl" type="color" v-model="blueColorLocal">
-      <input id="bluecolor-t" class="theme-color-in" type="text" v-model="blueColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="greencolor" class="theme-color-lb">{{$t('settings.cGreen')}}</label>
-      <input id="greencolor" class="theme-color-cl" type="color" v-model="greenColorLocal">
-      <input id="greencolor-t" class="theme-color-in" type="green" v-model="greenColorLocal">
-    </div>
-    <div class="color-item">
-      <label for="orangecolor" class="theme-color-lb">{{$t('settings.cOrange')}}</label>
-      <input id="orangecolor" class="theme-color-cl" type="color" v-model="orangeColorLocal">
-      <input id="orangecolor-t" class="theme-color-in" type="text" v-model="orangeColorLocal">
-    </div>
-  </div>
+      <div :label="$t('settings.style.radii._tab_label')" class="radius-container">
+        <div class="tab-header">
+          <p>{{$t('settings.radii_help')}}</p>
+          <button class="btn" @click="clearRoundness">{{$t('settings.style.switcher.clear_all')}}</button>
+        </div>
+        <RangeInput name="btnRadius" :label="$t('settings.btnRadius')" v-model="btnRadiusLocal" :fallback="previewTheme.radii.btn" max="16" hardMin="0"/>
+        <RangeInput name="inputRadius" :label="$t('settings.inputRadius')" v-model="inputRadiusLocal" :fallback="previewTheme.radii.input" max="9" hardMin="0"/>
+        <RangeInput name="checkboxRadius" :label="$t('settings.checkboxRadius')" v-model="checkboxRadiusLocal" :fallback="previewTheme.radii.checkbox" max="16" hardMin="0"/>
+        <RangeInput name="panelRadius" :label="$t('settings.panelRadius')" v-model="panelRadiusLocal" :fallback="previewTheme.radii.panel" max="50" hardMin="0"/>
+        <RangeInput name="avatarRadius" :label="$t('settings.avatarRadius')" v-model="avatarRadiusLocal" :fallback="previewTheme.radii.avatar" max="28" hardMin="0"/>
+        <RangeInput name="avatarAltRadius" :label="$t('settings.avatarAltRadius')" v-model="avatarAltRadiusLocal" :fallback="previewTheme.radii.avatarAlt" max="28" hardMin="0"/>
+        <RangeInput name="attachmentRadius" :label="$t('settings.attachmentRadius')" v-model="attachmentRadiusLocal" :fallback="previewTheme.radii.attachment" max="50" hardMin="0"/>
+        <RangeInput name="tooltipRadius" :label="$t('settings.tooltipRadius')" v-model="tooltipRadiusLocal" :fallback="previewTheme.radii.tooltip" max="50" hardMin="0"/>
+      </div>
 
-  <div class="radius-container">
-    <p>{{$t('settings.radii_help')}}</p>
-    <div class="radius-item">
-      <label for="btnradius" class="theme-radius-lb">{{$t('settings.btnRadius')}}</label>
-      <input id="btnradius" class="theme-radius-rn" type="range" v-model="btnRadiusLocal" max="16">
-      <input id="btnradius-t" class="theme-radius-in" type="text" v-model="btnRadiusLocal">
-    </div>
-    <div class="radius-item">
-      <label for="inputradius" class="theme-radius-lb">{{$t('settings.inputRadius')}}</label>
-      <input id="inputradius" class="theme-radius-rn" type="range" v-model="inputRadiusLocal" max="16">
-      <input id="inputradius-t" class="theme-radius-in" type="text" v-model="inputRadiusLocal">
-    </div>
-    <div class="radius-item">
-      <label for="panelradius" class="theme-radius-lb">{{$t('settings.panelRadius')}}</label>
-      <input id="panelradius" class="theme-radius-rn" type="range" v-model="panelRadiusLocal" max="50">
-      <input id="panelradius-t" class="theme-radius-in" type="text" v-model="panelRadiusLocal">
-    </div>
-    <div class="radius-item">
-      <label for="avatarradius" class="theme-radius-lb">{{$t('settings.avatarRadius')}}</label>
-      <input id="avatarradius" class="theme-radius-rn" type="range" v-model="avatarRadiusLocal" max="28">
-      <input id="avatarradius-t" class="theme-radius-in" type="green" v-model="avatarRadiusLocal">
-    </div>
-    <div class="radius-item">
-      <label for="avataraltradius" class="theme-radius-lb">{{$t('settings.avatarAltRadius')}}</label>
-      <input id="avataraltradius" class="theme-radius-rn" type="range" v-model="avatarAltRadiusLocal" max="28">
-      <input id="avataraltradius-t" class="theme-radius-in" type="text" v-model="avatarAltRadiusLocal">
-    </div>
-    <div class="radius-item">
-      <label for="attachmentradius" class="theme-radius-lb">{{$t('settings.attachmentRadius')}}</label>
-      <input id="attachmentrradius" class="theme-radius-rn" type="range" v-model="attachmentRadiusLocal" max="50">
-      <input id="attachmentradius-t" class="theme-radius-in" type="text" v-model="attachmentRadiusLocal">
-    </div>
-    <div class="radius-item">
-      <label for="tooltipradius" class="theme-radius-lb">{{$t('settings.tooltipRadius')}}</label>
-      <input id="tooltipradius" class="theme-radius-rn" type="range" v-model="tooltipRadiusLocal" max="20">
-      <input id="tooltipradius-t" class="theme-radius-in" type="text" v-model="tooltipRadiusLocal">
-    </div>
-  </div>
+      <div :label="$t('settings.style.shadows._tab_label')" class="shadow-container">
+        <div class="tab-header shadow-selector">
+          <div class="select-container">
+            {{$t('settings.style.shadows.component')}}
+            <label for="shadow-switcher" class="select">
+              <select id="shadow-switcher" v-model="shadowSelected" class="shadow-switcher">
+                <option v-for="shadow in shadowsAvailable"
+                        :value="shadow">
+                  {{$t('settings.style.shadows.components.' + shadow)}}
+                </option>
+              </select>
+              <i class="icon-down-open"/>
+            </label>
+          </div>
+          <div class="override">
+            <label for="override" class="label">
+              {{$t('settings.style.shadows.override')}}
+            </label>
+            <input
+              v-model="currentShadowOverriden"
+              name="override"
+              id="override"
+              class="input-override"
+              type="checkbox">
+            <label class="checkbox-label" for="override"></label>
+          </div>
+          <button class="btn" @click="clearShadows">{{$t('settings.style.switcher.clear_all')}}</button>
+        </div>
+        <shadow-control :ready="!!currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/>
+        <div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'">
+          <i18n path="settings.style.shadows.filter_hint.always_drop_shadow" tag="p">
+            <code>filter: drop-shadow()</code>
+          </i18n>
+          <p>{{$t('settings.style.shadows.filter_hint.avatar_inset')}}</p>
+          <i18n path="settings.style.shadows.filter_hint.drop_shadow_syntax" tag="p">
+            <code>drop-shadow</code>
+            <code>spread-radius</code>
+            <code>inset</code>
+          </i18n>
+          <i18n path="settings.style.shadows.filter_hint.inset_classic" tag="p">
+            <code>box-shadow</code>
+          </i18n>
+          <p>{{$t('settings.style.shadows.filter_hint.spread_zero')}}</p>
+        </div>
+      </div>
+
+      <div :label="$t('settings.style.fonts._tab_label')" class="fonts-container">
+        <div class="tab-header">
+          <p>{{$t('settings.style.fonts.help')}}</p>
+          <button class="btn" @click="clearFonts">{{$t('settings.style.switcher.clear_all')}}</button>
+        </div>
+        <FontControl
+          name="ui"
+          v-model="fontsLocal.interface"
+          :label="$t('settings.style.fonts.components.interface')"
+          :fallback="previewTheme.fonts.interface"
+          no-inherit="1"/>
+        <FontControl
+          name="input"
+          v-model="fontsLocal.input"
+          :label="$t('settings.style.fonts.components.input')"
+          :fallback="previewTheme.fonts.input"/>
+        <FontControl
+          name="post"
+          v-model="fontsLocal.post"
+          :label="$t('settings.style.fonts.components.post')"
+          :fallback="previewTheme.fonts.post"/>
+        <FontControl
+          name="postCode"
+          v-model="fontsLocal.postCode"
+          :label="$t('settings.style.fonts.components.postCode')"
+          :fallback="previewTheme.fonts.postCode"/>
+      </div>
+    </tab-switcher>
+  </keep-alive>
 
   <div class="apply-container">
-    <button class="btn submit" @click="setCustomTheme">{{$t('general.apply')}}</button>
+    <button class="btn submit" :disabled="!themeValid" @click="setCustomTheme">{{$t('general.apply')}}</button>
+    <button class="btn" @click="clearAll">{{$t('settings.style.switcher.reset')}}</button>
   </div>
 </div>
 </template>
 
 <script src="./style_switcher.js"></script>
 
-<style lang="scss">
-@import '../../_variables.scss';
-.style-switcher {
-  margin-right: 1em;
-}
-
-.import-warning {
-  color: $fallback--cRed;
-  color: var(--cRed, $fallback--cRed);
-}
-
-.apply-container,
-.radius-container,
-.color-container,
-.presets-container {
-  display: flex;
-
-  p {
-    flex: 2 0 100%;
-    margin-top: 2em;
-    margin-bottom: .5em;
-  }
-}
-
-.radius-container {
-  flex-direction: column;
-}
-
-.color-container {
-  flex-wrap: wrap;
-  justify-content: space-between;
-}
-
-.presets-container {
-  justify-content: center;
-  .import-export {
-    display: flex;
-
-    .btn {
-      margin-left: .5em;
-    }
-  }
-}
-
-.preview-container {
-  border-top: 1px dashed;
-  border-bottom: 1px dashed;
-  border-color: $fallback--border;
-  border-color: var(--border, $fallback--border);
-  margin: 1em -1em 0;
-  padding: 1em;
-
-  .btn {
-    margin-top: 1em;
-    min-height: 30px;
-    width: 10em;
-  }
-}
-
-.apply-container {
-  justify-content: center;
-}
-
-.radius-item,
-.color-item {
-  min-width: 20em;
-  display:flex;
-  flex: 1 1 0;
-  align-items: baseline;
-  margin: 5px 6px 5px 0;
-
-  label {
-    color: var(--faint, $fallback--faint);
-  }
-}
-
-.radius-item {
-  flex-basis: auto;
-}
-
-.theme-radius-rn,
-.theme-color-cl {
-  border: 0;
-  box-shadow: none;
-  background: transparent;
-  color: var(--faint, $fallback--faint);
-  align-self: stretch;
-}
-
-.theme-color-cl,
-.theme-radius-in,
-.theme-color-in {
-  margin-left: 4px;
-}
-
-.theme-color-in {
-  min-width: 4em;
-}
-
-.theme-radius-in {
-  min-width: 1em;
-}
-
-.theme-radius-in,
-.theme-color-in {
-  max-width: 7em;
-  flex: 1;
-}
-
-.theme-radius-lb,
-.theme-color-lb {
-  flex: 2;
-  min-width: 7em;
-}
-
-.theme-radius-lb{
-  max-width: 50em;
-}
-
-.theme-color-lb {
-  max-width: 10em;
-}
-
-.theme-color-cl {
-  padding: 1px;
-  max-width: 8em;
-  height: 100%;
-  flex: 0;
-  min-width: 2em;
-  cursor: pointer;
-  max-height: 29px;
-}
-
-.theme-preview-content {
-  padding: 20px;
-}
-
-.dummy {
-  .avatar {
-    background: linear-gradient(135deg, #b8e1fc 0%,#a9d2f3 10%,#90bae4 25%,#90bcea 37%,#90bff0 50%,#6ba8e5 51%,#a2daf5 83%,#bdf3fd 100%);
-    color: black;
-    text-align: center;
-    height: 48px;
-    line-height: 48px;
-    width: 48px;
-    float: left;
-    margin-right: 1em;
-  }
-}
-</style>
+<style src="./style_switcher.scss" lang="scss"></style>
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index 3fff38f6..9e3dee04 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -25,11 +25,14 @@ export default Vue.component('tab-switcher', {
             }
             return (<button onClick={this.activateTab(index)} class={ classes.join(' ') }>{slot.data.attrs.label}</button>)
           });
-    const contents = (
-      <div>
-        {this.$slots.default.filter(slot => slot.data)[this.active]}
-      </div>
-    );
+    const contents = this.$slots.default.filter(_=>_.data).map(( slot, index ) => {
+      const active = index === this.active
+      return (
+        <div class={active ? 'active' : 'hidden'}>
+          {slot}
+        </div>
+      )
+    });
     return (
       <div class="tab-switcher">
         <div class="tabs">
diff --git a/src/components/tab_switcher/tab_switcher.scss b/src/components/tab_switcher/tab_switcher.scss
index 374a19c5..fbd3321b 100644
--- a/src/components/tab_switcher/tab_switcher.scss
+++ b/src/components/tab_switcher/tab_switcher.scss
@@ -1,13 +1,21 @@
 @import '../../_variables.scss';
 
 .tab-switcher {
+  .contents {
+    .hidden {
+      display: none;
+    }
+  }
   .tabs {
     display: flex;
     position: relative;
     justify-content: center;
     width: 100%;
-    overflow: hidden;
+    overflow-y: hidden;
+    overflow-x: auto;
     padding-top: 5px;
+    height: 32px;
+    box-sizing: border-box;
 
     &::after, &::before {
       display: block;
@@ -17,20 +25,34 @@
 
     .tab, &::after, &::before {
       border-bottom: 1px solid;
-      border-bottom-color: $fallback--btn;
-      border-bottom-color: var(--btn, $fallback--btn);
+      border-bottom-color: $fallback--border;
+      border-bottom-color: var(--border, $fallback--border);
     }
 
     .tab {
+      position: relative;
       border-bottom-left-radius: 0;
       border-bottom-right-radius: 0;
-      padding: .3em 1em;
+      padding: 5px 1em 99px;
+      white-space: nowrap;
 
       &:not(.active) {
-        border-bottom: 1px solid;
-        border-bottom-color: $fallback--btn;
-        border-bottom-color: var(--btn, $fallback--btn);
         z-index: 4;
+
+        &:hover {
+          z-index: 6;
+        }
+
+        &::after {
+          content: '';
+          position: absolute;
+          left: 0;
+          right: 0;
+          top: 26px;
+          border-bottom: 1px solid;
+          border-bottom-color: $fallback--border;
+          border-bottom-color: var(--border, $fallback--border);
+        }
       }
 
       &.active {
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 2dd4376a..bc7f74c2 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -10,7 +10,7 @@
       <button @click.prevent="showNewStatuses" class="loadmore-button" v-if="timeline.newStatusCount > 0 && !timelineError">
         {{$t('timeline.show_new')}}{{newStatusCountStr}}
       </button>
-      <div @click.prevent class="loadmore-text" v-if="!timeline.newStatusCount > 0 && !timelineError">
+      <div @click.prevent class="loadmore-text faint" v-if="!timeline.newStatusCount > 0 && !timelineError">
         {{$t('timeline.up_to_date')}}
       </div>
     </div>
@@ -58,15 +58,7 @@
 
 .timeline {
   .loadmore-text {
-    opacity: 0.8;
-    background-color: transparent;
-    color: $fallback--faint;
-    color: var(--faint, $fallback--faint);
-  }
-
-  .loadmore-error {
-    color: $fallback--fg;
-    color: var(--fg, $fallback--fg);
+    opacity: 1;
   }
 }
 
@@ -79,7 +71,7 @@
   border-color: var(--border, $fallback--border);
   padding: 10px;
   z-index: 1;
-  background-color: $fallback--btn;
-  background-color: var(--btn, $fallback--btn);
+  background-color: $fallback--fg;
+  background-color: var(--panel, $fallback--fg);
 }
 </style>
diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js
index d22d4ec1..e7f19953 100644
--- a/src/components/user_card_content/user_card_content.js
+++ b/src/components/user_card_content/user_card_content.js
@@ -7,14 +7,18 @@ export default {
     return {
       hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined'
         ? this.$store.state.instance.hideUserStats
-        : this.$store.state.config.hideUserStats
+        : this.$store.state.config.hideUserStats,
+      betterShadow: this.$store.state.interface.browserSupport.cssFilter
     }
   },
   computed: {
     headingStyle () {
-      const color = this.$store.state.config.colors.bg
+      const color = this.$store.state.config.customTheme.colors
+            ? this.$store.state.config.customTheme.colors.bg  // v2
+            : this.$store.state.config.colors.bg // v1
+
       if (color) {
-        const rgb = hex2rgb(color)
+        const rgb = (typeof color === 'string') ? hex2rgb(color) : color
         const tintColor = `rgba(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)}, .5)`
         return {
           backgroundColor: `rgb(${Math.floor(rgb.r * 0.53)}, ${Math.floor(rgb.g * 0.56)}, ${Math.floor(rgb.b * 0.59)})`,
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index 4b8a730f..18504277 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -2,20 +2,20 @@
 <div id="heading" class="profile-panel-background" :style="headingStyle">
   <div class="panel-heading text-center">
     <div class='user-info'>
-      <router-link @click.native="activatePanel('timeline')" to='/user-settings' style="float: right; margin-top:16px;" v-if="!isOtherUser">
+      <router-link @click.native="activatePanel && activatePanel('timeline')" to='/user-settings' style="float: right; margin-top:16px;" v-if="!isOtherUser">
         <i class="icon-cog usersettings" :title="$t('tool_tip.user_settings')"></i>
       </router-link>
       <a :href="user.statusnet_profile_url" target="_blank" class="floater" v-if="isOtherUser">
         <i class="icon-link-ext usersettings"></i>
       </a>
       <div class='container'>
-        <router-link :to="{ name: 'user-profile', params: { id: user.id } }">
-          <StillImage class="avatar" :src="user.profile_image_url_original"/>
+        <router-link @click.native="activatePanel && activatePanel('timeline')" :to="{ name: 'user-profile', params: { id: user.id } }">
+          <StillImage class="avatar" :class='{ "better-shadow": betterShadow }' :src="user.profile_image_url_original"/>
         </router-link>
         <div class="name-and-screen-name">
           <div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div>
           <div :title="user.name" class='user-name' v-else>{{user.name}}</div>
-          <router-link class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }">
+          <router-link @click.native="activatePanel && activatePanel('timeline')" class='user-screen-name':to="{ name: 'user-profile', params: { id: user.id } }">
             <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span>
             <span v-if="!hideUserStatsLocal" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span>
           </router-link>
@@ -41,74 +41,74 @@
         </div>
       </div>
       <div v-if="isOtherUser" class="user-interactions">
-          <div class="follow" v-if="loggedIn">
-            <span v-if="user.following">
-              <!--Following them!-->
-              <button @click="unfollowUser" class="pressed">
-                {{ $t('user_card.following') }}
-              </button>
-            </span>
-            <span v-if="!user.following">
-              <button @click="followUser">
-                {{ $t('user_card.follow') }}
-              </button>
-            </span>
-          </div>
-          <div class='mute' v-if='isOtherUser'>
-            <span v-if='user.muted'>
-              <button @click="toggleMute" class="pressed">
-                {{ $t('user_card.muted') }}
-              </button>
-            </span>
-            <span v-if='!user.muted'>
-              <button @click="toggleMute">
-                {{ $t('user_card.mute') }}
-              </button>
-            </span>
-          </div>
-          <div class="remote-follow" v-if='!loggedIn && user.is_local'>
-            <form method="POST" :action='subscribeUrl'>
-              <input type="hidden" name="nickname" :value="user.screen_name">
-              <input type="hidden" name="profile" value="">
-              <button click="submit" class="remote-button">
-                {{ $t('user_card.remote_follow') }}
-              </button>
-            </form>
-          </div>
-          <div class='block' v-if='isOtherUser && loggedIn'>
-            <span v-if='user.statusnet_blocking'>
-              <button @click="unblockUser" class="pressed">
-                {{ $t('user_card.blocked') }}
-              </button>
-            </span>
-            <span v-if='!user.statusnet_blocking'>
-              <button @click="blockUser">
-                {{ $t('user_card.block') }}
-              </button>
-            </span>
-          </div>
+        <div class="follow" v-if="loggedIn">
+          <span v-if="user.following">
+            <!--Following them!-->
+            <button @click="unfollowUser" class="pressed">
+              {{ $t('user_card.following') }}
+            </button>
+          </span>
+          <span v-if="!user.following">
+            <button @click="followUser">
+              {{ $t('user_card.follow') }}
+            </button>
+          </span>
+        </div>
+        <div class='mute' v-if='isOtherUser'>
+          <span v-if='user.muted'>
+            <button @click="toggleMute" class="pressed">
+              {{ $t('user_card.muted') }}
+            </button>
+          </span>
+          <span v-if='!user.muted'>
+            <button @click="toggleMute">
+              {{ $t('user_card.mute') }}
+            </button>
+          </span>
+        </div>
+        <div class="remote-follow" v-if='!loggedIn && user.is_local'>
+          <form method="POST" :action='subscribeUrl'>
+            <input type="hidden" name="nickname" :value="user.screen_name">
+            <input type="hidden" name="profile" value="">
+            <button click="submit" class="remote-button">
+              {{ $t('user_card.remote_follow') }}
+            </button>
+          </form>
+        </div>
+        <div class='block' v-if='isOtherUser && loggedIn'>
+          <span v-if='user.statusnet_blocking'>
+            <button @click="unblockUser" class="pressed">
+              {{ $t('user_card.blocked') }}
+            </button>
+          </span>
+          <span v-if='!user.statusnet_blocking'>
+            <button @click="blockUser">
+              {{ $t('user_card.block') }}
+            </button>
+          </span>
         </div>
       </div>
     </div>
-    <div class="panel-body profile-panel-body">
-      <div v-if="!hideUserStatsLocal || switcher" class="user-counts" :class="{clickable: switcher}">
-        <div class="user-count" v-on:click.prevent="setProfileView('statuses')" :class="{selected: selected === 'statuses'}">
-          <h5>{{ $t('user_card.statuses') }}</h5>
-          <span v-if="!hideUserStatsLocal">{{user.statuses_count}} <br></span>
-        </div>
-        <div class="user-count" v-on:click.prevent="setProfileView('friends')" :class="{selected: selected === 'friends'}">
-          <h5>{{ $t('user_card.followees') }}</h5>
-          <span v-if="!hideUserStatsLocal">{{user.friends_count}}</span>
-        </div>
-        <div class="user-count" v-on:click.prevent="setProfileView('followers')" :class="{selected: selected === 'followers'}">
-          <h5>{{ $t('user_card.followers') }}</h5>
-          <span v-if="!hideUserStatsLocal">{{user.followers_count}}</span>
-        </div>
-      </div>
-      <p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p>
-      <p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p>
-    </div>
   </div>
+  <div class="panel-body profile-panel-body" v-if="switcher">
+    <div v-if="!hideUserStatsLocal || switcher" class="user-counts" :class="{clickable: switcher}">
+      <div class="user-count" v-on:click.prevent="setProfileView('statuses')" :class="{selected: selected === 'statuses'}">
+        <h5>{{ $t('user_card.statuses') }}</h5>
+        <span v-if="!hideUserStatsLocal">{{user.statuses_count}} <br></span>
+      </div>
+      <div class="user-count" v-on:click.prevent="setProfileView('friends')" :class="{selected: selected === 'friends'}">
+        <h5>{{ $t('user_card.followees') }}</h5>
+        <span v-if="!hideUserStatsLocal">{{user.friends_count}}</span>
+      </div>
+      <div class="user-count" v-on:click.prevent="setProfileView('followers')" :class="{selected: selected === 'followers'}">
+        <h5>{{ $t('user_card.followers') }}</h5>
+        <span v-if="!hideUserStatsLocal">{{user.followers_count}}</span>
+      </div>
+    </div>
+    <p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p>
+    <p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p>
+  </div>
+</div>
 </template>
 
 <script src="./user_card_content.js"></script>
@@ -120,10 +120,12 @@
   background-size: cover;
   border-radius: $fallback--panelRadius;
   border-radius: var(--panelRadius, $fallback--panelRadius);
+  overflow: hidden;
 
   .panel-heading {
     padding: 0.6em 0em;
     text-align: center;
+    box-shadow: none;
   }
 }
 
@@ -138,15 +140,14 @@
 }
 
 .user-info {
-  color: $fallback--lightFg;
-  color: var(--lightFg, $fallback--lightFg);
+  color: $fallback--lightText;
+  color: var(--lightText, $fallback--lightText);
   padding: 0 16px;
 
   .container {
     padding: 16px 10px 6px 10px;
     display: flex;
     max-height: 56px;
-    overflow: hidden;
 
     .avatar {
       border-radius: $fallback--avatarRadius;
@@ -155,8 +156,14 @@
       width: 56px;
       height: 56px;
       box-shadow: 0px 1px 8px rgba(0,0,0,0.75);
+      box-shadow: var(--avatarShadow);
       object-fit: cover;
 
+      &.better-shadow {
+        box-shadow: var(--avatarShadowInset);
+        filter: var(--avatarShadowFilter)
+      }
+
       &.animated::before {
         display: none;
       }
@@ -173,8 +180,8 @@
   }
 
   .usersettings {
-    color: $fallback--lightFg;
-    color: var(--lightFg, $fallback--lightFg);
+    color: $fallback--lightText;
+    color: var(--lightText, $fallback--lightText);
     opacity: .8;
   }
 
@@ -185,6 +192,16 @@
     text-overflow: ellipsis;
     white-space: nowrap;
     flex: 1 1 0;
+    // This is so that text doesn't get overlapped by avatar's shadow if it has
+    // big one
+    z-index: 1;
+
+    img {
+      width: 26px;
+      height: 26px;
+      vertical-align: middle;
+      object-fit: contain
+    }
   }
 
   .user-name{
@@ -193,8 +210,8 @@
   }
 
   .user-screen-name {
-    color: $fallback--lightFg;
-    color: var(--lightFg, $fallback--lightFg);
+    color: $fallback--lightText;
+    color: var(--lightText, $fallback--lightText);
     display: inline-block;
     font-weight: light;
     font-size: 15px;
@@ -269,8 +286,8 @@
   padding: .5em 1.5em 0em 1.5em;
   text-align: center;
   justify-content: space-between;
-  color: $fallback--lightFg;
-  color: var(--lightFg, $fallback--lightFg);
+  color: $fallback--lightText;
+  color: var(--lightText, $fallback--lightText);
 
   &.clickable {
     .user-count {
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 76224a03..eebf606a 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -72,7 +72,15 @@
     "fullname": "Display name",
     "password_confirm": "Password confirmation",
     "registration": "Registration",
-    "token": "Invite token"
+    "token": "Invite token",
+    "validations": {
+      "username_required": "cannot be left blank",
+      "fullname_required": "cannot be left blank",
+      "email_required": "cannot be left blank",
+      "password_required": "cannot be left blank",
+      "password_confirmation_required": "cannot be left blank",
+      "password_confirmation_match": "should be the same as password"
+    }
   },
   "settings": {
     "attachmentRadius": "Attachments",
@@ -116,13 +124,17 @@
     "general": "General",
     "hide_attachments_in_convo": "Hide attachments in conversations",
     "hide_attachments_in_tl": "Hide attachments in timeline",
+    "hide_isp": "Hide instance-specific panel",
+    "preload_images": "Preload images",
     "hide_post_stats": "Hide post statistics (e.g. the number of favorites)",
     "hide_user_stats": "Hide user statistics (e.g. the number of followers)",
     "import_followers_from_a_csv_file": "Import follows from a csv file",
     "import_theme": "Load preset",
     "inputRadius": "Input fields",
+    "checkboxRadius": "Checkboxes",
     "instance_default": "(default: {value})",
-    "instance_default_simple" : "(default)",
+    "instance_default_simple": "(default)",
+    "interface": "Interface",
     "interfaceLanguage": "Interface language",
     "invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.",
     "limited_availability": "Unavailable in your browser",
@@ -170,6 +182,8 @@
     "text": "Text",
     "theme": "Theme",
     "theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
+    "theme_help_v2_1": "You can also override certain component's colors and opacity by toggling the checkbox, use \"Clear all\" button to clear all overrides.",
+    "theme_help_v2_2": "Icons underneath some entries are background/text contrast indicators, hover over for detailed info. Please keep in mind that when using transparency contrast indicators show the worst possible case.",
     "tooltipRadius": "Tooltips/alerts",
     "user_settings": "User Settings",
     "values": {
@@ -177,7 +191,116 @@
       "true": "yes"
     },
     "notifications": "Notifications",
-    "enable_web_push_notifications": "Enable web push notifications"
+    "enable_web_push_notifications": "Enable web push notifications",
+    "style": {
+      "switcher": {
+        "keep_color": "Keep colors",
+        "keep_shadows": "Keep shadows",
+        "keep_opacity": "Keep opacity",
+        "keep_roundness": "Keep roundness",
+        "keep_fonts": "Keep fonts",
+        "save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme. When all checkboxes unset, exporting theme will save everything.",
+        "reset": "Reset",
+        "clear_all": "Clear all",
+        "clear_opacity": "Clear opacity"
+      },
+      "common": {
+        "color": "Color",
+        "opacity": "Opacity",
+        "contrast": {
+          "hint": "Contrast ratio is {ratio}, it {level} {context}",
+          "level": {
+            "aa": "meets Level AA guideline (minimal)",
+            "aaa": "meets Level AAA guideline (recommended)",
+            "bad": "doesn't meet any accessibility guidelines"
+          },
+          "context": {
+            "18pt": "for large (18pt+) text",
+            "text": "for text"
+          }
+        }
+      },
+      "common_colors": {
+        "_tab_label": "Common",
+        "main": "Common colors",
+        "foreground_hint": "See \"Advanced\" tab for more detailed control",
+        "rgbo": "Icons, accents, badges"
+      },
+      "advanced_colors": {
+        "_tab_label": "Advanced",
+        "alert": "Alert background",
+        "alert_error": "Error",
+        "badge": "Badge background",
+        "badge_notification": "Notification",
+        "panel_header": "Panel header",
+        "top_bar": "Top bar",
+        "borders": "Borders",
+        "buttons": "Buttons",
+        "inputs": "Input fields",
+        "faint_text": "Faded text"
+      },
+      "radii": {
+        "_tab_label": "Roundness"
+      },
+      "shadows": {
+        "_tab_label": "Shadow and lighting",
+        "component": "Component",
+        "override": "Override",
+        "shadow_id": "Shadow #{value}",
+        "blur": "Blur",
+        "spread": "Spread",
+        "inset": "Inset",
+        "hint": "For shadows you can also use --variable as a color value to use CSS3 variables. Please note that setting opacity won't work in this case.",
+        "filter_hint": {
+          "always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.",
+          "drop_shadow_syntax": "{0} does not support {1} parameter and {2} keyword.",
+          "avatar_inset": "Please note that combining both inset and non-inset shadows on avatars might give unexpected results with transparent avatars.",
+          "spread_zero": "Shadows with spread > 0 will appear as if it was set to zero",
+          "inset_classic": "Inset shadows will be using {0}"
+        },
+        "components": {
+          "panel": "Panel",
+          "panelHeader": "Panel header",
+          "topBar": "Top bar",
+          "avatar": "User avatar (in profile view)",
+          "avatarStatus": "User avatar (in post display)",
+          "popup": "Popups and tooltips",
+          "button": "Button",
+          "buttonHover": "Button (hover)",
+          "buttonPressed": "Button (pressed)",
+          "buttonPressedHover": "Button (pressed+hover)",
+          "input": "Input field"
+        }
+      },
+      "fonts": {
+        "_tab_label": "Fonts",
+        "help": "Select font to use for elements of UI. For \"custom\" you have to enter exact font name as it appears in system.",
+        "components": {
+          "interface": "Interface",
+          "input": "Input fields",
+          "post": "Post text",
+          "postCode": "Monospaced text in a post (rich text)"
+        },
+        "family": "Font name",
+        "size": "Size (in px)",
+        "weight": "Weight (boldness)",
+        "custom": "Custom"
+      },
+      "preview": {
+        "header": "Preview",
+        "content": "Content",
+        "error": "Example error",
+        "button": "Button",
+        "text": "A bunch of more {0} and {1}",
+        "mono": "content",
+        "input": "Just landed in L.A.",
+        "faint_link": "helpful manual",
+        "fine_print": "Read our {0} to learn nothing useful!",
+        "header_faint": "This is fine",
+        "checkbox": "I have skimmed over terms and conditions",
+        "link": "a nice lil' link"
+      }
+    }
   },
   "timeline": {
     "collapse": "Collapse",
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index 9c28ccf4..c764005a 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -55,7 +55,15 @@
     "fullname": "Отображаемое имя",
     "password_confirm": "Подтверждение пароля",
     "registration": "Регистрация",
-    "token": "Код приглашения"
+    "token": "Код приглашения",
+    "validations": {
+      "username_required": "не должно быть пустым",
+      "fullname_required": "не должно быть пустым",
+      "email_required": "не должен быть пустым",
+      "password_required": "не должен быть пустым",
+      "password_confirmation_required": "не должно быть пустым",
+      "password_confirmation_match": "должно совпадать с паролем"
+    }
   },
   "settings": {
     "attachmentRadius": "Прикреплённые файлы",
@@ -97,9 +105,12 @@
     "general": "Общие",
     "hide_attachments_in_convo": "Прятать вложения в разговорах",
     "hide_attachments_in_tl": "Прятать вложения в ленте",
+    "hide_isp": "Скрыть серверную панель",
     "import_followers_from_a_csv_file": "Импортировать читаемых из файла .csv",
     "import_theme": "Загрузить Тему",
     "inputRadius": "Поля ввода",
+    "checkboxRadius": "Чекбоксы",
+    "interface": "Интерфейс",
     "interfaceLanguage": "Язык интерфейса",
     "limited_availability": "Не доступно в вашем браузере",
     "links": "Ссылки",
@@ -139,8 +150,119 @@
     "text": "Текст",
     "theme": "Тема",
     "theme_help": "Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.",
+    "theme_help_v2_1": "Вы так же можете перепоределить цвета определенных компонентов нажав соотв. галочку. Используйте кнопку \"Очистить всё\" чтобы снять все переопределения",
+    "theme_help_v2_2": "Под некоторыми полями ввода это идикаторы контрастности, наведите на них мышью чтобы узнать больше. Приспользовании прозрачности контраст расчитывается для наихудшего варианта.",
     "tooltipRadius": "Всплывающие подсказки/уведомления",
-    "user_settings": "Настройки пользователя"
+    "user_settings": "Настройки пользователя",
+    "style": {
+      "switcher": {
+        "keep_color": "Оставить цвета",
+        "keep_shadows": "Оставить тени",
+        "keep_opacity": "Оставить прозрачность",
+        "keep_roundness": "Оставить скругление",
+        "keep_fonts": "Оставить шрифты",
+        "save_load_hint": "Опции \"оставить...\" позволяют сохранить текущие настройки при выборе другой темы или импорта её из файла. Так же они влияют на то какие компоненты будут сохранены при экспорте темы. Когда все галочки сняты все компоненты будут экспортированы.",
+        "reset": "Сбросить",
+        "clear_all": "Очистить всё",
+        "clear_opacity": "Очистить прозрачность"
+      },
+      "common": {
+        "color": "Цвет",
+        "opacity": "Прозрачность",
+        "contrast": {
+          "hint": "Уровень контраста: {ratio}, что {level} {context}",
+          "level": {
+            "aa": "соответствует гайдлайну Level AA (минимальный)",
+            "aaa": "соответствует гайдлайну Level AAA (рекомендуемый)",
+            "bad": "не соответствует каким либо гайдлайнам"
+          },
+          "context": {
+            "18pt": "для крупного (18pt+) текста",
+            "text": "для текста"
+          }
+        }
+      },
+      "common_colors": {
+        "_tab_label": "Общие",
+        "main": "Общие цвета",
+        "foreground_hint": "См. вкладку \"Дополнительно\" для более детального контроля",
+        "rgbo": "Иконки, акценты, ярылки"
+      },
+      "advanced_colors": {
+        "_tab_label": "Дополнительно",
+        "alert": "Фон уведомлений",
+        "alert_error": "Ошибки",
+        "badge": "Фон значков",
+        "badge_notification": "Уведомления",
+        "panel_header": "Заголовок панели",
+        "top_bar": "Верняя полоска",
+        "borders": "Границы",
+        "buttons": "Кнопки",
+        "inputs": "Поля ввода",
+        "faint_text": "Маловажный текст"
+      },
+      "radii": {
+        "_tab_label": "Скругление"
+      },
+      "shadows": {
+        "_tab_label": "Светотень",
+        "component": "Компонент",
+        "override": "Переопределить",
+        "shadow_id": "Тень №{value}",
+        "blur": "Размытие",
+        "spread": "Разброс",
+        "inset": "Внутренняя",
+        "hint": "Для теней вы так же можете использовать --variable в качестве цвета чтобы использовать CSS3-переменные. В таком случае прозрачность работать не будет.",
+        "filter_hint": {
+          "always_drop_shadow": "Внимание, эта тень всегда использует {0} когда браузер поддерживает это",
+          "drop_shadow_syntax": "{0} не поддерживает параметр {1} и ключевое слово {2}",
+          "avatar_inset": "Одновременное использование внутренних и внешних теней на (прозрачных) аватарках может дать не те результаты что вы ожидаете",
+          "spread_zero": "Тени с разбросом > 0 будут выглядеть как если бы разброс установлен в 0",
+          "inset_classic": "Внутренние тени будут использовать {0}"
+        },
+        "components": {
+          "panel": "Панель",
+          "panelHeader": "Заголовок панели",
+          "topBar": "Верхняя полоска",
+          "avatar": "Аватарка (профиль)",
+          "avatarStatus": "Аватарка (в ленте)",
+          "popup": "Всплывающие подсказки",
+          "button": "Кнопки",
+          "buttonHover": "Кнопки (наведен курсор)",
+          "buttonPressed": "Кнопки (нажата)",
+          "buttonPressedHover": "Кнопки (нажата+наведен курсор)",
+          "input": "Поля ввода"
+        }
+      },
+      "fonts": {
+        "_tab_label": "Шрифты",
+        "help": "Выберите тип шрифта для использования в интерфейсе. При выборе варианта \"другой\" надо ввести название шрифта в точности как он называется в системе.",
+        "components": {
+          "interface": "Интерфейс",
+          "input": "Поля ввода",
+          "post": "Текст постов",
+          "postCode": "Моноширинный текст в посте (форматирование)"
+        },
+        "family": "Шрифт",
+        "size": "Размер (в пикселях)",
+        "weight": "Ширина",
+        "custom": "Другой"
+      },
+      "preview": {
+        "header": "Пример",
+        "content": "Контент",
+        "error": "Ошибка стоп 000",
+        "button": "Кнопка",
+        "text": "Еще немного {0} и масенькая {1}",
+        "mono": "контента",
+        "input": "Что нового?",
+        "faint_link": "Его придется убрать",
+        "fine_print": "Если проблемы остались — ваш гуртовщик мыши плохо стоит. {0}.",
+        "header_faint": "Все идет по плану",
+        "checkbox": "Я подтверждаю что не было ни единого разрыва",
+        "link": "ссылка"
+      }
+    }
   },
   "timeline": {
     "collapse": "Свернуть",
diff --git a/src/lib/persisted_state.js b/src/lib/persisted_state.js
index 32fc93c6..ccd92633 100644
--- a/src/lib/persisted_state.js
+++ b/src/lib/persisted_state.js
@@ -75,6 +75,7 @@ export default function createPersistedState ({
         loaded = true
       } catch (e) {
         console.log("Couldn't load state")
+        console.error(e)
         loaded = true
       }
       subscriber(store)((mutation, state) => {
diff --git a/src/modules/config.js b/src/modules/config.js
index 1ad9df07..ccfd0190 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -1,5 +1,5 @@
 import { set, delete as del } from 'vue'
-import StyleSetter from '../services/style_setter/style_setter.js'
+import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
 
 const browserLocale = (window.navigator.language || 'en').split('-')[0]
 
@@ -9,6 +9,7 @@ const defaultState = {
   hideAttachments: false,
   hideAttachmentsInConv: false,
   hideNsfw: true,
+  preloadImage: true,
   loopVideo: true,
   loopVideoSilentOnly: true,
   autoLoad: true,
@@ -55,10 +56,10 @@ const config = {
       commit('setOption', {name, value})
       switch (name) {
         case 'theme':
-          StyleSetter.setPreset(value, commit)
+          setPreset(value, commit)
           break
         case 'customTheme':
-          StyleSetter.setColors(value, commit)
+          applyTheme(value, commit)
       }
     }
   }
diff --git a/src/modules/errors.js b/src/modules/errors.js
new file mode 100644
index 00000000..c809e1b5
--- /dev/null
+++ b/src/modules/errors.js
@@ -0,0 +1,12 @@
+import { capitalize } from 'lodash'
+
+export function humanizeErrors (errors) {
+  return Object.entries(errors).reduce((errs, [k, val]) => {
+    let message = val.reduce((acc, message) => {
+      let key = capitalize(k.replace(/_/g, ' '))
+      return acc + [key, message].join(' ') + '. '
+    }, '')
+    return [...errs, message]
+  }, [])
+}
+
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 641424b6..7c27d52a 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -1,5 +1,5 @@
 import { set } from 'vue'
-import StyleSetter from '../services/style_setter/style_setter.js'
+import { setPreset } from '../services/style_setter/style_setter.js'
 
 const defaultState = {
   // Stuff from static/config.json and apiConfig
@@ -60,7 +60,7 @@ const instance = {
           dispatch('setPageTitle')
           break
         case 'theme':
-          StyleSetter.setPreset(value, commit)
+          setPreset(value, commit)
       }
     }
   }
diff --git a/src/modules/interface.js b/src/modules/interface.js
index 5abc2c81..956c9cb3 100644
--- a/src/modules/interface.js
+++ b/src/modules/interface.js
@@ -5,6 +5,12 @@ const defaultState = {
     currentSaveStateNotice: null,
     noticeClearTimeout: null,
     notificationPermission: null
+  },
+  browserSupport: {
+    cssFilter: window.CSS && window.CSS.supports && (
+      window.CSS.supports('filter', 'drop-shadow(0 0)') ||
+      window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)')
+    )
   }
 }
 
diff --git a/src/modules/users.js b/src/modules/users.js
index e4fa472d..d2ac95cd 100644
--- a/src/modules/users.js
+++ b/src/modules/users.js
@@ -2,6 +2,8 @@ import backendInteractorService from '../services/backend_interactor_service/bac
 import { compact, map, each, merge } from 'lodash'
 import { set } from 'vue'
 import registerPushNotifications from '../services/push/push.js'
+import oauthApi from '../services/new_api/oauth'
+import { humanizeErrors } from './errors'
 
 // TODO: Unify with mergeOrAdd in statuses.js
 export const mergeOrAdd = (arr, obj, item) => {
@@ -10,12 +12,12 @@ export const mergeOrAdd = (arr, obj, item) => {
   if (oldItem) {
     // We already have this, so only merge the new info.
     merge(oldItem, item)
-    return {item: oldItem, new: false}
+    return { item: oldItem, new: false }
   } else {
     // This is a new item, prepare it
     arr.push(item)
     obj[item.id] = item
-    return {item, new: true}
+    return { item, new: true }
   }
 }
 
@@ -28,7 +30,7 @@ const getNotificationPermission = () => {
 }
 
 export const mutations = {
-  setMuted (state, { user: {id}, muted }) {
+  setMuted (state, { user: { id }, muted }) {
     const user = state.usersObject[id]
     set(user, 'muted', muted)
   },
@@ -52,18 +54,31 @@ export const mutations = {
   setUserForStatus (state, status) {
     status.user = state.usersObject[status.user.id]
   },
-  setColor (state, { user: {id}, highlighted }) {
+  setColor (state, { user: { id }, highlighted }) {
     const user = state.usersObject[id]
     set(user, 'highlight', highlighted)
+  },
+  signUpPending (state) {
+    state.signUpPending = true
+    state.signUpErrors = []
+  },
+  signUpSuccess (state) {
+    state.signUpPending = false
+  },
+  signUpFailure (state, errors) {
+    state.signUpPending = false
+    state.signUpErrors = errors
   }
 }
 
 export const defaultState = {
+  loggingIn: false,
   lastLoginName: false,
   currentUser: false,
-  loggingIn: false,
   users: [],
-  usersObject: {}
+  usersObject: {},
+  signUpPending: false,
+  signUpErrors: []
 }
 
 const users = {
@@ -71,7 +86,7 @@ const users = {
   mutations,
   actions: {
     fetchUser (store, id) {
-      store.rootState.api.backendInteractor.fetchUser({id})
+      store.rootState.api.backendInteractor.fetchUser({ id })
         .then((user) => store.commit('addNewUsers', user))
     },
     registerPushNotifications (store) {
@@ -96,6 +111,34 @@ const users = {
         store.commit('setUserForStatus', status)
       })
     },
+    async signUp (store, userInfo) {
+      store.commit('signUpPending')
+
+      let rootState = store.rootState
+
+      let response = await rootState.api.backendInteractor.register(userInfo)
+      if (response.ok) {
+        const data = {
+          oauth: rootState.oauth,
+          instance: rootState.instance.server
+        }
+        let app = await oauthApi.getOrCreateApp(data)
+        let result = await oauthApi.getTokenWithCredentials({
+          app,
+          instance: data.instance,
+          username: userInfo.username,
+          password: userInfo.password
+        })
+        store.commit('signUpSuccess')
+        store.commit('setToken', result.access_token)
+        store.dispatch('loginUser', result.access_token)
+      } else {
+        let data = await response.json()
+        let errors = humanizeErrors(JSON.parse(data.error))
+        store.commit('signUpFailure', errors)
+        throw Error(errors)
+      }
+    },
     logout (store) {
       store.commit('clearCurrentUser')
       store.commit('setToken', false)
@@ -138,7 +181,7 @@ const users = {
                   })
 
                   // Fetch our friends
-                  store.rootState.api.backendInteractor.fetchFriends({id: user.id})
+                  store.rootState.api.backendInteractor.fetchFriends({ id: user.id })
                     .then((friends) => commit('addNewUsers', friends))
                 })
             } else {
diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js
index 13dd8979..7576c518 100644
--- a/src/services/color_convert/color_convert.js
+++ b/src/services/color_convert/color_convert.js
@@ -1,6 +1,15 @@
 import { map } from 'lodash'
 
 const rgb2hex = (r, g, b) => {
+  if (r === null || typeof r === 'undefined') {
+    return undefined
+  }
+  if (r[0] === '#') {
+    return r
+  }
+  if (typeof r === 'object') {
+    ({ r, g, b } = r)
+  }
   [r, g, b] = map([r, g, b], (val) => {
     val = Math.ceil(val)
     val = val < 0 ? 0 : val
@@ -10,6 +19,91 @@ const rgb2hex = (r, g, b) => {
   return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}`
 }
 
+/**
+ * Converts 8-bit RGB component into linear component
+ * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ * https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml
+ * https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
+ *
+ * @param {Number} bit - color component [0..255]
+ * @returns {Number} linear component [0..1]
+ */
+const c2linear = (bit) => {
+  // W3C gives 0.03928 while wikipedia states 0.04045
+  // what those magical numbers mean - I don't know.
+  // something about gamma-correction, i suppose.
+  // Sticking with W3C example.
+  const c = bit / 255
+  if (c < 0.03928) {
+    return c / 12.92
+  } else {
+    return Math.pow((c + 0.055) / 1.055, 2.4)
+  }
+}
+
+/**
+ * Converts sRGB into linear RGB
+ * @param {Object} srgb - sRGB color
+ * @returns {Object} linear rgb color
+ */
+const srgbToLinear = (srgb) => {
+  return 'rgb'.split('').reduce((acc, c) => { acc[c] = c2linear(srgb[c]); return acc }, {})
+}
+
+/**
+ * Calculates relative luminance for given color
+ * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
+ * https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml
+ *
+ * @param {Object} srgb - sRGB color
+ * @returns {Number} relative luminance
+ */
+const relativeLuminance = (srgb) => {
+  const {r, g, b} = srgbToLinear(srgb)
+  return 0.2126 * r + 0.7152 * g + 0.0722 * b
+}
+
+/**
+ * Generates color ratio between two colors. Order is unimporant
+ * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef
+ *
+ * @param {Object} a - sRGB color
+ * @param {Object} b - sRGB color
+ * @returns {Number} color ratio
+ */
+const getContrastRatio = (a, b) => {
+  const la = relativeLuminance(a)
+  const lb = relativeLuminance(b)
+  const [l1, l2] = la > lb ? [la, lb] : [lb, la]
+
+  return (l1 + 0.05) / (l2 + 0.05)
+}
+
+/**
+ * This performs alpha blending between solid background and semi-transparent foreground
+ *
+ * @param {Object} fg - top layer color
+ * @param {Number} fga - top layer's alpha
+ * @param {Object} bg - bottom layer color
+ * @returns {Object} sRGB of resulting color
+ */
+const alphaBlend = (fg, fga, bg) => {
+  if (fga === 1 || typeof fga === 'undefined') return fg
+  return 'rgb'.split('').reduce((acc, c) => {
+    // Simplified https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
+    // for opaque bg and transparent fg
+    acc[c] = (fg[c] * fga + bg[c] * (1 - fga))
+    return acc
+  }, {})
+}
+
+const invert = (rgb) => {
+  return 'rgb'.split('').reduce((acc, c) => {
+    acc[c] = 255 - rgb[c]
+    return acc
+  }, {})
+}
+
 const hex2rgb = (hex) => {
   const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
   return result ? {
@@ -19,16 +113,18 @@ const hex2rgb = (hex) => {
   } : null
 }
 
-const rgbstr2hex = (rgb) => {
-  if (rgb[0] === '#') {
-    return rgb
-  }
-  rgb = rgb.match(/\d+/g)
-  return `#${((Number(rgb[0]) << 16) + (Number(rgb[1]) << 8) + Number(rgb[2])).toString(16)}`
+const mixrgb = (a, b) => {
+  return Object.keys(a).reduce((acc, k) => {
+    acc[k] = (a[k] + b[k]) / 2
+    return acc
+  }, {})
 }
 
 export {
   rgb2hex,
   hex2rgb,
-  rgbstr2hex
+  mixrgb,
+  invert,
+  getContrastRatio,
+  alphaBlend
 }
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 493d444e..10e7ed9b 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,5 +1,6 @@
 import { times } from 'lodash'
-import { rgb2hex, hex2rgb } from '../color_convert/color_convert.js'
+import { brightness, invertLightness, convert, contrastRatio } from 'chromatism'
+import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend } from '../color_convert/color_convert.js'
 
 // While this is not used anymore right now, I left it in if we want to do custom
 // styles that aren't just colors, so user can pick from a few different distinct
@@ -39,8 +40,6 @@ const setStyle = (href, commit) => {
       colors[name] = color
     })
 
-    commit('setOption', { name: 'colors', value: colors })
-
     body.removeChild(baseEl)
 
     const styleEl = document.createElement('style')
@@ -53,7 +52,27 @@ const setStyle = (href, commit) => {
   cssEl.addEventListener('load', setDynamic)
 }
 
-const setColors = (col, commit) => {
+const rgb2rgba = function (rgba) {
+  return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`
+}
+
+const getTextColor = function (bg, text, preserve) {
+  const bgIsLight = convert(bg).hsl.l > 50
+  const textIsLight = convert(text).hsl.l > 50
+
+  if ((bgIsLight && textIsLight) || (!bgIsLight && !textIsLight)) {
+    const base = typeof text.a !== 'undefined' ? { a: text.a } : {}
+    const result = Object.assign(base, invertLightness(text).rgb)
+    if (!preserve && getContrastRatio(bg, result) < 4.5) {
+      return contrastRatio(bg, text).rgb
+    }
+    return result
+  }
+  return text
+}
+
+const applyTheme = (input, commit) => {
+  const { rules, theme } = generatePreset(input)
   const head = document.head
   const body = document.body
   body.style.display = 'none'
@@ -62,56 +81,411 @@ const setColors = (col, commit) => {
   head.appendChild(styleEl)
   const styleSheet = styleEl.sheet
 
-  const isDark = (col.text.r + col.text.g + col.text.b) > (col.bg.r + col.bg.g + col.bg.b)
-  let colors = {}
-  let radii = {}
-
-  const mod = isDark ? -10 : 10
-
-  colors.bg = rgb2hex(col.bg.r, col.bg.g, col.bg.b)                         // background
-  colors.lightBg = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg
-  colors.btn = rgb2hex(col.fg.r, col.fg.g, col.fg.b)                         // panels & buttons
-  colors.input = `rgba(${col.fg.r}, ${col.fg.g}, ${col.fg.b}, .5)`
-  colors.border = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod)       // borders
-  colors.faint = `rgba(${col.text.r}, ${col.text.g}, ${col.text.b}, .5)`
-  colors.fg = rgb2hex(col.text.r, col.text.g, col.text.b)                   // text
-  colors.lightFg = rgb2hex(col.text.r - mod * 5, col.text.g - mod * 5, col.text.b - mod * 5) // strong text
-
-  colors['base07'] = rgb2hex(col.text.r - mod * 2, col.text.g - mod * 2, col.text.b - mod * 2)
-
-  colors.link = rgb2hex(col.link.r, col.link.g, col.link.b)                   // links
-  colors.icon = rgb2hex((col.bg.r + col.text.r) / 2, (col.bg.g + col.text.g) / 2, (col.bg.b + col.text.b) / 2) // icons
-
-  colors.cBlue = col.cBlue && rgb2hex(col.cBlue.r, col.cBlue.g, col.cBlue.b)
-  colors.cRed = col.cRed && rgb2hex(col.cRed.r, col.cRed.g, col.cRed.b)
-  colors.cGreen = col.cGreen && rgb2hex(col.cGreen.r, col.cGreen.g, col.cGreen.b)
-  colors.cOrange = col.cOrange && rgb2hex(col.cOrange.r, col.cOrange.g, col.cOrange.b)
-
-  colors.cAlertRed = col.cRed && `rgba(${col.cRed.r}, ${col.cRed.g}, ${col.cRed.b}, .5)`
-
-  radii.btnRadius = col.btnRadius
-  radii.inputRadius = col.inputRadius
-  radii.panelRadius = col.panelRadius
-  radii.avatarRadius = col.avatarRadius
-  radii.avatarAltRadius = col.avatarAltRadius
-  radii.tooltipRadius = col.tooltipRadius
-  radii.attachmentRadius = col.attachmentRadius
-
   styleSheet.toString()
-  styleSheet.insertRule(`body { ${Object.entries(colors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';')} }`, 'index-max')
-  styleSheet.insertRule(`body { ${Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';')} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.radii} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.colors} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
   body.style.display = 'initial'
 
-  commit('setOption', { name: 'colors', value: colors })
-  commit('setOption', { name: 'radii', value: radii })
-  commit('setOption', { name: 'customTheme', value: col })
+  // commit('setOption', { name: 'colors', value: htmlColors })
+  // commit('setOption', { name: 'radii', value: radii })
+  commit('setOption', { name: 'customTheme', value: input })
+  commit('setOption', { name: 'colors', value: theme.colors })
+}
+
+const getCssShadow = (input, usesDropShadow) => {
+  if (input.length === 0) {
+    return 'none'
+  }
+
+  return input
+    .filter(_ => usesDropShadow ? _.inset : _)
+    .map((shad) => [
+      shad.x,
+      shad.y,
+      shad.blur,
+      shad.spread
+    ].map(_ => _ + 'px').concat([
+      getCssColor(shad.color, shad.alpha),
+      shad.inset ? 'inset' : ''
+    ]).join(' ')).join(', ')
+}
+
+const getCssShadowFilter = (input) => {
+  if (input.length === 0) {
+    return 'none'
+  }
+
+  return input
+  // drop-shadow doesn't support inset or spread
+    .filter((shad) => !shad.inset && Number(shad.spread) === 0)
+    .map((shad) => [
+      shad.x,
+      shad.y,
+      // drop-shadow's blur is twice as strong compared to box-shadow
+      shad.blur / 2
+    ].map(_ => _ + 'px').concat([
+      getCssColor(shad.color, shad.alpha)
+    ]).join(' '))
+    .map(_ => `drop-shadow(${_})`)
+    .join(' ')
+}
+
+const getCssColor = (input, a) => {
+  let rgb = {}
+  if (typeof input === 'object') {
+    rgb = input
+  } else if (typeof input === 'string') {
+    if (input.startsWith('#')) {
+      rgb = hex2rgb(input)
+    } else if (input.startsWith('--')) {
+      return `var(${input})`
+    } else {
+      return input
+    }
+  }
+  return rgb2rgba({ ...rgb, a })
+}
+
+const generateColors = (input) => {
+  const colors = {}
+  const opacity = Object.assign({
+    alert: 0.5,
+    input: 0.5,
+    faint: 0.5
+  }, Object.entries(input.opacity || {}).reduce((acc, [k, v]) => {
+    if (typeof v !== 'undefined') {
+      acc[k] = v
+    }
+    return acc
+  }, {}))
+  const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => {
+    if (typeof v === 'object') {
+      acc[k] = v
+    } else {
+      acc[k] = hex2rgb(v)
+    }
+    return acc
+  }, {})
+
+  const isLightOnDark = convert(col.bg).hsl.l < convert(col.text).hsl.l
+  const mod = isLightOnDark ? 1 : -1
+
+  colors.text = col.text
+  colors.lightText = brightness(20 * mod, colors.text).rgb
+  colors.link = col.link
+  colors.faint = col.faint || Object.assign({}, col.text)
+
+  colors.bg = col.bg
+  colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb
+
+  colors.fg = col.fg
+  colors.fgText = col.fgText || getTextColor(colors.fg, colors.text)
+  colors.fgLink = col.fgLink || getTextColor(colors.fg, colors.link, true)
+
+  colors.border = col.border || brightness(2 * mod, colors.fg).rgb
+
+  colors.btn = col.btn || Object.assign({}, col.fg)
+  colors.btnText = col.btnText || getTextColor(colors.btn, colors.fgText)
+
+  colors.input = col.input || Object.assign({}, col.fg)
+  colors.inputText = col.inputText || getTextColor(colors.input, colors.lightText)
+
+  colors.panel = col.panel || Object.assign({}, col.fg)
+  colors.panelText = col.panelText || getTextColor(colors.panel, colors.fgText)
+  colors.panelLink = col.panelLink || getTextColor(colors.panel, colors.fgLink)
+  colors.panelFaint = col.panelFaint || getTextColor(colors.panel, colors.faint)
+
+  colors.topBar = col.topBar || Object.assign({}, col.fg)
+  colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText)
+  colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink)
+
+  colors.faintLink = col.faintLink || Object.assign({}, col.link)
+
+  colors.icon = mixrgb(colors.bg, colors.text)
+
+  colors.cBlue = col.cBlue || hex2rgb('#0000FF')
+  colors.cRed = col.cRed || hex2rgb('#FF0000')
+  colors.cGreen = col.cGreen || hex2rgb('#00FF00')
+  colors.cOrange = col.cOrange || hex2rgb('#E3FF00')
+
+  colors.alertError = col.alertError || Object.assign({}, colors.cRed)
+  colors.alertErrorText = getTextColor(alphaBlend(colors.alertError, opacity.alert, colors.bg), colors.text)
+  colors.alertErrorPanelText = getTextColor(alphaBlend(colors.alertError, opacity.alert, colors.panel), colors.panelText)
+
+  colors.badgeNotification = col.badgeNotification || Object.assign({}, colors.cRed)
+  colors.badgeNotificationText = contrastRatio(colors.badgeNotification).rgb
+
+  Object.entries(opacity).forEach(([ k, v ]) => {
+    if (typeof v === 'undefined') return
+    if (k === 'alert') {
+      colors.alertError.a = v
+      return
+    }
+    if (k === 'faint') {
+      colors[k + 'Link'].a = v
+      colors['panelFaint'].a = v
+    }
+    if (k === 'bg') {
+      colors['lightBg'].a = v
+    }
+    if (colors[k]) {
+      colors[k].a = v
+    } else {
+      console.error('Wrong key ' + k)
+    }
+  })
+
+  const htmlColors = Object.entries(colors)
+        .reduce((acc, [k, v]) => {
+          if (!v) return acc
+          acc.solid[k] = rgb2hex(v)
+          acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v)
+          return acc
+        }, { complete: {}, solid: {} })
+  return {
+    rules: {
+      colors: Object.entries(htmlColors.complete)
+        .filter(([k, v]) => v)
+        .map(([k, v]) => `--${k}: ${v}`)
+        .join(';')
+    },
+    theme: {
+      colors: htmlColors.solid,
+      opacity
+    }
+  }
+}
+
+const generateRadii = (input) => {
+  let inputRadii = input.radii || {}
+  // v1 -> v2
+  if (typeof input.btnRadius !== 'undefined') {
+    inputRadii = Object
+      .entries(input)
+      .filter(([k, v]) => k.endsWith('Radius'))
+      .reduce((acc, e) => { acc[e[0].split('Radius')[0]] = e[1]; return acc }, {})
+  }
+  const radii = Object.entries(inputRadii).filter(([k, v]) => v).reduce((acc, [k, v]) => {
+    acc[k] = v
+    return acc
+  }, {
+    btn: 4,
+    input: 4,
+    checkbox: 2,
+    panel: 10,
+    avatar: 5,
+    avatarAlt: 50,
+    tooltip: 2,
+    attachment: 5
+  })
+
+  return {
+    rules: {
+      radii: Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}Radius: ${v}px`).join(';')
+    },
+    theme: {
+      radii
+    }
+  }
+}
+
+const generateFonts = (input) => {
+  const fonts = Object.entries(input.fonts || {}).filter(([k, v]) => v).reduce((acc, [k, v]) => {
+    acc[k] = Object.entries(v).filter(([k, v]) => v).reduce((acc, [k, v]) => {
+      acc[k] = v
+      return acc
+    }, acc[k])
+    return acc
+  }, {
+    interface: {
+      family: 'sans-serif'
+    },
+    input: {
+      family: 'inherit'
+    },
+    post: {
+      family: 'inherit'
+    },
+    postCode: {
+      family: 'monospace'
+    }
+  })
+
+  return {
+    rules: {
+      fonts: Object
+        .entries(fonts)
+        .filter(([k, v]) => v)
+        .map(([k, v]) => `--${k}Font: ${v.family}`).join(';')
+    },
+    theme: {
+      fonts
+    }
+  }
+}
+
+const generateShadows = (input) => {
+  const border = (top, shadow) => ({
+    x: 0,
+    y: top ? 1 : -1,
+    blur: 0,
+    spread: 0,
+    color: shadow ? '#000000' : '#FFFFFF',
+    alpha: 0.2,
+    inset: true
+  })
+  const buttonInsetFakeBorders = [border(true, false), border(false, true)]
+  const inputInsetFakeBorders = [border(true, true), border(false, false)]
+  const hoverGlow = {
+    x: 0,
+    y: 0,
+    blur: 4,
+    spread: 0,
+    color: '--faint',
+    alpha: 1
+  }
+
+  const shadows = {
+    panel: [{
+      x: 1,
+      y: 1,
+      blur: 4,
+      spread: 0,
+      color: '#000000',
+      alpha: 0.6
+    }],
+    topBar: [{
+      x: 0,
+      y: 0,
+      blur: 4,
+      spread: 0,
+      color: '#000000',
+      alpha: 0.6
+    }],
+    popup: [{
+      x: 2,
+      y: 2,
+      blur: 3,
+      spread: 0,
+      color: '#000000',
+      alpha: 0.5
+    }],
+    avatar: [{
+      x: 0,
+      y: 1,
+      blur: 8,
+      spread: 0,
+      color: '#000000',
+      alpha: 0.7
+    }],
+    avatarStatus: [],
+    panelHeader: [],
+    button: [{
+      x: 0,
+      y: 0,
+      blur: 2,
+      spread: 0,
+      color: '#000000',
+      alpha: 1
+    }, ...buttonInsetFakeBorders],
+    buttonHover: [hoverGlow, ...buttonInsetFakeBorders],
+    buttonPressed: [hoverGlow, ...inputInsetFakeBorders],
+    input: [...inputInsetFakeBorders, {
+      x: 0,
+      y: 0,
+      blur: 2,
+      inset: true,
+      spread: 0,
+      color: '#000000',
+      alpha: 1
+    }],
+    ...(input.shadows || {})
+  }
+
+  return {
+    rules: {
+      shadows: Object
+        .entries(shadows)
+      // TODO for v2.1: if shadow doesn't have non-inset shadows with spread > 0 - optionally
+      // convert all non-inset shadows into filter: drop-shadow() to boost performance
+        .map(([k, v]) => [
+          `--${k}Shadow: ${getCssShadow(v)}`,
+          `--${k}ShadowFilter: ${getCssShadowFilter(v)}`,
+          `--${k}ShadowInset: ${getCssShadow(v, true)}`
+        ].join(';'))
+        .join(';')
+    },
+    theme: {
+      shadows
+    }
+  }
+}
+
+const composePreset = (colors, radii, shadows, fonts) => {
+  return {
+    rules: {
+      ...shadows.rules,
+      ...colors.rules,
+      ...radii.rules,
+      ...fonts.rules
+    },
+    theme: {
+      ...shadows.theme,
+      ...colors.theme,
+      ...radii.theme,
+      ...fonts.theme
+    }
+  }
+}
+
+const generatePreset = (input) => {
+  const shadows = generateShadows(input)
+  const colors = generateColors(input)
+  const radii = generateRadii(input)
+  const fonts = generateFonts(input)
+
+  return composePreset(colors, radii, shadows, fonts)
+}
+
+const getThemes = () => {
+  return window.fetch('/static/styles.json')
+    .then((data) => data.json())
+    .then((themes) => {
+      return Promise.all(Object.entries(themes).map(([k, v]) => {
+        if (typeof v === 'object') {
+          return Promise.resolve([k, v])
+        } else if (typeof v === 'string') {
+          return window.fetch(v)
+            .then((data) => data.json())
+            .then((theme) => {
+              return [k, theme]
+            })
+            .catch((e) => {
+              console.error(e)
+              return []
+            })
+        }
+      }))
+    })
+    .then((promises) => {
+      return promises
+        .filter(([k, v]) => v)
+        .reduce((acc, [k, v]) => {
+          acc[k] = v
+          return acc
+        }, {})
+    })
 }
 
 const setPreset = (val, commit) => {
-  window.fetch('/static/styles.json')
-    .then((data) => data.json())
-    .then((themes) => {
-      const theme = themes[val] ? themes[val] : themes['pleroma-dark']
+  getThemes().then((themes) => {
+    const theme = themes[val] ? themes[val] : themes['pleroma-dark']
+    const isV1 = Array.isArray(theme)
+    const data = isV1 ? {} : theme.theme
+
+    if (isV1) {
       const bgRgb = hex2rgb(theme[1])
       const fgRgb = hex2rgb(theme[2])
       const textRgb = hex2rgb(theme[3])
@@ -122,7 +496,7 @@ const setPreset = (val, commit) => {
       const cBlueRgb = hex2rgb(theme[7] || '#0000FF')
       const cOrangeRgb = hex2rgb(theme[8] || '#E3FF00')
 
-      const col = {
+      data.colors = {
         bg: bgRgb,
         fg: fgRgb,
         text: textRgb,
@@ -132,23 +506,32 @@ const setPreset = (val, commit) => {
         cGreen: cGreenRgb,
         cOrange: cOrangeRgb
       }
+    }
 
-      // This is a hack, this function is only called during initial load.
-      // We want to cancel loading the theme from config.json if we're already
-      // loading a theme from the persisted state.
-      // Needed some way of dealing with the async way of things.
-      // load config -> set preset -> wait for styles.json to load ->
-      // load persisted state -> set colors -> styles.json loaded -> set colors
-      if (!window.themeLoaded) {
-        setColors(col, commit)
-      }
-    })
+    // This is a hack, this function is only called during initial load.
+    // We want to cancel loading the theme from config.json if we're already
+    // loading a theme from the persisted state.
+    // Needed some way of dealing with the async way of things.
+    // load config -> set preset -> wait for styles.json to load ->
+    // load persisted state -> set colors -> styles.json loaded -> set colors
+    if (!window.themeLoaded) {
+      applyTheme(data, commit)
+    }
+  })
 }
 
-const StyleSetter = {
+export {
   setStyle,
   setPreset,
-  setColors
+  applyTheme,
+  getTextColor,
+  generateColors,
+  generateRadii,
+  generateShadows,
+  generateFonts,
+  generatePreset,
+  getThemes,
+  composePreset,
+  getCssShadow,
+  getCssShadowFilter
 }
-
-export default StyleSetter
diff --git a/src/services/user_highlighter/user_highlighter.js b/src/services/user_highlighter/user_highlighter.js
index ebb25eca..f6ddfb9c 100644
--- a/src/services/user_highlighter/user_highlighter.js
+++ b/src/services/user_highlighter/user_highlighter.js
@@ -11,7 +11,7 @@ const highlightStyle = (prefs) => {
   if (type === 'striped') {
     return {
       backgroundImage: [
-        'repeating-linear-gradient(-45deg,',
+        'repeating-linear-gradient(135deg,',
         `${tintColor} ,`,
         `${tintColor} 20px,`,
         `${tintColor2} 20px,`,
diff --git a/static/font/config.json b/static/font/config.json
index 20cb3254..3abeffe9 100644
--- a/static/font/config.json
+++ b/static/font/config.json
@@ -1,5 +1,4 @@
 {
-  "name": "",
   "css_prefix_text": "icon-",
   "css_use_suffix": false,
   "hinting": true,
@@ -51,7 +50,7 @@
     {
       "uid": "09feb4465d9bd1364f4e301c9ddbaa92",
       "css": "retweet",
-      "code": 59396,
+      "code": 59398,
       "src": "fontawesome"
     },
     {
@@ -66,12 +65,6 @@
       "code": 61925,
       "src": "fontawesome"
     },
-    {
-      "uid": "1a5cfa186647e8c929c2b17b9fc4dac1",
-      "css": "plus-squared",
-      "code": 59398,
-      "src": "font-awesome"
-    },
     {
       "uid": "e99461abfef3923546da8d745372c995",
       "css": "cog",
@@ -191,6 +184,36 @@
       "css": "brush",
       "code": 59411,
       "src": "iconic"
+    },
+    {
+      "uid": "ca90da02d2c6a3183f2458e4dc416285",
+      "css": "adjust",
+      "code": 59396,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "5e2ab018e3044337bcef5f7e94098ea1",
+      "css": "thumbs-up-alt",
+      "code": 61796,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "c76b7947c957c9b78b11741173c8349b",
+      "css": "attention",
+      "code": 59412,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "1a5cfa186647e8c929c2b17b9fc4dac1",
+      "css": "plus-squared",
+      "code": 61694,
+      "src": "fontawesome"
+    },
+    {
+      "uid": "44e04715aecbca7f266a17d5a7863c68",
+      "css": "plus",
+      "code": 59413,
+      "src": "fontawesome"
     }
   ]
 }
\ No newline at end of file
diff --git a/static/font/css/fontello-codes.css b/static/font/css/fontello-codes.css
index b1c76c3f..5cfcbf6a 100644
--- a/static/font/css/fontello-codes.css
+++ b/static/font/css/fontello-codes.css
@@ -3,9 +3,9 @@
 .icon-upload:before { content: '\e801'; } /* '' */
 .icon-star:before { content: '\e802'; } /* '' */
 .icon-star-empty:before { content: '\e803'; } /* '' */
-.icon-retweet:before { content: '\e804'; } /* '' */
+.icon-adjust:before { content: '\e804'; } /* '' */
 .icon-eye-off:before { content: '\e805'; } /* '' */
-.icon-plus-squared:before { content: '\e806'; } /* '' */
+.icon-retweet:before { content: '\e806'; } /* '' */
 .icon-cog:before { content: '\e807'; } /* '' */
 .icon-logout:before { content: '\e808'; } /* '' */
 .icon-down-open:before { content: '\e809'; } /* '' */
@@ -19,6 +19,8 @@
 .icon-lock:before { content: '\e811'; } /* '' */
 .icon-globe:before { content: '\e812'; } /* '' */
 .icon-brush:before { content: '\e813'; } /* '' */
+.icon-attention:before { content: '\e814'; } /* '' */
+.icon-plus:before { content: '\e815'; } /* '' */
 .icon-spin3:before { content: '\e832'; } /* '' */
 .icon-spin4:before { content: '\e834'; } /* '' */
 .icon-link-ext:before { content: '\f08e'; } /* '' */
@@ -26,7 +28,9 @@
 .icon-menu:before { content: '\f0c9'; } /* '' */
 .icon-mail-alt:before { content: '\f0e0'; } /* '' */
 .icon-comment-empty:before { content: '\f0e5'; } /* '' */
+.icon-plus-squared:before { content: '\f0fe'; } /* '' */
 .icon-reply:before { content: '\f112'; } /* '' */
 .icon-lock-open-alt:before { content: '\f13e'; } /* '' */
+.icon-thumbs-up-alt:before { content: '\f164'; } /* '' */
 .icon-binoculars:before { content: '\f1e5'; } /* '' */
 .icon-user-plus:before { content: '\f234'; } /* '' */
\ No newline at end of file
diff --git a/static/font/css/fontello-embedded.css b/static/font/css/fontello-embedded.css
index bea63f38..58a57456 100644
--- a/static/font/css/fontello-embedded.css
+++ b/static/font/css/fontello-embedded.css
@@ -1,15 +1,15 @@
 @font-face {
   font-family: 'fontello';
-  src: url('../font/fontello.eot?99189355');
-  src: url('../font/fontello.eot?99189355#iefix') format('embedded-opentype'),
-       url('../font/fontello.svg?99189355#fontello') format('svg');
+  src: url('../font/fontello.eot?4112743');
+  src: url('../font/fontello.eot?4112743#iefix') format('embedded-opentype'),
+       url('../font/fontello.svg?4112743#fontello') format('svg');
   font-weight: normal;
   font-style: normal;
 }
 @font-face {
   font-family: 'fontello';
-  src: url('data:application/octet-stream;base64,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') format('woff'),
-       url('data:application/octet-stream;base64,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') format('truetype');
+  src: url('data:application/octet-stream;base64,d09GRgABAAAAACdYAA8AAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+L1N8Y21hcAAAAdgAAAEyAAADrCjhbUljdnQgAAADDAAAABMAAAAgBv/+9GZwZ20AAAMgAAAFkAAAC3CKkZBZZ2FzcAAACLAAAAAIAAAACAAAABBnbHlmAAAIuAAAGoEAACjSSnDq5WhlYWQAACM8AAAAMwAAADYTu6FIaGhlYQAAI3AAAAAgAAAAJAfJA/9obXR4AAAjkAAAAFIAAACQgg//5mxvY2EAACPkAAAASgAAAEq11aikbWF4cAAAJDAAAAAgAAAAIAF5DaZuYW1lAAAkUAAAAXcAAALNzJ0eIHBvc3QAACXIAAABFAAAAZCo9e7HcHJlcAAAJtwAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZJ7LOIGBlYGBqYppDwMDQw+EZnzAYMjIBBRlYGVmwAoC0lxTGBxeMHwyYY78X8gQxZzOMA8ozAiSAwD4wAwzAHic5dI5bsJAFIfxz4GQjWwkZN9pU0WuKaMchPPAZXKGSNyCxtIrZ6hSQf7j97osF4itH5LH0njE+4BNoCPP0oXqk4pyLbVatesddtv1Lh96vuFIK30b2ovVaZbmaZGatMqDPM6T3Czr9RqM9u3057e/XpV2f23vt293ebuhL3d14h5bbLOjc+3RZ58DDnWqYwaccMqQM8654JIrrrXjLXfc88AjT4y0Te+PE/yXq19+qvd4GpWJuTJzC/q/sVAasVA6sVD6saC5YEETwoJmhQVNDQulKwuaJBbK6SxouljQnLGgiWNBs8eCKsCCesCCysCCGsGCasGCulG3TgVhtVNLpKlTVaSZU1+kuVNppIVTc6TGqT7SyqlD8sCpSPLYqU3yxKlScuPUK8vaMfoC3OeGSAAAeJxjYEADEhDInP4/CYQBEw4D9wB4nK1WaXfTRhQdeUmchCwlCy1qYcTEabBGJmzBgAlBsmMgXZytlaCLFDvpvvGJ3+Bf82Tac+g3flrvGy8kkLTncJqTo3fnzdXM22USWpLYC+uRlJsvxdTWJo3sPAnphk3LUXwoO3shZYrJ3wVREK2W2rcdh0REIlC1rrBEEPseWZpkfOhRRsu2pFdNyi096S5b40G9Vd9+GjrKsTuhpGYzdGg9siVVGFWiSKY9UtKmZaj6K0krvL/CzFfNUMKITiJpvBnG0EjeG2e0ymg1tuMoimyy3ChSJJrhQRR5lNUS5+SKCQzKB82Q8sqnEeXD/Iis2KOcVrBLttP8vi95p3c5P7Ffb1G25EAfyI7s4Ox0JV+EW1th3LST7ShUEXbXd0Js2exU/2aP8ppGA7crMr3QjGCpfIUQKz+hzP4hWS2cT/mSR6NaspETQetlTuxLPoHW44gpcc0YWdDd0QkR1P2SMwz2mD4e/PHeKZYLEwJ4HMt6RyWcCBMpYXM0SdowcmAlZYsqqfWumDjldVrEW8J+7drRl85o41B3YjxbDx1bOVHJ8WhSp5lMndpJzaMpDaKUdCZ4zK8DKD+iSV5tYzWJlUfTOGbGhEQiAi3cS1NBLDuxpCkEzaMZvbkbprl2LVqkyQP13KP39OZWuLnTU9oO9LNGf1anYjrYC9PpaeQv8Wna5SJF6frpGX5M4kHWAjKRLTbDlIMHb/0O0svXlhyF1wbY7u3zK6h91kTwpAH7G9AeT9UpCUyFmFWIVkBirWtZlsnVrBapyNR3Q5pWvqzTBIpyHBfHvoxx/V8zM5aYEr7fidOzIy49c+1LCNMcfJt1PZrXqcVyAXFmeU6nWZbv6zTH8gOd5lme1+kIS1unoyw/1GmB5Uc6HWN5QQuadN/BkIsw5AIOkDCEpQNDWF6CISwVDGG5CENYFmEIyyUYwvJjGMJyGYawvKxl1dRTSePamVgGbEJgYo4eucxF5WoquVRCu2hUakOeEm6VVBTPqn9loF488oY5sBZIl8iaXzHOlY9G5fjWFS1vGjtXwLHqbx+O9jnxUtaLhT8F/9XWVCW9Ys3Dk6vwG4aebCeqNql4dE2Xz1U9uv5fVFRYC/QbSIVYKMqybHBnIoSPOp2GaqCVQ8xszDy063XLmp/D/TcxQhZQ/fg3FBoL3INOWUlZ7eCs1dfbstw7g3I4EyxJMTfz+lb4IiOz0n6RWcqej3wecAWMSmXYagOtFbzZJzEPmd4kzwRxW1E2SNrYzgSJDRzzgHnznQQmYeqqDeRO4YYN+AVhbsF5J1yieqMsh+5F7PMopPxbp+JE9qhojMCz2Rthr+9Cym9xDCQ0+aV+DFQVoakYNRXQNFJuqAZfxtm6bULGDvQjKnbDsqziw8cW95WSbRmEfKSI1aOjn9Zeok6q3H5mFJfvnb4FwSA1MX9733RxkMq7WskyR20DU7calVPXmkPjVYfq5lH1vePsEzlrmm66Jx56X9Oq28HFXCyw9m0O0lImF9T1YYUNosvFpVDqZTRJ77gHGBYY0O9Qio3/q/rYfJ4rVYXRcSTfTtS30edgDPwP2H9H9QPQ92Pocg0uz/eaE59u9OFsma6iF+un6Dcwa625WboG3NB0A+IhR62OuMoNfKcGcXqkuRzpIeBj3RXiAcAmgMXgE921jOZTAKP5jDk+wOfMYdBkDoMt5jDYZs4awA5zGOwyh8Eecxh8wZx1gC+ZwyBkDoOIOQyeMCcAeMocBl8xh8HXzGHwDXPuA3zLHAYxcxgkzGGwr+nWMMwtXtBdoLZBVaADU09Y3MPiUFNlyP6OF4b9vUHM/sEgpv6o6faQ+hMvDPVng5j6i0FM/VXTnSH1N14Y6u8GMfUPg5j6TL8Yy2UGv4x8lwoHlF1sPufvifcP28VAuQABAAH//wAPeJzFegtwXNd53vnPue979+7r7r0LYLFY7GJ38RIILvZBkRS4fFMiRIIkRAEURUMUSUWESEiKbDGyqKgWo5FqRVQcRfWMJ3I0lTVpbbkK6TpsXdsZR7JTup2R65jSOO1MY2c8lN2ynlZpOiy57HfuLkDq1Uw70+kCuHvPPY97zn/+//u//z9gxNi1/87/kv8uG2DZZk++K6YrjNNWQZzxRUL1ES/jeYqaHil6UdLyK0iXl1J1HZXlpV7po4a8+KgOfP6X0anYaOzVV3GZisnv2PVyNPrqq9FHfXnzla9EP9owOiYbMAVzOideETVmsDgbYk22pbmxhveajGNWW5mpmYsGabq2yHShL6IDV2ZUEpguF2yeKQqfxSM+dcvawkQhXynenE5Yau9IsVpyeZbqjaXvlKcV+vOlcq1aDyaytIYq9cZExRfaCKFKL8gqXNqr9Pl5L+vxdHf6d71cgvuZ9Jacf+WHQZZy/iWnXjidr0cu+blvmunTXvR01KPTQTJ+2cpalxMDrs8TuYTS7SzdPHvWz+V8XKhvcLAvS7v9y+jhu5dH0cW6HGf4yL35EeSwlfWx3mZ3ImopQpWbw5b3ptcLhBqMEGSfTHkuhbtTqlUbybK8FsOdUX3xSvT8uJNy/udlx3do/IduH6WfsHPOSUrn6NdO9K3We44dI/3UKT1hKQYFb0WdlDrYCoLWIN64PA8Tu1FuDmS6PDdiGrqmCnI+OKHiQOAnYkL1RqixgqAReiNItmdXyH/C7Phn/+mvjt7/n7469OMftzDPwPr4eQ69lv/JT/Kv/Wpxkc60p5z5hAnjw69dhQ59SiSYzjw20hxkAgKFcihEnNMMvkgqCfEpxhJxx0Y7Pa6qqZFiPC+VgyDN/BifpAruX9/z3DSfeYbTw9+/+BfHtcf+1fv/8okan9/93KvP7abxT7/5yCNv/lJeGMPLr50XF/k5yKqbTbJN7E52Z3Om2sOZskeD+u7eiHdObxgqQ4E1UrYyVVEXIT+oLh1jpOF3gWkCvwtMiOPSGJQZaDSbxQ2bmtqeHOsa8Hp1tXuk2BijRrWh6T5VS3peS3l+pQ5VnoAWeymNw1wL+VDSY9JWG5M0UQkaqPahzLqfhIYn/cDTNd2lAmobpXIjCxum+sj4Kso/eccBOhqztxyK+bFN43bs/Jpfrsmolr7J7Jp+umLbe6/8o0qlT7WEaw/YZKZmb/1D5bLtl2f+/eNDj/7F5vV3F2oHc/aDOwtHb9m4ev2pF+g+qNihzXYsZo9vin1aoftb++6vmGXN0ocHTtweH0489UWrbmqap5HaurrjyR5Kdx1IJgdumj96m3Xq/kPNdQMH60kW6uM1ZZw/xfrZRrahuS5PiiYhC+qlk3bMJE3RNWXBAIbpxPX5G4SokpTihqbfX0z3+6nBZIgLnlYGDKygMZqIF/Jj1DF4CQGpfnm3hH2lan0N1frbd41+KckspeIQKT9vGVffUzUO5KQF2LJxFop7xvTdBVpvqnMKHTbOODn7rIEnre/IJ5bB00rYYcH1E7pDXCjk0E6/x7rgOBesjEcXtAfUn0WsC5HIBavHv6AvqBELzVRuiNYZn7VlcU7sg54b7Cjb3NxweG5qvcKUNRYnVh3siSmCRFvJoG1MWZSwsghLoEUmuIDm8SP779qz69ZtI8P5XDKhq/4ItCnvEnSpCBDEunU/8D3oSBnLBujqQEdYcblUhjXjGmpWI5SeBFLIrlFaUrc+FPADYJU6B+WrBJ3B9FB0fM3uE7v53kf2UsbQf8Oyk4OaGp2O6PrtXd2mrsQeN5xYT7BTi2lbfEU1Bq2ocUQ3yFJ/w3CDYrutcXu62zRE/HFIMJoJdqpRfZunKGa7sUWH18zMfGZm5oSsj2VTPRXN1VLTpK6NGFOZmKXfZzprVa2ZVV3NqUQzPVFy9LBtV3fuJt3RvekbmtprVHVjptO0Owb4C/eAMbHAz7MyfBX00YMKABQ1rnJNPcZUwVVYsyKYUNgxaeka8XlZEDOwcWnZgk35ha7icLGsqz3QRz9KEBFcTy1eDaWXCsJH5UJe0+OeH0xUspw8aHu+dAsV5AX6OAHx+wH5dBgYQ4ZxZuOBAxvPGJbEOlksVqk+8A2NA4c0u/UjO+Nfdn34HD9j0wq7xhOqa3JxYCM9s/GAZdimBuFCGVon0FHhBo26dutty4u+4rsXoOGvwJmZeLDkqy6Jb/JxoG1X048QgwQgBQY9kxwiSEg/BcvMl6lNGwKzY2Tiq62D8JKtg7Z9N75pkAbtjLPfppda99o2/aGdtfbbdutdPLb32xm861rr2mfFOXEfW8n6mhn5bprB+9gsdJ7YFLHhIbaSVkovFOTLAEmqBxLYdCnBUh1F3GqB35C30FUUsrzz9P0jm7Ype+nX0wdGtzjd063S4Hwuq43SVLra3frGaNpx0j79tJJbW6+3EhuUQ0/fRr+WVbHdv7Nty58dQMduZ8vovOxo5dKHhmlHdzWNjt0GV2THz8TcSisx9fRBpUmX0mOyo5Sfcu3atXPKitCOo/D3K9gdzd29HicRxZrciGMqnGVSIDWK9LaS8RxjQDtBmpiXEsDSgXOqGuKcOistfioeGxspFbqCWF+8L5lMGCFTcCV0wael+muNgIr9bYUCltXL8WopiAP0gIWNeBvf6PDkvkn88rVXLp3ZR72UvfIUbMrRxEmYiLWrWrzy1ECdqkVxsljl6Zsm+Ya9G5TVrcuXF87OUe8rAMV9sqHBXzOsxNV9oQry1+QXs7Hmh8I1t1e8ju1knwI4/TY7zb7M/hl7s9n1QpObxjNPzucUVTmxigs+Pc4EIHzr9jf6p2ebDZZKONwwU8Z8kswYKaqpzMcjHPbJJUrOR0lYFPp9W4c2erPM8yLerT3Nyf+znp5HM8sjkDc11yx9/auv/eOXv/TSi88/9/SpJx7/zG8eXzhy6MBde2d2bK/VaiX81CZ8+JagBt8Mq+0lz5f8EhBZAn6GZXDNsFzu1MOq64RNACfVsBH+BDaFPtR/qayn2mWB9nqnfYD2QWd8WS/Hb3TGl+WgU76xfyPe5sBLG37Bi26ToIALfewtX+O7rT3hI3o96l1963qViPvu1pDG4vqTDzR754aaT7pu+4AyDVx/7d9cn8YvbujTuoeysqL1M1z5722Noj62FfdXP3+9L32LesOK1s9ln3/98UP9zfXO911NFKvVIr8U6qjEtR/wR8R24FrQ9MwQ19gSrGUSHP7S7FCDhrkEbUA1fhSAlrHvBoINtt7tQNvLFj3Yusey7kYNDUmckw1kwyUM/QH/4tK76IPvCoLwXdwPqYhE0UYHQPnzrXdoqD2qRFG8JmvdbfE/ab3beie8tejL4evDacj3wON8k9/exmqVPkjhAy/E6qL07stL66xKfHU/4BjjvttZ28tyJS/bD+/HO4bwNkvWYwJWZ1Fg3dceEm+KfcwBH97A3ms6DLSMtg72gPhs2f6GCzMe0QmTIPVwCGP3ohMhspBxnDHLDMPZBpaizTJNi2i39rQtf/QDXfjC39dnAH2GPqkPh6vW9i93VYAPKz7c1oD/NpT56300jc903sG1qbm5uabTl08M+vFCMmHC8NUq3HKjmpd2WCn2l+LVMY7IIhVTPRAoTwZC0r9PKg0YHkj6JPkpT4eb8rKCrpr945RYPWi2nuMX/qC7uvuB3dVu/tpw72VQmcu9w5mx8YEEP3W/mhvNqUc/R35+fHzOGO83zaHV9E/+mIYya1fl86vWZlrv/HHvMAjQmuHedGXmwDO3z3whZtlBludTthX7wsyOp+d3V5c4DH8qjJf62HCzDNKCjcLSj2GRCEOIQs9Cs4wUmioki/VkTEMQkuwHoLgUqB3HASeCWBpEpOLrKfDis9SLKRO9nfOvvhfGyvEX/81LPIHbrz2wZoZP3/JK6zs+nqdoA6LhB468+OKRB7JMhPHbHObj0Lfp7/ij298wp2fXr2XfZt9i5+AeXmLPME2qF5wFZom7n7Ifg13NsV1Qs0k2wXKsi1lYDqeX6Yv0Ej1Hn6fH6NN0mO4FrP81+49QSQ0Bwh66nWR4aDCN3qe/oh/RD+nP6Du0iibwjORzthUqZOH9GztvfwYeWMaZ30a9wN3/+znobCvWTHgXsS09//8EMTcX7kSzxrjQBdePMV0TuoxZDaEZsBMSBi0AuY4DK0FuZ/DFxKyqcNDfqbYYm6sVgo9VxWHGdZXrCxhDbY+htsdQr4+hqu0x1L1Yu3pbz//lm+fm1neFTPFdukD/gv6U7qS97AfsLfbP2TfYn7Cvs99in4GMNMgRCIU/C6/zRmT4v5QJkJS8Mkk1RDv1oCQDnXWklWqeXi1ptTFF4qTMcHjD5OW1vF4vlwpglxNjHBQUjwHVWhY3gG8ZA2l53JRk/KTLv0pJn6SCHLTsyxAK9jPhV8uVsIEWyMZ4QRnDYtRySZazhGgKcX9e83XEXr508wjIGtWgrOkVOVTQCNBZ93XMAF01Pcu9hq+HQZheLmn+hBynDxNqaH0iywNNjldDK3Dj8hivyQgO3HgC865klT7hVzAqOjfyYeALtKrXMAoucvWlelCpY7lYlqelCnXpDPFcz+uuKGEKslyW8wLxqGIdfh0jYcJ+I8shnXrDBypMEmLL2pjM0oXSqKBFHrNBOOnLa8OvlyYp1agX5BylgCs1CEQAROGq6ohD5W+UsLIU5DWGXYtSqV6Scq9rKZdSCAjCaACRbOBpPr3+yPcfXkrsUBKhNXFFxFNJ0FxuaAJbpiiWqilkABCFUPDRSAN5VBG9I742HFIziuCIsfAyrptogngJHS2uqBEhPDepGIj5iKsmp6SpKVzVLLgTKL/QTIwG9qkKhIkKubodVWICoyoGGfILAwvQ/oQqHAev505Xj9BUNakKW4nYeJGmGIqp7KooMtwUlLYwB1WR85RxKHFL1xOKbkr/xV2Z/nIRRvCoITC0UEmB68YIqqNzYQhT9zVNNYyY4mEcDC5coSDgNuIWx4dUjhIXjkA8KEUFQ7TxHm54AoEml+tWISX8kpIWpsAERIS7UhwKajTMAXJSFN1QdUdBAcGwGk7EUXgC3bkMQrllQFSapqumY93/m9PkUAT9UxI2pKBVBzaPD8mZW9ghDlGjESai2FHipkUi0UnK4dL6D2RwmW4zhGqjGYZATKKHciWuOaoGucLFifAB7rkhxUpYOfZaF4Zu6YqqqY5UDSzNMSEUFUsQcS5cQz4XJrZVaOQqFoZUsSxL0XWdTNXQDQhJSFlCHSwhXFmtKggnLCPKhQQzFwJQNPxgEjftVOSuK1rUwhwQx7mmZ3PSujm8rKIhqhUiBhkrhmooZKcjqoNVK47hKi5ZtoeYXYXIsRcJYSmKKXNSVihgHjMSUn8xD0t3w62EvGNqVGIxt7FoFJW0a7qqKVNqEDWEDjNReRQ6QjJVJRBFKtyAIF1uWarMWdmmKlUDe4A1KzAIiEAjLA8d5b7j0oqk7pBrlklJaQcQNbcEQi0V0kXIJdtIfZLjqBkjbrqmw5WYHua3viJOiwEgcsDyzT7QYh5XJTfZKrO3i8v8uMfPh7TV08p5wERZMhAwVl2mpcBe6e2vf3bXpk27afaxWXo519/6nrd7FU3mDvzo8TdosPwPd98yO0t/mzuQa32vMeOhAr7j2t+Cg/w3MYf4tB9+9FDT6cF+czPkRVvbpLKXQXZQymNLCWZMCGLdD7/lqCCSeQbhLsJlYarLLbDNMmGhzMqmCCbNYFUZ3kLyqeIN8aGM18rJalk+0LVU0I7oBPkyfya5VqkBuKwgJLP0B3QrvMBUdf0xOFLT0e8zHIO+5qXMfOLKa4m8mfLodTNfyu87aliWgQs57xBB7YAg1+ByNR67cqlQiCcQChUKIhH3vE5cAmEkwMUKbKhZAhFWQrE/qGI1TMiTFxHmXgSbKkwUCxPhQuQJSrnQOUZp1ArtY5YwRyUTWoEkhyKR8y/m/AUQv4shN7yYDRZwIwvfkU/fC5nhe52n8sjkYi7M7T8kfoV9KbNp9kbTHfCB0nxqQ1UiWic1UGKh+opjOqwYSrogz45mNawFoUE7Q6JG1KXQoPCR1orMoOy/3oljL4c+3EprJ174RzIviAaCoUFiWzevXDE4PTTtJRyLlalsyIMR6Yg13fP7SLoumR+FKAJdkynSSZJ5VDisconyqTDbKnP45Ubo2FySbncdwQNPVGTHRhWP6dJTDx3buBkzUGaSam1iz5337ny+utrkzt/ZnqWs5glz/aZ9+2kirNx77/S2zbU1Brf/R6fWam7ad/eRzz10fEM4hphrTi4c/wcGXFXi4J5dK1ZOrrrZTIqKMP3Yzw1bW7ulNNhS2lW57EfrZO/PGQan9jnMtWsHxS+xV31sPbu1KcER0d9Kok1tySevn33QcSElzSDpqJBUdrFj4XRkrhkh1p/zkqyP+pQlIa6EBCSVCXzpyrMk89B1STSk8EIha367HpJaiVI55Ft12ahE//XOXTOb9j5w9L6jOzf092tFtzs2ERcWL1Cx9MKBu1pqOiod/QAfKG2767OP/tbJe2TjBTTOqUVDcxNirjd78+aUl83t3LB3z9ldQz0xiouotu/P5+5+oVRsXYopmhGWtt01kE937bqhbarfTbDl3PHFUJfXsZPN5CAMMg6AaYzBYfQDF5UO0AwwsAY4kOV8MiSkhHlkGWXvR6TrINJtjoK8a4v/u7Y35JznmtbqnmKtXpyQaWfqHIfWOqkgQJAstxPO/ZW6zDFL003Gw5PG5dRAuVStT/RLaz6wsTUuc870rESj1qNhto/eLlYtY8CwLvgZ+2DrRTWmNOGLHzho+y71Rj3aE+ap6e0NByhsVy22xsOeZwBT9FOZuOEOOmpaU3XDjhn/+tmHjBHTbJBVmisSIA4sTGW0NUpBG0XiLeiUxFsxy+Cop2oNr2tCVbtGZK6tjAX2YS2Snlca1DasZCeYXZIEP+9FW++nk4np1gXbvlnmPIZ3WVHNSJ0+sPHqe3L6PNh4ABGUg/XcFJPNstbNmP3wtC0sql29iMXNr+dp+cXaeRFc9vEfdnKfjWZ1kBTVYG3PpgJk1TDbILnU/A0pbgnHUzK9WJoI3UWqE3bX2jMVqfZZVnik3SkXbizPebEr/yVMfIl4mPP6xNLCDfkxii1n1MgjV+bJ3DBltmTj58R7/DzizFXspuawPKcX2If2AVPbSX9g/oCtgdUTijxrWs43SzvNcjg4acT4wXNQdpcjqgnPlmT0MybdeqhqF6vFK+cH6tTVd34qV9rUwzMbBvs+9ae5dH3o31VrTj4b4U42no3ktd+fTxTW0tiIqKP5v21tbuvkt3r8Zxvp7gx1Z4JNj/vfHZ3u/UKhbCZAC62EkRGHN7jB7oGR1Z3cCPzNRawvYLewg02nKsGtZEsm2vE2ARwAPGKobEzSJGydiAjYY1ZK4cEbquXpM1s+fJ5rxomtWT2Q7+1JxFhAgRaCG/y79A9AMMRAUicn+Vh4JA1nIHEt9KYIasIYdJKvkySnOkm5LNH7D3//EZq+dTwa6b5jczpXyqPMT3yPnnz6F8+Uh4//fs+AMFzQPHB4JeLpXkyPzh6ip39BsV88zZ/acWpq8uGhTG1ibGBtSqg7Tn3x1I7Wz+55dV65p2QoDqgPqGlUdX0jk0kOV74wg6r5V2+0xQKY0vrmpDwB6iPpj+WhDOBcHFMln5a+VYeQdJmrA/GQTlPm0BRtqlYrTPiFgYKhZkbaae7l3HVhKaG9lLVGZPqxVnq2rbBnQtU90y6cdf3nP2Cm66Uanw2bnG3r9Fmp0Gc9WvdhQ6VwXRdFjY1I7lPCiqRiK1BsULdFmSJbDFOnkoIWguQtgQSWoqe7vP2/DlDlWnVMDcF1OWsrU2O5AFq8lSzEEQitSHj5VZN79zZOejmz9XPbpl47k+Yn6fl92Yt3f1lJxBTLAXsQpb5V+5rj2YR22vVtysq0btbyoqf/enubp/GnxD7swZG208hB8UBI2DGwc0Yqa+dHQH0kFIqQoBY/volAG+kpJKERIDTNJLFcX0/aS8ZcU2MFKuhSU0FcPpz4y0J320fE1VJeC1L89pDa3Zj986IDrh+mBb+WDW5M/52970X+wv1yM2TO8mw7f3xOnAzPxdLsDrajuf02MvS+HpnoAp6sjMOelK1MN/RFZghjUQMnFZ1TbgRzD95gcKqMPKZWjKYG1pVq7SRtoyrzA1lq61JhaRUVX/V0P+Xrfpg9kTWSVJTD+kkOdMJlUkxUsooWwCrlbqPTab8XOtXr7fNifxRq1x9Fff5in0ldpmn6am7gtm3FvZXhzUlUej2rM6WE5SJE0mKpaNdw2jMQDzmGI4O/L4005f8QhOPRaOtL4Wh0OMTg8UJXYjjfV+hLTZZHKOFG00t1zcLKhJX30n467zuJ7nQuEUmN+p7iuFqTtf835aGQa8SYx4rwOjezv2oGE0NcN8A0eG8q4oD2iq0KqTI1L4HtJs0RiO91rpPMBKs6VxcwkK6yBZN03Zi1SCbbFehehC2x6dFP7iQbHr+hpw4NrPw9zdEQ7Wdke30v+hr6beDXuXicsUatsvKmkcHyQL4v29MV9+JeMoHVRRsRNdX2LcvamYTjiBfitPxA/k1UgmKq0AlJ1OU7etZ3OydGn1ci9OXnw0MvWcTvf44orcm3LOMVxE+Ptr/5a60Z1LS+296nXrrotE7QMy2nfejk0nr8fc15/eRJGXiF187ZyDnlhEhCt0fZTvZo85HRIrf0XJ8rBK8kuWKIrYx0IIxu6YsuMStiscgxZkd4xObH4KtYxLYi84jUga0GF/MMIbwxwwxDmTVlamSK2O3bb9u2edP6dfWJlSuGBgfymZ4glYhZJkzeICMaupvSJGW5pk5IYPKu//Nb+J8Fy1GbNIsgPLVMtWlidVINKjDqShjBBMDoFD079wR/7JsntFP052+G575vOtqCYb0VnhlDWAu4aR0e7j1durmV3rhbcRLZ0up+2x6dOTQzatu3jp/sHabDT7zxJH/8G4/d+tG+7UFb3+0dpd/J7NiYXbWhvirfza08PlZ9uJf9L9DM7WYAAAB4nGNgZGBgAOKp1/Oa4/ltvjJwM78AijDcEF93Fkb///o/iaWCOR3I5WBgAokCAIVoDg4AeJxjYGRgYI78X8jAwFL2/+v/zywVDEARFKACAKM8Bs94nGN+wcDALAjEC5Bw5P+/zEBxFn0QGyoGUrf6/z8W/f//QZjpFAMDCIPFgZipCaoPrPb/V7CZL4D8l///g9VEQvELJD5MH9R8ljIGBgAslihRAAAAAAAAAEoAzgESAWwBqAJaAuADogQkBFoExAU+BpAGxgb6BzAIBAhMDFAMjg0SDVoOMA7AD14PvBAiEJIRJBGQEeYSUBL2E74UaQAAAAEAAAAkAfgACwAAAAAAAgAsADwAcwAAAKoLcAAAAAB4nHWQ3WrCMBiG38yfbQrb2GCny9FQxuoPDEQQBIeebCcyPB211rZSG0mj4G3sHnYxu4ldy17bOIayljTP9+TLl68BcI1vCOTPE0fOAmeMcj7BKXqWC/TPlovkF8slVPFmuUz/brmCBwSWq7jBByuI4jmjBT4tC1yJS8snuBB3lgv0j5aL5J7lEm7Fq+UyvWe5golILVdxL74GarXVURAaWRvUZbvZ6sjpViqqKHFj6a5NqHQq+3KuEuPHsXI8tdzz2A/Wsav34X6e+DqNVCJbTnOvRn7ia9f4s131dBO0jZnLuVZLObQZcqXVwveMExqz6jYaf8/DAAorbKER8apCGEjUaOuc22iihQ5pygzJzDwrQgIXMY2LNXeE2UrKuM8xZ5TQ+syIyQ48fpdHfkwKuD9mFX20ehhPSLszosxL9uWwu8OsESnJMt3Mzn57T7HhaW1aw127LnXWlcTwoIbkfezWFjQevZPdiqHtosH3n//7AelzhFMAeJxtT8dWwzAQ9BCX2CT03ks46gQ/JMsbW0SWhAohf0/sPG7sYXZm+yZ7yc6q5H9bYA8TpMiQo8AUJSrsY4Y5DnCIIxzjBKc4wzkucIkrXOMGt7jDPR7wiCc84wWvWOAtyQXXglQerTK8SX3grhqAUW/DJufNZ/ShoA0xs1wWjsKaKEyEaXNlWhND2Zi1ZsaSznkIXHSFlSJER9m3bMhUTrZdGPOlouWOFdGOPq1JqVQZscpaZWrKahd9V27nkA7S6NSq6DNvpX4f8WOqpF4x+gmzP8K4CmlPOk57LtWg5sL020DYPTAbRjD/FbmjJnNk1WY+LBz3j+Whi33t2fakrapqqY2IijtfRk+ODe1J8gsCHmwDeJxj8N7BcCIoYiMjY1/kBsadHAwcDMkFGxlYnTYxMDJogRibuZgYOSAsPgYwi81pF9MBoDQnkM3utIvBAcJmZnDZqMLYERixwaEjYiNzistGNRBvF0cDAyOLQ0dySARISSQQbOZhYuTR2sH4v3UDS+9GJgYXAAx2I/QAAA==') format('woff'),
+       url('data:application/octet-stream;base64,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') format('truetype');
 }
 /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
 /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
@@ -17,7 +17,7 @@
 @media screen and (-webkit-min-device-pixel-ratio:0) {
   @font-face {
     font-family: 'fontello';
-    src: url('../font/fontello.svg?99189355#fontello') format('svg');
+    src: url('../font/fontello.svg?4112743#fontello') format('svg');
   }
 }
 */
@@ -56,9 +56,9 @@
 .icon-upload:before { content: '\e801'; } /* '' */
 .icon-star:before { content: '\e802'; } /* '' */
 .icon-star-empty:before { content: '\e803'; } /* '' */
-.icon-retweet:before { content: '\e804'; } /* '' */
+.icon-adjust:before { content: '\e804'; } /* '' */
 .icon-eye-off:before { content: '\e805'; } /* '' */
-.icon-plus-squared:before { content: '\e806'; } /* '' */
+.icon-retweet:before { content: '\e806'; } /* '' */
 .icon-cog:before { content: '\e807'; } /* '' */
 .icon-logout:before { content: '\e808'; } /* '' */
 .icon-down-open:before { content: '\e809'; } /* '' */
@@ -72,6 +72,8 @@
 .icon-lock:before { content: '\e811'; } /* '' */
 .icon-globe:before { content: '\e812'; } /* '' */
 .icon-brush:before { content: '\e813'; } /* '' */
+.icon-attention:before { content: '\e814'; } /* '' */
+.icon-plus:before { content: '\e815'; } /* '' */
 .icon-spin3:before { content: '\e832'; } /* '' */
 .icon-spin4:before { content: '\e834'; } /* '' */
 .icon-link-ext:before { content: '\f08e'; } /* '' */
@@ -79,7 +81,9 @@
 .icon-menu:before { content: '\f0c9'; } /* '' */
 .icon-mail-alt:before { content: '\f0e0'; } /* '' */
 .icon-comment-empty:before { content: '\f0e5'; } /* '' */
+.icon-plus-squared:before { content: '\f0fe'; } /* '' */
 .icon-reply:before { content: '\f112'; } /* '' */
 .icon-lock-open-alt:before { content: '\f13e'; } /* '' */
+.icon-thumbs-up-alt:before { content: '\f164'; } /* '' */
 .icon-binoculars:before { content: '\f1e5'; } /* '' */
 .icon-user-plus:before { content: '\f234'; } /* '' */
\ No newline at end of file
diff --git a/static/font/css/fontello-ie7-codes.css b/static/font/css/fontello-ie7-codes.css
index 5ba45f75..fa7c1002 100644
--- a/static/font/css/fontello-ie7-codes.css
+++ b/static/font/css/fontello-ie7-codes.css
@@ -3,9 +3,9 @@
 .icon-upload { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
 .icon-star { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
 .icon-star-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
-.icon-retweet { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
+.icon-adjust { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
 .icon-eye-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
-.icon-plus-squared { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
+.icon-retweet { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
 .icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe807;&nbsp;'); }
 .icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe808;&nbsp;'); }
 .icon-down-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe809;&nbsp;'); }
@@ -19,6 +19,8 @@
 .icon-lock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe811;&nbsp;'); }
 .icon-globe { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe812;&nbsp;'); }
 .icon-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe813;&nbsp;'); }
+.icon-attention { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe814;&nbsp;'); }
+.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe815;&nbsp;'); }
 .icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe832;&nbsp;'); }
 .icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe834;&nbsp;'); }
 .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
@@ -26,7 +28,9 @@
 .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c9;&nbsp;'); }
 .icon-mail-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e0;&nbsp;'); }
 .icon-comment-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e5;&nbsp;'); }
+.icon-plus-squared { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0fe;&nbsp;'); }
 .icon-reply { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf112;&nbsp;'); }
 .icon-lock-open-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13e;&nbsp;'); }
+.icon-thumbs-up-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf164;&nbsp;'); }
 .icon-binoculars { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf1e5;&nbsp;'); }
 .icon-user-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf234;&nbsp;'); }
\ No newline at end of file
diff --git a/static/font/css/fontello-ie7.css b/static/font/css/fontello-ie7.css
index 6ab5e0ca..b37a63cd 100644
--- a/static/font/css/fontello-ie7.css
+++ b/static/font/css/fontello-ie7.css
@@ -14,9 +14,9 @@
 .icon-upload { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe801;&nbsp;'); }
 .icon-star { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe802;&nbsp;'); }
 .icon-star-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe803;&nbsp;'); }
-.icon-retweet { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
+.icon-adjust { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe804;&nbsp;'); }
 .icon-eye-off { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe805;&nbsp;'); }
-.icon-plus-squared { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
+.icon-retweet { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe806;&nbsp;'); }
 .icon-cog { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe807;&nbsp;'); }
 .icon-logout { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe808;&nbsp;'); }
 .icon-down-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe809;&nbsp;'); }
@@ -30,6 +30,8 @@
 .icon-lock { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe811;&nbsp;'); }
 .icon-globe { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe812;&nbsp;'); }
 .icon-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe813;&nbsp;'); }
+.icon-attention { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe814;&nbsp;'); }
+.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe815;&nbsp;'); }
 .icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe832;&nbsp;'); }
 .icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe834;&nbsp;'); }
 .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
@@ -37,7 +39,9 @@
 .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0c9;&nbsp;'); }
 .icon-mail-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e0;&nbsp;'); }
 .icon-comment-empty { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0e5;&nbsp;'); }
+.icon-plus-squared { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf0fe;&nbsp;'); }
 .icon-reply { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf112;&nbsp;'); }
 .icon-lock-open-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf13e;&nbsp;'); }
+.icon-thumbs-up-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf164;&nbsp;'); }
 .icon-binoculars { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf1e5;&nbsp;'); }
 .icon-user-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf234;&nbsp;'); }
\ No newline at end of file
diff --git a/static/font/css/fontello.css b/static/font/css/fontello.css
index 2a3d708d..38caec46 100644
--- a/static/font/css/fontello.css
+++ b/static/font/css/fontello.css
@@ -1,11 +1,11 @@
 @font-face {
   font-family: 'fontello';
-  src: url('../font/fontello.eot?60305294');
-  src: url('../font/fontello.eot?60305294#iefix') format('embedded-opentype'),
-       url('../font/fontello.woff2?60305294') format('woff2'),
-       url('../font/fontello.woff?60305294') format('woff'),
-       url('../font/fontello.ttf?60305294') format('truetype'),
-       url('../font/fontello.svg?60305294#fontello') format('svg');
+  src: url('../font/fontello.eot?3996201');
+  src: url('../font/fontello.eot?3996201#iefix') format('embedded-opentype'),
+       url('../font/fontello.woff2?3996201') format('woff2'),
+       url('../font/fontello.woff?3996201') format('woff'),
+       url('../font/fontello.ttf?3996201') format('truetype'),
+       url('../font/fontello.svg?3996201#fontello') format('svg');
   font-weight: normal;
   font-style: normal;
 }
@@ -15,7 +15,7 @@
 @media screen and (-webkit-min-device-pixel-ratio:0) {
   @font-face {
     font-family: 'fontello';
-    src: url('../font/fontello.svg?60305294#fontello') format('svg');
+    src: url('../font/fontello.svg?3996201#fontello') format('svg');
   }
 }
 */
@@ -59,9 +59,9 @@
 .icon-upload:before { content: '\e801'; } /* '' */
 .icon-star:before { content: '\e802'; } /* '' */
 .icon-star-empty:before { content: '\e803'; } /* '' */
-.icon-retweet:before { content: '\e804'; } /* '' */
+.icon-adjust:before { content: '\e804'; } /* '' */
 .icon-eye-off:before { content: '\e805'; } /* '' */
-.icon-plus-squared:before { content: '\e806'; } /* '' */
+.icon-retweet:before { content: '\e806'; } /* '' */
 .icon-cog:before { content: '\e807'; } /* '' */
 .icon-logout:before { content: '\e808'; } /* '' */
 .icon-down-open:before { content: '\e809'; } /* '' */
@@ -75,6 +75,8 @@
 .icon-lock:before { content: '\e811'; } /* '' */
 .icon-globe:before { content: '\e812'; } /* '' */
 .icon-brush:before { content: '\e813'; } /* '' */
+.icon-attention:before { content: '\e814'; } /* '' */
+.icon-plus:before { content: '\e815'; } /* '' */
 .icon-spin3:before { content: '\e832'; } /* '' */
 .icon-spin4:before { content: '\e834'; } /* '' */
 .icon-link-ext:before { content: '\f08e'; } /* '' */
@@ -82,7 +84,9 @@
 .icon-menu:before { content: '\f0c9'; } /* '' */
 .icon-mail-alt:before { content: '\f0e0'; } /* '' */
 .icon-comment-empty:before { content: '\f0e5'; } /* '' */
+.icon-plus-squared:before { content: '\f0fe'; } /* '' */
 .icon-reply:before { content: '\f112'; } /* '' */
 .icon-lock-open-alt:before { content: '\f13e'; } /* '' */
+.icon-thumbs-up-alt:before { content: '\f164'; } /* '' */
 .icon-binoculars:before { content: '\f1e5'; } /* '' */
 .icon-user-plus:before { content: '\f234'; } /* '' */
\ No newline at end of file
diff --git a/static/font/demo.html b/static/font/demo.html
index 26a1875e..cb1aa970 100644
--- a/static/font/demo.html
+++ b/static/font/demo.html
@@ -229,11 +229,11 @@ body {
 }
 @font-face {
       font-family: 'fontello';
-      src: url('./font/fontello.eot?32487936');
-      src: url('./font/fontello.eot?32487936#iefix') format('embedded-opentype'),
-           url('./font/fontello.woff?32487936') format('woff'),
-           url('./font/fontello.ttf?32487936') format('truetype'),
-           url('./font/fontello.svg?32487936#fontello') format('svg');
+      src: url('./font/fontello.eot?15755415');
+      src: url('./font/fontello.eot?15755415#iefix') format('embedded-opentype'),
+           url('./font/fontello.woff?15755415') format('woff'),
+           url('./font/fontello.ttf?15755415') format('truetype'),
+           url('./font/fontello.svg?15755415#fontello') format('svg');
       font-weight: normal;
       font-style: normal;
     }
@@ -304,9 +304,9 @@ body {
         <div class="the-icons span3" title="Code: 0xe803"><i class="demo-icon icon-star-empty">&#xe803;</i> <span class="i-name">icon-star-empty</span><span class="i-code">0xe803</span></div>
       </div>
       <div class="row">
-        <div class="the-icons span3" title="Code: 0xe804"><i class="demo-icon icon-retweet">&#xe804;</i> <span class="i-name">icon-retweet</span><span class="i-code">0xe804</span></div>
+        <div class="the-icons span3" title="Code: 0xe804"><i class="demo-icon icon-adjust">&#xe804;</i> <span class="i-name">icon-adjust</span><span class="i-code">0xe804</span></div>
         <div class="the-icons span3" title="Code: 0xe805"><i class="demo-icon icon-eye-off">&#xe805;</i> <span class="i-name">icon-eye-off</span><span class="i-code">0xe805</span></div>
-        <div class="the-icons span3" title="Code: 0xe806"><i class="demo-icon icon-plus-squared">&#xe806;</i> <span class="i-name">icon-plus-squared</span><span class="i-code">0xe806</span></div>
+        <div class="the-icons span3" title="Code: 0xe806"><i class="demo-icon icon-retweet">&#xe806;</i> <span class="i-name">icon-retweet</span><span class="i-code">0xe806</span></div>
         <div class="the-icons span3" title="Code: 0xe807"><i class="demo-icon icon-cog">&#xe807;</i> <span class="i-name">icon-cog</span><span class="i-code">0xe807</span></div>
       </div>
       <div class="row">
@@ -328,19 +328,25 @@ body {
         <div class="the-icons span3" title="Code: 0xe813"><i class="demo-icon icon-brush">&#xe813;</i> <span class="i-name">icon-brush</span><span class="i-code">0xe813</span></div>
       </div>
       <div class="row">
+        <div class="the-icons span3" title="Code: 0xe814"><i class="demo-icon icon-attention">&#xe814;</i> <span class="i-name">icon-attention</span><span class="i-code">0xe814</span></div>
+        <div class="the-icons span3" title="Code: 0xe815"><i class="demo-icon icon-plus">&#xe815;</i> <span class="i-name">icon-plus</span><span class="i-code">0xe815</span></div>
         <div class="the-icons span3" title="Code: 0xe832"><i class="demo-icon icon-spin3 animate-spin">&#xe832;</i> <span class="i-name">icon-spin3</span><span class="i-code">0xe832</span></div>
         <div class="the-icons span3" title="Code: 0xe834"><i class="demo-icon icon-spin4 animate-spin">&#xe834;</i> <span class="i-name">icon-spin4</span><span class="i-code">0xe834</span></div>
+      </div>
+      <div class="row">
         <div class="the-icons span3" title="Code: 0xf08e"><i class="demo-icon icon-link-ext">&#xf08e;</i> <span class="i-name">icon-link-ext</span><span class="i-code">0xf08e</span></div>
         <div class="the-icons span3" title="Code: 0xf08f"><i class="demo-icon icon-link-ext-alt">&#xf08f;</i> <span class="i-name">icon-link-ext-alt</span><span class="i-code">0xf08f</span></div>
-      </div>
-      <div class="row">
         <div class="the-icons span3" title="Code: 0xf0c9"><i class="demo-icon icon-menu">&#xf0c9;</i> <span class="i-name">icon-menu</span><span class="i-code">0xf0c9</span></div>
         <div class="the-icons span3" title="Code: 0xf0e0"><i class="demo-icon icon-mail-alt">&#xf0e0;</i> <span class="i-name">icon-mail-alt</span><span class="i-code">0xf0e0</span></div>
-        <div class="the-icons span3" title="Code: 0xf0e5"><i class="demo-icon icon-comment-empty">&#xf0e5;</i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xf0e5</span></div>
-        <div class="the-icons span3" title="Code: 0xf112"><i class="demo-icon icon-reply">&#xf112;</i> <span class="i-name">icon-reply</span><span class="i-code">0xf112</span></div>
       </div>
       <div class="row">
+        <div class="the-icons span3" title="Code: 0xf0e5"><i class="demo-icon icon-comment-empty">&#xf0e5;</i> <span class="i-name">icon-comment-empty</span><span class="i-code">0xf0e5</span></div>
+        <div class="the-icons span3" title="Code: 0xf0fe"><i class="demo-icon icon-plus-squared">&#xf0fe;</i> <span class="i-name">icon-plus-squared</span><span class="i-code">0xf0fe</span></div>
+        <div class="the-icons span3" title="Code: 0xf112"><i class="demo-icon icon-reply">&#xf112;</i> <span class="i-name">icon-reply</span><span class="i-code">0xf112</span></div>
         <div class="the-icons span3" title="Code: 0xf13e"><i class="demo-icon icon-lock-open-alt">&#xf13e;</i> <span class="i-name">icon-lock-open-alt</span><span class="i-code">0xf13e</span></div>
+      </div>
+      <div class="row">
+        <div class="the-icons span3" title="Code: 0xf164"><i class="demo-icon icon-thumbs-up-alt">&#xf164;</i> <span class="i-name">icon-thumbs-up-alt</span><span class="i-code">0xf164</span></div>
         <div class="the-icons span3" title="Code: 0xf1e5"><i class="demo-icon icon-binoculars">&#xf1e5;</i> <span class="i-name">icon-binoculars</span><span class="i-code">0xf1e5</span></div>
         <div class="the-icons span3" title="Code: 0xf234"><i class="demo-icon icon-user-plus">&#xf234;</i> <span class="i-name">icon-user-plus</span><span class="i-code">0xf234</span></div>
       </div>
diff --git a/static/font/font/fontello.eot b/static/font/font/fontello.eot
index 0533282b..7dfef262 100644
Binary files a/static/font/font/fontello.eot and b/static/font/font/fontello.eot differ
diff --git a/static/font/font/fontello.svg b/static/font/font/fontello.svg
index ec7c464d..6e5616a1 100644
--- a/static/font/font/fontello.svg
+++ b/static/font/font/fontello.svg
@@ -14,11 +14,11 @@
 
 <glyph glyph-name="star-empty" unicode="&#xe803;" d="M635 297l170 166-235 34-106 213-105-213-236-34 171-166-41-235 211 111 211-111z m294 199q0-12-15-27l-202-197 48-279q0-4 0-12 0-28-23-28-10 0-22 7l-251 132-250-132q-12-7-23-7-11 0-17 9t-6 19q0 4 1 12l48 279-203 197q-14 15-14 27 0 21 31 26l280 40 126 254q11 23 27 23t28-23l125-254 280-40q32-5 32-26z" horiz-adv-x="928.6" />
 
-<glyph glyph-name="retweet" unicode="&#xe804;" d="M714 18q0-7-5-13t-13-5h-535q-5 0-8 1t-5 4-3 4-2 7 0 6v335h-107q-15 0-25 11t-11 25q0 13 8 23l179 214q11 12 27 12t28-12l178-214q9-10 9-23 0-15-11-25t-25-11h-107v-214h321q9 0 14-6l89-108q4-5 4-11z m357 232q0-13-8-23l-178-214q-12-13-28-13t-27 13l-179 214q-8 10-8 23 0 14 11 25t25 11h107v214h-322q-9 0-14 7l-89 107q-4 5-4 11 0 7 5 12t13 6h536q4 0 7-1t5-4 3-5 2-6 1-7v-334h107q14 0 25-11t10-25z" horiz-adv-x="1071.4" />
+<glyph glyph-name="adjust" unicode="&#xe804;" d="M429 53v608q-83 0-153-41t-110-111-41-152 41-152 110-111 153-41z m428 304q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
 
 <glyph glyph-name="eye-off" unicode="&#xe805;" d="M310 112l43 79q-48 35-76 88t-27 114q0 67 34 125-128-65-213-197 94-144 239-209z m217 424q0 11-8 19t-19 7q-70 0-120-50t-50-119q0-11 8-19t19-8 19 8 8 19q0 48 34 82t82 34q11 0 19 8t8 19z m202 106q0-4 0-5-59-105-176-316t-176-316l-28-50q-5-9-15-9-7 0-75 39-9 6-9 16 0 7 25 49-80 36-147 96t-117 137q-11 17-11 38t11 39q86 131 212 207t277 76q50 0 100-10l31 54q5 9 15 9 3 0 10-3t18-9 18-10 18-10 10-7q9-5 9-15z m21-249q0-78-44-142t-117-91l157 280q4-25 4-47z m250-72q0-19-11-38-22-36-61-81-84-96-194-149t-234-53l41 74q119 10 219 76t169 171q-65 100-158 164l35 63q53-36 102-85t81-103q11-19 11-39z" horiz-adv-x="1000" />
 
-<glyph glyph-name="plus-squared" unicode="&#xe806;" d="M714 321v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-25-10t-11-25v-72q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
+<glyph glyph-name="retweet" unicode="&#xe806;" d="M714 18q0-7-5-13t-13-5h-535q-5 0-8 1t-5 4-3 4-2 7 0 6v335h-107q-15 0-25 11t-11 25q0 13 8 23l179 214q11 12 27 12t28-12l178-214q9-10 9-23 0-15-11-25t-25-11h-107v-214h321q9 0 14-6l89-108q4-5 4-11z m357 232q0-13-8-23l-178-214q-12-13-28-13t-27 13l-179 214q-8 10-8 23 0 14 11 25t25 11h107v214h-322q-9 0-14 7l-89 107q-4 5-4 11 0 7 5 12t13 6h536q4 0 7-1t5-4 3-5 2-6 1-7v-334h107q14 0 25-11t10-25z" horiz-adv-x="1071.4" />
 
 <glyph glyph-name="cog" unicode="&#xe807;" d="M571 357q0 59-41 101t-101 42-101-42-42-101 42-101 101-42 101 42 41 101z m286 61v-124q0-7-4-13t-11-7l-104-16q-10-30-21-51 19-27 59-77 6-6 6-13t-5-13q-15-21-55-61t-53-39q-7 0-14 5l-77 60q-25-13-51-21-9-76-16-104-4-16-20-16h-124q-8 0-14 5t-6 12l-16 103q-27 9-50 21l-79-60q-6-5-14-5-8 0-14 6-70 64-92 94-4 5-4 13 0 6 5 12 8 12 28 37t30 40q-15 28-23 55l-102 15q-7 1-11 7t-5 13v124q0 7 5 13t10 7l104 16q8 25 22 51-23 32-60 77-6 7-6 14 0 5 5 12 15 20 55 60t53 40q7 0 15-5l77-60q24 13 50 21 9 76 17 104 3 16 20 16h124q7 0 13-5t7-12l15-103q28-9 51-20l79 59q5 5 13 5 7 0 14-5 72-67 92-95 4-5 4-12 0-7-4-13-9-12-29-37t-30-40q15-28 23-54l102-16q7-1 12-7t4-13z" horiz-adv-x="857.1" />
 
@@ -46,6 +46,10 @@
 
 <glyph glyph-name="brush" unicode="&#xe813;" d="M464 209q0-124-87-212t-210-87q-81 0-149 40 68 39 109 108t40 151q0 61 44 105t105 44 105-44 43-105z m415 562q32-32 32-79t-33-79l-318-318q-20 55-61 97t-97 62l318 318q32 32 79 32t80-33z" horiz-adv-x="928" />
 
+<glyph glyph-name="attention" unicode="&#xe814;" d="M571 90v106q0 8-5 13t-12 5h-108q-7 0-12-5t-5-13v-106q0-8 5-13t12-6h108q7 0 12 6t5 13z m-1 208l10 257q0 6-5 10-7 6-14 6h-122q-6 0-14-6-5-4-5-12l9-255q0-5 6-9t13-3h103q8 0 14 3t5 9z m-7 522l428-786q20-35-1-70-9-17-26-26t-35-10h-858q-18 0-35 10t-26 26q-21 35-1 70l429 786q9 17 26 27t36 10 36-10 27-27z" horiz-adv-x="1000" />
+
+<glyph glyph-name="plus" unicode="&#xe815;" d="M786 446v-107q0-22-16-38t-38-15h-232v-233q0-22-16-37t-38-16h-107q-22 0-38 16t-15 37v233h-232q-23 0-38 15t-16 38v107q0 23 16 38t38 16h232v232q0 22 15 38t38 16h107q23 0 38-16t16-38v-232h232q23 0 38-16t16-38z" horiz-adv-x="785.7" />
+
 <glyph glyph-name="spin3" unicode="&#xe832;" d="M494 857c-266 0-483-210-494-472-1-19 13-20 13-20l84 0c16 0 19 10 19 18 10 199 176 358 378 358 107 0 205-45 273-118l-58-57c-11-12-11-27 5-31l247-50c21-5 46 11 37 44l-58 227c-2 9-16 22-29 13l-65-60c-89 91-214 148-352 148z m409-508c-16 0-19-10-19-18-10-199-176-358-377-358-108 0-205 45-274 118l59 57c10 12 10 27-5 31l-248 50c-21 5-46-11-37-44l58-227c2-9 16-22 30-13l64 60c89-91 214-148 353-148 265 0 482 210 493 473 1 18-13 19-13 19l-84 0z" horiz-adv-x="1000" />
 
 <glyph glyph-name="spin4" unicode="&#xe834;" d="M498 857c-114 0-228-39-320-116l0 0c173 140 428 130 588-31 134-134 164-332 89-495-10-29-5-50 12-68 21-20 61-23 84 0 3 3 12 15 15 24 71 180 33 393-112 539-99 98-228 147-356 147z m-409-274c-14 0-29-5-39-16-3-3-13-15-15-24-71-180-34-393 112-539 185-185 479-195 676-31l0 0c-173-140-428-130-589 31-134 134-163 333-89 495 11 29 6 50-12 68-11 11-27 17-44 16z" horiz-adv-x="1001" />
@@ -60,10 +64,14 @@
 
 <glyph glyph-name="comment-empty" unicode="&#xf0e5;" d="M500 643q-114 0-213-39t-157-105-59-142q0-62 40-119t113-98l48-28-15-53q-13-51-39-97 85 36 154 96l24 21 32-3q38-5 72-5 114 0 213 39t157 105 59 142-59 142-157 105-213 39z m500-286q0-97-67-179t-182-130-251-48q-39 0-81 4-110-97-257-135-27-8-63-12h-3q-8 0-15 6t-9 15v1q-2 2 0 6t1 6 2 5l4 5t4 5 4 5q4 5 17 19t20 22 17 22 18 28 15 33 15 42q-88 50-138 123t-51 157q0 97 67 179t182 130 251 48 251-48 182-130 67-179z" horiz-adv-x="1000" />
 
+<glyph glyph-name="plus-squared" unicode="&#xf0fe;" d="M714 321v72q0 14-10 25t-25 10h-179v179q0 15-11 25t-25 11h-71q-15 0-25-11t-11-25v-179h-178q-15 0-25-10t-11-25v-72q0-14 11-25t25-10h178v-179q0-14 11-25t25-11h71q15 0 25 11t11 25v179h179q14 0 25 10t10 25z m143 304v-536q0-66-47-113t-114-48h-535q-67 0-114 48t-47 113v536q0 66 47 113t114 48h535q67 0 114-48t47-113z" horiz-adv-x="857.1" />
+
 <glyph glyph-name="reply" unicode="&#xf112;" d="M1000 232q0-93-71-252-1-4-6-13t-7-17-7-12q-7-10-16-10-8 0-13 6t-5 14q0 5 1 15t2 13q3 38 3 69 0 56-10 101t-27 77-45 56-59 39-74 24-86 12-98 3h-125v-143q0-14-10-25t-26-11-25 11l-285 286q-11 10-11 25t11 25l285 286q11 10 25 10t26-10 10-25v-143h125q398 0 488-225 30-75 30-186z" horiz-adv-x="1000" />
 
 <glyph glyph-name="lock-open-alt" unicode="&#xf13e;" d="M589 428q23 0 38-15t16-38v-322q0-22-16-37t-38-16h-535q-23 0-38 16t-16 37v322q0 22 16 38t38 15h17v179q0 103 74 177t176 73 177-73 73-177q0-14-10-25t-25-11h-36q-14 0-25 11t-11 25q0 59-42 101t-101 42-101-42-41-101v-179h410z" horiz-adv-x="642.9" />
 
+<glyph glyph-name="thumbs-up-alt" unicode="&#xf164;" d="M143 107q0 15-11 25t-25 11q-15 0-25-11t-11-25q0-15 11-25t25-11q15 0 25 11t11 25z m89 286v-357q0-15-10-25t-26-11h-160q-15 0-25 11t-11 25v357q0 14 11 25t25 10h160q15 0 26-10t10-25z m661 0q0-48-31-83 9-25 9-43 1-42-24-76 9-31 0-66-9-31-31-52 5-62-27-101-36-43-110-44h-72q-37 0-80 9t-68 16-67 22q-69 24-88 25-15 0-25 11t-11 25v357q0 14 10 25t24 11q13 1 42 33t57 67q38 49 56 67 10 10 17 27t10 27 8 34q4 22 7 34t11 29 19 28q10 11 25 11 25 0 46-6t33-15 22-22 14-25 7-28 2-25 1-22q0-21-6-43t-10-33-16-31q-1-4-5-10t-6-13-5-13h155q43 0 75-32t32-75z" horiz-adv-x="928.6" />
+
 <glyph glyph-name="binoculars" unicode="&#xf1e5;" d="M393 678v-428q0-15-11-25t-25-11v-321q0-15-10-25t-26-11h-285q-15 0-25 11t-11 25v285l139 488q4 12 17 12h237z m178 0v-392h-142v392h142z m429-500v-285q0-15-11-25t-25-11h-285q-15 0-25 11t-11 25v321q-15 0-25 11t-11 25v428h237q13 0 17-12z m-589 661v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z m375 0v-125h-197v125q0 8 5 13t13 5h161q8 0 13-5t5-13z" horiz-adv-x="1000" />
 
 <glyph glyph-name="user-plus" unicode="&#xf234;" d="M393 357q-89 0-152 63t-62 151 62 152 152 63 151-63 63-152-63-151-151-63z m536-71h196q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-196v-197q0-7-6-12t-12-6h-107q-8 0-13 6t-5 12v197h-197q-7 0-12 5t-6 13v107q0 7 6 12t12 6h197v196q0 7 5 13t13 5h107q7 0 12-5t6-13v-196z m-411-125q0-29 21-51t50-21h143v-133q-38-28-95-28h-488q-67 0-108 39t-41 106q0 30 2 58t8 61 15 60 24 55 34 45 48 30 62 11q11 0 22-10 44-34 86-51t92-17 92 17 86 51q11 10 22 10 73 0 121-54h-125q-29 0-50-21t-21-50v-107z" horiz-adv-x="1142.9" />
diff --git a/static/font/font/fontello.ttf b/static/font/font/fontello.ttf
index 3f91b643..1fe7c631 100644
Binary files a/static/font/font/fontello.ttf and b/static/font/font/fontello.ttf differ
diff --git a/static/font/font/fontello.woff b/static/font/font/fontello.woff
index ec5cf4aa..fc65e325 100644
Binary files a/static/font/font/fontello.woff and b/static/font/font/fontello.woff differ
diff --git a/static/font/font/fontello.woff2 b/static/font/font/fontello.woff2
index 8eed845a..8513d894 100644
Binary files a/static/font/font/fontello.woff2 and b/static/font/font/fontello.woff2 differ
diff --git a/static/styles.json b/static/styles.json
index 7116ef20..00ad6ae1 100644
--- a/static/styles.json
+++ b/static/styles.json
@@ -5,5 +5,11 @@
   "bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"],
   "ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ],
   "monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ],
-  "mammal": [ "Mammal", "#272c37", "#444b5d", "#f8f8f8", "#9bacc8", "#7f3142", "#2bd850", "#2b90d9", "#ca8f04" ]
+  "mammal": [ "Mammal", "#272c37", "#444b5d", "#f8f8f8", "#9bacc8", "#7f3142", "#2bd850", "#2b90d9", "#ca8f04" ],
+
+  "redmond-xx": "/static/themes/redmond-xx.json",
+  "redmond-xx-se": "/static/themes/redmond-xx-se.json",
+  "redmond-xxi": "/static/themes/redmond-xxi.json",
+  "breezy-dark": "/static/themes/breezy-dark.json",
+  "breezy-light": "/static/themes/breezy-light.json"
 }
diff --git a/static/themes/breezy-dark.json b/static/themes/breezy-dark.json
new file mode 100644
index 00000000..6119bf88
--- /dev/null
+++ b/static/themes/breezy-dark.json
@@ -0,0 +1,139 @@
+{
+  "_pleroma_theme_version": 2,
+  "name": "Breezy Dark (beta)",
+  "theme": {
+    "shadows": {
+      "panel": [
+        {
+          "x": "1",
+          "y": "2",
+          "blur": "6",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.6
+        }
+      ],
+      "button": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": "0",
+          "spread": "1",
+          "color": "#ffffff",
+          "alpha": "0.15",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "panelHeader": [
+        {
+          "x": 0,
+          "y": "40",
+          "blur": "40",
+          "spread": "-40",
+          "inset": true,
+          "color": "#ffffff",
+          "alpha": "0.1"
+        }
+      ],
+      "buttonHover": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "--link",
+          "alpha": "0.3",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "buttonPressed": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": "0",
+          "spread": "50",
+          "color": "--faint",
+          "alpha": 1,
+          "inset": true
+        },
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#ffffff",
+          "alpha": 0.2,
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": 0,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "input": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#FFFFFF",
+          "alpha": "0.2",
+          "inset": true
+        }
+      ]
+    },
+    "fonts": {},
+    "opacity": {
+      "input": "1",
+      "panel": "0"
+    },
+    "colors": {
+      "bg": "#31363b",
+      "text": "#eff0f1",
+      "link": "#3daee9",
+      "fg": "#31363b",
+      "panel": "#31363b",
+      "input": "#232629",
+      "topBarLink": "#eff0f1",
+      "btn": "#31363b",
+      "border": "#4c545b",
+      "cRed": "#da4453",
+      "cBlue": "#3daee9",
+      "cGreen": "#27ae60",
+      "cOrange": "#f67400"
+    },
+    "radii": {
+      "btn": "2",
+      "input": "2",
+      "checkbox": "1",
+      "panel": "2",
+      "avatar": "2",
+      "avatarAlt": "2",
+      "tooltip": "2",
+      "attachment": "2"
+    }
+  }
+}
diff --git a/static/themes/breezy-light.json b/static/themes/breezy-light.json
new file mode 100644
index 00000000..becf704f
--- /dev/null
+++ b/static/themes/breezy-light.json
@@ -0,0 +1,139 @@
+{
+  "_pleroma_theme_version": 2,
+  "name": "Breezy Light (beta)",
+  "theme": {
+    "shadows": {
+      "panel": [
+        {
+          "x": "1",
+          "y": "2",
+          "blur": "6",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.6
+        }
+      ],
+      "button": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": "0",
+          "spread": "1",
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "panelHeader": [
+        {
+          "x": 0,
+          "y": "40",
+          "blur": "40",
+          "spread": "-40",
+          "inset": true,
+          "color": "#ffffff",
+          "alpha": "0.1"
+        }
+      ],
+      "buttonHover": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "--link",
+          "alpha": "0.3",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "buttonPressed": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": "0",
+          "spread": "50",
+          "color": "--faint",
+          "alpha": 1,
+          "inset": true
+        },
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#ffffff",
+          "alpha": 0.2,
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": 0,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "input": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#000000",
+          "alpha": "0.2",
+          "inset": true
+        }
+      ]
+    },
+    "fonts": {},
+    "opacity": {
+      "input": "1"
+    },
+    "colors": {
+      "bg": "#eff0f1",
+      "text": "#232627",
+      "link": "#2980b9",
+      "fg": "#bcc2c7",
+      "panel": "#475057",
+      "panelText": "#fcfcfc",
+      "input": "#fcfcfc",
+      "topBar": "#475057",
+      "topBarLink": "#eff0f1",
+      "btn": "#eff0f1",
+      "cRed": "#da4453",
+      "cBlue": "#2980b9",
+      "cGreen": "#27ae60",
+      "cOrange": "#f67400"
+    },
+    "radii": {
+      "btn": "2",
+      "input": "2",
+      "checkbox": "1",
+      "panel": "2",
+      "avatar": "2",
+      "avatarAlt": "2",
+      "tooltip": "2",
+      "attachment": "2"
+    }
+  }
+}
diff --git a/static/themes/redmond-xx-se.json b/static/themes/redmond-xx-se.json
new file mode 100644
index 00000000..70ee89d1
--- /dev/null
+++ b/static/themes/redmond-xx-se.json
@@ -0,0 +1,297 @@
+{
+  "_pleroma_theme_version": 2,
+  "name": "Redmond XX SE",
+  "theme": {
+    "shadows": {
+      "panel": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "panelHeader": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": 0,
+          "spread": "3",
+          "inset": true,
+          "color": "#c0c0c0",
+          "alpha": 1
+        },
+        {
+          "x": "-2200",
+          "y": 0,
+          "blur": "200",
+          "spread": "-2000",
+          "inset": true,
+          "color": "#1084d0",
+          "alpha": 1
+        }
+      ],
+      "button": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "buttonHover": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "buttonPressed": [
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "input": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--input",
+          "alpha": "1",
+          "inset": true
+        }
+      ]
+    },
+    "fonts": {},
+    "opacity": {
+      "input": "1",
+      "faint": "1"
+    },
+    "colors": {
+      "bg": "#c0c0c0",
+      "text": "#000000",
+      "link": "#0000ff",
+      "fg": "#c0c0c0",
+      "panel": "#000080",
+      "panelFaint": "#c0c0c0",
+      "input": "#ffffff",
+      "topBar": "#000080",
+      "topBarLink": "#ffffff",
+      "btn": "#c0c0c0",
+      "faint": "#3f3f3f",
+      "faintLink": "#404080",
+      "border": "#808080",
+      "cRed": "#FF0000",
+      "cBlue": "#008080",
+      "cGreen": "#008000",
+      "cOrange": "#808000"
+    },
+    "radii": {
+      "btn": "0",
+      "input": "0",
+      "checkbox": "0",
+      "panel": "0",
+      "avatar": "0",
+      "avatarAlt": "0",
+      "tooltip": "0",
+      "attachment": "0"
+    }
+  }
+}
diff --git a/static/themes/redmond-xx.json b/static/themes/redmond-xx.json
new file mode 100644
index 00000000..4fd6a369
--- /dev/null
+++ b/static/themes/redmond-xx.json
@@ -0,0 +1,288 @@
+{
+  "_pleroma_theme_version": 2,
+  "name": "Redmond XX",
+  "theme": {
+    "shadows": {
+      "panel": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "panelHeader": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": 0,
+          "spread": "3",
+          "inset": true,
+          "color": "#c0c0c0",
+          "alpha": 1
+        }
+      ],
+      "button": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "buttonHover": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "buttonPressed": [
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "input": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--input",
+          "alpha": "1",
+          "inset": true
+        }
+      ]
+    },
+    "fonts": {},
+    "opacity": {
+      "input": "1",
+      "faint": "1"
+    },
+    "colors": {
+      "bg": "#c0c0c0",
+      "text": "#000000",
+      "link": "#0000ff",
+      "fg": "#c0c0c0",
+      "panel": "#000080",
+      "panelFaint": "#c0c0c0",
+      "input": "#ffffff",
+      "topBar": "#000080",
+      "topBarLink": "#ffffff",
+      "btn": "#c0c0c0",
+      "faint": "#3f3f3f",
+      "faintLink": "#404080",
+      "border": "#808080",
+      "cRed": "#FF0000",
+      "cBlue": "#008080",
+      "cGreen": "#008000",
+      "cOrange": "#808000"
+    },
+    "radii": {
+      "btn": "0",
+      "input": "0",
+      "checkbox": "0",
+      "panel": "0",
+      "avatar": "0",
+      "avatarAlt": "0",
+      "tooltip": "0",
+      "attachment": "0"
+    }
+  }
+}
diff --git a/static/themes/redmond-xxi.json b/static/themes/redmond-xxi.json
new file mode 100644
index 00000000..d10bf138
--- /dev/null
+++ b/static/themes/redmond-xxi.json
@@ -0,0 +1,270 @@
+{
+  "_pleroma_theme_version": 2,
+  "name": "Redmond XXI",
+  "theme": {
+    "shadows": {
+      "panel": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#404040",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#dfdfdf",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "panelHeader": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": 0,
+          "spread": "3",
+          "inset": true,
+          "color": "#d6d6ce",
+          "alpha": 1
+        },
+        {
+          "x": "-2200",
+          "y": 0,
+          "blur": "200",
+          "spread": "-2000",
+          "inset": true,
+          "color": "#a5cef7",
+          "alpha": 1
+        }
+      ],
+      "button": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#404040",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "buttonHover": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#404040",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "buttonPressed": [
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#404040",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--bg",
+          "alpha": "1",
+          "inset": true
+        }
+      ],
+      "input": [
+        {
+          "x": "-1",
+          "y": "-1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "0",
+          "spread": 0,
+          "color": "#848484",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "-2",
+          "y": "-2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#d4d0c8",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "2",
+          "y": "2",
+          "blur": "0",
+          "spread": 0,
+          "color": "#404040",
+          "alpha": "1",
+          "inset": true
+        },
+        {
+          "x": "0",
+          "y": "0",
+          "blur": "0",
+          "spread": "3",
+          "color": "--input",
+          "alpha": "1",
+          "inset": true
+        }
+      ]
+    },
+    "fonts": {},
+    "opacity": {
+      "input": "1",
+      "faint": "1"
+    },
+    "colors": {
+      "bg": "#d6d6ce",
+      "text": "#000000",
+      "link": "#0000ff",
+      "fg": "#d6d6ce",
+      "panel": "#042967",
+      "panelFaint": "#FFFFFF",
+      "input": "#ffffff",
+      "topBar": "#042967",
+      "topBarLink": "#ffffff",
+      "btn": "#d6d6ce",
+      "faint": "#3f3f3f",
+      "faintLink": "#404080",
+      "border": "#808080",
+      "cRed": "#c42726",
+      "cBlue": "#6699cc",
+      "cGreen": "#669966",
+      "cOrange": "#cc6633"
+    },
+    "radii": {
+      "btn": "0",
+      "input": "0",
+      "checkbox": "0",
+      "panel": "0",
+      "avatar": "0",
+      "avatarAlt": "0",
+      "tooltip": "0",
+      "attachment": "0"
+    }
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index 85c68036..6b8a97cb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1205,6 +1205,10 @@ chokidar@^1.0.0, chokidar@^1.4.1:
   optionalDependencies:
     fsevents "^1.0.0"
 
+chromatism@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/chromatism/-/chromatism-3.0.0.tgz#a7249d353c1e4f3577e444ac41171c4e2e624b12"
+
 chromedriver@^2.21.2:
   version "2.35.0"
   resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.35.0.tgz#c103ba2fb3d1671f666058159f5cbaa816902e4d"
@@ -5980,6 +5984,10 @@ vue@^2.1.10, vue@^2.5.13:
   version "2.5.13"
   resolved "https://registry.yarnpkg.com/vue/-/vue-2.5.13.tgz#95bd31e20efcf7a7f39239c9aa6787ce8cf578e1"
 
+vuelidate@^0.7.4:
+  version "0.7.4"
+  resolved "https://registry.yarnpkg.com/vuelidate/-/vuelidate-0.7.4.tgz#5a0e54be09ac0192f1aa3387d74b92e0945bf8aa"
+
 vuex@^3.0.1:
   version "3.0.1"
   resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.0.1.tgz#e761352ebe0af537d4bb755a9b9dc4be3df7efd2"