From 8c9dc92afb7391b5a033e72fdf590aca9e53dea2 Mon Sep 17 00:00:00 2001
From: Andreas Nedbal <git@pixelde.su>
Date: Tue, 3 Jan 2023 12:35:05 +0100
Subject: [PATCH] Move stylesheets back to `app/assets/stylesheets`

---
 app/assets/stylesheets/_utilities.scss        |  15 +
 app/assets/stylesheets/_variables.scss        | 105 +++
 app/assets/stylesheets/application.sass.scss  | 119 +++
 .../components/_announcements.scss            |  16 +
 .../stylesheets/components/_answerbox.scss    |  86 ++
 .../stylesheets/components/_avatars.scss      |  12 +
 .../stylesheets/components/_buttons.scss      |  19 +
 .../stylesheets/components/_comments.scss     |  39 +
 .../stylesheets/components/_container.scss    |  10 +
 app/assets/stylesheets/components/_entry.scss |  22 +
 app/assets/stylesheets/components/_flags.scss | 758 ++++++++++++++++++
 app/assets/stylesheets/components/_icons.scss |   4 +
 .../components/_inbox-actions.scss            |   9 +
 .../stylesheets/components/_inbox-entry.scss  |  22 +
 .../stylesheets/components/_jumbotron.scss    |  35 +
 .../stylesheets/components/_locales.scss      |  32 +
 .../stylesheets/components/_mobile-nav.scss   |  61 ++
 .../components/_notifications.scss            |  59 ++
 .../stylesheets/components/_profile.scss      |  97 +++
 .../components/_push-settings.scss            |   7 +
 .../stylesheets/components/_question.scss     |  18 +
 .../stylesheets/components/_smiles.scss       |  28 +
 .../stylesheets/components/_themes.scss       |  15 +
 .../stylesheets/components/_totp-setup.scss   |  76 ++
 .../stylesheets/components/_userbox.scss      |  37 +
 app/assets/stylesheets/elements/_body.scss    |  17 +
 app/assets/stylesheets/overrides/_alerts.scss |  11 +
 app/assets/stylesheets/overrides/_badges.scss |   6 +
 .../overrides/_bootstrap-datetimepicker.scss  |   3 +
 .../stylesheets/overrides/_buttons.scss       |  64 ++
 app/assets/stylesheets/overrides/_card.scss   |  18 +
 app/assets/stylesheets/overrides/_colors.scss |  13 +
 .../stylesheets/overrides/_dropdown.scss      |  35 +
 app/assets/stylesheets/overrides/_inputs.scss |  22 +
 app/assets/stylesheets/overrides/_links.scss  |   7 +
 .../stylesheets/overrides/_list-group.scss    |  21 +
 .../stylesheets/overrides/_minicolors.scss    |   9 +
 app/assets/stylesheets/overrides/_modal.scss  |  13 +
 app/assets/stylesheets/overrides/_navbar.scss |  58 ++
 .../stylesheets/overrides/_sweet-alert.scss   |   7 +
 app/assets/stylesheets/overrides/_toasts.scss |   5 +
 .../stylesheets/overrides/_turbolinks.scss    |  10 +
 42 files changed, 2020 insertions(+)
 create mode 100644 app/assets/stylesheets/_utilities.scss
 create mode 100644 app/assets/stylesheets/_variables.scss
 create mode 100644 app/assets/stylesheets/application.sass.scss
 create mode 100644 app/assets/stylesheets/components/_announcements.scss
 create mode 100644 app/assets/stylesheets/components/_answerbox.scss
 create mode 100644 app/assets/stylesheets/components/_avatars.scss
 create mode 100644 app/assets/stylesheets/components/_buttons.scss
 create mode 100644 app/assets/stylesheets/components/_comments.scss
 create mode 100644 app/assets/stylesheets/components/_container.scss
 create mode 100644 app/assets/stylesheets/components/_entry.scss
 create mode 100644 app/assets/stylesheets/components/_flags.scss
 create mode 100644 app/assets/stylesheets/components/_icons.scss
 create mode 100644 app/assets/stylesheets/components/_inbox-actions.scss
 create mode 100644 app/assets/stylesheets/components/_inbox-entry.scss
 create mode 100644 app/assets/stylesheets/components/_jumbotron.scss
 create mode 100644 app/assets/stylesheets/components/_locales.scss
 create mode 100644 app/assets/stylesheets/components/_mobile-nav.scss
 create mode 100644 app/assets/stylesheets/components/_notifications.scss
 create mode 100644 app/assets/stylesheets/components/_profile.scss
 create mode 100644 app/assets/stylesheets/components/_push-settings.scss
 create mode 100644 app/assets/stylesheets/components/_question.scss
 create mode 100644 app/assets/stylesheets/components/_smiles.scss
 create mode 100644 app/assets/stylesheets/components/_themes.scss
 create mode 100644 app/assets/stylesheets/components/_totp-setup.scss
 create mode 100644 app/assets/stylesheets/components/_userbox.scss
 create mode 100644 app/assets/stylesheets/elements/_body.scss
 create mode 100644 app/assets/stylesheets/overrides/_alerts.scss
 create mode 100644 app/assets/stylesheets/overrides/_badges.scss
 create mode 100644 app/assets/stylesheets/overrides/_bootstrap-datetimepicker.scss
 create mode 100644 app/assets/stylesheets/overrides/_buttons.scss
 create mode 100644 app/assets/stylesheets/overrides/_card.scss
 create mode 100644 app/assets/stylesheets/overrides/_colors.scss
 create mode 100644 app/assets/stylesheets/overrides/_dropdown.scss
 create mode 100644 app/assets/stylesheets/overrides/_inputs.scss
 create mode 100644 app/assets/stylesheets/overrides/_links.scss
 create mode 100644 app/assets/stylesheets/overrides/_list-group.scss
 create mode 100644 app/assets/stylesheets/overrides/_minicolors.scss
 create mode 100644 app/assets/stylesheets/overrides/_modal.scss
 create mode 100644 app/assets/stylesheets/overrides/_navbar.scss
 create mode 100644 app/assets/stylesheets/overrides/_sweet-alert.scss
 create mode 100644 app/assets/stylesheets/overrides/_toasts.scss
 create mode 100644 app/assets/stylesheets/overrides/_turbolinks.scss

