diff --git a/app/assets/stylesheets/_variables.scss b/app/assets/stylesheets/_variables.scss
index 819418b6..f57f46c3 100644
--- a/app/assets/stylesheets/_variables.scss
+++ b/app/assets/stylesheets/_variables.scss
@@ -26,7 +26,8 @@ $avatar-sizes: (
   "xs": 20px,
   "sm": 30px,
   "md": 40px,
-  "lg": 80px
+  "lg": 80px,
+  "xl": 160px,
 );
 
 :root {
diff --git a/app/assets/stylesheets/application.css.scss b/app/assets/stylesheets/application.css.scss
index 6401bf6b..eb59637c 100644
--- a/app/assets/stylesheets/application.css.scss
+++ b/app/assets/stylesheets/application.css.scss
@@ -101,6 +101,7 @@ $navbar-inverse-toggle-border-color: #512da8;
 "components/avatars",
 "components/buttons",
 "components/jumbotron",
+"components/profile",
 "components/question";
 
 body { padding-top: 50px; }
diff --git a/app/assets/stylesheets/components/_profile.scss b/app/assets/stylesheets/components/_profile.scss
new file mode 100644
index 00000000..5674db9a
--- /dev/null
+++ b/app/assets/stylesheets/components/_profile.scss
@@ -0,0 +1,62 @@
+.profile {
+  &__avatar {
+    display: block;
+    width: map-get($avatar-sizes, "xl");
+    height: map-get($avatar-sizes, "xl");
+    margin: -(map-get($avatar-sizes, "xl") / 2) auto 0;
+    border-radius: $avatar-border-radius;
+    box-shadow: $box-shadow;
+  }
+
+  &__header-container {
+    margin-bottom: map-get($spacers, 3);
+    position: relative;
+    z-index: -1;
+    width: 100%;
+    overflow: hidden;
+    background: linear-gradient(
+      to top,
+      rgba(0, 0, 0, 0.10),
+      rgba(0, 0, 0, 0.10)
+    ) var(--primary);
+    max-height: 440px;
+  }
+
+  &__header-image {
+    display: block;
+    min-width: 900px;
+    width: 100%;
+  }
+
+  &__name,
+  &__biography,
+  &__website,
+  &__location {
+    margin-bottom: map-get($spacers, 3);
+  }
+
+  &__actions,
+  &__biography {
+    margin-top: map-get($spacers, 3);
+  }
+
+  &__display-name {
+    font-weight: bold;
+    font-size: 1.1em;
+  }
+
+  &__screen-name {
+    &:only-child {
+      @extend .profile__display-name;
+    }
+
+    &:not(:only-child) {
+      font-size: 0.9em;
+      color: RGB(var(--muted-text));
+    }
+  }
+}
+
+.user--banned {
+  text-decoration: line-through !important;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/scss/user.scss b/app/assets/stylesheets/scss/user.scss
index 507ce9c7..ea9dada6 100644
--- a/app/assets/stylesheets/scss/user.scss
+++ b/app/assets/stylesheets/scss/user.scss
@@ -1,118 +1,3 @@
-.profile--img {
-  min-height: 80px;
-  min-width: 80px;
-  height: 80px;
-  width: 8px;
-}
-
-.profile--displayname {
-  font-weight: 700;
-  font-size: 1.2em;
-  margin-top: -0.165em;
-  line-height: 1.33em;
-}
-
-.profile--username {
-  font-size: 0.9em;
-  color: rgba(0, 0, 0, 0.4);
-  line-height: 1.33;
-}
-
-.profile--followtag {
-  margin: 0px 0px 0.2em;
-}
-
-.profile--text {
-  margin-bottom: 2px;
-  line-height: 1.5em;
-  margin-top: 0.65em;
-}
-
-#profile--header {
-  position: relative;
-  z-index: -1;
-  width: 100%;
-  overflow: hidden;
-  background-color: darken($navbar-inverse-bg, 10%);
-  max-height: 440px;
-}
-
-.profile--panel .panel-heading {
-  color: theme-color('primary');
-  border-bottom: 2px solid theme-color('primary');
-  background-color: #fff;
-  text-transform: uppercase;
-}
-
-.profile--panel .panel-body {
-  padding-top: 0px;
-}
-
-.inbox--panel .panel-heading {
-  color: theme-color('info');
-  border-bottom: 2px solid theme-color('info');
-  background-color: #fff;
-  text-transform: uppercase;
-}
-
-.warning--panel .panel-heading {
-  color: theme-color('danger');
-  border-bottom: 2px solid theme-color('danger');
-  background-color: #fff;
-  text-transform: uppercase;
-}
-
-.profile--follow-btn {
-  margin-top: 5px;
-}
-
-.profile--avatar {
-  width: 100%;
-  height: auto;
-  border: medium none;
-}
-
-.profile--panel-badge {
-  width: 100%;
-  text-align: center;
-  padding-top: 0.15em;
-  padding-bottom: 0.15em;
-  text-transform: uppercase;
-  font-weight: bold;
-  margin: 0;
-  color: #fff;
-}
-
-$colours: danger theme-color('danger'),
-          default #BBB,
-          success theme-color('success'),
-          warning theme-color('warning'),
-          primary theme-color('primary'),
-          info #2980b9;
-
-@each $colour in $colours {
-  .panel-badge-#{nth($colour, 1)} {
-    background-color: nth($colour, 2);
-  }
-}
-
-.user--banned {
-  text-decoration: line-through !important;
-}
-
-.profile--header-img {
-  display: block;
-  min-width: 900px;
-  width: 100%;
-}
-
-@media(min-width: 767px) {
-  .container.headerable {
-    padding-top: 0;
-    margin-top: -30px;
-  }
-}
-
 .userbox--header {
   width: 100%;
   height: auto;
diff --git a/app/views/layouts/user/profile.haml b/app/views/layouts/user/profile.haml
index 7d35c155..c551a4c3 100644
--- a/app/views/layouts/user/profile.haml
+++ b/app/views/layouts/user/profile.haml
@@ -1,11 +1,11 @@
-#profile--header
-  %img.profile--header-img{src: @user.profile_header.url(:web)}
-.container.j2-page.headerable
+.profile__header-container
+  %img.profile__header-image{src: @user.profile_header.url(:web)}
+.container
   .row
-    #profile-info.col-md-3.col-xs-12.col-sm-4.j2-col-reset
-      = render 'user/profile_info'
+    .col-md-3.col-xs-12.col-sm-4
+      = render 'user/profile'
       .d-none.d-sm-block= render 'shared/links'
-    .col-md-9.col-xs-12.col-sm-8.j2-col-reset
+    .col-md-9.col-xs-12.col-sm-8
       = render "questionbox"
       = render "tabs/profile"
       = yield
diff --git a/app/views/user/_actions.haml b/app/views/user/_actions.haml
new file mode 100644
index 00000000..f257fb09
--- /dev/null
+++ b/app/views/user/_actions.haml
@@ -0,0 +1,32 @@
+.profile__actions
+  - if user_signed_in?
+    - type ||= :nil
+    - if user == current_user
+      %a.btn.btn-dark.btn-block{href: edit_user_profile_path} Edit profile
+    - else
+      - if current_user.following? user
+        %button#editprofile.btn.btn-primary.btn-block{type: :button, name: 'user-action', data: { action: :unfollow, type: type, target: user.screen_name }}
+          = t 'views.actions.unfollow'
+      - else
+        %button#editprofile.btn.btn-primary.btn-block{type: :button, name: 'user-action', data: { action: :follow, type: type, target: user.screen_name }}
+          = t 'views.actions.follow'
+    - unless user == current_user
+      .btn-group.btn-block
+        %button.btn.btn-light.btn-block.btn-sm.dropdown-toggle{data: { toggle: :dropdown }, aria: { expanded: :false }}
+          = t 'views.actions.title'
+          %span.caret
+        .dropdown-menu
+          %a.dropdown-item.d-block.d-sm-none{href: '#', data: { target: "#modal-group-memberships", toggle: :modal }}
+            %i.fa.fa-users
+            = t 'views.actions.group'
+          %a.dropdown-item{href: '#', data: { action: 'report-user', target: user.screen_name }}
+            %i.fa.fa-exclamation-triangle
+            = t 'views.actions.report'
+          - if current_user.mod?
+            %a.dropdown-item{href: '#', data: { target: "#modal-privileges", toggle: :modal }}
+              %i.fa.fa-wrench
+              = raw t('views.actions.privilege', user: user.screen_name)
+            - unless user.has_role?(:administrator)
+              %a.dropdown-item{href: '#', data: { target: "#modal-ban", toggle: :modal }}
+                %i.fa.fa-ban
+                = t 'views.actions.ban'
diff --git a/app/views/user/_actions.html.haml b/app/views/user/_actions.html.haml
deleted file mode 100644
index 7f3ae676..00000000
--- a/app/views/user/_actions.html.haml
+++ /dev/null
@@ -1,40 +0,0 @@
-- if user_signed_in?
-  - type ||= :nil
-  - if user == current_user
-    %a.btn.btn-default.btn-block.profile--follow-btn{href: edit_user_profile_path} Edit profile
-  - else
-    - if current_user.following? user
-      %button#editprofile.btn.btn-default.btn-block.profile--follow-btn{type: :button, name: 'user-action', data: { action: :unfollow, type: type, target: user.screen_name }}
-        = t 'views.actions.unfollow'
-    - else
-      %button#editprofile.btn.btn-primary.btn-block.profile--follow-btn{type: :button, name: 'user-action', data: { action: :follow, type: type, target: user.screen_name }}
-        = t 'views.actions.follow'
-  - unless user == current_user
-    .btn-group.btn-block
-      %button.btn.btn-default.btn-block.btn-sm.dropdown-toggle{data: { toggle: :dropdown }, aria: { expanded: :false }}
-        = t 'views.actions.title'
-        %span.caret
-      %ul.dropdown-menu
-        /
-          %li
-            %a{href: '#', name: 'user-action', data: { action: :block, type: type, target: user.screen_name }}
-              %i.fa.fa-minus-circle
-              Block
-        %li.visible-xs
-          %a{href: '#', data: { target: "#modal-group-memberships", toggle: :modal }}
-            %i.fa.fa-users
-            = t 'views.actions.group'
-        %li
-          %a{href: '#', data: { action: 'report-user', target: user.screen_name }}
-            %i.fa.fa-exclamation-triangle
-            = t 'views.actions.report'
-        - if current_user.mod?
-          %li
-            %a{href: '#', data: { target: "#modal-privileges", toggle: :modal }}
-              %i.fa.fa-wrench
-              = raw t('views.actions.privilege', user: user.screen_name)
-          - unless user.has_role?(:administrator)
-            %li
-              %a{href: '#', data: { target: "#modal-ban", toggle: :modal }}
-                %i.fa.fa-ban
-                = t 'views.actions.ban'
diff --git a/app/views/user/_profile.haml b/app/views/user/_profile.haml
new file mode 100644
index 00000000..55783cd2
--- /dev/null
+++ b/app/views/user/_profile.haml
@@ -0,0 +1,38 @@
+.card#profile
+  %img.profile__avatar{src: @user.profile_picture.url(:large)}
+  .card-body
+    .profile__name
+      - unless @user.display_name.blank?
+        .profile__display-name
+          = @user.display_name
+      .profile__screen-name
+        = @user.screen_name
+    .profile__badge-container
+      - if @user.banned?
+        %span.badge.badge-dark
+          %i.fa.fa-fw.fa-ban
+          = t 'views.user.title.banned'
+      - if @user.following? current_user
+        .badge.badge-light
+          = t 'views.user.follows_you'
+      - if user_signed_in? && current_user.has_role?(:administrator)
+        - if @user.has_role?(:administrator)
+          %span.badge.badge-danger
+            %i.fa.fa-fw.fa-flask
+            = t 'views.user.title.admin'
+        - if @user.has_role?(:moderator)
+          %span.badge.badge-success
+            %i.fa.fa-fw.fa-users
+            = t 'views.user.title.moderator'
+    - unless @user.bio.blank?
+      .profile__biography
+        = markdown @user.bio
+    - unless @user.website.blank?
+      .profile__website
+        %i.fa.fa-fw.fa-globe
+        %a{href: @user.website}= @user.display_website
+    - unless @user.location.blank?
+      .profile__location
+        %i.fa.fa-fw.fa-location-arrow
+        = @user.location
+    = render 'user/actions', user: @user, type: :follower
diff --git a/app/views/user/_profile_info.html.haml b/app/views/user/_profile_info.html.haml
deleted file mode 100644
index 29a833e7..00000000
--- a/app/views/user/_profile_info.html.haml
+++ /dev/null
@@ -1,39 +0,0 @@
-.card#profile
-  %img.profile--avatar{src: @user.profile_picture.url(:large)}
-  - if user_signed_in? && current_user.has_role?(:administrator)
-    - if @user.has_role?(:administrator)
-      .profile--panel-badge.panel-badge-danger
-        %i.fa.fa-flask
-        = t 'views.user.title.admin'
-    - if @user.has_role?(:moderator)
-      .profile--panel-badge.panel-badge-success
-        %i.fa.fa-users
-        = t 'views.user.title.moderator'
-  - if @user.banned?
-    .profile--panel-badge.panel-badge-default
-      %i.fa.fa-ban
-      = t 'views.user.title.banned'
-  - if @user.following? current_user
-    .profile--panel-badge.panel-badge-default
-      = t 'views.user.follows_you'
-  .card-body
-    .profile--panel-name
-      - if @user.display_name.blank?
-        .profile--displayname
-          = @user.screen_name
-      - else
-        .profile--displayname
-          = @user.display_name
-        .profile--username
-          = @user.screen_name
-    - unless @user.bio.blank?
-      %p.profile--text= markdown @user.bio
-    - unless @user.website.blank?
-      %p.profile--text
-        %i.fa.fa-globe
-        %a{href: @user.website}= @user.display_website
-    - unless @user.location.blank?
-      %p.profile--text
-        %i.fa.fa-location-arrow
-        = @user.location
-    = render 'user/actions', user: @user, type: :follower