diff --git a/app/assets/stylesheets/_utilities.scss b/app/assets/stylesheets/_utilities.scss
new file mode 100644
index 00000000..249b170d
--- /dev/null
+++ b/app/assets/stylesheets/_utilities.scss
@@ -0,0 +1,15 @@
+.ios-web-app {
+  padding-top: 1em;
+}
+
+.fs-10 {
+  font-size: 10em;
+}
+
+.pe-none {
+  pointer-events: none;
+}
+
+.empty:not(:only-child) {
+  display: none;
+}
diff --git a/app/assets/stylesheets/_variables.scss b/app/assets/stylesheets/_variables.scss
new file mode 100644
index 00000000..7c950fbf
--- /dev/null
+++ b/app/assets/stylesheets/_variables.scss
@@ -0,0 +1,105 @@
+// Font settings
+$lexend-font-path: "/assets";
+$lexend-weights: 500, 600;
+$fa-font-path: "/assets";
+
+$font-family-sans-serif: "Lexend", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+$font-family-serif: Georgia, "DejaVu Serif", "Times New Roman", Times, serif;
+$font-family-monospace: "PragmataPro", Monaco, "Ubuntu Mono", Menlo, "DejaVu Sans Mono", monospace;
+$font-family-base: $font-family-sans-serif;
+
+$font-size-base: 1rem;
+$font-size-large: ceil(($font-size-base * 1.25)); // ~18px
+$font-size-small: ceil(($font-size-base * 0.85)); // ~12px
+
+$font-size-h1: floor(($font-size-base * 2.6)); // ~36px
+$font-size-h2: floor(($font-size-base * 2.15)); // ~30px
+$font-size-h3: ceil(($font-size-base * 1.7)); // ~24px
+$font-size-h4: ceil(($font-size-base * 1.25)); // ~18px
+$font-size-h5: $font-size-base;
+$font-size-h6: ceil(($font-size-base * 0.85)); // ~12px
+
+// Usual navbar height
+$navbar-height: 56px;
+
+// Color overrides for Bootstrap
+$primary: #5e35b1;
+
+// Cards
+$card-border-width: 0;
+
+// List Groups
+$list-group-border-width: 0;
+
+// nProgress
+$nprogress-color: lighten($primary, 25%);
+
+// Color names for theme generation
+$color-names: (
+  "primary",
+  "danger",
+  "warning",
+  "info",
+  "success",
+  "dark",
+  "light"
+);
+
+// Avatar variables
+$avatar-border-radius: 4px;
+
+$avatar-sizes: (
+  "xs": 20px,
+  "sm": 30px,
+  "md": 40px,
+  "lg": 80px,
+  "xl": 120px,
+  "xxl": 160px,
+);
+
+$spacers: (
+  10: (1rem * 6)
+);
+
+:root {
+  --background: #f0edf4;
+  --input-bg: var(--background);
+  --raised-bg: #ffffff;
+  --raised-accent: #f7f7f7;
+
+  /**
+   NOTE for all *-text variables
+   ----------------------------------------------
+   The text-variables are present as triplets
+   because in some places it's required to adjust
+   their transparency.
+
+   So, for general usage, use:
+   color: RGB(var(--*-text));
+
+   And for transparent usage, use:
+   color: rgba(var(--*-text), .7);
+
+   The uppercase RGB is required because internally
+   SassC wants more than one argument for rgb(),
+   hence writing RGB() bypasses that check, but
+   browsers interpret it correctly.
+   */
+
+  --primary-text: 255, 255, 255;
+  --danger-text: 255, 255, 255;
+  --warning-text: 41, 41, 41;
+  --info-text: 255, 255, 255;
+  --success-text: 255, 255, 255;
+  --dark-text: 255, 255, 255;
+  --light-text: 0, 0, 0;
+
+  --body-text: 0, 0, 0;
+  --muted-text: 108, 117, 125;
+  --input-text: 0, 0, 0;
+  --input-placeholder: 108, 117, 125;
+
+  --turbolinks-progress-color: #a58adc; // --primary lightened by 25%
+}
+
+$gray: #e2e2e2;
diff --git a/app/assets/stylesheets/application.sass.scss b/app/assets/stylesheets/application.sass.scss
new file mode 100644
index 00000000..3873ed44
--- /dev/null
+++ b/app/assets/stylesheets/application.sass.scss
@@ -0,0 +1,119 @@
+/**
+ SETTINGS
+ ----------------------------------------------
+ Variable definitions, tools and mixins used
+ across all styling definitions.
+ */
+@use "@fontsource/lexend/scss/mixins" as Lexend;
+
+@import "variables";
+
+/**
+  VENDOR
+  ----------------------------------------------
+  Imported vendor assets used by Retrospring.
+  */
+
+@import "@melloware/coloris/dist/coloris",
+"bootstrap/scss/bootstrap",
+"croppr/dist/croppr",
+"font-awesome/scss/font-awesome",
+"sweetalert/dist/sweetalert",
+"toastify-js/src/toastify";
+
+
+@each $weight in $lexend-weights {
+  @include Lexend.fontFace($weight: $weight,
+    $display: fallback,
+    $fontDir: "assets/"
+  );
+}
+
+// Using Lexend Light (300) as Regular (400) as Regular is quite thick.
+@each $subset,
+$unicodeRangeValues in Lexend.$unicodeMap {
+  @font-face {
+    font-family: Lexend;
+    font-style: normal;
+    font-display: swap;
+    font-weight: 400;
+    src: url("/assets/lexend-#{$subset}-300-normal.woff2") format("woff2"),
+    url("/assets/lexend-all-300-normal.woff") format("woff");
+    unicode-range: $unicodeRangeValues;
+  }
+}
+
+/**
+  OVERRIDES
+  ----------------------------------------------
+  The imports from "overrides/" define almost barely
+  any style adjustments but rather override default
+  Bootstrap behaviour.
+
+  The largest change to regular bootstrap is the switch
+  to using the available CSS variables for most elements
+  used on the site, so theming can be done with changing
+  only those.
+  */
+
+@import "overrides/alerts",
+"overrides/badges",
+"overrides/bootstrap-datetimepicker",
+"overrides/buttons",
+"overrides/colors",
+"overrides/card",
+"overrides/dropdown",
+"overrides/inputs",
+"overrides/links",
+"overrides/list-group",
+"overrides/minicolors",
+"overrides/modal",
+"overrides/navbar",
+"overrides/turbolinks",
+"overrides/toasts",
+"overrides/sweet-alert";
+
+/**
+  ELEMENTS
+  ----------------------------------------------
+  Styles directly applied to HTML elements
+  */
+
+@import "elements/body";
+
+/**
+  COMPONENTS
+  ----------------------------------------------
+  Custom components defined for Retrospring.
+  */
+
+@import "components/announcements",
+"components/answerbox",
+"components/avatars",
+"components/buttons",
+"components/comments",
+"components/container",
+"components/entry",
+"components/flags",
+"components/icons",
+"components/inbox-actions",
+"components/inbox-entry",
+"components/jumbotron",
+"components/locales",
+"components/mobile-nav",
+"components/notifications",
+"components/profile",
+"components/push-settings",
+"components/question",
+"components/smiles",
+"components/themes",
+"components/totp-setup",
+"components/userbox";
+
+/**
+  UTILITIES
+  ----------------------------------------------
+  Classes used for very specific cases
+  */
+
+@import "utilities";
diff --git a/app/assets/stylesheets/components/_announcements.scss b/app/assets/stylesheets/components/_announcements.scss
new file mode 100644
index 00000000..f69e2c5b
--- /dev/null
+++ b/app/assets/stylesheets/components/_announcements.scss
@@ -0,0 +1,16 @@
+.announcement {
+  width: 100%;
+  border-radius: 0;
+  text-align: center;
+
+  p {
+    margin-bottom: 0;
+  }
+
+  &__container {
+    position: fixed;
+    top: $navbar-height;
+    width: 100%;
+    z-index: 1024;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_answerbox.scss b/app/assets/stylesheets/components/_answerbox.scss
new file mode 100644
index 00000000..74b33157
--- /dev/null
+++ b/app/assets/stylesheets/components/_answerbox.scss
@@ -0,0 +1,86 @@
+.answerbox {
+  &__question-text, 
+  &__question-user, 
+  &__answer-user, 
+  &__answer-date {
+    margin-bottom: 0;
+    overflow: hidden;
+    word-break: break-word;
+  }
+  
+  &__answer-date {
+    font-size: .8rem;
+    line-height: .8;
+    overflow: visible;
+  }
+
+  &__answer-text {
+    margin-bottom: map-get($spacers, 3);
+  }
+
+  &__question-user-avatar,
+  &__answer-user-avatar {
+    margin-right: map-get($spacers, 2);
+    border-radius: $avatar-border-radius;
+  }
+
+  & .text-muted a, 
+  & .text-muted a:hover {
+    color: var(--muted-text);
+    text-decoration: none;
+  }
+
+  &__action {
+    padding-left: 0;
+    padding-right: map-get($spacers, 1);
+
+    & i {
+      font-size: 1.4rem;
+      vertical-align: top;
+    }
+
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: none;
+    }
+
+    &[name="ab-smile"],
+    &[name="ab-smile-comment"] {
+      color: var(--primary);
+
+      &:hover {
+        color: var(--success);
+      }
+
+      &[data-action="unsmile"] {
+        color: var(--success);
+        
+        &:hover {
+          color: var(--danger);
+        }
+      }
+    }
+  }
+
+  &__actions {
+    text-align: right;
+    justify-content: space-between;
+    padding-top: 10px;
+
+    @include media-breakpoint-up('sm') {
+      justify-content: flex-end;
+      padding-top: 0;
+    }
+  }
+
+  .card-body {
+    padding-bottom: .6rem;
+  }
+}
+
+body:not(.cap-web-share) {
+  [name="ab-share"] {
+    display: none;
+  }
+}
diff --git a/app/assets/stylesheets/components/_avatars.scss b/app/assets/stylesheets/components/_avatars.scss
new file mode 100644
index 00000000..6d2bf1cf
--- /dev/null
+++ b/app/assets/stylesheets/components/_avatars.scss
@@ -0,0 +1,12 @@
+[class^="avatar-"] {
+  border-radius: $avatar-border-radius;
+}
+
+@each $name, $size in $avatar-sizes {
+  .avatar-#{$name} {
+    min-height: $size;
+    min-width: $size;
+    height: $size;
+    width: $size;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_buttons.scss b/app/assets/stylesheets/components/_buttons.scss
new file mode 100644
index 00000000..6550b4d8
--- /dev/null
+++ b/app/assets/stylesheets/components/_buttons.scss
@@ -0,0 +1,19 @@
+.btn-fab {
+  border-radius: 100%;
+  box-shadow: 0px 1px 6px rgba(0, 0, 0, 0.12), 0px 1px 6px rgba(0, 0, 0, 0.12);
+  margin: 0px;
+  padding: 3px 5px 4px 8px;
+  font-size: 26px;
+  width: 56px;
+  height: 56px;
+  transition: box-shadow 0.28s cubic-bezier(0.4, 0, 0.2, 1) 0s;
+  outline: medium none !important;
+  text-transform: uppercase;
+  text-decoration: none;
+  position: fixed;
+  bottom: unquote('calc(#{$navbar-height} + env(safe-area-inset-bottom))');
+  right: 0px;
+  margin-right: 7px;
+  margin-bottom: 7px;
+  z-index: 99;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_comments.scss b/app/assets/stylesheets/components/_comments.scss
new file mode 100644
index 00000000..1ee43d24
--- /dev/null
+++ b/app/assets/stylesheets/components/_comments.scss
@@ -0,0 +1,39 @@
+.comment {
+  list-style-type: none;
+  margin-bottom: map-get($spacers, 2);
+
+  &__container {
+    padding-left: 0;
+  }
+
+  &__user,
+  &__content {
+    margin-bottom: 0;
+    word-break: break-word;
+  }
+
+  &__user-avatar {
+    margin-right: map-get($spacers, 2);
+    border-radius: $avatar-border-radius;
+  }
+
+  &__input-group {
+    position: relative;
+  }
+
+  &__input {
+    padding-right: 2.5rem;
+
+    &.is-invalid {
+      background-image: none;
+    }
+  }
+
+  &__character-count {
+    position: absolute;
+    z-index: 5;
+    right: .5rem;
+    top: .5rem;
+  }
+}
+
diff --git a/app/assets/stylesheets/components/_container.scss b/app/assets/stylesheets/components/_container.scss
new file mode 100644
index 00000000..701a5517
--- /dev/null
+++ b/app/assets/stylesheets/components/_container.scss
@@ -0,0 +1,10 @@
+.container--main {
+  padding-top: map-get($spacers, 3);
+  padding-bottom: map-get($spacers, 3);
+  // Sass doesn't know about the safe-area-inset-* env vars and throws a syntax error
+  // We can get around this by using unquote()
+  // Sass also has its own built-in max() function which is not the same as the CSS one
+  // In order to use the correct one we can write it as Max() instead
+  padding-left: unquote('Max(15px, env(safe-area-inset-left))');
+  padding-right: unquote('Max(15px, env(safe-area-inset-right))');
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_entry.scss b/app/assets/stylesheets/components/_entry.scss
new file mode 100644
index 00000000..9d3dc03b
--- /dev/null
+++ b/app/assets/stylesheets/components/_entry.scss
@@ -0,0 +1,22 @@
+.entry {
+  $this: &;
+  margin: map-get($spacers, 4) 0;
+
+  &__value {
+    display: block;
+    font-size: 4rem;
+    line-height: 1;
+    margin-bottom: 0;
+    text-align: center;
+  }
+
+  &__description {
+    color: var(--primary);
+    display: block;
+    font-size: .8rem;
+    font-weight: bold;
+    margin-top: 0px;
+    text-align: center;
+    text-transform: uppercase;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_flags.scss b/app/assets/stylesheets/components/_flags.scss
new file mode 100644
index 00000000..766ae6b1
--- /dev/null
+++ b/app/assets/stylesheets/components/_flags.scss
@@ -0,0 +1,758 @@
+.flag {
+  background-image: url("/flags/main.png");
+  background-repeat: no-repeat;
+  width: 16px;
+  height: 11px;
+  background-position: -0px 16px;
+}
+.flag-kz {
+  background-position: -0px -0px;
+}
+.flag-ad {
+  background-position: -0px -11px;
+}
+.flag-af {
+  background-position: -0px -22px;
+}
+.flag-ag {
+  background-position: -0px -33px;
+}
+.flag-ai {
+  background-position: -0px -44px;
+}
+.flag-al {
+  background-position: -0px -55px;
+}
+.flag-am {
+  background-position: -0px -66px;
+}
+.flag-an {
+  background-position: -0px -77px;
+}
+.flag-ao {
+  background-position: -0px -88px;
+}
+.flag-ar {
+  background-position: -0px -99px;
+}
+.flag-as {
+  background-position: -0px -110px;
+}
+.flag-at {
+  background-position: -0px -121px;
+}
+.flag-au {
+  background-position: -0px -132px;
+}
+.flag-aw {
+  background-position: -0px -143px;
+}
+.flag-ax {
+  background-position: -0px -154px;
+}
+.flag-az {
+  background-position: -0px -165px;
+}
+.flag-ba {
+  background-position: -0px -176px;
+}
+.flag-bb {
+  background-position: -0px -187px;
+}
+.flag-bd {
+  background-position: -0px -198px;
+}
+.flag-be {
+  background-position: -0px -209px;
+}
+.flag-bf {
+  background-position: -0px -220px;
+}
+.flag-bg {
+  background-position: -0px -231px;
+}
+.flag-bh {
+  background-position: -0px -242px;
+}
+.flag-bi {
+  background-position: -0px -253px;
+}
+.flag-bj {
+  background-position: -0px -264px;
+}
+.flag-bm {
+  background-position: -0px -275px;
+}
+.flag-bn {
+  background-position: -0px -286px;
+}
+.flag-bo {
+  background-position: -0px -297px;
+}
+.flag-br {
+  background-position: -0px -308px;
+}
+.flag-bs {
+  background-position: -0px -319px;
+}
+.flag-bt {
+  background-position: -0px -330px;
+}
+.flag-bv {
+  background-position: -0px -341px;
+}
+.flag-bw {
+  background-position: -0px -352px;
+}
+.flag-by {
+  background-position: -0px -363px;
+}
+.flag-bz {
+  background-position: -0px -374px;
+}
+.flag-ca {
+  background-position: -0px -385px;
+}
+.flag-catalonia {
+  background-position: -0px -396px;
+}
+.flag-cc {
+  background-position: -0px -407px;
+}
+.flag-cd {
+  background-position: -0px -418px;
+}
+.flag-cf {
+  background-position: -0px -429px;
+}
+.flag-cg {
+  background-position: -0px -440px;
+}
+.flag-ch {
+  background-position: -0px -451px;
+}
+.flag-ci {
+  background-position: -0px -462px;
+}
+.flag-ck {
+  background-position: -0px -473px;
+}
+.flag-cl {
+  background-position: -0px -484px;
+}
+.flag-cm {
+  background-position: -0px -495px;
+}
+.flag-cn {
+  background-position: -0px -506px;
+}
+.flag-co {
+  background-position: -0px -517px;
+}
+.flag-cr {
+  background-position: -0px -528px;
+}
+.flag-cs {
+  background-position: -0px -539px;
+}
+.flag-cu {
+  background-position: -0px -550px;
+}
+.flag-cv {
+  background-position: -0px -561px;
+}
+.flag-cx {
+  background-position: -0px -572px;
+}
+.flag-cy {
+  background-position: -0px -583px;
+}
+.flag-cz {
+  background-position: -0px -594px;
+}
+.flag-de {
+  background-position: -0px -605px;
+}
+.flag-dj {
+  background-position: -0px -616px;
+}
+.flag-dk {
+  background-position: -0px -627px;
+}
+.flag-dm {
+  background-position: -0px -638px;
+}
+.flag-do {
+  background-position: -0px -649px;
+}
+.flag-dz {
+  background-position: -0px -660px;
+}
+.flag-ec {
+  background-position: -0px -671px;
+}
+.flag-ee {
+  background-position: -0px -682px;
+}
+.flag-eg {
+  background-position: -0px -693px;
+}
+.flag-eh {
+  background-position: -0px -704px;
+}
+.flag-england {
+  background-position: -0px -715px;
+}
+.flag-er {
+  background-position: -0px -726px;
+}
+.flag-es {
+  background-position: -0px -737px;
+}
+.flag-et {
+  background-position: -0px -748px;
+}
+.flag-europeanunion {
+  background-position: -0px -759px;
+}
+.flag-fam {
+  background-position: -0px -770px;
+}
+.flag-fi {
+  background-position: -0px -781px;
+}
+.flag-fj {
+  background-position: -0px -792px;
+}
+.flag-fk {
+  background-position: -0px -803px;
+}
+.flag-fm {
+  background-position: -0px -814px;
+}
+.flag-fo {
+  background-position: -0px -825px;
+}
+.flag-fr {
+  background-position: -0px -836px;
+}
+.flag-ga {
+  background-position: -0px -847px;
+}
+.flag-gb {
+  background-position: -0px -858px;
+}
+.flag-gd {
+  background-position: -0px -869px;
+}
+.flag-ge {
+  background-position: -0px -880px;
+}
+.flag-gf {
+  background-position: -0px -891px;
+}
+.flag-gh {
+  background-position: -0px -902px;
+}
+.flag-gi {
+  background-position: -0px -913px;
+}
+.flag-gl {
+  background-position: -0px -924px;
+}
+.flag-gm {
+  background-position: -0px -935px;
+}
+.flag-gn {
+  background-position: -0px -946px;
+}
+.flag-gp {
+  background-position: -0px -957px;
+}
+.flag-gq {
+  background-position: -0px -968px;
+}
+.flag-gr {
+  background-position: -0px -979px;
+}
+.flag-gs {
+  background-position: -0px -990px;
+}
+.flag-gt {
+  background-position: -0px -1001px;
+}
+.flag-gu {
+  background-position: -0px -1012px;
+}
+.flag-gw {
+  background-position: -0px -1023px;
+}
+.flag-gy {
+  background-position: -0px -1034px;
+}
+.flag-hk {
+  background-position: -0px -1045px;
+}
+.flag-hm {
+  background-position: -0px -1056px;
+}
+.flag-hn {
+  background-position: -0px -1067px;
+}
+.flag-hr {
+  background-position: -0px -1078px;
+}
+.flag-ht {
+  background-position: -0px -1089px;
+}
+.flag-hu {
+  background-position: -0px -1100px;
+}
+.flag-id {
+  background-position: -0px -1111px;
+}
+.flag-ie {
+  background-position: -0px -1122px;
+}
+.flag-il {
+  background-position: -0px -1133px;
+}
+.flag-in {
+  background-position: -0px -1144px;
+}
+.flag-io {
+  background-position: -0px -1155px;
+}
+.flag-iq {
+  background-position: -0px -1166px;
+}
+.flag-ir {
+  background-position: -0px -1177px;
+}
+.flag-is {
+  background-position: -0px -1188px;
+}
+.flag-it {
+  background-position: -0px -1199px;
+}
+.flag-jm {
+  background-position: -0px -1210px;
+}
+.flag-jo {
+  background-position: -0px -1221px;
+}
+.flag-jp {
+  background-position: -0px -1232px;
+}
+.flag-ke {
+  background-position: -0px -1243px;
+}
+.flag-kg {
+  background-position: -0px -1254px;
+}
+.flag-kh {
+  background-position: -0px -1265px;
+}
+.flag-ki {
+  background-position: -0px -1276px;
+}
+.flag-km {
+  background-position: -0px -1287px;
+}
+.flag-kn {
+  background-position: -0px -1298px;
+}
+.flag-kp {
+  background-position: -0px -1309px;
+}
+.flag-kr {
+  background-position: -0px -1320px;
+}
+.flag-kw {
+  background-position: -0px -1331px;
+}
+.flag-ky {
+  background-position: -0px -1342px;
+}
+.flag-ae {
+  background-position: -0px -1353px;
+}
+.flag-la {
+  background-position: -0px -1364px;
+}
+.flag-lb {
+  background-position: -0px -1375px;
+}
+.flag-lc {
+  background-position: -0px -1386px;
+}
+.flag-li {
+  background-position: -0px -1397px;
+}
+.flag-lk {
+  background-position: -0px -1408px;
+}
+.flag-lr {
+  background-position: -0px -1419px;
+}
+.flag-ls {
+  background-position: -0px -1430px;
+}
+.flag-lt {
+  background-position: -0px -1441px;
+}
+.flag-lu {
+  background-position: -0px -1452px;
+}
+.flag-lv {
+  background-position: -0px -1463px;
+}
+.flag-ly {
+  background-position: -0px -1474px;
+}
+.flag-ma {
+  background-position: -0px -1485px;
+}
+.flag-mc {
+  background-position: -0px -1496px;
+}
+.flag-md {
+  background-position: -0px -1507px;
+}
+.flag-zm {
+  background-position: -0px -1518px;
+}
+.flag-mg {
+  background-position: -0px -1529px;
+}
+.flag-mh {
+  background-position: -0px -1540px;
+}
+.flag-mk {
+  background-position: -0px -1551px;
+}
+.flag-ml {
+  background-position: -0px -1562px;
+}
+.flag-mm {
+  background-position: -0px -1573px;
+}
+.flag-mn {
+  background-position: -0px -1584px;
+}
+.flag-mo {
+  background-position: -0px -1595px;
+}
+.flag-mp {
+  background-position: -0px -1606px;
+}
+.flag-mq {
+  background-position: -0px -1617px;
+}
+.flag-mr {
+  background-position: -0px -1628px;
+}
+.flag-ms {
+  background-position: -0px -1639px;
+}
+.flag-mt {
+  background-position: -0px -1650px;
+}
+.flag-mu {
+  background-position: -0px -1661px;
+}
+.flag-mv {
+  background-position: -0px -1672px;
+}
+.flag-mw {
+  background-position: -0px -1683px;
+}
+.flag-mx {
+  background-position: -0px -1694px;
+}
+.flag-my {
+  background-position: -0px -1705px;
+}
+.flag-mz {
+  background-position: -0px -1716px;
+}
+.flag-na {
+  background-position: -0px -1727px;
+}
+.flag-nc {
+  background-position: -0px -1738px;
+}
+.flag-ne {
+  background-position: -0px -1749px;
+}
+.flag-nf {
+  background-position: -0px -1760px;
+}
+.flag-ng {
+  background-position: -0px -1771px;
+}
+.flag-ni {
+  background-position: -0px -1782px;
+}
+.flag-nl {
+  background-position: -0px -1793px;
+}
+.flag-no {
+  background-position: -0px -1804px;
+}
+.flag-np {
+  background-position: -0px -1815px;
+  width: 9px;
+}
+.flag-nr {
+  background-position: -0px -1826px;
+}
+.flag-nu {
+  background-position: -0px -1837px;
+}
+.flag-nz {
+  background-position: -0px -1848px;
+}
+.flag-om {
+  background-position: -0px -1859px;
+}
+.flag-pa {
+  background-position: -0px -1870px;
+}
+.flag-pe {
+  background-position: -0px -1881px;
+}
+.flag-pf {
+  background-position: -0px -1892px;
+}
+.flag-pg {
+  background-position: -0px -1903px;
+}
+.flag-ph {
+  background-position: -0px -1914px;
+}
+.flag-pk {
+  background-position: -0px -1925px;
+}
+.flag-pl {
+  background-position: -0px -1936px;
+}
+.flag-pm {
+  background-position: -0px -1947px;
+}
+.flag-pn {
+  background-position: -0px -1958px;
+}
+.flag-pr {
+  background-position: -0px -1969px;
+}
+.flag-ps {
+  background-position: -0px -1980px;
+}
+.flag-pt {
+  background-position: -0px -1991px;
+}
+.flag-pw {
+  background-position: -0px -2002px;
+}
+.flag-py {
+  background-position: -0px -2013px;
+}
+.flag-qa {
+  background-position: -0px -2024px;
+}
+.flag-re {
+  background-position: -0px -2035px;
+}
+.flag-ro {
+  background-position: -0px -2046px;
+}
+.flag-rs {
+  background-position: -0px -2057px;
+}
+.flag-ru {
+  background-position: -0px -2068px;
+}
+.flag-rw {
+  background-position: -0px -2079px;
+}
+.flag-sa {
+  background-position: -0px -2090px;
+}
+.flag-sb {
+  background-position: -0px -2101px;
+}
+.flag-sc {
+  background-position: -0px -2112px;
+}
+.flag-scotland {
+  background-position: -0px -2123px;
+}
+.flag-sd {
+  background-position: -0px -2134px;
+}
+.flag-se {
+  background-position: -0px -2145px;
+}
+.flag-sg {
+  background-position: -0px -2156px;
+}
+.flag-sh {
+  background-position: -0px -2167px;
+}
+.flag-si {
+  background-position: -0px -2178px;
+}
+.flag-sj {
+  background-position: -0px -2189px;
+}
+.flag-sk {
+  background-position: -0px -2200px;
+}
+.flag-sl {
+  background-position: -0px -2211px;
+}
+.flag-sm {
+  background-position: -0px -2222px;
+}
+.flag-sn {
+  background-position: -0px -2233px;
+}
+.flag-so {
+  background-position: -0px -2244px;
+}
+.flag-sr {
+  background-position: -0px -2255px;
+}
+.flag-st {
+  background-position: -0px -2266px;
+}
+.flag-sv {
+  background-position: -0px -2277px;
+}
+.flag-sy {
+  background-position: -0px -2288px;
+}
+.flag-sz {
+  background-position: -0px -2299px;
+}
+.flag-tc {
+  background-position: -0px -2310px;
+}
+.flag-td {
+  background-position: -0px -2321px;
+}
+.flag-tf {
+  background-position: -0px -2332px;
+}
+.flag-tg {
+  background-position: -0px -2343px;
+}
+.flag-th {
+  background-position: -0px -2354px;
+}
+.flag-tj {
+  background-position: -0px -2365px;
+}
+.flag-tk {
+  background-position: -0px -2376px;
+}
+.flag-tl {
+  background-position: -0px -2387px;
+}
+.flag-tm {
+  background-position: -0px -2398px;
+}
+.flag-tn {
+  background-position: -0px -2409px;
+}
+.flag-to {
+  background-position: -0px -2420px;
+}
+.flag-tr {
+  background-position: -0px -2431px;
+}
+.flag-tt {
+  background-position: -0px -2442px;
+}
+.flag-tv {
+  background-position: -0px -2453px;
+}
+.flag-tw {
+  background-position: -0px -2464px;
+}
+.flag-tz {
+  background-position: -0px -2475px;
+}
+.flag-ua {
+  background-position: -0px -2486px;
+}
+.flag-ug {
+  background-position: -0px -2497px;
+}
+.flag-um {
+  background-position: -0px -2508px;
+}
+.flag-us {
+  background-position: -0px -2519px;
+}
+.flag-uy {
+  background-position: -0px -2530px;
+}
+.flag-uz {
+  background-position: -0px -2541px;
+}
+.flag-va {
+  background-position: -0px -2552px;
+}
+.flag-vc {
+  background-position: -0px -2563px;
+}
+.flag-ve {
+  background-position: -0px -2574px;
+}
+.flag-vg {
+  background-position: -0px -2585px;
+}
+.flag-vi {
+  background-position: -0px -2596px;
+}
+.flag-vn {
+  background-position: -0px -2607px;
+}
+.flag-vu {
+  background-position: -0px -2618px;
+}
+.flag-wales {
+  background-position: -0px -2629px;
+}
+.flag-wf {
+  background-position: -0px -2640px;
+}
+.flag-ws {
+  background-position: -0px -2651px;
+}
+.flag-ye {
+  background-position: -0px -2662px;
+}
+.flag-yt {
+  background-position: -0px -2673px;
+}
+.flag-za {
+  background-position: -0px -2684px;
+}
+.flag-zw {
+  background-position: -0px -2695px;
+}
+.flag-me {
+  background-position: -0px -2706px;
+  height: 12px;
+}
+.flag-pirate {
+  background-image: url('/flags/pirate.png');
+  background-position: 0 0;
+}
+.flag-dizzle {
+  background-image: url('/flags/dizzle.png');
+  background-position: 0 0;
+}
diff --git a/app/assets/stylesheets/components/_icons.scss b/app/assets/stylesheets/components/_icons.scss
new file mode 100644
index 00000000..ef1db1ef
--- /dev/null
+++ b/app/assets/stylesheets/components/_icons.scss
@@ -0,0 +1,4 @@
+.icon--showcase {
+  text-align: center;
+  font-size: 5rem;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_inbox-actions.scss b/app/assets/stylesheets/components/_inbox-actions.scss
new file mode 100644
index 00000000..ee7b664d
--- /dev/null
+++ b/app/assets/stylesheets/components/_inbox-actions.scss
@@ -0,0 +1,9 @@
+.inbox-actions {
+  .form-group {
+    margin-bottom: 0;
+  }
+
+  .card-body {
+    padding: $card-spacer-y $card-spacer-x;
+  }
+}
diff --git a/app/assets/stylesheets/components/_inbox-entry.scss b/app/assets/stylesheets/components/_inbox-entry.scss
new file mode 100644
index 00000000..38cdf4ba
--- /dev/null
+++ b/app/assets/stylesheets/components/_inbox-entry.scss
@@ -0,0 +1,22 @@
+.inbox-entry {
+  &--new {
+    box-shadow: 0 0.125rem 0.25rem var(--primary);
+
+    .card-header {
+      background-color: var(--primary);
+      color: RGB(var(--primary-text));
+
+      a {
+        color: RGB(var(--primary-text));
+
+        &.dropdown-item {
+          color: inherit;
+        }
+      }
+
+      .text-muted {
+        color: RGBA(var(--primary-text), 0.8) !important;
+      }
+    }
+  }
+}
diff --git a/app/assets/stylesheets/components/_jumbotron.scss b/app/assets/stylesheets/components/_jumbotron.scss
new file mode 100644
index 00000000..cb020fa6
--- /dev/null
+++ b/app/assets/stylesheets/components/_jumbotron.scss
@@ -0,0 +1,35 @@
+.jumbotron {
+  $this: &;
+  display: flex;
+  background-color: var(--primary);
+  color: RGB(var(--primary-text));
+  text-align: center;
+  border-radius: 0;
+
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6 {
+    color: RGB(var(--primary-text));
+  }
+
+  a:not(.btn) {
+    color: RGB(var(--primary-text));
+    opacity: 0.6;
+
+    &:hover {
+      opacity: 1;
+    }
+
+    .btn {
+      opacity: 1;
+    }
+  }
+
+  &__content {
+    width: 100%;
+    align-self: center;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_locales.scss b/app/assets/stylesheets/components/_locales.scss
new file mode 100644
index 00000000..48a6ff5c
--- /dev/null
+++ b/app/assets/stylesheets/components/_locales.scss
@@ -0,0 +1,32 @@
+.locales {
+  text-align: center;
+
+  &__panel {
+    position: relative;
+    display:  none;
+    padding:  5px;
+
+    ul {
+      margin:          0;
+      padding:         0;
+      padding-top:     map-get($spacers, 3);
+      width:           100%;
+      list-style:      none;
+      display:         inline-flex;
+      flex-direction:  row;
+      flex-wrap:       wrap;
+      align-items:     center;
+      justify-content: center;
+      
+      li {
+        margin:     0 5px 10px 5px;
+        flex:       0 0 auto;
+
+        * {
+          display:        inline-block;
+          vertical-align: middle;
+        }
+      }
+    }
+  }
+}
diff --git a/app/assets/stylesheets/components/_mobile-nav.scss b/app/assets/stylesheets/components/_mobile-nav.scss
new file mode 100644
index 00000000..f1a87b2e
--- /dev/null
+++ b/app/assets/stylesheets/components/_mobile-nav.scss
@@ -0,0 +1,61 @@
+#rs-mobile-nav {
+  .container {
+    padding: 0;
+  }
+
+  padding: 4px 0 unquote('calc(env(safe-area-inset-bottom) + 4px)') 0;
+
+  .navbar-icon-row {
+    flex-direction: row;
+    justify-content: space-around;
+    width: 100%;
+
+    .nav-link {
+      padding: 0;
+
+      .fa {
+        padding-top: 8px;
+        font-size: 20px;
+      }
+
+      .badge {
+        position: absolute;
+        top: 4px;
+        transform: translateX(16px);
+      }
+    }
+  }
+}
+
+@include media-breakpoint-down("md") {
+  .notification-dropdown,
+  .profile-dropdown {
+    bottom: unquote("calc(env(safe-area-inset-bottom) + #{$navbar-height + 2px})");
+    position: fixed;
+    top: unset;
+  }
+
+  .profile-dropdown {
+    left: unset;
+    right: unquote("calc(env(safe-area-inset-right) + 15px)");
+  }
+
+  .dropdown-menu.notification-dropdown {
+    left: unquote("calc(env(safe-area-inset-left) + 8px)");
+    max-width: unquote("calc(100vw - (8px + env(safe-area-inset-right)) - (8px + env(safe-area-inset-left)))");
+    min-width: unset;
+    right: unquote("calc(env(safe-area-inset-right) + 8px)");
+    width: unquote("calc(100vw - (8px + env(safe-area-inset-right)) - (8px + env(safe-area-inset-left)))");
+    max-height: calc(100% - 40px - 2rem);
+    overflow-y: scroll;
+
+    .dropdown-item {
+      padding: 8px;
+    }
+
+    .notification {
+      padding: 0;
+      white-space: normal;
+    }
+  }
+}
diff --git a/app/assets/stylesheets/components/_notifications.scss b/app/assets/stylesheets/components/_notifications.scss
new file mode 100644
index 00000000..07ce4e23
--- /dev/null
+++ b/app/assets/stylesheets/components/_notifications.scss
@@ -0,0 +1,59 @@
+.notification {
+  word-break: break-word;
+
+  &__user {
+    margin-top: 0;
+  }
+
+  &__user,
+  &__text {
+    margin-bottom: 0;
+    white-space: normal;
+  }
+
+  &__icon {
+    margin-right: map-get($spacers, 2);
+    min-width: 40px;
+  }
+
+  &__heading {
+    margin-bottom: 0;
+  }
+
+  &__list-heading {
+    margin: 0px;
+    text-transform: uppercase;
+    font-weight: bold;
+    color: RGB(var(--muted-text));
+  }
+
+  &__bell-icon:before {
+    font-size: 64px;
+    text-align: center;
+    display: block;
+    margin-bottom: 2px;
+  }
+
+  &-dropdown {
+    min-width: 400px;
+
+    & .dropdown-item:hover,
+    & .dropdown-item:active {
+      background: transparent;
+      color: RGB(var(--body-text));
+    }
+  }
+
+  .dropdown-item > & {
+    padding: 5px 10px;
+  }
+
+  .list-group-item {
+    margin-top: map-get($spacers, 2);
+    background-color: var(--raised-accent);
+
+    p {
+      margin-bottom: 0;
+    }
+  }
+}
diff --git a/app/assets/stylesheets/components/_profile.scss b/app/assets/stylesheets/components/_profile.scss
new file mode 100644
index 00000000..6d8a8229
--- /dev/null
+++ b/app/assets/stylesheets/components/_profile.scss
@@ -0,0 +1,97 @@
+.profile {
+  &__avatar {
+    display: block;
+    width: map-get($avatar-sizes, "xl");
+    height: map-get($avatar-sizes, "xl");
+    margin: -(map-get($avatar-sizes, "xl") / 2.5) map-get($spacers, 4) 0;
+    border-radius: $avatar-border-radius;
+    box-shadow: $box-shadow;
+
+    @include media-breakpoint-up(sm) {
+      width: map-get($avatar-sizes, "xxl");
+      height: map-get($avatar-sizes, "xxl");
+      margin: -(map-get($avatar-sizes, "xxl") / 2) auto 0;
+    }
+  }
+
+  &__header-card {
+    margin-top: map-get($spacers, 3);
+    overflow: hidden;
+  }
+
+  &__name-container {
+    align-self: center;
+    max-width: 100%;
+    overflow: hidden;
+
+    @include media-breakpoint-up(sm) {
+      padding: map-get($spacers, 4);
+      padding-bottom: 0;
+    }
+  }
+
+  &__header-container {
+    position: relative;
+    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;
+    width: 100%;
+  }
+
+  &__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;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+
+    @include media-breakpoint-up(sm) {
+      white-space: initial;
+    }
+  }
+
+  &__screen-name {
+    &:only-child {
+      @extend .profile__display-name;
+    }
+
+    &:not(:only-child) {
+      font-size: 0.9em;
+      color: RGB(var(--muted-text));
+    }
+  }
+
+  @include media-breakpoint-up(sm) {
+    &__name {
+      margin-bottom: map-get($spacers, 3);
+    }
+
+    & .card-body {
+      padding-top: 0;
+    }
+  }
+}
+
+.user--banned {
+  text-decoration: line-through !important;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_push-settings.scss b/app/assets/stylesheets/components/_push-settings.scss
new file mode 100644
index 00000000..c5d38d94
--- /dev/null
+++ b/app/assets/stylesheets/components/_push-settings.scss
@@ -0,0 +1,7 @@
+.push-notifications {
+  &-unavailable {
+    body.cap-service-worker.cap-notification & {
+      display: none;
+    }
+  }
+}
diff --git a/app/assets/stylesheets/components/_question.scss b/app/assets/stylesheets/components/_question.scss
new file mode 100644
index 00000000..7d03e06b
--- /dev/null
+++ b/app/assets/stylesheets/components/_question.scss
@@ -0,0 +1,18 @@
+.question {
+  &--fixed {
+    position: absolute;
+    width: 100%;
+    z-index: 999;
+
+    @include media-breakpoint-up('sm') {
+      position: fixed;
+    }
+  }
+
+  &--hidden {
+    visibility: hidden;
+    position: relative;
+    box-shadow: none;
+    z-index: -1;
+  }
+}
diff --git a/app/assets/stylesheets/components/_smiles.scss b/app/assets/stylesheets/components/_smiles.scss
new file mode 100644
index 00000000..b1725d2c
--- /dev/null
+++ b/app/assets/stylesheets/components/_smiles.scss
@@ -0,0 +1,28 @@
+.smiles {
+  margin-bottom: map-get($spacers, 2);
+
+  &__user-list {
+    margin: 0;
+    padding: 0;
+    list-style-type: none;
+  }
+    
+  &__user-list-entry {
+    margin-bottom: map-get($spacers, 3);
+    
+    * {
+      display: inline-block;
+      vertical-align: middle;
+    }
+  
+    img {
+      height: map-get($avatar-sizes, "lg");
+      width: map-get($avatar-sizes, "lg");
+      border-radius: $avatar-border-radius;
+    }
+  
+    span {
+      margin-left: 5px;
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_themes.scss b/app/assets/stylesheets/components/_themes.scss
new file mode 100644
index 00000000..1b3cf159
--- /dev/null
+++ b/app/assets/stylesheets/components/_themes.scss
@@ -0,0 +1,15 @@
+.theme-success {
+  --background: #f4fcf6;
+  --primary: var(--success);
+}
+
+.theme-warning {
+  --background: #fcfaf4;
+  --primary: var(--warning);
+  --primary-text: 0, 0, 0;
+}
+
+.theme-danger {
+  --background: #fceff1;
+  --primary: var(--danger);
+}
diff --git a/app/assets/stylesheets/components/_totp-setup.scss b/app/assets/stylesheets/components/_totp-setup.scss
new file mode 100644
index 00000000..2bcf341b
--- /dev/null
+++ b/app/assets/stylesheets/components/_totp-setup.scss
@@ -0,0 +1,76 @@
+%totp-input {
+  font-family: "Monaco", "Inconsolata", "Cascadia Code", "Consolas", monospace;
+  width: 100px;
+}
+
+.totp-setup {
+  &__card {
+    background: var(--primary);
+    padding: 10px;
+    border-radius: 5px;
+
+    min-width: 256px;
+    max-width: 256px;
+    width: 100%;
+    margin: 0 auto;
+  }
+
+  &__card-container {
+    min-width: 276px;
+    max-width: 276px;
+    width: 100%;
+    padding: 0;
+  }
+
+  &__qr {
+    background: white;
+    border-radius: 5px;
+  }
+
+  &__text {
+    background: #000;
+    color: #fff;
+    margin: 10px 0 0 0;
+    padding: 5px;
+    border-radius: 5px;
+
+    code {
+      display: block;
+      color: var(--warning);
+    }
+  }
+
+  &__code-field {
+    @extend %totp-input;
+  }
+
+  &__recovery {
+    &-container {
+      max-width: 455px;
+    }
+
+    &-icon {
+      font-size: .75in;
+    }
+
+    &-title {
+      text-align: left;
+    }
+
+    &-codes {
+      display: grid;
+      grid-template-columns: 1fr 1fr;
+      padding: 0;
+
+      li {
+        list-style-type: none;
+        font-size: 16px;
+        text-align: center;
+      }
+    }
+  }
+}
+
+#user_otp_attempt {
+  @extend %totp-input;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/components/_userbox.scss b/app/assets/stylesheets/components/_userbox.scss
new file mode 100644
index 00000000..09de41ec
--- /dev/null
+++ b/app/assets/stylesheets/components/_userbox.scss
@@ -0,0 +1,37 @@
+.userbox {
+  &__header {
+    width: 100%;
+    height: auto;
+    max-height: 70px;
+
+    @include media-breakpoint-up(sm) { 
+      max-height: 60px;
+    }
+  }
+
+  &__avatar {
+    display: block;
+    width: map-get($avatar-sizes, "lg");
+    height: map-get($avatar-sizes, "lg");
+    margin-top: -(map-get($avatar-sizes, "lg") / 2);
+    margin-left: auto;
+    margin-right: auto;
+    border-radius: $avatar-border-radius;
+    box-shadow: $box-shadow;
+  }
+
+  .profile__name {
+    display: block;
+    margin: map-get($spacers, 3) 0;
+    text-align: center;
+  }
+
+  .card-body {
+    display: flex;
+    flex-direction: column;
+  }
+
+  .profile__actions {
+    margin-top: auto;
+  }
+}
diff --git a/app/assets/stylesheets/elements/_body.scss b/app/assets/stylesheets/elements/_body.scss
new file mode 100644
index 00000000..e33a8ebb
--- /dev/null
+++ b/app/assets/stylesheets/elements/_body.scss
@@ -0,0 +1,17 @@
+body {
+  overflow-y: scroll;
+  word-wrap: break-word;
+  color: RGB(var(--body-text));
+  background-color: var(--background);
+  @include media-breakpoint-up('lg') {
+    padding-top: $navbar-height;
+  }
+  @include media-breakpoint-down('md') {
+    padding-bottom: calc($navbar-height + unquote('env(safe-area-inset-bottom, 0)'));
+  }
+
+  &.not-logged-in {
+    padding-top: $navbar-height;
+    padding-bottom: 0;
+  }
+}
diff --git a/app/assets/stylesheets/overrides/_alerts.scss b/app/assets/stylesheets/overrides/_alerts.scss
new file mode 100644
index 00000000..8e9c2073
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_alerts.scss
@@ -0,0 +1,11 @@
+@each $color in $color-names {
+  .alert-#{$color} {
+    color: RGB(var(--#{$color}-text));
+    background-color: var(--#{$color});
+    border-color: var(--#{$color});
+
+    .alert-link {
+      color: RGB(var(--#{$color}-text));
+    }
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_badges.scss b/app/assets/stylesheets/overrides/_badges.scss
new file mode 100644
index 00000000..3fa32589
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_badges.scss
@@ -0,0 +1,6 @@
+@each $color in $color-names {
+  .badge-#{$color} {
+    color: var(--#{$color});
+    background-color: RGB(var(--#{$color}-text));
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_bootstrap-datetimepicker.scss b/app/assets/stylesheets/overrides/_bootstrap-datetimepicker.scss
new file mode 100644
index 00000000..c7a66d09
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_bootstrap-datetimepicker.scss
@@ -0,0 +1,3 @@
+.remove-native-picker::-webkit-calendar-picker-indicator{
+  display: none
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_buttons.scss b/app/assets/stylesheets/overrides/_buttons.scss
new file mode 100644
index 00000000..bb33b8d0
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_buttons.scss
@@ -0,0 +1,64 @@
+.btn {
+  color: RGB(var(--body-text));
+}
+
+.btn-link:hover {
+  color: RGB(var(--body-text));
+}
+
+@each $color in $color-names {
+  .btn-#{$color} {
+
+    color: RGB(var(--#{$color}-text));
+    background-color: var(--#{$color});
+    border-color: var(--#{$color});
+    border-width: 0;
+
+    &:hover {
+      background: linear-gradient(
+        to top,
+        rgba(0, 0, 0, 0.10),
+        rgba(0, 0, 0, 0.10)
+      ) var(--#{$color});
+    }
+
+    &:not(:disabled):not(.disabled):active,
+    &:not(:disabled):not(.disabled).active {
+      border: none;
+      background: linear-gradient(
+        to top,
+        rgba(0, 0, 0, 0.25),
+        rgba(0, 0, 0, 0.25)
+      ) var(--#{$color});
+
+      &:focus {
+        background: linear-gradient(
+          to top,
+          rgba(0, 0, 0, 0.30),
+          rgba(0, 0, 0, 0.30)
+        ) var(--#{$color});
+        box-shadow: none;
+      }
+    }
+
+    &:focus,
+    &:focus:hover {
+      background: linear-gradient(
+        to top,
+        rgba(0, 0, 0, 0.30),
+        rgba(0, 0, 0, 0.30)
+      ) var(--#{$color});
+      box-shadow: none;
+    }
+  }
+
+  .btn-outline-#{$color} {
+    color: var(--#{$color});
+  }
+}
+
+.btn {
+  .fa {
+    pointer-events: none;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_card.scss b/app/assets/stylesheets/overrides/_card.scss
new file mode 100644
index 00000000..949c21bb
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_card.scss
@@ -0,0 +1,18 @@
+.card {
+  margin-bottom: map-get($spacers, 3);
+  box-shadow: $box-shadow-sm;
+  background-color: var(--raised-bg);
+
+  p:last-child {
+    margin-bottom: 0;
+  }
+
+  &--fullheight {
+    height: calc(100% - map-get($spacers, 3));
+  }
+}
+
+.card-header,
+.card-footer {
+  background-color: var(--raised-accent);
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_colors.scss b/app/assets/stylesheets/overrides/_colors.scss
new file mode 100644
index 00000000..400c8d0d
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_colors.scss
@@ -0,0 +1,13 @@
+@each $color in $color-names {
+  .bg-#{$color} {
+    background-color: var(--#{$color}) !important;
+  }
+
+  .text-#{$color} {
+    color: var(--#{$color}) !important;
+  }
+}
+
+.text-muted {
+  color: RGB(var(--muted-text)) !important;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_dropdown.scss b/app/assets/stylesheets/overrides/_dropdown.scss
new file mode 100644
index 00000000..5d647c3b
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_dropdown.scss
@@ -0,0 +1,35 @@
+.dropdown-menu {
+  color: RGB(var(--body-text));
+  background-color: var(--raised-bg);
+  box-shadow: $box-shadow-lg;
+  border: none;
+}
+
+.dropdown-item {
+  color: RGB(var(--body-text));
+
+  &.active, 
+  &:active,
+  &:active:hover {
+    color: RGB(var(--primary-text));
+    background-color: var(--primary);
+  }
+
+  &:hover {
+    background-color: var(--raised-accent);
+  }
+}
+
+.dropdown-divider {
+  border-top: 1px solid var(--raised-accent);
+}
+
+.dropdown-toggle {
+  -webkit-appearance: none;
+}
+
+@include media-breakpoint-up('md') {
+  .dropdown-menu--lists {
+    max-width: 275px;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_inputs.scss b/app/assets/stylesheets/overrides/_inputs.scss
new file mode 100644
index 00000000..a1ef2007
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_inputs.scss
@@ -0,0 +1,22 @@
+.form-control {
+  background-color: var(--input-bg);
+  color: RGB(var(--input-text));
+  border: 0;
+
+  &:focus {
+    background-color: var(--input-bg);
+    color: RGB(var(--input-text));
+    border-color: var(--primary);
+    box-shadow: .5px 0 0 0.1rem var(--primary);
+  }
+
+  &::placeholder {
+    color: RGB(var(--input-placeholder));
+  }
+}
+
+.input-group-text {
+  color: RGB(var(--body-text));
+  background-color: var(--raised-accent);
+  border: 0;
+}
diff --git a/app/assets/stylesheets/overrides/_links.scss b/app/assets/stylesheets/overrides/_links.scss
new file mode 100644
index 00000000..34bbae92
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_links.scss
@@ -0,0 +1,7 @@
+a {
+  color: var(--primary);
+
+  &:hover {
+    color: var(--primary);
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_list-group.scss b/app/assets/stylesheets/overrides/_list-group.scss
new file mode 100644
index 00000000..9e1d63b6
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_list-group.scss
@@ -0,0 +1,21 @@
+.list-group-item {
+  background-color: transparent;
+  
+  &.active,
+  &.active:hover {
+    background-color: var(--primary);
+    border-color: var(--primary);
+
+    a {
+      color: var(--primary-text);
+    }
+  }
+}
+
+.list-group-item-action {
+  color: RGB(var(--body-text));
+  
+  &:hover, &:focus {
+    background-color: var(--raised-accent);
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_minicolors.scss b/app/assets/stylesheets/overrides/_minicolors.scss
new file mode 100644
index 00000000..4628eaef
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_minicolors.scss
@@ -0,0 +1,9 @@
+#update_theme .minicolors-theme-bootstrap .minicolors-swatch {
+  top: 0;
+  left: 0;
+  width: 38px;
+  height: 38px;
+  border: 0;
+  border-top-right-radius: 0;
+  border-bottom-right-radius: 0;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_modal.scss b/app/assets/stylesheets/overrides/_modal.scss
new file mode 100644
index 00000000..04773c30
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_modal.scss
@@ -0,0 +1,13 @@
+.modal-content {
+  background-color: var(--raised-bg);
+  border: 0;
+}
+
+.modal-header {
+  border-bottom: 0;
+}
+
+.modal-footer {
+  background-color: var(--raised-accent);
+  border-top: 0;
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_navbar.scss b/app/assets/stylesheets/overrides/_navbar.scss
new file mode 100644
index 00000000..e00e0e81
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_navbar.scss
@@ -0,0 +1,58 @@
+.navbar-themed {
+  .navbar-brand {
+    color: RGB(var(--primary-text));
+
+    &:hover,
+    &:focus {
+      color: RGB(var(--primary-text));
+    }
+
+    /* svg-logo! \o/ */
+    svg {
+      height: $navbar-brand-font-size;
+      path {
+        fill: RGB(var(--primary-text));
+      }
+    }
+  }
+
+  .navbar-nav {
+    .nav-link {
+      color: rgba(var(--primary-text), .5);
+
+      &:hover,
+      &:focus {
+        color: rgba(var(--primary-text), .75);
+      }
+
+      &.disabled {
+        color: rgba(var(--primary-text), .25);
+      }
+    }
+
+    .show > .nav-link,
+    .active > .nav-link,
+    .nav-link.show,
+    .nav-link.active {
+      color: RGB(var(--primary-text));
+    }
+  }
+
+  .navbar-toggler {
+    color: RGB(var(--primary-text));
+    border-color: RGB(var(--primary-text));
+  }
+
+  .navbar-toggler-icon {
+    background-image: escape-svg($navbar-dark-toggler-icon-bg);
+  }
+
+  .navbar-text {
+    color: RGB(var(--primary-text));
+    a,
+    a:hover,
+    a:focus {
+      color: RGB(var(--primary-text));
+    }
+  }
+}
diff --git a/app/assets/stylesheets/overrides/_sweet-alert.scss b/app/assets/stylesheets/overrides/_sweet-alert.scss
new file mode 100644
index 00000000..78bea1b0
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_sweet-alert.scss
@@ -0,0 +1,7 @@
+.sweet-alert {
+  font-family: inherit;
+}
+
+.sweet-overlay {
+  z-index: 1031;
+}
diff --git a/app/assets/stylesheets/overrides/_toasts.scss b/app/assets/stylesheets/overrides/_toasts.scss
new file mode 100644
index 00000000..88d2f2de
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_toasts.scss
@@ -0,0 +1,5 @@
+.toastify {
+  @include media-breakpoint-up('md') {
+    transform: translateY(56px) !important;
+  }
+}
\ No newline at end of file
diff --git a/app/assets/stylesheets/overrides/_turbolinks.scss b/app/assets/stylesheets/overrides/_turbolinks.scss
new file mode 100644
index 00000000..8161a7ca
--- /dev/null
+++ b/app/assets/stylesheets/overrides/_turbolinks.scss
@@ -0,0 +1,10 @@
+.turbolinks-progress-bar {
+  background: var(--turbolinks-progress-color);
+
+  @include media-breakpoint-down('md') {
+    top: unset !important;
+    bottom: calc(45px + env(safe-area-inset-bottom)) !important;
+    position: fixed;
+    left: 0 !important;
+  }
+}
\ No newline at end of file