From 5cd18be47b53d62c3f5bc6587a04ae3e0479d23c Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Tue, 28 Dec 2021 18:30:34 -0500
Subject: Enable anonymous users to interact with statuses remotely

---
 src/components/retweet_button/retweet_button.vue | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

(limited to 'src/components/retweet_button/retweet_button.vue')

diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index 859ce499..6e5980ac 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -20,13 +20,19 @@
         :title="$t('timeline.no_retweet_hint')"
       />
     </span>
-    <span v-else>
+    <a
+      v-else
+      class="button-unstyled interactive"
+      target="_blank"
+      role="button"
+      :href="remoteInteractionLink"
+    >
       <FAIcon
         class="fa-scale-110 fa-old-padding"
         icon="retweet"
         :title="$t('tool_tip.repeat')"
       />
-    </span>
+    </a>
     <span
       v-if="!mergedConfig.hidePostStats && status.repeat_num > 0"
       class="no-event"
-- 
cgit v1.2.3-70-g09d2


From b2e482774102a4e92b79c21cc57353e6677adf13 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Sun, 16 Jan 2022 01:01:19 -0500
Subject: Add badges to status interacting buttons

Now, the following badges will be added:
0: (+) sign to reply, favourite, repeat, react and extra buttons
1: (-) sign to unfavourite and unrepeat
2: (x) sign to close reply form, close react popover, and close extra buttons popover
3: Check mark to favourited and repeated statuses

https://git.pleroma.social/pleroma/pleroma-fe/-/issues/1092
---
 src/App.scss                                       |  2 +-
 src/components/extra_buttons/extra_buttons.js      | 19 +++++++++-
 src/components/extra_buttons/extra_buttons.vue     | 34 +++++++++++++++--
 src/components/favorite_button/favorite_button.js  | 12 +++++-
 src/components/favorite_button/favorite_button.vue | 43 +++++++++++++++++++---
 src/components/react_button/react_button.js        | 17 ++++++++-
 src/components/react_button/react_button.vue       | 35 +++++++++++++++---
 src/components/reply_button/reply_button.js        | 12 +++++-
 src/components/reply_button/reply_button.vue       | 32 ++++++++++++++--
 src/components/retweet_button/retweet_button.js    | 14 ++++++-
 src/components/retweet_button/retweet_button.vue   | 43 +++++++++++++++++++---
 11 files changed, 229 insertions(+), 34 deletions(-)

(limited to 'src/components/retweet_button/retweet_button.vue')

diff --git a/src/App.scss b/src/App.scss
index ab025d63..3e23ebfa 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -752,7 +752,7 @@ option {
 }
 
 .fa-old-padding {
-  &.svg-inline--fa {
+  &.svg-inline--fa, &-layer {
     padding: 0 0.3em;
   }
 }
diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js
index 22ffb65a..68fa66ad 100644
--- a/src/components/extra_buttons/extra_buttons.js
+++ b/src/components/extra_buttons/extra_buttons.js
@@ -6,7 +6,9 @@ import {
   faEyeSlash,
   faThumbtack,
   faShareAlt,
-  faExternalLinkAlt
+  faExternalLinkAlt,
+  faPlus,
+  faTimes
 } from '@fortawesome/free-solid-svg-icons'
 import {
   faBookmark as faBookmarkReg,
@@ -21,13 +23,26 @@ library.add(
   faThumbtack,
   faShareAlt,
   faExternalLinkAlt,
-  faFlag
+  faFlag,
+  faPlus,
+  faTimes
 )
 
 const ExtraButtons = {
   props: ['status'],
   components: { Popover },
+  data () {
+    return {
+      expanded: false
+    }
+  },
   methods: {
+    onShow () {
+      this.expanded = true
+    },
+    onClose () {
+      this.expanded = false
+    },
     deleteStatus () {
       const confirmed = window.confirm(this.$t('status.delete_confirm'))
       if (confirmed) {
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index 2c893bf3..23d74fce 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -6,6 +6,8 @@
     :offset="{ y: 5 }"
     :bound-to="{ x: 'container' }"
     remove-padding
+    @show="onShow"
+    @close="onClose"
   >
     <template #content="{close}">
       <div class="dropdown-menu">
@@ -122,10 +124,24 @@
     </template>
     <template #trigger>
       <span class="button-unstyled popover-trigger">
-        <FAIcon
-          class="fa-scale-110 fa-old-padding"
-          icon="ellipsis-h"
-        />
+        <FALayers class="fa-old-padding-layer">
+          <FAIcon
+            class="fa-scale-110 "
+            icon="ellipsis-h"
+          />
+          <FAIcon
+            v-if="!expanded"
+            class="focus-marker"
+            transform="shrink-6 up-8 right-16"
+            icon="plus"
+          />
+          <FAIcon
+            v-else
+            class="focus-marker"
+            transform="shrink-6 up-8 right-16"
+            icon="times"
+          />
+        </FALayers>
       </span>
     </template>
   </Popover>
@@ -151,6 +167,16 @@
       color: $fallback--text;
       color: var(--text, $fallback--text);
     }
+
+    .focus-marker {
+      visibility: hidden;
+    }
+
+    &:hover, &:focus {
+      .focus-marker {
+        visibility: visible;
+      }
+    }
   }
 }
 </style>
diff --git a/src/components/favorite_button/favorite_button.js b/src/components/favorite_button/favorite_button.js
index 5cd05f73..c996cba2 100644
--- a/src/components/favorite_button/favorite_button.js
+++ b/src/components/favorite_button/favorite_button.js
@@ -1,13 +1,21 @@
 import { mapGetters } from 'vuex'
 import { library } from '@fortawesome/fontawesome-svg-core'
-import { faStar } from '@fortawesome/free-solid-svg-icons'
+import {
+  faStar,
+  faPlus,
+  faMinus,
+  faCheck
+} from '@fortawesome/free-solid-svg-icons'
 import {
   faStar as faStarRegular
 } from '@fortawesome/free-regular-svg-icons'
 
 library.add(
   faStar,
-  faStarRegular
+  faStarRegular,
+  faPlus,
+  faMinus,
+  faCheck
 )
 
 const FavoriteButton = {
diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue
index d5c4c61e..4015e1e6 100644
--- a/src/components/favorite_button/favorite_button.vue
+++ b/src/components/favorite_button/favorite_button.vue
@@ -7,11 +7,31 @@
       :title="$t('tool_tip.favorite')"
       @click.prevent="favorite()"
     >
-      <FAIcon
-        class="fa-scale-110 fa-old-padding"
-        :icon="[status.favorited ? 'fas' : 'far', 'star']"
-        :spin="animated"
-      />
+      <FALayers class="fa-scale-110 fa-old-padding-layer">
+        <FAIcon
+          class="fa-scale-110"
+          :icon="[status.favorited ? 'fas' : 'far', 'star']"
+          :spin="animated"
+        />
+        <FAIcon
+          v-if="status.favorited"
+          class="active-marker"
+          transform="shrink-6 up-9 right-12"
+          icon="check"
+        />
+        <FAIcon
+          v-if="!status.favorited"
+          class="focus-marker"
+          transform="shrink-6 up-9 right-12"
+          icon="plus"
+        />
+        <FAIcon
+          v-else
+          class="focus-marker"
+          transform="shrink-6 up-9 right-12"
+          icon="minus"
+        />
+      </FALayers>
     </button>
     <span v-else>
       <FAIcon
@@ -57,6 +77,19 @@
       color: $fallback--cOrange;
       color: var(--cOrange, $fallback--cOrange);
     }
+
+    .focus-marker {
+      visibility: hidden;
+    }
+
+    &:hover, &:focus {
+      .focus-marker {
+        visibility: visible;
+      }
+      .active-marker {
+        visibility: hidden;
+      }
+    }
   }
 }
 </style>
diff --git a/src/components/react_button/react_button.js b/src/components/react_button/react_button.js
index 37d6e7d0..5e052e1e 100644
--- a/src/components/react_button/react_button.js
+++ b/src/components/react_button/react_button.js
@@ -1,15 +1,21 @@
 import Popover from '../popover/popover.vue'
 import { library } from '@fortawesome/fontawesome-svg-core'
+import { faPlus, faTimes } from '@fortawesome/free-solid-svg-icons'
 import { faSmileBeam } from '@fortawesome/free-regular-svg-icons'
 import { trim } from 'lodash'
 
-library.add(faSmileBeam)
+library.add(
+  faPlus,
+  faTimes,
+  faSmileBeam
+)
 
 const ReactButton = {
   props: ['status'],
   data () {
     return {
-      filterWord: ''
+      filterWord: '',
+      expanded: false
     }
   },
   components: {
@@ -25,6 +31,13 @@ const ReactButton = {
       }
       close()
     },
+    onShow () {
+      this.expanded = true
+      this.focusInput()
+    },
+    onClose () {
+      this.expanded = false
+    },
     focusInput () {
       this.$nextTick(() => {
         const input = this.$el.querySelector('input')
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 5a809847..e30f6b68 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -7,7 +7,8 @@
     :bound-to="{ x: 'container' }"
     remove-padding
     popover-class="ReactButton popover-default"
-    @show="focusInput"
+    @show="onShow"
+    @close="onClose"
   >
     <template #content="{close}">
       <div class="reaction-picker-filter">
@@ -46,10 +47,24 @@
         class="button-unstyled popover-trigger"
         :title="$t('tool_tip.add_reaction')"
       >
-        <FAIcon
-          class="fa-scale-110 fa-old-padding"
-          :icon="['far', 'smile-beam']"
-        />
+        <FALayers>
+          <FAIcon
+            class="fa-scale-110 fa-old-padding"
+            :icon="['far', 'smile-beam']"
+          />
+          <FAIcon
+            v-if="!expanded"
+            class="focus-marker"
+            transform="shrink-6 up-9 right-17"
+            icon="plus"
+          />
+          <FAIcon
+            v-else
+            class="focus-marker"
+            transform="shrink-6 up-9 right-17"
+            icon="times"
+          />
+        </FALayers>
       </span>
     </template>
   </Popover>
@@ -125,6 +140,16 @@
       color: $fallback--text;
       color: var(--text, $fallback--text);
     }
+
+    .focus-marker {
+      visibility: hidden;
+    }
+
+    &:hover, &:focus {
+      .focus-marker {
+        visibility: visible;
+      }
+    }
   }
 }
 
diff --git a/src/components/reply_button/reply_button.js b/src/components/reply_button/reply_button.js
index c7bd2a2b..d6382982 100644
--- a/src/components/reply_button/reply_button.js
+++ b/src/components/reply_button/reply_button.js
@@ -1,7 +1,15 @@
 import { library } from '@fortawesome/fontawesome-svg-core'
-import { faReply } from '@fortawesome/free-solid-svg-icons'
+import {
+  faReply,
+  faPlus,
+  faTimes
+} from '@fortawesome/free-solid-svg-icons'
 
-library.add(faReply)
+library.add(
+  faReply,
+  faPlus,
+  faTimes
+)
 
 const ReplyButton = {
   name: 'ReplyButton',
diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue
index c17041da..56156c55 100644
--- a/src/components/reply_button/reply_button.vue
+++ b/src/components/reply_button/reply_button.vue
@@ -7,10 +7,24 @@
       :title="$t('tool_tip.reply')"
       @click.prevent="$emit('toggle')"
     >
-      <FAIcon
-        class="fa-scale-110 fa-old-padding"
-        icon="reply"
-      />
+      <FALayers class="fa-old-padding-layer">
+        <FAIcon
+          class="fa-scale-110"
+          icon="reply"
+        />
+        <FAIcon
+          v-if="!replying"
+          class="focus-marker"
+          transform="shrink-6 up-8 right-16"
+          icon="plus"
+        />
+        <FAIcon
+          v-else
+          class="focus-marker"
+          transform="shrink-6 up-8 right-16"
+          icon="times"
+        />
+      </FALayers>
     </button>
     <span v-else>
       <FAIcon
@@ -52,6 +66,16 @@
       color: $fallback--cBlue;
       color: var(--cBlue, $fallback--cBlue);
     }
+
+    .focus-marker {
+      visibility: hidden;
+    }
+
+    &:hover, &:focus {
+      .focus-marker {
+        visibility: visible;
+      }
+    }
   }
 
 }
diff --git a/src/components/retweet_button/retweet_button.js b/src/components/retweet_button/retweet_button.js
index 2103fd0b..b7911814 100644
--- a/src/components/retweet_button/retweet_button.js
+++ b/src/components/retweet_button/retweet_button.js
@@ -1,7 +1,17 @@
 import { library } from '@fortawesome/fontawesome-svg-core'
-import { faRetweet } from '@fortawesome/free-solid-svg-icons'
+import {
+  faRetweet,
+  faPlus,
+  faMinus,
+  faCheck
+} from '@fortawesome/free-solid-svg-icons'
 
-library.add(faRetweet)
+library.add(
+  faRetweet,
+  faPlus,
+  faMinus,
+  faCheck
+)
 
 const RetweetButton = {
   props: ['status', 'loggedIn', 'visibility'],
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index 5a15d387..ed84066d 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -7,11 +7,31 @@
       :title="$t('tool_tip.repeat')"
       @click.prevent="retweet()"
     >
-      <FAIcon
-        class="fa-scale-110 fa-old-padding"
-        icon="retweet"
-        :spin="animated"
-      />
+      <FALayers class="fa-old-padding-layer">
+        <FAIcon
+          class="fa-scale-110"
+          icon="retweet"
+          :spin="animated"
+        />
+        <FAIcon
+          v-if="status.repeated"
+          class="active-marker"
+          transform="shrink-6 up-9 right-12"
+          icon="check"
+        />
+        <FAIcon
+          v-if="!status.repeated"
+          class="focus-marker"
+          transform="shrink-6 up-9 right-12"
+          icon="plus"
+        />
+        <FAIcon
+          v-else
+          class="focus-marker"
+          transform="shrink-6 up-9 right-12"
+          icon="minus"
+        />
+      </FALayers>
     </button>
     <span v-else-if="loggedIn">
       <FAIcon
@@ -64,6 +84,19 @@
       color: $fallback--cGreen;
       color: var(--cGreen, $fallback--cGreen);
     }
+
+    .focus-marker {
+      visibility: hidden;
+    }
+
+    &:hover, &:focus {
+      .focus-marker {
+        visibility: visible;
+      }
+      .active-marker {
+        visibility: hidden;
+      }
+    }
   }
 }
 </style>
-- 
cgit v1.2.3-70-g09d2


From 97951fccfdce726c350ab633acc45213d675adb9 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Wed, 19 Jan 2022 19:45:38 -0500
Subject: Use :focus-visible instead of :focus for focus markers

In this way, after the user clicked with a pointer and moved that
pointer away, the focus marker will no longer show a focused style.

As Safari remains the only major browser engine that does not support
:focus-visible, a fallback to :focus is used if there is no browser
support for :focus-visible.

https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible
---
 src/components/extra_buttons/extra_buttons.vue     | 5 +++--
 src/components/favorite_button/favorite_button.vue | 9 +++++++--
 src/components/react_button/react_button.vue       | 5 +++--
 src/components/reply_button/reply_button.vue       | 5 +++--
 src/components/retweet_button/retweet_button.vue   | 9 +++++++--
 5 files changed, 23 insertions(+), 10 deletions(-)

(limited to 'src/components/retweet_button/retweet_button.vue')

diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index 23d74fce..d15e3102 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -168,11 +168,12 @@
       color: var(--text, $fallback--text);
     }
 
-    .focus-marker {
+    .focus-marker,
+    &:focus:not(:focus-visible):not(:hover) .focus-marker {
       visibility: hidden;
     }
 
-    &:hover, &:focus {
+    &:hover, &:focus, &:focus-visible {
       .focus-marker {
         visibility: visible;
       }
diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue
index 4015e1e6..01db63be 100644
--- a/src/components/favorite_button/favorite_button.vue
+++ b/src/components/favorite_button/favorite_button.vue
@@ -78,11 +78,16 @@
       color: var(--cOrange, $fallback--cOrange);
     }
 
-    .focus-marker {
+    .focus-marker,
+    &:focus:not(:focus-visible):not(:hover) .focus-marker {
       visibility: hidden;
     }
 
-    &:hover, &:focus {
+    &:focus:not(:focus-visible):not(:hover) .active-marker {
+      visibility: visible;
+    }
+
+    &:hover, &:focus, &:focus-visible {
       .focus-marker {
         visibility: visible;
       }
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index e30f6b68..885869f9 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -141,11 +141,12 @@
       color: var(--text, $fallback--text);
     }
 
-    .focus-marker {
+    .focus-marker,
+    &:focus:not(:focus-visible):not(:hover) .focus-marker {
       visibility: hidden;
     }
 
-    &:hover, &:focus {
+    &:hover, &:focus, &:focus-visible {
       .focus-marker {
         visibility: visible;
       }
diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue
index d75e6fd9..0466ceb3 100644
--- a/src/components/reply_button/reply_button.vue
+++ b/src/components/reply_button/reply_button.vue
@@ -67,11 +67,12 @@
       color: var(--cBlue, $fallback--cBlue);
     }
 
-    .focus-marker {
+    .focus-marker,
+    &:focus:not(:focus-visible):not(:hover) .focus-marker {
       visibility: hidden;
     }
 
-    &:hover, &:focus {
+    &:hover, &:focus, &:focus-visible {
       .focus-marker {
         visibility: visible;
       }
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index ed84066d..d88adacc 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -85,11 +85,16 @@
       color: var(--cGreen, $fallback--cGreen);
     }
 
-    .focus-marker {
+    .focus-marker,
+    &:focus:not(:focus-visible):not(:hover) .focus-marker {
       visibility: hidden;
     }
 
-    &:hover, &:focus {
+    &:focus:not(:focus-visible):not(:hover) .active-marker {
+      visibility: visible;
+    }
+
+    &:hover, &:focus, &:focus-visible {
       .focus-marker {
         visibility: visible;
       }
-- 
cgit v1.2.3-70-g09d2


From 11672bc4907d41706ad164f1ca3c485f034061c1 Mon Sep 17 00:00:00 2001
From: Tusooa Zhu <tusooa@kazv.moe>
Date: Wed, 19 Jan 2022 21:18:02 -0500
Subject: Fix styling on Safari

---
 src/_mixins.scss                                   | 17 +++++++++++++++++
 src/components/extra_buttons/extra_buttons.vue     | 10 ++++++----
 src/components/favorite_button/favorite_button.vue | 17 ++++++++++-------
 src/components/react_button/react_button.vue       | 10 ++++++----
 src/components/reply_button/reply_button.vue       | 10 ++++++----
 src/components/retweet_button/retweet_button.vue   | 17 ++++++++++-------
 6 files changed, 55 insertions(+), 26 deletions(-)
 create mode 100644 src/_mixins.scss

(limited to 'src/components/retweet_button/retweet_button.vue')

diff --git a/src/_mixins.scss b/src/_mixins.scss
new file mode 100644
index 00000000..1fed16c3
--- /dev/null
+++ b/src/_mixins.scss
@@ -0,0 +1,17 @@
+@mixin unfocused-style {
+  @content;
+
+  &:focus:not(:focus-visible):not(:hover) {
+    @content;
+  }
+}
+
+@mixin focused-style {
+  &:hover, &:focus {
+    @content;
+  }
+
+  &:focus-visible {
+    @content;
+  }
+}
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index d15e3102..ae50c316 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -151,6 +151,7 @@
 
 <style lang="scss">
 @import '../../_variables.scss';
+@import '../../_mixins.scss';
 
 .ExtraButtons {
   /* override of popover internal stuff */
@@ -168,12 +169,13 @@
       color: var(--text, $fallback--text);
     }
 
-    .focus-marker,
-    &:focus:not(:focus-visible):not(:hover) .focus-marker {
-      visibility: hidden;
+    @include unfocused-style {
+      .focus-marker {
+        visibility: hidden;
+      }
     }
 
-    &:hover, &:focus, &:focus-visible {
+    @include focused-style {
       .focus-marker {
         visibility: visible;
       }
diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue
index 01db63be..74a1dfbb 100644
--- a/src/components/favorite_button/favorite_button.vue
+++ b/src/components/favorite_button/favorite_button.vue
@@ -53,6 +53,7 @@
 
 <style lang="scss">
 @import '../../_variables.scss';
+@import '../../_mixins.scss';
 
 .FavoriteButton {
   display: flex;
@@ -78,19 +79,21 @@
       color: var(--cOrange, $fallback--cOrange);
     }
 
-    .focus-marker,
-    &:focus:not(:focus-visible):not(:hover) .focus-marker {
-      visibility: hidden;
-    }
+    @include unfocused-style {
+      .focus-marker {
+        visibility: hidden;
+      }
 
-    &:focus:not(:focus-visible):not(:hover) .active-marker {
-      visibility: visible;
+      .active-marker {
+        visibility: visible;
+      }
     }
 
-    &:hover, &:focus, &:focus-visible {
+    @include focused-style {
       .focus-marker {
         visibility: visible;
       }
+
       .active-marker {
         visibility: hidden;
       }
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 885869f9..8fa4d08b 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -74,6 +74,7 @@
 
 <style lang="scss">
 @import '../../_variables.scss';
+@import '../../_mixins.scss';
 
 .ReactButton {
   .reaction-picker-filter {
@@ -141,12 +142,13 @@
       color: var(--text, $fallback--text);
     }
 
-    .focus-marker,
-    &:focus:not(:focus-visible):not(:hover) .focus-marker {
-      visibility: hidden;
+    @include unfocused-style {
+      .focus-marker {
+        visibility: hidden;
+      }
     }
 
-    &:hover, &:focus, &:focus-visible {
+    @include focused-style {
       .focus-marker {
         visibility: visible;
       }
diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue
index 0466ceb3..ea97fbaa 100644
--- a/src/components/reply_button/reply_button.vue
+++ b/src/components/reply_button/reply_button.vue
@@ -46,6 +46,7 @@
 
 <style lang="scss">
 @import '../../_variables.scss';
+@import '../../_mixins.scss';
 
 .ReplyButton {
   display: flex;
@@ -67,12 +68,13 @@
       color: var(--cBlue, $fallback--cBlue);
     }
 
-    .focus-marker,
-    &:focus:not(:focus-visible):not(:hover) .focus-marker {
-      visibility: hidden;
+    @include unfocused-style {
+      .focus-marker {
+        visibility: hidden;
+      }
     }
 
-    &:hover, &:focus, &:focus-visible {
+    @include focused-style {
       .focus-marker {
         visibility: visible;
       }
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index d88adacc..396d1200 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -60,6 +60,7 @@
 
 <style lang="scss">
 @import '../../_variables.scss';
+@import '../../_mixins.scss';
 
 .RetweetButton {
   display: flex;
@@ -85,19 +86,21 @@
       color: var(--cGreen, $fallback--cGreen);
     }
 
-    .focus-marker,
-    &:focus:not(:focus-visible):not(:hover) .focus-marker {
-      visibility: hidden;
-    }
+    @include unfocused-style {
+      .focus-marker {
+        visibility: hidden;
+      }
 
-    &:focus:not(:focus-visible):not(:hover) .active-marker {
-      visibility: visible;
+      .active-marker {
+        visibility: visible;
+      }
     }
 
-    &:hover, &:focus, &:focus-visible {
+    @include focused-style {
       .focus-marker {
         visibility: visible;
       }
+
       .active-marker {
         visibility: hidden;
       }
-- 
cgit v1.2.3-70-g09d2


From 7dc22774532872fc99aa7768cf299ab623e9d155 Mon Sep 17 00:00:00 2001
From: tusooa <tusooa@kazv.moe>
Date: Mon, 9 Jan 2023 13:02:16 -0500
Subject: Use stylelint

---
 .stylelintrc.json                                  |   9 +-
 build/webpack.base.conf.js                         |   3 +-
 package.json                                       |   1 +
 src/App.scss                                       |  78 ++++++------
 src/_mixins.scss                                   |   5 +-
 src/_variables.scss                                |  14 ++-
 src/components/about/about.vue                     |   3 -
 src/components/account_actions/account_actions.vue |   3 +-
 src/components/announcement/announcement.vue       |   8 +-
 .../announcements_page/announcements_page.vue      |   3 +-
 .../async_component_error.vue                      |   5 +-
 src/components/attachment/attachment.scss          |  47 +++----
 src/components/autosuggest/autosuggest.vue         |   4 +-
 src/components/avatar_list/avatar_list.vue         |   2 +-
 src/components/basic_user_card/basic_user_card.vue |   2 +-
 src/components/block_card/block_card.vue           |   1 +
 src/components/chat/chat.scss                      |   4 +-
 src/components/chat/chat.vue                       |   4 +-
 src/components/chat_list/chat_list.vue             |   2 +-
 src/components/chat_list_item/chat_list_item.scss  |   9 +-
 src/components/chat_list_item/chat_list_item.vue   |   4 +-
 src/components/chat_message/chat_message.scss      |  94 +++++++-------
 src/components/chat_message/chat_message.vue       |   4 +-
 src/components/chat_new/chat_new.scss              |   2 +-
 src/components/chat_new/chat_new.vue               |   4 +-
 src/components/chat_title/chat_title.vue           |   2 +-
 src/components/checkbox/checkbox.vue               |  16 +--
 src/components/color_input/color_input.scss        |  19 +--
 src/components/contrast_ratio/contrast_ratio.vue   |   1 -
 src/components/conversation/conversation.vue       |  31 ++---
 src/components/desktop_nav/desktop_nav.scss        |  39 +++---
 src/components/dialog_modal/dialog_modal.vue       |  10 +-
 .../edit_status_modal/edit_status_modal.vue        |   1 +
 src/components/emoji_input/emoji_input.vue         |  24 ++--
 src/components/emoji_picker/emoji_picker.scss      |  35 +++---
 src/components/emoji_reactions/emoji_reactions.vue |   5 +-
 src/components/extra_buttons/extra_buttons.vue     |  13 +-
 src/components/favorite_button/favorite_button.vue |   4 +-
 src/components/flash/flash.vue                     |   5 +-
 src/components/follow_card/follow_card.vue         |   3 +-
 .../follow_request_card/follow_request_card.vue    |   4 +-
 src/components/font_control/font_control.vue       |   5 +-
 src/components/gallery/gallery.vue                 | 100 ++++++++-------
 .../global_notice_list/global_notice_list.vue      |   5 +-
 src/components/link-preview/link-preview.vue       |   5 +-
 src/components/list/list.vue                       |   2 +-
 src/components/lists_card/lists_card.vue           |  11 +-
 src/components/lists_edit/lists_edit.vue           |   2 +-
 .../lists_user_search/lists_user_search.vue        |   4 +-
 src/components/login_form/login_form.vue           |   7 +-
 src/components/media_modal/media_modal.vue         |  57 +++++----
 src/components/media_upload/media_upload.vue       |   2 +-
 src/components/mention_link/mention_link.scss      |   7 +-
 src/components/mentions_line/mentions_line.scss    |   2 +-
 src/components/mobile_nav/mobile_nav.vue           |   8 +-
 .../mobile_post_status_button.vue                  |   5 +-
 src/components/modal/modal.vue                     |   7 +-
 .../moderation_tools/moderation_tools.vue          |   7 +-
 .../mrf_transparency_panel.scss                    |  14 ++-
 .../mrf_transparency_panel.vue                     |   4 +-
 src/components/mute_card/mute_card.vue             |   1 +
 src/components/nav_panel/nav_panel.vue             |   7 +-
 src/components/navigation/navigation_entry.vue     |   4 +-
 src/components/navigation/navigation_pins.vue      |   3 +-
 src/components/notification/notification.scss      |  17 +--
 src/components/notifications/notifications.scss    |   9 +-
 src/components/panel_loading/panel_loading.vue     |   3 +-
 src/components/password_reset/password_reset.vue   |   2 +-
 src/components/poll/poll.vue                       |  12 +-
 src/components/poll/poll_form.vue                  |   3 +-
 src/components/popover/popover.vue                 |  37 +++---
 .../post_status_form/post_status_form.vue          |  67 +++++-----
 src/components/react_button/react_button.vue       |  24 ++--
 src/components/registration/registration.vue       |   6 +-
 .../remote_user_resolver/remote_user_resolver.vue  |   3 -
 src/components/reply_button/reply_button.vue       |   5 +-
 src/components/report/report.scss                  |   2 +-
 src/components/retweet_button/retweet_button.vue   |   4 +-
 src/components/rich_content/rich_content.scss      |   6 +-
 src/components/scope_selector/scope_selector.vue   |   3 +-
 src/components/search/search.vue                   |  14 +--
 src/components/search_bar/search_bar.vue           |   2 +-
 src/components/select/select.vue                   |   7 +-
 src/components/selectable_list/selectable_list.vue |   3 +-
 .../settings_modal/helpers/choice_setting.vue      |   5 -
 .../settings_modal/helpers/size_setting.vue        |   9 +-
 src/components/settings_modal/settings_modal.scss  |  51 ++++----
 .../settings_modal/settings_modal_content.scss     |   8 +-
 src/components/settings_modal/tabs/general_tab.vue |   1 +
 .../settings_modal/tabs/mutes_and_blocks_tab.scss  |  44 +++----
 .../settings_modal/tabs/profile_tab.scss           |   7 +-
 .../settings_modal/tabs/security_tab/mfa.vue       |  11 +-
 .../tabs/security_tab/mfa_backup_codes.vue         |   3 +-
 .../settings_modal/tabs/theme_tab/preview.vue      |  15 +--
 .../settings_modal/tabs/theme_tab/theme_tab.scss   | 120 ++++++++++--------
 src/components/shadow_control/shadow_control.vue   |  40 +++---
 src/components/shout_panel/shout_panel.vue         |   2 +-
 src/components/side_drawer/side_drawer.vue         |  18 +--
 src/components/staff_panel/staff_panel.vue         |   1 -
 src/components/status/status.scss                  |  10 +-
 src/components/status/status.vue                   |   2 +-
 src/components/status_body/status_body.scss        |  13 +-
 .../status_history_modal/status_history_modal.vue  |   1 +
 src/components/status_popover/status_popover.vue   |   3 +-
 src/components/sticker_picker/sticker_picker.vue   |   7 +-
 src/components/still-image/still-image.vue         |   6 +-
 src/components/tab_switcher/tab_switcher.scss      |  50 +++++---
 .../terms_of_service_panel.vue                     |   2 +-
 src/components/thread_tree/thread_tree.vue         |   4 +-
 src/components/timeline/timeline.scss              |   7 +-
 src/components/timeline_menu/timeline_menu.vue     | 139 +++++++++++----------
 .../update_notification/update_notification.scss   |  14 ++-
 src/components/user_avatar/user_avatar.vue         |   5 +-
 src/components/user_card/user_card.scss            | 114 +++++++++--------
 .../user_list_popover/user_list_popover.vue        |   2 +-
 src/components/user_note/user_note.vue             |   2 +-
 src/components/user_popover/user_popover.vue       |   4 +-
 src/components/user_profile/user_profile.vue       |   6 +-
 .../user_reporting_modal/user_reporting_modal.vue  |   4 +-
 src/components/who_to_follow/who_to_follow.vue     |   3 -
 .../who_to_follow_panel/who_to_follow_panel.vue    |  16 ++-
 src/hocs/with_load_more/with_load_more.scss        |   3 +-
 src/hocs/with_subscription/with_subscription.scss  |   2 +-
 src/panel.scss                                     |  16 +--
 yarn.lock                                          |  13 +-
 125 files changed, 969 insertions(+), 839 deletions(-)

(limited to 'src/components/retweet_button/retweet_button.vue')

diff --git a/.stylelintrc.json b/.stylelintrc.json
index dc96d5e0..7517362c 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -10,12 +10,17 @@
     "declaration-no-important": true,
     "rscss/no-descendant-combinator": false,
     "rscss/class-format": [
-      true,
+      false,
       {
         "component": "pascal-case",
         "variant": "^-[a-z]\\w+",
         "element": "^[a-z]\\w+"
       }
-    ]
+    ],
+    "selector-class-pattern": null,
+    "import-notation": null,
+    "custom-property-pattern": null,
+    "keyframes-name-pattern": null,
+    "scss/operator-no-newline-after": null
   }
 }
diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js
index bf946922..7e69352a 100644
--- a/build/webpack.base.conf.js
+++ b/build/webpack.base.conf.js
@@ -6,7 +6,7 @@ var ServiceWorkerWebpackPlugin = require('serviceworker-webpack5-plugin')
 var CopyPlugin = require('copy-webpack-plugin');
 var { VueLoaderPlugin } = require('vue-loader')
 var ESLintPlugin = require('eslint-webpack-plugin');
-
+var StylelintPlugin = require('stylelint-webpack-plugin');
 
 var env = process.env.NODE_ENV
 // check env & config/index.js to decide weither to enable CSS Sourcemaps for the
@@ -111,6 +111,7 @@ module.exports = {
       extensions: ['js', 'vue'],
       formatter: require('eslint-formatter-friendly')
     }),
+    new StylelintPlugin({}),
     new VueLoaderPlugin(),
     // This copies Ruffle's WASM to a directory so that JS side can access it
     new CopyPlugin({
diff --git a/package.json b/package.json
index 1949a16e..8658af93 100644
--- a/package.json
+++ b/package.json
@@ -120,6 +120,7 @@
     "stylelint-config-recommended-vue": "^1.4.0",
     "stylelint-config-standard": "29.0.0",
     "stylelint-rscss": "0.4.0",
+    "stylelint-webpack-plugin": "^3.3.0",
     "vue-loader": "17.0.1",
     "vue-style-loader": "4.1.3",
     "webpack": "5.75.0",
diff --git a/src/App.scss b/src/App.scss
index 75b2667c..0d2daa7d 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -1,5 +1,7 @@
 // stylelint-disable rscss/class-format
-@import './_variables.scss';
+/* stylelint-disable no-descending-specificity */
+@import "./variables";
+@import "./panel";
 
 :root {
   --navbar-height: 3.5rem;
@@ -123,7 +125,7 @@ h4 {
   font-weight: 1000;
 }
 
-i[class*=icon-],
+i[class*="icon-"],
 .svg-inline--fa,
 .iconLetter {
   color: $fallback--icon;
@@ -132,7 +134,7 @@ i[class*=icon-],
 
 .button-unstyled:hover,
 a:hover {
-  > i[class*=icon-],
+  > i[class*="icon-"],
   > .svg-inline--fa,
   > .iconLetter {
     color: var(--text);
@@ -141,12 +143,11 @@ a:hover {
 
 nav {
   z-index: var(--ZI_navbar);
-  color: var(--topBarText);
   background-color: $fallback--fg;
   background-color: var(--topBar, $fallback--fg);
   color: $fallback--faint;
   color: var(--faint, $fallback--faint);
-  box-shadow: 0 0 4px rgba(0, 0, 0, 0.6);
+  box-shadow: 0 0 4px rgb(0 0 0 / 60%);
   box-shadow: var(--topBarShadow);
   box-sizing: border-box;
   height: var(--navbar-height);
@@ -191,13 +192,11 @@ nav {
 }
 
 .underlay {
-  grid-column-start: 1;
-  grid-column-end: span 3;
-  grid-row-start: 1;
-  grid-row-end: 1;
+  grid-column: 1 / span 3;
+  grid-row: 1 / 1;
   pointer-events: none;
-  background-color: rgba(0, 0, 0, 0.15);
-  background-color: var(--underlay, rgba(0, 0, 0, 0.15));
+  background-color: rgb(0 0 0 / 15%);
+  background-color: var(--underlay, rgb(0 0 0 / 15%));
   z-index: -1000;
 }
 
@@ -215,8 +214,10 @@ nav {
   grid-template-columns:
     var(--effectiveSidebarColumnWidth)
     var(--effectiveContentColumnWidth);
+  /* stylelint-disable declaration-block-no-redundant-longhand-properties */
   grid-template-areas: "sidebar content";
   grid-template-rows: 1fr;
+  /* stylelint-enable declaration-block-no-redundant-longhand-properties */
   box-sizing: border-box;
   margin: 0 auto;
   align-content: flex-start;
@@ -231,8 +232,7 @@ nav {
     display: grid;
     grid-template-columns: 100%;
     box-sizing: border-box;
-    grid-row-start: 1;
-    grid-row-end: 1;
+    grid-row: 1 / 1;
     margin: 0 calc(var(--___columnMargin) / 2);
     padding: calc(var(--___columnMargin)) 0;
     row-gap: var(--___columnMargin);
@@ -307,7 +307,7 @@ nav {
     align-content: start;
   }
 
-  &.-reverse:not(.-wide):not(.-mobile) {
+  &.-reverse:not(.-wide, .-mobile) {
     grid-template-columns:
       var(--effectiveContentColumnWidth)
       var(--effectiveSidebarColumnWidth);
@@ -336,11 +336,8 @@ nav {
     padding: 0;
 
     .column {
-      margin-left: 0;
-      margin-right: 0;
       padding-top: 0;
-      margin-top: var(--navbar-height);
-      margin-bottom: 0;
+      margin-top: var(--navbar-height) 0 0 0;
     }
 
     .panel-heading,
@@ -389,7 +386,7 @@ nav {
     background: transparent;
   }
 
-  i[class*=icon-],
+  i[class*="icon-"],
   .svg-inline--fa {
     color: $fallback--text;
     color: var(--btnText, $fallback--text);
@@ -400,12 +397,15 @@ nav {
   }
 
   &:hover {
-    box-shadow: 0 0 4px rgba(255, 255, 255, 0.3);
+    box-shadow: 0 0 4px rgb(255 255 255 / 30%);
     box-shadow: var(--buttonHoverShadow);
   }
 
   &:active {
-    box-shadow: 0 0 4px 0 rgba(255, 255, 255, 0.3), 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset;
+    box-shadow:
+      0 0 4px 0 rgb(255 255 255 / 30%),
+      0 1px 0 0 rgb(0 0 0 / 20%) inset,
+      0 -1px 0 0 rgb(255 255 255 / 20%) inset;
     box-shadow: var(--buttonPressedShadow);
     color: $fallback--text;
     color: var(--btnPressedText, $fallback--text);
@@ -438,7 +438,10 @@ nav {
     color: var(--btnToggledText, $fallback--text);
     background-color: $fallback--fg;
     background-color: var(--btnToggled, $fallback--fg);
-    box-shadow: 0 0 4px 0 rgba(255, 255, 255, 0.3), 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset;
+    box-shadow:
+      0 0 4px 0 rgb(255 255 255 / 30%),
+      0 1px 0 0 rgb(0 0 0 / 20%) inset,
+      0 -1px 0 0 rgb(255 255 255 / 20%) inset;
     box-shadow: var(--buttonPressedShadow);
 
     svg,
@@ -503,7 +506,10 @@ textarea,
   border: none;
   border-radius: $fallback--inputRadius;
   border-radius: var(--inputRadius, $fallback--inputRadius);
-  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.2) inset, 0 -1px 0 0 rgba(255, 255, 255, 0.2) inset, 0 0 2px 0 rgba(0, 0, 0, 1) inset;
+  box-shadow:
+    0 1px 0 0 rgb(0 0 0 / 20%) inset,
+    0 -1px 0 0 rgb(255 255 255 / 20%) inset,
+    0 0 2px 0 rgb(0 0 0 / 100%) inset;
   box-shadow: var(--inputShadow);
   background-color: $fallback--fg;
   background-color: var(--input, $fallback--fg);
@@ -521,13 +527,13 @@ textarea,
   padding: 0 var(--_padding);
 
   &:disabled,
-  &[disabled=disabled],
+  &[disabled="disabled"],
   &.disabled {
     cursor: not-allowed;
     opacity: 0.5;
   }
 
-  &[type=range] {
+  &[type="range"] {
     background: none;
     border: none;
     margin: 0;
@@ -535,7 +541,7 @@ textarea,
     flex: 1;
   }
 
-  &[type=radio] {
+  &[type="radio"] {
     display: none;
 
     &:checked + label::before {
@@ -555,7 +561,7 @@ textarea,
     + label::before {
       flex-shrink: 0;
       display: inline-block;
-      content: '';
+      content: "";
       transition: box-shadow 200ms;
       width: 1.1em;
       height: 1.1em;
@@ -575,7 +581,7 @@ textarea,
     }
   }
 
-  &[type=checkbox] {
+  &[type="checkbox"] {
     display: none;
 
     &:checked + label::before {
@@ -594,7 +600,7 @@ textarea,
     + label::before {
       flex-shrink: 0;
       display: inline-block;
-      content: '✓';
+      content: "✓";
       transition: color 200ms;
       width: 1.1em;
       height: 1.1em;
@@ -634,10 +640,10 @@ option {
 }
 
 .hide-number-spinner {
-  -moz-appearance: textfield;
+  appearance: textfield;
 
-  &[type=number]::-webkit-inner-spin-button,
-  &[type=number]::-webkit-outer-spin-button {
+  &[type="number"]::-webkit-inner-spin-button,
+  &[type="number"]::-webkit-outer-spin-button {
     opacity: 0;
     display: none;
   }
@@ -669,8 +675,6 @@ option {
   }
 }
 
-@import './panel.scss';
-
 .fa {
   color: grey;
 }
@@ -686,7 +690,7 @@ option {
   max-width: 10em;
   min-width: 1.7em;
   height: 1.3em;
-  padding: 0.15em 0.15em;
+  padding: 0.15em;
   vertical-align: middle;
   font-weight: normal;
   font-style: normal;
@@ -789,7 +793,8 @@ option {
 
 .fa-old-padding {
   &.iconLetter,
-  &.svg-inline--fa, &-layer {
+  &.svg-inline--fa,
+  &-layer {
     padding: 0 0.3em;
   }
 }
@@ -883,3 +888,4 @@ option {
 .fade-leave-active {
   opacity: 0;
 }
+/* stylelint-enable no-descending-specificity */
diff --git a/src/_mixins.scss b/src/_mixins.scss
index 1fed16c3..e99fe26f 100644
--- a/src/_mixins.scss
+++ b/src/_mixins.scss
@@ -1,13 +1,14 @@
 @mixin unfocused-style {
   @content;
 
-  &:focus:not(:focus-visible):not(:hover) {
+  &:focus:not(:focus-visible, :hover) {
     @content;
   }
 }
 
 @mixin focused-style {
-  &:hover, &:focus {
+  &:hover,
+  &:focus {
     @content;
   }
 
diff --git a/src/_variables.scss b/src/_variables.scss
index 099d3606..751fc9a4 100644
--- a/src/_variables.scss
+++ b/src/_variables.scss
@@ -4,20 +4,20 @@ $darkened-background: whitesmoke;
 
 $fallback--bg: #121a24;
 $fallback--fg: #182230;
-$fallback--faint: rgba(185, 185, 186, .5);
+$fallback--faint: rgb(185 185 186 / 50%);
 $fallback--text: #b9b9ba;
 $fallback--link: #d8a070;
 $fallback--icon: #666;
-$fallback--lightBg: rgb(21, 30, 42);
+$fallback--lightBg: rgb(21 30 42);
 $fallback--lightText: #b9b9ba;
 $fallback--border: #222;
-$fallback--cRed: #ff0000;
+$fallback--cRed: #f00;
 $fallback--cBlue: #0095ff;
 $fallback--cGreen: #0fa00f;
 $fallback--cOrange: orange;
 
-$fallback--alertError: rgba(211,16,20,.5);
-$fallback--alertWarning: rgba(111,111,20,.5);
+$fallback--alertError: rgb(211 16 20 / 50%);
+$fallback--alertWarning: rgb(111 111 20 / 50%);
 
 $fallback--panelRadius: 10px;
 $fallback--checkboxRadius: 2px;
@@ -29,6 +29,8 @@ $fallback--avatarAltRadius: 10px;
 $fallback--attachmentRadius: 10px;
 $fallback--chatMessageRadius: 10px;
 
-$fallback--buttonShadow: 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;
+$fallback--buttonShadow: 0 0 2px 0 rgb(0 0 0 / 100%),
+  0 1px 0 0 rgb(255 255 255 / 20%) inset,
+  0 -1px 0 0 rgb(0 0 0 / 20%) inset;
 
 $status-margin: 0.75em;
diff --git a/src/components/about/about.vue b/src/components/about/about.vue
index 33586c97..8a551485 100644
--- a/src/components/about/about.vue
+++ b/src/components/about/about.vue
@@ -9,6 +9,3 @@
 </template>
 
 <script src="./about.js"></script>
-
-<style lang="scss">
-</style>
diff --git a/src/components/account_actions/account_actions.vue b/src/components/account_actions/account_actions.vue
index 218aa6b3..973a5935 100644
--- a/src/components/account_actions/account_actions.vue
+++ b/src/components/account_actions/account_actions.vue
@@ -80,7 +80,8 @@
 <script src="./account_actions.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
+
 .AccountActions {
   .ellipsis-button {
     width: 2.5em;
diff --git a/src/components/announcement/announcement.vue b/src/components/announcement/announcement.vue
index c1b35981..a1c5791e 100644
--- a/src/components/announcement/announcement.vue
+++ b/src/components/announcement/announcement.vue
@@ -102,19 +102,19 @@
 @import "../../variables";
 
 .announcement {
-  border-bottom-width: 1px;
-  border-bottom-style: solid;
-  border-bottom-color: var(--border, $fallback--border);
+  border-bottom: 1px solid var(--border, $fallback--border);
   border-radius: 0;
   padding: var(--status-margin, $status-margin);
 
-  .heading, .body {
+  .heading,
+  .body {
     margin-bottom: var(--status-margin, $status-margin);
   }
 
   .footer {
     display: flex;
     flex-direction: column;
+
     .times {
       display: flex;
       flex-direction: column;
diff --git a/src/components/announcements_page/announcements_page.vue b/src/components/announcements_page/announcements_page.vue
index 59ed283d..78d3ecee 100644
--- a/src/components/announcements_page/announcements_page.vue
+++ b/src/components/announcements_page/announcements_page.vue
@@ -67,7 +67,8 @@
   .post-form {
     padding: var(--status-margin, $status-margin);
 
-    .heading, .body {
+    .heading,
+    .body {
       margin-bottom: var(--status-margin, $status-margin);
     }
 
diff --git a/src/components/async_component_error/async_component_error.vue b/src/components/async_component_error/async_component_error.vue
index 26ab5d21..2ff8974c 100644
--- a/src/components/async_component_error/async_component_error.vue
+++ b/src/components/async_component_error/async_component_error.vue
@@ -34,9 +34,10 @@ export default {
   height: 100%;
   align-items: center;
   justify-content: center;
+
   .btn {
-    margin: .5em;
-    padding: .5em 2em;
+    margin: 0.5em;
+    padding: 0.5em 2em;
   }
 }
 </style>
diff --git a/src/components/attachment/attachment.scss b/src/components/attachment/attachment.scss
index b2dea98d..cf38d45b 100644
--- a/src/components/attachment/attachment.scss
+++ b/src/components/attachment/attachment.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Attachment {
   display: inline-flex;
@@ -102,14 +102,13 @@
     padding-top: 0.5em;
   }
 
-
   .play-icon {
     position: absolute;
     font-size: 64px;
     top: calc(50% - 32px);
     left: calc(50% - 32px);
-    color: rgba(255, 255, 255, 0.75);
-    text-shadow: 0 0 2px rgba(0, 0, 0, 0.4);
+    color: rgb(255 255 255 / 75%);
+    text-shadow: 0 0 2px rgb(0 0 0 / 40%);
 
     &::before {
       margin: 0;
@@ -135,18 +134,32 @@
       margin-left: 0.5em;
       font-size: 1.25em;
       // TODO: theming? hard to theme with unknown background image color
-      background: rgba(230, 230, 230, 0.7);
+      background: rgb(230 230 230 / 70%);
 
       .svg-inline--fa {
-        color: rgba(0, 0, 0, 0.6);
+        color: rgb(0 0 0 / 60%);
       }
 
       &:hover .svg-inline--fa {
-        color: rgba(0, 0, 0, 0.9);
+        color: rgb(0 0 0 / 90%);
       }
     }
   }
 
+  &.-contain-fit {
+    img,
+    canvas {
+      object-fit: contain;
+    }
+  }
+
+  &.-cover-fit {
+    img,
+    canvas {
+      object-fit: cover;
+    }
+  }
+
   .oembed-container {
     line-height: 1.2em;
     flex: 1 0 100%;
@@ -160,8 +173,9 @@
 
     .image {
       flex: 1;
+
       img {
-        border: 0px;
+        border: 0;
         border-radius: 5px;
         height: 100%;
         object-fit: cover;
@@ -172,9 +186,10 @@
       flex: 2;
       margin: 8px;
       word-break: break-all;
+
       h1 {
         font-size: 1rem;
-        margin: 0px;
+        margin: 0;
       }
     }
   }
@@ -251,18 +266,4 @@
   &.-loading {
     cursor: progress;
   }
-
-  &.-contain-fit {
-    img,
-    canvas {
-      object-fit: contain;
-    }
-  }
-
-  &.-cover-fit {
-    img,
-    canvas {
-      object-fit: cover;
-    }
-  }
 }
diff --git a/src/components/autosuggest/autosuggest.vue b/src/components/autosuggest/autosuggest.vue
index f283ab82..7b7102fd 100644
--- a/src/components/autosuggest/autosuggest.vue
+++ b/src/components/autosuggest/autosuggest.vue
@@ -24,7 +24,7 @@
 <script src="./autosuggest.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .autosuggest {
   position: relative;
@@ -50,7 +50,7 @@
     border-radius: var(--inputRadius, $fallback--inputRadius);
     border-top-left-radius: 0;
     border-top-right-radius: 0;
-    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
+    box-shadow: 1px 1px 4px rgb(0 0 0 / 60%);
     box-shadow: var(--panelShadow);
     overflow-y: auto;
     z-index: 1;
diff --git a/src/components/avatar_list/avatar_list.vue b/src/components/avatar_list/avatar_list.vue
index 9a6ca3f6..2d00cb7b 100644
--- a/src/components/avatar_list/avatar_list.vue
+++ b/src/components/avatar_list/avatar_list.vue
@@ -17,7 +17,7 @@
 <script src="./avatar_list.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .avatars {
   display: flex;
diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue
index 418de926..705e20f5 100644
--- a/src/components/basic_user_card/basic_user_card.vue
+++ b/src/components/basic_user_card/basic_user_card.vue
@@ -49,7 +49,7 @@
   margin: 0;
   padding: 0.6em 1em;
 
-   --emoji-size: 14px;
+  --emoji-size: 14px;
 
   &-collapsed-content {
     margin-left: 0.7em;
diff --git a/src/components/block_card/block_card.vue b/src/components/block_card/block_card.vue
index 2fe66d4c..b14ef844 100644
--- a/src/components/block_card/block_card.vue
+++ b/src/components/block_card/block_card.vue
@@ -37,6 +37,7 @@
 .block-card-content-container {
   margin-top: 0.5em;
   text-align: right;
+
   button {
     width: 10em;
   }
diff --git a/src/components/chat/chat.scss b/src/components/chat/chat.scss
index f2e154ab..43e7a5e4 100644
--- a/src/components/chat/chat.scss
+++ b/src/components/chat/chat.scss
@@ -17,7 +17,7 @@
     width: 100%;
     overflow: visible;
     min-height: calc(100vh - var(--navbar-height));
-    margin: 0 0 0 0;
+    margin: 0;
     border-radius: 10px 10px 0 0;
     border-radius: var(--panelRadius, 10px) var(--panelRadius, 10px) 0 0;
 
@@ -66,7 +66,7 @@
     display: flex;
     justify-content: center;
     align-items: center;
-    box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3), 0 2px 4px rgba(0, 0, 0, 0.3);
+    box-shadow: 0 1px 1px rgb(0 0 0 / 30%), 0 2px 4px rgb(0 0 0 / 30%);
     z-index: 10;
     transition: 0.35s all;
     transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
diff --git a/src/components/chat/chat.vue b/src/components/chat/chat.vue
index 2e7df7bd..b1e5468c 100644
--- a/src/components/chat/chat.vue
+++ b/src/components/chat/chat.vue
@@ -95,6 +95,6 @@
 
 <script src="./chat.js"></script>
 <style lang="scss">
-@import '../../_variables.scss';
-@import './chat.scss';
+@import "../../variables";
+@import "./chat";
 </style>
diff --git a/src/components/chat_list/chat_list.vue b/src/components/chat_list/chat_list.vue
index 1248c4c8..27a475ed 100644
--- a/src/components/chat_list/chat_list.vue
+++ b/src/components/chat_list/chat_list.vue
@@ -45,7 +45,7 @@
 <script src="./chat_list.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .chat-list {
   min-height: 25em;
diff --git a/src/components/chat_list_item/chat_list_item.scss b/src/components/chat_list_item/chat_list_item.scss
index c6b45c34..3a84672b 100644
--- a/src/components/chat_list_item/chat_list_item.scss
+++ b/src/components/chat_list_item/chat_list_item.scss
@@ -13,7 +13,7 @@
 
   &:hover {
     background-color: var(--selectedPost, $fallback--lightBg);
-    box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.1);
+    box-shadow: 0 0 3px 1px rgb(0 0 0 / 10%);
   }
 
   .chat-list-item-left {
@@ -67,6 +67,7 @@
     canvas {
       display: none;
     }
+
     img {
       visibility: visible;
     }
@@ -79,13 +80,11 @@
 
   .chat-preview-body {
     --emoji-size: 1.4em;
+
+    padding-right: 1em;
   }
 
   .time-wrapper {
     line-height: var(--post-line-height);
   }
-
-  .chat-preview-body {
-    padding-right: 1em;
-  }
 }
diff --git a/src/components/chat_list_item/chat_list_item.vue b/src/components/chat_list_item/chat_list_item.vue
index c7c0e878..69ad609b 100644
--- a/src/components/chat_list_item/chat_list_item.vue
+++ b/src/components/chat_list_item/chat_list_item.vue
@@ -48,6 +48,6 @@
 <script src="./chat_list_item.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-@import './chat_list_item.scss';
+@import "../../variables";
+@import "./chat_list_item";
 </style>
diff --git a/src/components/chat_message/chat_message.scss b/src/components/chat_message/chat_message.scss
index 1913479f..fd5b7aa4 100644
--- a/src/components/chat_message/chat_message.scss
+++ b/src/components/chat_message/chat_message.scss
@@ -1,12 +1,12 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .chat-message-wrapper {
-
   &.hovered-message-chain {
     .animated.Avatar {
       canvas {
         display: none;
       }
+
       img {
         visibility: visible;
       }
@@ -28,7 +28,8 @@
   .menu-icon {
     cursor: pointer;
 
-    &:hover, .extra-button-popover.open & {
+    &:hover,
+    .extra-button-popover.open & {
       color: $fallback--text;
       color: var(--text, $fallback--text);
     }
@@ -54,27 +55,11 @@
     width: 32px;
   }
 
-  .link-preview, .attachments {
+  .link-preview,
+  .attachments {
     margin-bottom: 1em;
   }
 
-  .chat-message-inner {
-    display: flex;
-    flex-direction: column;
-    align-items: flex-start;
-    max-width: 80%;
-    min-width: 10em;
-    width: 100%;
-
-    &.with-media {
-      width: 100%;
-
-      .status {
-        width: 100%;
-      }
-    }
-  }
-
   .status {
     border-radius: $fallback--chatMessageRadius;
     border-radius: var(--chatMessageRadius, $fallback--chatMessageRadius);
@@ -86,7 +71,7 @@
     position: relative;
     float: right;
     font-size: 0.8em;
-    margin: -1em 0 -0.5em 0;
+    margin: -1em 0 -0.5em;
     font-style: italic;
     opacity: 0.8;
   }
@@ -103,18 +88,54 @@
   }
 
   .pending {
-    .status-content.media-body, .created-at {
+    .status-content.media-body,
+    .created-at {
       color: var(--faint);
     }
   }
 
   .error {
-    .status-content.media-body, .created-at {
+    .status-content.media-body,
+    .created-at {
       color: $fallback--cRed;
       color: var(--badgeNotification, $fallback--cRed);
     }
   }
 
+  .chat-message-inner {
+    display: flex;
+    flex-direction: column;
+    align-items: flex-start;
+    max-width: 80%;
+    min-width: 10em;
+    width: 100%;
+  }
+
+  .outgoing {
+    display: flex;
+    flex-flow: row wrap;
+    align-content: end;
+    justify-content: flex-end;
+
+    a {
+      color: var(--chatMessageOutgoingLink, $fallback--link);
+    }
+
+    .status {
+      color: var(--chatMessageOutgoingText, $fallback--text);
+      background-color: var(--chatMessageOutgoingBg, $fallback--lightBg);
+      border: 1px solid var(--chatMessageOutgoingBorder, --lightBg);
+    }
+
+    .chat-message-inner {
+      align-items: flex-end;
+    }
+
+    .chat-message-menu {
+      right: 0.4rem;
+    }
+  }
+
   .incoming {
     a {
       color: var(--chatMessageIncomingLink, $fallback--link);
@@ -137,36 +158,17 @@
     }
   }
 
-  .outgoing {
-    display: flex;
-    flex-direction: row;
-    flex-wrap: wrap;
-    align-content: end;
-    justify-content: flex-end;
-
-    a {
-      color: var(--chatMessageOutgoingLink, $fallback--link);
-    }
+  .chat-message-inner.with-media {
+    width: 100%;
 
     .status {
-      color: var(--chatMessageOutgoingText, $fallback--text);
-      background-color: var(--chatMessageOutgoingBg, $fallback--lightBg);
-      border: 1px solid var(--chatMessageOutgoingBorder, --lightBg);
-    }
-
-    .chat-message-inner {
-      align-items: flex-end;
-    }
-
-    .chat-message-menu {
-      right: 0.4rem;
+      width: 100%;
     }
   }
 
   .visible {
     opacity: 1;
   }
-
 }
 
 .chat-message-date-separator {
diff --git a/src/components/chat_message/chat_message.vue b/src/components/chat_message/chat_message.vue
index d635c47e..381574c3 100644
--- a/src/components/chat_message/chat_message.vue
+++ b/src/components/chat_message/chat_message.vue
@@ -33,7 +33,7 @@
           <div
             class="media status"
             :class="{ 'without-attachment': !hasAttachment, 'pending': chatViewItem.data.pending, 'error': chatViewItem.data.error }"
-            style="position: relative"
+            style="position: relative;"
             @mouseenter="hovered = true"
             @mouseleave="hovered = false"
           >
@@ -98,6 +98,6 @@
 
 <script src="./chat_message.js"></script>
 <style lang="scss">
-@import './chat_message.scss';
+@import "./chat_message";
 
 </style>
diff --git a/src/components/chat_new/chat_new.scss b/src/components/chat_new/chat_new.scss
index 240e1a38..b145ecf9 100644
--- a/src/components/chat_new/chat_new.scss
+++ b/src/components/chat_new/chat_new.scss
@@ -1,7 +1,7 @@
 .chat-new {
   .input-wrap {
     display: flex;
-    margin: 0.7em 0.5em 0.7em 0.5em;
+    margin: 0.7em 0.5em;
 
     input {
       width: 100%;
diff --git a/src/components/chat_new/chat_new.vue b/src/components/chat_new/chat_new.vue
index bf09a379..52306c1d 100644
--- a/src/components/chat_new/chat_new.vue
+++ b/src/components/chat_new/chat_new.vue
@@ -46,6 +46,6 @@
 
 <script src="./chat_new.js"></script>
 <style lang="scss">
-@import '../../_variables.scss';
-@import './chat_new.scss';
+@import "../../variables";
+@import "./chat_new";
 </style>
diff --git a/src/components/chat_title/chat_title.vue b/src/components/chat_title/chat_title.vue
index ab7491fa..93db4fa7 100644
--- a/src/components/chat_title/chat_title.vue
+++ b/src/components/chat_title/chat_title.vue
@@ -26,7 +26,7 @@
 <script src="./chat_title.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .chat-title {
   display: flex;
diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue
index b6768d67..7139d4fc 100644
--- a/src/components/checkbox/checkbox.vue
+++ b/src/components/checkbox/checkbox.vue
@@ -32,7 +32,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .checkbox {
   position: relative;
@@ -49,13 +49,13 @@ export default {
     right: 0;
     top: 0;
     display: block;
-    content: '✓';
+    content: "✓";
     transition: color 200ms;
     width: 1.1em;
     height: 1.1em;
     border-radius: $fallback--checkboxRadius;
     border-radius: var(--checkboxRadius, $fallback--checkboxRadius);
-    box-shadow: 0px 0px 2px black inset;
+    box-shadow: 0 0 2px black inset;
     box-shadow: var(--inputShadow);
     background-color: $fallback--fg;
     background-color: var(--input, $fallback--fg);
@@ -71,15 +71,16 @@ export default {
   &.disabled {
     .checkbox-indicator::before,
     .label {
-      opacity: .5;
+      opacity: 0.5;
     }
+
     .label {
       color: $fallback--faint;
       color: var(--faint, $fallback--faint);
     }
   }
 
-  input[type=checkbox] {
+  input[type="checkbox"] {
     display: none;
 
     &:checked + .checkbox-indicator::before {
@@ -88,15 +89,14 @@ export default {
     }
 
     &:indeterminate + .checkbox-indicator::before {
-      content: '–';
+      content: "–";
       color: $fallback--text;
       color: var(--inputText, $fallback--text);
     }
-
   }
 
   & > span {
-    margin-left: .5em;
+    margin-left: 0.5em;
   }
 }
 </style>
diff --git a/src/components/color_input/color_input.scss b/src/components/color_input/color_input.scss
index 3de31fde..ca46199a 100644
--- a/src/components/color_input/color_input.scss
+++ b/src/components/color_input/color_input.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .color-input {
   display: inline-flex;
@@ -8,7 +8,7 @@
     flex: 0 0 0;
     max-width: 9em;
     align-items: stretch;
-    padding: .2em 8px;
+    padding: 0.2em 8px;
 
     input {
       background: none;
@@ -31,6 +31,7 @@
         min-height: 100%;
       }
     }
+
     .computedIndicator,
     .transparentIndicator {
       flex: 0 0 2em;
@@ -38,22 +39,27 @@
       align-self: stretch;
       min-height: 100%;
     }
+
     .transparentIndicator {
       // forgot to install counter-strike source, ooops
-      background-color: #FF00FF;
+      background-color: #f0f;
       position: relative;
-      &::before, &::after {
+
+      &::before,
+      &::after {
         display: block;
-        content: '';
-        background-color: #000000;
+        content: "";
+        background-color: #000;
         position: absolute;
         height: 50%;
         width: 50%;
       }
+
       &::after {
         top: 0;
         left: 0;
       }
+
       &::before {
         bottom: 0;
         right: 0;
@@ -64,5 +70,4 @@
   .label {
     flex: 1 1 auto;
   }
-
 }
diff --git a/src/components/contrast_ratio/contrast_ratio.vue b/src/components/contrast_ratio/contrast_ratio.vue
index 374cb9ba..bbd6fd4a 100644
--- a/src/components/contrast_ratio/contrast_ratio.vue
+++ b/src/components/contrast_ratio/contrast_ratio.vue
@@ -87,7 +87,6 @@ export default {
 .contrast-ratio {
   display: flex;
   justify-content: flex-end;
-
   margin-top: -4px;
   margin-bottom: 5px;
 
diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue
index afa04db0..7577129e 100644
--- a/src/components/conversation/conversation.vue
+++ b/src/components/conversation/conversation.vue
@@ -210,17 +210,16 @@
 <script src="./conversation.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Conversation {
   z-index: 1;
 
   .conversation-dive-to-top-level-box {
     padding: var(--status-margin, $status-margin);
-    border-bottom-width: 1px;
-    border-bottom-style: solid;
-    border-bottom-color: var(--border, $fallback--border);
+    border-bottom: 1px solid var(--border, $fallback--border);
     border-radius: 0;
+
     /* Make the button stretch along the whole row */
     display: flex;
     align-items: stretch;
@@ -235,52 +234,48 @@
   .thread-ancestor.-faded .StatusContent {
     --link: var(--faintLink);
     --text: var(--faint);
+
     color: var(--text);
   }
 
   .thread-ancestor-dive-box {
     padding-left: var(--status-margin, $status-margin);
-    border-bottom-width: 1px;
-    border-bottom-style: solid;
-    border-bottom-color: var(--border, $fallback--border);
+    border-bottom: 1px solid var(--border, $fallback--border);
     border-radius: 0;
+
     /* Make the button stretch along the whole row */
-    &, &-inner {
+    &,
+    &-inner {
       display: flex;
       align-items: stretch;
       flex-direction: column;
     }
   }
+
   .thread-ancestor-dive-box-inner {
     padding: var(--status-margin, $status-margin);
   }
 
   .conversation-status {
-    border-bottom-width: 1px;
-    border-bottom-style: solid;
-    border-bottom-color: var(--border, $fallback--border);
+    border-bottom: 1px solid var(--border, $fallback--border);
     border-radius: 0;
   }
 
   .thread-ancestor-has-other-replies .conversation-status,
+  &:last-child .conversation-status,
   .thread-ancestor:last-child .conversation-status,
   .thread-ancestor:last-child .thread-ancestor-dive-box,
-  &:last-child .conversation-status,
   &.-expanded .thread-tree .conversation-status {
     border-bottom: none;
   }
 
   .thread-ancestors + .thread-tree > .conversation-status {
-    border-top-width: 1px;
-    border-top-style: solid;
-    border-top-color: var(--border, $fallback--border);
+    border-top: 1px solid var(--border, $fallback--border);
   }
 
   /* expanded conversation in timeline */
   &.status-fadein.-expanded .thread-body {
-    border-left-width: 4px;
-    border-left-style: solid;
-    border-left-color: $fallback--cRed;
+    border-left: 4px solid $fallback--cRed;
     border-left-color: var(--cRed, $fallback--cRed);
     border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
     border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
diff --git a/src/components/desktop_nav/desktop_nav.scss b/src/components/desktop_nav/desktop_nav.scss
index 1ec25385..00f434bf 100644
--- a/src/components/desktop_nav/desktop_nav.scss
+++ b/src/components/desktop_nav/desktop_nav.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .DesktopNav {
   width: 100%;
@@ -14,9 +14,11 @@
 
   .inner-nav {
     display: grid;
+    /* stylelint-disable declaration-block-no-redundant-longhand-properties */
     grid-template-rows: var(--navbar-height);
     grid-template-columns: 2fr auto 2fr;
     grid-template-areas: "sitename logo actions";
+    /* stylelint-enable declaration-block-no-redundant-longhand-properties */
     box-sizing: border-box;
     padding: 0 1.2em;
     margin: auto;
@@ -27,20 +29,13 @@
     --miniColumn: 25rem;
     --maxiColumn: 45rem;
     --columnGap: 1em;
-    max-width: calc(
-      var(--sidebarColumnWidth, var(--miniColumn)) +
-      var(--contentColumnWidth, var(--maxiColumn)) +
-      var(--columnGap)
-    );
-  }
 
-  &.-column-stretch.-wide .inner-nav {
-    max-width: calc(
-      var(--sidebarColumnWidth, var(--miniColumn)) +
-      var(--contentColumnWidth, var(--maxiColumn)) +
-      var(--notifsColumnWidth, var(--miniColumn)) +
-      var(--columnGap)
-    );
+    max-width:
+      calc(
+        var(--sidebarColumnWidth, var(--miniColumn)) +
+        var(--contentColumnWidth, var(--maxiColumn)) +
+        var(--columnGap)
+      );
   }
 
   &.-logoLeft .inner-nav {
@@ -48,8 +43,19 @@
     grid-template-areas: "logo sitename actions";
   }
 
+  &.-column-stretch.-wide .inner-nav {
+    max-width:
+      calc(
+        var(--sidebarColumnWidth, var(--miniColumn)) +
+        var(--contentColumnWidth, var(--maxiColumn)) +
+        var(--notifsColumnWidth, var(--miniColumn)) +
+        var(--columnGap)
+      );
+  }
+
   .button-default {
-    &, svg {
+    &,
+    svg {
       color: $fallback--text;
       color: var(--btnTopBarText, $fallback--text);
     }
@@ -70,7 +76,7 @@
       color: $fallback--text;
       color: var(--btnToggledTopBarText, $fallback--text);
       background-color: $fallback--fg;
-      background-color: var(--btnToggledTopBar, $fallback--fg)
+      background-color: var(--btnToggledTopBar, $fallback--fg);
     }
   }
 
@@ -82,6 +88,7 @@
     transition-duration: 100ms;
 
     @media all and (min-width: 800px) {
+      /* stylelint-disable-next-line declaration-no-important */
       opacity: 1 !important;
     }
 
diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue
index 06b270c3..24d65142 100644
--- a/src/components/dialog_modal/dialog_modal.vue
+++ b/src/components/dialog_modal/dialog_modal.vue
@@ -25,7 +25,7 @@
 <script src="./dialog_modal.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 // TODO: unify with other modals.
 .dark-overlay {
@@ -38,7 +38,7 @@
     position: fixed;
     right: 0;
     top: 0;
-    background: rgba(27,31,35,.5);
+    background: rgb(27 31 35 / 50%);
     z-index: 99;
   }
 }
@@ -65,7 +65,7 @@
 
   .dialog-modal-content {
     margin: 0;
-    padding: 1rem 1rem;
+    padding: 1rem;
     background-color: $fallback--bg;
     background-color: var(--bg, $fallback--bg);
     white-space: normal;
@@ -73,7 +73,7 @@
 
   .dialog-modal-footer {
     margin: 0;
-    padding: .5em .5em;
+    padding: 0.5em;
     background-color: $fallback--bg;
     background-color: var(--bg, $fallback--bg);
     border-top: 1px solid $fallback--border;
@@ -83,7 +83,7 @@
 
     button {
       width: auto;
-      margin-left: .5rem;
+      margin-left: 0.5rem;
     }
   }
 }
diff --git a/src/components/edit_status_modal/edit_status_modal.vue b/src/components/edit_status_modal/edit_status_modal.vue
index 1dbacaab..db62972d 100644
--- a/src/components/edit_status_modal/edit_status_modal.vue
+++ b/src/components/edit_status_modal/edit_status_modal.vue
@@ -26,6 +26,7 @@
 .modal-view.edit-form-modal-view {
   align-items: flex-start;
 }
+
 .edit-form-modal-panel {
   flex-shrink: 0;
   margin-top: 25%;
diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index c9bbc18f..ccba0393 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -91,22 +91,18 @@
 <script src="./emoji_input.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .emoji-input {
   display: flex;
   flex-direction: column;
   position: relative;
 
-  &.with-picker input {
-    padding-right: 30px;
-  }
-
   .emoji-picker-icon {
     position: absolute;
     top: 0;
     right: 0;
-    margin: .2em .25em;
+    margin: 0.2em 0.25em;
     font-size: 1.3em;
     cursor: pointer;
     line-height: 24px;
@@ -123,14 +119,19 @@
     margin-top: 2px;
 
     &.hide {
-      display: none
+      display: none;
     }
   }
 
-  input, textarea {
+  input,
+  textarea {
     flex: 1 0 auto;
   }
 
+  &.with-picker input {
+    padding-right: 30px;
+  }
+
   .hidden-overlay {
     opacity: 0;
     pointer-events: none;
@@ -140,8 +141,10 @@
     right: 0;
     left: 0;
     overflow: hidden;
+
     /* DEBUG STUFF */
     color: red;
+
     /* set opacity to non-zero to see the overlay */
 
     .caret {
@@ -151,6 +154,7 @@
     }
   }
 }
+
 .autocomplete {
   &-panel {
     position: absolute;
@@ -160,7 +164,7 @@
     display: flex;
     cursor: pointer;
     padding: 0.2em 0.4em;
-    border-bottom: 1px solid rgba(0, 0, 0, 0.4);
+    border-bottom: 1px solid rgb(0 0 0 / 40%);
     height: 32px;
 
     .image {
@@ -169,7 +173,6 @@
       line-height: 32px;
       text-align: center;
       font-size: 32px;
-
       margin-right: 4px;
 
       img {
@@ -199,6 +202,7 @@
       background-color: $fallback--fg;
       background-color: var(--selectedMenuPopover, $fallback--fg);
       color: var(--selectedMenuPopoverText, $fallback--text);
+
       --faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
       --faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
       --lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
diff --git a/src/components/emoji_picker/emoji_picker.scss b/src/components/emoji_picker/emoji_picker.scss
index dda12197..0ec261a4 100644
--- a/src/components/emoji_picker/emoji_picker.scss
+++ b/src/components/emoji_picker/emoji_picker.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 $emoji-picker-header-height: 36px;
 $emoji-picker-header-picture-width: 32px;
@@ -14,7 +14,7 @@ $emoji-picker-emoji-size: 32px;
   background-color: var(--popover, $fallback--bg);
   color: $fallback--link;
   color: var(--popoverText, $fallback--link);
-  --lightText: var(--popoverLightText, $fallback--faint);
+
   --faint: var(--popoverFaintText, $fallback--faint);
   --faintLink: var(--popoverFaintLink, $fallback--faint);
   --lightText: var(--popoverLightText, $fallback--lightText);
@@ -28,6 +28,7 @@ $emoji-picker-emoji-size: 32px;
     max-width: $emoji-picker-header-picture-width;
     height: $emoji-picker-header-picture-height;
     max-height: $emoji-picker-header-picture-height;
+
     .still-image {
       max-width: 100%;
       max-height: 100%;
@@ -62,25 +63,18 @@ $emoji-picker-emoji-size: 32px;
     display: flex;
     flex-direction: column;
     flex: 1 1 auto;
-    min-height: 0px;
+    min-height: 0;
   }
 
   .emoji-tabs {
     flex-grow: 1;
     display: flex;
-    flex-direction: row;
-    flex-wrap: nowrap;
+    flex-flow: row nowrap;
     overflow-x: auto;
   }
 
-  .emoji-groups {
-    height: 100%;
-    min-height: 200px;
-  }
-
   .additional-tabs {
     display: flex;
-    flex: 1;
     border-left: 1px solid;
     border-left-color: $fallback--icon;
     border-left-color: var(--icon, $fallback--icon);
@@ -122,7 +116,7 @@ $emoji-picker-emoji-size: 32px;
   }
 
   .sticker-picker {
-    flex: 1 1 auto
+    flex: 1 1 auto;
   }
 
   .stickers,
@@ -152,22 +146,27 @@ $emoji-picker-emoji-size: 32px;
     }
 
     &-groups {
+      height: 100%;
+      min-height: 200px;
       flex: 1 1 1px;
       position: relative;
       overflow: auto;
       user-select: none;
-      mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
-            linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
-            linear-gradient(to top, white, white);
+      mask:
+        linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
+        linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
+        linear-gradient(to top, white, white);
       transition: mask-size 150ms;
       mask-size: 100% 20px, 100% 20px, auto;
       // Autoprefixed seem to ignore this one, and also syntax is different
-      -webkit-mask-composite: xor;
+      mask-composite: xor;
       mask-composite: exclude;
+
       &.scrolled {
         &-top {
           mask-size: 100% 20px, 100% 0, auto;
         }
+
         &-bottom {
           mask-size: 100% 0, 100% 20px, auto;
         }
@@ -201,7 +200,6 @@ $emoji-picker-emoji-size: 32px;
       align-items: center;
       justify-content: center;
       margin: 4px;
-
       cursor: pointer;
 
       .emoji-picker-emoji.-custom {
@@ -209,12 +207,11 @@ $emoji-picker-emoji-size: 32px;
         max-width: 100%;
         max-height: 100%;
       }
+
       .emoji-picker-emoji.-unicode {
         font-size: 24px;
         overflow: hidden;
       }
     }
-
   }
-
 }
diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue
index 4eb22a65..a63daa97 100644
--- a/src/components/emoji_reactions/emoji_reactions.vue
+++ b/src/components/emoji_reactions/emoji_reactions.vue
@@ -28,7 +28,7 @@
 
 <script src="./emoji_reactions.js"></script>
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .EmojiReactions {
   display: flex;
@@ -55,6 +55,7 @@
 
     &.not-clickable {
       cursor: default;
+
       &:hover {
         box-shadow: $fallback--buttonShadow;
         box-shadow: var(--buttonShadow);
@@ -75,10 +76,10 @@
     display: flex;
     align-items: center;
     justify-content: center;
+
     &:hover {
       text-decoration: underline;
     }
   }
-
 }
 </style>
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index b2fad1c9..a84d47f6 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -172,15 +172,10 @@
 <script src="./extra_buttons.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-@import '../../_mixins.scss';
+@import "../../variables";
+@import "../../mixins";
 
 .ExtraButtons {
-  /* override of popover internal stuff */
-  .popover-trigger-button {
-    width: auto;
-  }
-
   .popover-trigger {
     position: static;
     padding: 10px;
@@ -190,10 +185,12 @@
       color: $fallback--text;
       color: var(--text, $fallback--text);
     }
-
   }
 
   .popover-trigger-button {
+    /* override of popover internal stuff */
+    width: auto;
+
     @include unfocused-style {
       .focus-marker {
         visibility: hidden;
diff --git a/src/components/favorite_button/favorite_button.vue b/src/components/favorite_button/favorite_button.vue
index ea01720a..58d14945 100644
--- a/src/components/favorite_button/favorite_button.vue
+++ b/src/components/favorite_button/favorite_button.vue
@@ -58,8 +58,8 @@
 <script src="./favorite_button.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-@import '../../_mixins.scss';
+@import "../../variables";
+@import "../../mixins";
 
 .FavoriteButton {
   display: flex;
diff --git a/src/components/flash/flash.vue b/src/components/flash/flash.vue
index 95f71950..9f58d314 100644
--- a/src/components/flash/flash.vue
+++ b/src/components/flash/flash.vue
@@ -42,7 +42,8 @@
 <script src="./flash.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
+
 .Flash {
   display: inline-block;
   width: 100%;
@@ -78,7 +79,7 @@
 
   .hidden {
     display: none;
-    visibility: 'hidden';
+    visibility: "hidden";
   }
 }
 </style>
diff --git a/src/components/follow_card/follow_card.vue b/src/components/follow_card/follow_card.vue
index c919b11a..eff69fb2 100644
--- a/src/components/follow_card/follow_card.vue
+++ b/src/components/follow_card/follow_card.vue
@@ -39,9 +39,8 @@
   &-content-container {
     flex-shrink: 0;
     display: flex;
-    flex-direction: row;
+    flex-flow: row wrap;
     justify-content: space-between;
-    flex-wrap: wrap;
     line-height: 1.5em;
   }
 
diff --git a/src/components/follow_request_card/follow_request_card.vue b/src/components/follow_request_card/follow_request_card.vue
index 1b12ba4b..eb222cc7 100644
--- a/src/components/follow_request_card/follow_request_card.vue
+++ b/src/components/follow_request_card/follow_request_card.vue
@@ -22,8 +22,8 @@
 <style lang="scss">
 .follow-request-card-content-container {
   display: flex;
-  flex-direction: row;
-  flex-wrap: wrap;
+  flex-flow: row wrap;
+
   button {
     margin-top: 0.5em;
     margin-right: 0.5em;
diff --git a/src/components/font_control/font_control.vue b/src/components/font_control/font_control.vue
index 83c1cef7..bb7e64bc 100644
--- a/src/components/font_control/font_control.vue
+++ b/src/components/font_control/font_control.vue
@@ -50,17 +50,20 @@
 <script src="./font_control.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
+
 .font-control {
   input.custom-font {
     min-width: 10em;
   }
+
   &.custom {
     /* TODO Should make proper joiners... */
     .font-switcher {
       border-top-right-radius: 0;
       border-bottom-right-radius: 0;
     }
+
     .custom-font {
       border-top-left-radius: 0;
       border-bottom-left-radius: 0;
diff --git a/src/components/gallery/gallery.vue b/src/components/gallery/gallery.vue
index ccf6e3e2..744b8198 100644
--- a/src/components/gallery/gallery.vue
+++ b/src/components/gallery/gallery.vue
@@ -86,7 +86,7 @@
 <script src='./gallery.js'></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Gallery {
   .gallery-rows {
@@ -100,6 +100,53 @@
     width: 100%;
     flex-grow: 1;
 
+    .gallery-row-inner {
+      position: absolute;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      display: flex;
+      flex-flow: row wrap;
+      align-content: stretch;
+
+      .gallery-item {
+        margin: 0 0.5em 0 0;
+        flex-grow: 1;
+        height: 100%;
+        box-sizing: border-box;
+        // to make failed images a bit more noticeable on chromium
+        min-width: 2em;
+
+        &:last-child {
+          margin: 0;
+        }
+      }
+
+      &.-grid {
+        width: 100%;
+        height: auto;
+        position: relative;
+        display: grid;
+        grid-gap: 0.5em;
+        grid-template-columns: repeat(auto-fill, minmax(15em, 1fr));
+
+        .gallery-item {
+          margin: 0;
+          height: 200px;
+        }
+      }
+    }
+
+    &.-grid,
+    &.-minimal {
+      height: auto;
+
+      .gallery-row-inner {
+        position: relative;
+      }
+    }
+
     &:not(:first-child) {
       margin-top: 0.5em;
     }
@@ -114,7 +161,7 @@
         linear-gradient(to top, white, white);
 
       /* Autoprefixed seem to ignore this one, and also syntax is different */
-      -webkit-mask-composite: xor;
+      mask-composite: xor;
       mask-composite: exclude;
     }
   }
@@ -138,54 +185,5 @@
       padding: 0 2em;
     }
   }
-
-  .gallery-row {
-    &.-grid,
-    &.-minimal {
-      height: auto;
-      .gallery-row-inner {
-        position: relative;
-      }
-    }
-  }
-
-  .gallery-row-inner {
-    position: absolute;
-    top: 0;
-    left: 0;
-    right: 0;
-    bottom: 0;
-    display: flex;
-    flex-direction: row;
-    flex-wrap: nowrap;
-    align-content: stretch;
-
-    &.-grid {
-      width: 100%;
-      height: auto;
-      position: relative;
-      display: grid;
-      grid-column-gap: 0.5em;
-      grid-row-gap: 0.5em;
-      grid-template-columns: repeat(auto-fill, minmax(15em, 1fr));
-
-      .gallery-item {
-        margin: 0;
-        height: 200px;
-      }
-    }
-  }
-
-  .gallery-item {
-    margin: 0 0.5em 0 0;
-    flex-grow: 1;
-    height: 100%;
-    box-sizing: border-box;
-    // to make failed images a bit more noticeable on chromium
-    min-width: 2em;
-    &:last-child {
-      margin: 0;
-    }
-  }
 }
 </style>
diff --git a/src/components/global_notice_list/global_notice_list.vue b/src/components/global_notice_list/global_notice_list.vue
index d828b819..0e58476f 100644
--- a/src/components/global_notice_list/global_notice_list.vue
+++ b/src/components/global_notice_list/global_notice_list.vue
@@ -25,7 +25,7 @@
 <script src="./global_notice_list.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .global-notice-list {
   position: fixed;
@@ -73,6 +73,7 @@
   .global-success {
     background-color: var(--alertPopupSuccess, $fallback--cGreen);
     color: var(--alertPopupSuccessText, $fallback--text);
+
     .svg-inline--fa {
       color: var(--alertPopupSuccessText, $fallback--text);
     }
@@ -81,6 +82,7 @@
   .global-info {
     background-color: var(--alertPopupNeutral, $fallback--fg);
     color: var(--alertPopupNeutralText, $fallback--text);
+
     .svg-inline--fa {
       color: var(--alertPopupNeutralText, $fallback--text);
     }
@@ -88,6 +90,7 @@
 
   .close-notice {
     padding-right: 0.2em;
+
     .svg-inline--fa:hover {
       opacity: 0.6;
     }
diff --git a/src/components/link-preview/link-preview.vue b/src/components/link-preview/link-preview.vue
index 220527f2..09f341ac 100644
--- a/src/components/link-preview/link-preview.vue
+++ b/src/components/link-preview/link-preview.vue
@@ -33,7 +33,7 @@
 <script src="./link-preview.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .link-preview-card {
   display: flex;
@@ -46,6 +46,7 @@
     flex-shrink: 0;
     width: 120px;
     max-width: 25%;
+
     img {
       width: 100%;
       height: 100%;
@@ -67,7 +68,7 @@
   }
 
   .card-description {
-    margin: 0.5em 0 0 0;
+    margin: 0.5em 0 0;
     overflow: hidden;
     text-overflow: ellipsis;
     word-break: break-word;
diff --git a/src/components/list/list.vue b/src/components/list/list.vue
index a6223cce..f17766b4 100644
--- a/src/components/list/list.vue
+++ b/src/components/list/list.vue
@@ -35,7 +35,7 @@ export default {
 </script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .list {
   &-item:not(:last-child) {
diff --git a/src/components/lists_card/lists_card.vue b/src/components/lists_card/lists_card.vue
index 13866d8c..925da3a5 100644
--- a/src/components/lists_card/lists_card.vue
+++ b/src/components/lists_card/lists_card.vue
@@ -21,12 +21,16 @@
 <script src="./lists_card.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .list-card {
   display: flex;
 }
 
+.list-name {
+  flex-grow: 1;
+}
+
 .list-name,
 .button-list-edit {
   margin: 0;
@@ -39,13 +43,10 @@
     background-color: var(--selectedMenu, $fallback--lightBg);
     color: $fallback--link;
     color: var(--selectedMenuText, $fallback--link);
+
     --faint: var(--selectedMenuFaintText, $fallback--faint);
     --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
     --lightText: var(--selectedMenuLightText, $fallback--lightText);
   }
 }
-
-.list-name {
-  flex-grow: 1;
-}
 </style>
diff --git a/src/components/lists_edit/lists_edit.vue b/src/components/lists_edit/lists_edit.vue
index 6521aba6..eec0f978 100644
--- a/src/components/lists_edit/lists_edit.vue
+++ b/src/components/lists_edit/lists_edit.vue
@@ -164,7 +164,7 @@
 <script src="./lists_edit.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .ListEdit {
   --panel-body-padding: 0.5em;
diff --git a/src/components/lists_user_search/lists_user_search.vue b/src/components/lists_user_search/lists_user_search.vue
index 8633170c..6ca107e6 100644
--- a/src/components/lists_user_search/lists_user_search.vue
+++ b/src/components/lists_user_search/lists_user_search.vue
@@ -27,12 +27,12 @@
 
 <script src="./lists_user_search.js"></script>
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .ListsUserSearch {
   .input-wrap {
     display: flex;
-    margin: 0.7em 0.5em 0.7em 0.5em;
+    margin: 0.7em 0.5em;
 
     input {
       width: 100%;
diff --git a/src/components/login_form/login_form.vue b/src/components/login_form/login_form.vue
index 7a430c51..829e88ad 100644
--- a/src/components/login_form/login_form.vue
+++ b/src/components/login_form/login_form.vue
@@ -93,7 +93,7 @@
 <script src="./login_form.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .login-form {
   display: flex;
@@ -110,7 +110,7 @@
   }
 
   .login-bottom {
-    margin-top: 1.0em;
+    margin-top: 1em;
     display: flex;
     flex-direction: row;
     align-items: center;
@@ -121,7 +121,7 @@
     display: flex;
     flex-direction: column;
     padding: 0.3em 0.5em 0.6em;
-    line-height:24px;
+    line-height: 24px;
   }
 
   .form-bottom {
@@ -142,7 +142,6 @@
 
   .error {
     text-align: center;
-
     animation-name: shakeError;
     animation-duration: 0.4s;
     animation-timing-function: ease-in-out;
diff --git a/src/components/media_modal/media_modal.vue b/src/components/media_modal/media_modal.vue
index d59055b3..6464b99f 100644
--- a/src/components/media_modal/media_modal.vue
+++ b/src/components/media_modal/media_modal.vue
@@ -120,32 +120,12 @@ $modal-view-button-icon-half-height: calc(#{$modal-view-button-icon-height} / 2)
 $modal-view-button-icon-width: 3em;
 $modal-view-button-icon-margin: 0.5em;
 
-.modal-view.media-modal-view {
-  z-index: var(--ZI_media_modal);
-  flex-direction: column;
-
-  .modal-view-button-arrow,
-  .modal-view-button-hide {
-    opacity: 0.75;
-
-    &:focus,
-    &:hover {
-      outline: none;
-      box-shadow: none;
-    }
-
-    &:hover {
-      opacity: 1;
-    }
-  }
-  overflow: hidden;
-}
-
 .media-modal-view {
   @keyframes media-fadein {
     from {
       opacity: 0;
     }
+
     to {
       opacity: 1;
     }
@@ -226,7 +206,7 @@ $modal-view-button-icon-margin: 0.5em;
     appearance: none;
     overflow: visible;
     cursor: pointer;
-    transition: opacity 333ms cubic-bezier(.4,0,.22,1);
+    transition: opacity 333ms cubic-bezier(0.4, 0, 0.22, 1);
     height: $modal-view-button-icon-height;
     width: $modal-view-button-icon-width;
 
@@ -236,9 +216,9 @@ $modal-view-button-icon-margin: 0.5em;
       width: $modal-view-button-icon-width;
       font-size: 1rem;
       line-height: $modal-view-button-icon-height;
-      color: #FFF;
+      color: #fff;
       text-align: center;
-      background-color: rgba(0,0,0,.3);
+      background-color: rgb(0 0 0 / 30%);
     }
   }
 
@@ -254,13 +234,14 @@ $modal-view-button-icon-margin: 0.5em;
       position: absolute;
       top: 0;
       line-height: $modal-view-button-icon-height;
-      color: #FFF;
+      color: #fff;
       text-align: center;
-      background-color: rgba(0,0,0,.3);
+      background-color: rgb(0 0 0 / 30%);
     }
 
     &--prev {
       left: 0;
+
       .arrow-icon {
         left: $modal-view-button-icon-margin;
       }
@@ -268,6 +249,7 @@ $modal-view-button-icon-margin: 0.5em;
 
     &--next {
       right: 0;
+
       .arrow-icon {
         right: $modal-view-button-icon-margin;
       }
@@ -278,10 +260,33 @@ $modal-view-button-icon-margin: 0.5em;
     position: absolute;
     top: 0;
     right: 0;
+
     .button-icon {
       top: $modal-view-button-icon-margin;
       right: $modal-view-button-icon-margin;
     }
   }
 }
+
+.modal-view.media-modal-view {
+  z-index: var(--ZI_media_modal);
+  flex-direction: column;
+
+  .modal-view-button-arrow,
+  .modal-view-button-hide {
+    opacity: 0.75;
+
+    &:focus,
+    &:hover {
+      outline: none;
+      box-shadow: none;
+    }
+
+    &:hover {
+      opacity: 1;
+    }
+  }
+
+  overflow: hidden;
+}
 </style>
diff --git a/src/components/media_upload/media_upload.vue b/src/components/media_upload/media_upload.vue
index a538a5ed..2799495b 100644
--- a/src/components/media_upload/media_upload.vue
+++ b/src/components/media_upload/media_upload.vue
@@ -29,7 +29,7 @@
 <script src="./media_upload.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .media-upload {
   cursor: pointer; // We use <label> for interactivity... i wonder if it's fine
diff --git a/src/components/mention_link/mention_link.scss b/src/components/mention_link/mention_link.scss
index 8b2af926..69e9fed1 100644
--- a/src/components/mention_link/mention_link.scss
+++ b/src/components/mention_link/mention_link.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .MentionLink {
   position: relative;
@@ -59,6 +59,7 @@
         font-weight: 600;
       }
     }
+
     &.-has-selection {
       color: var(--alertNeutralText, $fallback--text);
       background-color: var(--alertNeutral, $fallback--fg);
@@ -100,10 +101,6 @@
     }
   }
 
-  .full {
-    pointer-events: none;
-  }
-
   .serverName.-faded {
     color: var(--faintLink, $fallback--link);
   }
diff --git a/src/components/mentions_line/mentions_line.scss b/src/components/mentions_line/mentions_line.scss
index 9a622e75..b7dfbfb8 100644
--- a/src/components/mentions_line/mentions_line.scss
+++ b/src/components/mentions_line/mentions_line.scss
@@ -2,7 +2,7 @@
   word-break: break-all;
 
   .mention-link:not(:first-child)::before {
-    content: ' ';
+    content: " ";
   }
 
   .showMoreLess {
diff --git a/src/components/mobile_nav/mobile_nav.vue b/src/components/mobile_nav/mobile_nav.vue
index 0f1fe621..d6fe102c 100644
--- a/src/components/mobile_nav/mobile_nav.vue
+++ b/src/components/mobile_nav/mobile_nav.vue
@@ -94,7 +94,7 @@
 <script src="./mobile_nav.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .MobileNav {
   z-index: var(--ZI_navbar);
@@ -127,7 +127,7 @@
   }
 
   .site-name {
-    padding: 0 .3em;
+    padding: 0 0.3em;
     display: inline-block;
   }
 
@@ -156,7 +156,7 @@
     position: fixed;
     top: 0;
     left: 0;
-    box-shadow: 1px 1px 4px rgba(0,0,0,.6);
+    box-shadow: 1px 1px 4px rgb(0 0 0 / 60%);
     box-shadow: var(--panelShadow);
     transition-property: transform;
     transition-duration: 0.25s;
@@ -182,7 +182,7 @@
     color: var(--topBarText);
     background-color: $fallback--fg;
     background-color: var(--topBar, $fallback--fg);
-    box-shadow: 0px 0px 4px rgba(0,0,0,.6);
+    box-shadow: 0 0 4px rgb(0 0 0 / 60%);
     box-shadow: var(--topBarShadow);
 
     .spacer {
diff --git a/src/components/mobile_post_status_button/mobile_post_status_button.vue b/src/components/mobile_post_status_button/mobile_post_status_button.vue
index 28a2c440..ef0f51fe 100644
--- a/src/components/mobile_post_status_button/mobile_post_status_button.vue
+++ b/src/components/mobile_post_status_button/mobile_post_status_button.vue
@@ -13,7 +13,7 @@
 <script src="./mobile_post_status_button.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .MobilePostButton {
   &.button-default {
@@ -30,9 +30,8 @@
     display: flex;
     justify-content: center;
     align-items: center;
-    box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3), 0px 4px 6px rgba(0, 0, 0, 0.3);
+    box-shadow: 0 2px 2px rgb(0 0 0 / 30%), 0 4px 6px rgb(0 0 0 / 30%);
     z-index: 10;
-
     transition: 0.35s transform;
     transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
   }
diff --git a/src/components/modal/modal.vue b/src/components/modal/modal.vue
index 2187f392..9f767ede 100644
--- a/src/components/modal/modal.vue
+++ b/src/components/modal/modal.vue
@@ -59,7 +59,7 @@ export default {
 
   &.modal-background {
     pointer-events: initial;
-    background-color: rgba(0, 0, 0, 0.5);
+    background-color: rgb(0 0 0 / 50%);
   }
 
   &.open {
@@ -69,10 +69,11 @@ export default {
 
 @keyframes modal-background-fadein {
   from {
-    background-color: rgba(0, 0, 0, 0);
+    background-color: rgb(0 0 0 / 0%);
   }
+
   to {
-    background-color: rgba(0, 0, 0, 0.5);
+    background-color: rgb(0 0 0 / 50%);
   }
 }
 </style>
diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue
index 8535ef27..b708cdc8 100644
--- a/src/components/moderation_tools/moderation_tools.vue
+++ b/src/components/moderation_tools/moderation_tools.vue
@@ -166,18 +166,21 @@
 <script src="./moderation_tools.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .moderation-tools-popover {
   height: 100%;
+
   .trigger {
+    /* stylelint-disable-next-line declaration-no-important */
     display: flex !important;
     height: 100%;
   }
 }
 
 .moderation-tools-button {
-  svg,i {
+  svg,
+  i {
     font-size: 0.8em;
   }
 }
diff --git a/src/components/mrf_transparency_panel/mrf_transparency_panel.scss b/src/components/mrf_transparency_panel/mrf_transparency_panel.scss
index 80ea01d4..a262ed1c 100644
--- a/src/components/mrf_transparency_panel/mrf_transparency_panel.scss
+++ b/src/components/mrf_transparency_panel/mrf_transparency_panel.scss
@@ -2,19 +2,21 @@
   margin: 1em;
 
   table {
-    width:100%;
+    width: 100%;
     text-align: left;
-    padding-left:10px;
-    padding-bottom:20px;
+    padding-left: 10px;
+    padding-bottom: 20px;
 
-    th, td {
+    th,
+    td {
       width: 180px;
       max-width: 360px;
-      overflow:  hidden;
+      overflow: hidden;
       vertical-align: text-top;
     }
 
-    th+th, td+td {
+    th + th,
+    td + td {
       width: auto;
     }
   }
diff --git a/src/components/mrf_transparency_panel/mrf_transparency_panel.vue b/src/components/mrf_transparency_panel/mrf_transparency_panel.vue
index 1787fa07..97af4787 100644
--- a/src/components/mrf_transparency_panel/mrf_transparency_panel.vue
+++ b/src/components/mrf_transparency_panel/mrf_transparency_panel.vue
@@ -227,6 +227,6 @@
 <script src="./mrf_transparency_panel.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-@import './mrf_transparency_panel.scss';
+@import "../../variables";
+@import "./mrf_transparency_panel";
 </style>
diff --git a/src/components/mute_card/mute_card.vue b/src/components/mute_card/mute_card.vue
index ca33c6c5..97e91cbc 100644
--- a/src/components/mute_card/mute_card.vue
+++ b/src/components/mute_card/mute_card.vue
@@ -37,6 +37,7 @@
 .mute-card-content-container {
   margin-top: 0.5em;
   text-align: right;
+
   button {
     width: 10em;
   }
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index d628c380..1a826cc4 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -102,7 +102,7 @@
 <script src="./nav_panel.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .NavPanel {
   .panel {
@@ -169,8 +169,9 @@
   }
 
   .nav-panel-heading {
-   // breaks without a unit
-   --panel-heading-height-padding: 0em;
+    // breaks without a unit
+    // stylelint-disable-next-line length-zero-no-unit
+    --panel-heading-height-padding: 0px;
   }
 }
 </style>
diff --git a/src/components/navigation/navigation_entry.vue b/src/components/navigation/navigation_entry.vue
index f4d53836..411ca536 100644
--- a/src/components/navigation/navigation_entry.vue
+++ b/src/components/navigation/navigation_entry.vue
@@ -63,7 +63,7 @@
 <script src="./navigation_entry.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .NavigationEntry {
   display: flex;
@@ -102,6 +102,7 @@
     background-color: var(--selectedMenu, $fallback--lightBg);
     color: $fallback--link;
     color: var(--selectedMenuText, $fallback--link);
+
     --faint: var(--selectedMenuFaintText, $fallback--faint);
     --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
     --lightText: var(--selectedMenuLightText, $fallback--lightText);
@@ -117,6 +118,7 @@
     background-color: var(--selectedMenu, $fallback--lightBg);
     color: $fallback--text;
     color: var(--selectedMenuText, $fallback--text);
+
     --faint: var(--selectedMenuFaintText, $fallback--faint);
     --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
     --lightText: var(--selectedMenuLightText, $fallback--lightText);
diff --git a/src/components/navigation/navigation_pins.vue b/src/components/navigation/navigation_pins.vue
index 6a9ed6f5..4fbb4f95 100644
--- a/src/components/navigation/navigation_pins.vue
+++ b/src/components/navigation/navigation_pins.vue
@@ -27,7 +27,8 @@
 <script src="./navigation_pins.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
+
 .NavigationPins {
   display: flex;
   flex-wrap: wrap;
diff --git a/src/components/notification/notification.scss b/src/components/notification/notification.scss
index 38978137..654aca3c 100644
--- a/src/components/notification/notification.scss
+++ b/src/components/notification/notification.scss
@@ -1,13 +1,14 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 // TODO Copypaste from Status, should unify it somehow
 .Notification {
-   border-bottom: 1px solid;
-   border-color: $fallback--border;
-   border-color: var(--border, $fallback--border);
-   word-wrap: break-word;
-   word-break: break-word;
-   --emoji-size: 14px;
+  border-bottom: 1px solid;
+  border-color: $fallback--border;
+  border-color: var(--border, $fallback--border);
+  word-wrap: break-word;
+  word-break: break-word;
+
+  --emoji-size: 14px;
 
   &:hover {
     --_still-image-img-visibility: visible;
@@ -54,7 +55,7 @@
       margin-left: 0.2em;
 
       &::before {
-        content: ' ';
+        content: " ";
       }
     }
 
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index 9b241565..41cfcef0 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Notifications {
   &:not(.minimal) {
@@ -25,12 +25,13 @@
 
     &.unseen {
       .notification-overlay {
-        background-image: linear-gradient(135deg, var(--badgeNotification, $fallback--cRed) 4px, transparent 10px)
+        background-image: linear-gradient(135deg, var(--badgeNotification, $fallback--cRed) 4px, transparent 10px);
       }
     }
   }
 }
 
+/* stylelint-disable-next-line no-descending-specificity */
 .notification {
   box-sizing: border-box;
 
@@ -38,6 +39,7 @@
     canvas {
       display: none;
     }
+
     img {
       visibility: visible;
     }
@@ -79,7 +81,8 @@
     }
   }
 
-  .follow-text, .move-text {
+  .follow-text,
+  .move-text {
     padding: 0.5em 0;
     overflow-wrap: break-word;
     display: flex;
diff --git a/src/components/panel_loading/panel_loading.vue b/src/components/panel_loading/panel_loading.vue
index d916d8a6..17458e49 100644
--- a/src/components/panel_loading/panel_loading.vue
+++ b/src/components/panel_loading/panel_loading.vue
@@ -23,7 +23,7 @@ export default {}
 </script>
 
 <style lang="scss">
-@import 'src/_variables.scss';
+@import "src/variables";
 
 .panel-loading {
   display: flex;
@@ -33,6 +33,7 @@ export default {}
   font-size: 2em;
   color: $fallback--text;
   color: var(--text, $fallback--text);
+
   .loading-text svg {
     line-height: 0;
     vertical-align: middle;
diff --git a/src/components/password_reset/password_reset.vue b/src/components/password_reset/password_reset.vue
index 90673f44..d6e10250 100644
--- a/src/components/password_reset/password_reset.vue
+++ b/src/components/password_reset/password_reset.vue
@@ -77,7 +77,7 @@
 
 <script src="./password_reset.js"></script>
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .password-reset-form {
   display: flex;
diff --git a/src/components/poll/poll.vue b/src/components/poll/poll.vue
index f6b12a54..cacc3298 100644
--- a/src/components/poll/poll.vue
+++ b/src/components/poll/poll.vue
@@ -90,7 +90,7 @@
 <script src="./poll.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .poll {
   .votes {
@@ -98,9 +98,11 @@
     flex-direction: column;
     margin: 0 0 0.5em;
   }
+
   .poll-option {
     margin: 0.75em 0.5em;
   }
+
   .option-result {
     height: 100%;
     display: flex;
@@ -109,6 +111,7 @@
     color: $fallback--lightText;
     color: var(--lightText, $fallback--lightText);
   }
+
   .option-result-label {
     display: flex;
     align-items: center;
@@ -116,10 +119,12 @@
     z-index: 1;
     word-break: break-word;
   }
+
   .result-percentage {
     width: 3.5em;
     flex-shrink: 0;
   }
+
   .result-fill {
     height: 100%;
     position: absolute;
@@ -133,20 +138,25 @@
     left: 0;
     transition: width 0.5s;
   }
+
   .option-vote {
     display: flex;
     align-items: center;
   }
+
   input {
     width: 3.5em;
   }
+
   .footer {
     display: flex;
     align-items: center;
   }
+
   &.loading * {
     cursor: progress;
   }
+
   .poll-vote-button {
     padding: 0 0.5em;
     margin-right: 0.5em;
diff --git a/src/components/poll/poll_form.vue b/src/components/poll/poll_form.vue
index 146754db..09d411ca 100644
--- a/src/components/poll/poll_form.vue
+++ b/src/components/poll/poll_form.vue
@@ -95,7 +95,7 @@
 <script src="./poll_form.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .poll-form {
   display: flex;
@@ -117,6 +117,7 @@
 
   .input-container {
     width: 100%;
+
     input {
       // Hack: dodge the floating X icon
       padding-right: 2.5em;
diff --git a/src/components/popover/popover.vue b/src/components/popover/popover.vue
index 2869d736..fd0fd821 100644
--- a/src/components/popover/popover.vue
+++ b/src/components/popover/popover.vue
@@ -41,7 +41,7 @@
 <script src="./popover.js" />
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .popover-trigger-button {
   display: inline-block;
@@ -52,31 +52,31 @@
   position: fixed;
   min-width: 0;
   max-width: calc(100vw - 20px);
-  box-shadow: 2px 2px 3px rgba(0, 0, 0, 0.5);
+  box-shadow: 2px 2px 3px rgb(0 0 0 / 50%);
   box-shadow: var(--popupShadow);
 }
 
 .popover-default {
-  &:after {
-    content: '';
+  &::after {
+    content: "";
     position: absolute;
     top: 0;
     bottom: 0;
     left: 0;
     right: 0;
     z-index: 3;
-    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
+    box-shadow: 1px 1px 4px rgb(0 0 0 / 60%);
     box-shadow: var(--panelShadow);
     pointer-events: none;
   }
 
   border-radius: $fallback--btnRadius;
   border-radius: var(--btnRadius, $fallback--btnRadius);
-
   background-color: $fallback--bg;
   background-color: var(--popover, $fallback--bg);
   color: $fallback--text;
   color: var(--popoverText, $fallback--text);
+
   --faint: var(--popoverFaintText, $fallback--faint);
   --faintLink: var(--popoverFaintLink, $fallback--faint);
   --lightText: var(--popoverLightText, $fallback--lightText);
@@ -87,7 +87,7 @@
 
 .dropdown-menu {
   display: block;
-  padding: .5rem 0;
+  padding: 0.5rem 0;
   font-size: 1em;
   text-align: left;
   list-style: none;
@@ -97,7 +97,7 @@
 
   .dropdown-divider {
     height: 0;
-    margin: .5rem 0;
+    margin: 0.5rem 0;
     overflow: hidden;
     border-top: 1px solid $fallback--border;
     border-top: 1px solid var(--border, $fallback--border);
@@ -113,7 +113,7 @@
     text-align: inherit;
     white-space: nowrap;
     border: none;
-    border-radius: 0px;
+    border-radius: 0;
     background-color: transparent;
     box-shadow: none;
     width: 100%;
@@ -126,7 +126,7 @@
       svg {
         width: 22px;
         margin-right: 0.75rem;
-        color: var(--menuPopoverIcon, $fallback--icon)
+        color: var(--menuPopoverIcon, $fallback--icon);
       }
     }
 
@@ -137,17 +137,21 @@
       }
     }
 
-    &:active, &:hover {
+    &:active,
+    &:hover {
       background-color: $fallback--lightBg;
       background-color: var(--selectedMenuPopover, $fallback--lightBg);
       box-shadow: none;
+
       --btnText: var(--selectedMenuPopoverText, $fallback--link);
       --faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
       --faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
       --lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
       --icon: var(--selectedMenuPopoverIcon, $fallback--icon);
+
       svg {
         color: var(--selectedMenuPopoverIcon, $fallback--icon);
+
         --icon: var(--selectedMenuPopoverIcon, $fallback--icon);
       }
     }
@@ -161,16 +165,16 @@
       max-height: 22px;
       line-height: 22px;
       text-align: center;
-      border-radius: 0px;
+      border-radius: 0;
       background-color: $fallback--fg;
       background-color: var(--input, $fallback--fg);
-      box-shadow: 0px 0px 2px black inset;
+      box-shadow: 0 0 2px black inset;
       box-shadow: var(--inputShadow);
       margin-right: 0.75em;
 
       &.menu-checkbox-checked::after {
         font-size: 1.25em;
-        content: '✓';
+        content: "✓";
       }
 
       &.-radio {
@@ -178,16 +182,15 @@
 
         &.menu-checkbox-checked::after {
           font-size: 2em;
-          content: '•';
+          content: "•";
         }
       }
     }
-
   }
 
   .button-default.dropdown-item {
     &,
-    i[class*=icon-] {
+    i[class*="icon-"] {
       color: $fallback--text;
       color: var(--btnText, $fallback--text);
     }
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index f65058f4..c51639db 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -331,7 +331,7 @@
 <script src="./post_status_form.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .post-status-form {
   position: relative;
@@ -378,7 +378,9 @@
     &:hover {
       text-decoration: underline;
     }
-    svg, i {
+
+    svg,
+    i {
       margin-left: 0.2em;
       font-size: 0.8em;
       transform: rotate(90deg);
@@ -428,7 +430,25 @@
     }
   }
 
-  .media-upload-icon, .poll-icon, .emoji-icon {
+  // Order is not necessary but a good indicator
+  .media-upload-icon {
+    order: 1;
+    justify-content: left;
+  }
+
+  .emoji-icon {
+    order: 2;
+    justify-content: center;
+  }
+
+  .poll-icon {
+    order: 3;
+    justify-content: right;
+  }
+
+  .media-upload-icon,
+  .poll-icon,
+  .emoji-icon {
     font-size: 1.85em;
     line-height: 1.1;
     flex: 1;
@@ -436,16 +456,20 @@
     display: flex;
     align-items: center;
 
-    &.selected, &:hover {
+    &.selected,
+    &:hover {
       // needs to be specific to override icon default color
-      svg, i, label {
+      svg,
+      i,
+      label {
         color: $fallback--lightText;
         color: var(--lightText, $fallback--lightText);
       }
     }
 
     &.disabled {
-      svg, i {
+      svg,
+      i {
         cursor: not-allowed;
         color: $fallback--icon;
         color: var(--btnDisabledText, $fallback--icon);
@@ -458,32 +482,17 @@
     }
   }
 
-  // Order is not necessary but a good indicator
-  .media-upload-icon {
-    order: 1;
-    justify-content: left;
-  }
-
-  .emoji-icon {
-    order: 2;
-    justify-content: center;
-  }
-
-  .poll-icon {
-    order: 3;
-    justify-content: right;
-  }
-
   .error {
     text-align: center;
   }
 
   .media-upload-wrapper {
-    margin-right: .2em;
-    margin-bottom: .5em;
+    margin-right: 0.2em;
+    margin-bottom: 0.5em;
     width: 18em;
 
-    img, video {
+    img,
+    video {
       object-fit: contain;
       max-height: 10em;
     }
@@ -557,18 +566,14 @@
     }
   }
 
-  .btn[disabled] {
-    cursor: not-allowed;
-  }
-
   @keyframes fade-in {
     from { opacity: 0; }
-    to   { opacity: 0.6; }
+    to { opacity: 0.6; }
   }
 
   @keyframes fade-out {
     from { opacity: 0.6; }
-    to   { opacity: 0; }
+    to { opacity: 0; }
   }
 
   .drop-indicator {
diff --git a/src/components/react_button/react_button.vue b/src/components/react_button/react_button.vue
index 0c5fe321..a813b6fd 100644
--- a/src/components/react_button/react_button.vue
+++ b/src/components/react_button/react_button.vue
@@ -73,8 +73,8 @@
 <script src="./react_button.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-@import '../../_mixins.scss';
+@import "../../variables";
+@import "../../mixins";
 
 .ReactButton {
   .reaction-picker-filter {
@@ -104,20 +104,19 @@
     text-align: center;
     align-content: flex-start;
     user-select: none;
-
-    mask: linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
-          linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
-          linear-gradient(to top, white, white);
+    mask:
+      linear-gradient(to top, white 0, transparent 100%) bottom no-repeat,
+      linear-gradient(to bottom, white 0, transparent 100%) top no-repeat,
+      linear-gradient(to top, white, white);
     transition: mask-size 150ms;
     mask-size: 100% 20px, 100% 20px, auto;
 
     /* Autoprefixed seem to ignore this one, and also syntax is different */
-    -webkit-mask-composite: xor;
+    mask-composite: xor;
     mask-composite: exclude;
 
     .emoji-button {
       cursor: pointer;
-
       flex-basis: 20%;
       line-height: 1.5;
       align-content: center;
@@ -128,11 +127,6 @@
     }
   }
 
-  /* override of popover internal stuff */
-  .popover-trigger-button {
-    width: auto;
-  }
-
   .popover-trigger {
     padding: 10px;
     margin: -10px;
@@ -141,10 +135,12 @@
       color: $fallback--text;
       color: var(--text, $fallback--text);
     }
-
   }
 
   .popover-trigger-button {
+    /* override of popover internal stuff */
+    width: auto;
+
     @include unfocused-style {
       .focus-marker {
         visibility: hidden;
diff --git a/src/components/registration/registration.vue b/src/components/registration/registration.vue
index 24d9b59b..a26162f0 100644
--- a/src/components/registration/registration.vue
+++ b/src/components/registration/registration.vue
@@ -277,7 +277,7 @@
 
 <script src="./registration.js"></script>
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 $validations-cRed: #f04124;
 
 .registration-form {
@@ -321,7 +321,7 @@ $validations-cRed: #f04124;
 
   .form-group--error {
     animation-name: shakeError;
-    animation-duration: .6s;
+    animation-duration: 0.6s;
     animation-timing-function: ease-in-out;
   }
 
@@ -350,7 +350,7 @@ $validations-cRed: #f04124;
   }
 
   form textarea {
-    line-height:16px;
+    line-height: 16px;
     resize: vertical;
   }
 
diff --git a/src/components/remote_user_resolver/remote_user_resolver.vue b/src/components/remote_user_resolver/remote_user_resolver.vue
index f8945225..07aac169 100644
--- a/src/components/remote_user_resolver/remote_user_resolver.vue
+++ b/src/components/remote_user_resolver/remote_user_resolver.vue
@@ -15,6 +15,3 @@
 </template>
 
 <script src="./remote_user_resolver.js"></script>
-
-<style lang="scss">
-</style>
diff --git a/src/components/reply_button/reply_button.vue b/src/components/reply_button/reply_button.vue
index dada511b..6e3964b7 100644
--- a/src/components/reply_button/reply_button.vue
+++ b/src/components/reply_button/reply_button.vue
@@ -51,8 +51,8 @@
 <script src="./reply_button.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-@import '../../_mixins.scss';
+@import "../../variables";
+@import "../../mixins";
 
 .ReplyButton {
   display: flex;
@@ -86,6 +86,5 @@
       }
     }
   }
-
 }
 </style>
diff --git a/src/components/report/report.scss b/src/components/report/report.scss
index 578b4eb1..9762400b 100644
--- a/src/components/report/report.scss
+++ b/src/components/report/report.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Report {
   .report-content {
diff --git a/src/components/retweet_button/retweet_button.vue b/src/components/retweet_button/retweet_button.vue
index 240828e3..7700ee0d 100644
--- a/src/components/retweet_button/retweet_button.vue
+++ b/src/components/retweet_button/retweet_button.vue
@@ -65,8 +65,8 @@
 <script src="./retweet_button.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-@import '../../_mixins.scss';
+@import "../../variables";
+@import "../../mixins";
 
 .RetweetButton {
   display: flex;
diff --git a/src/components/rich_content/rich_content.scss b/src/components/rich_content/rich_content.scss
index 52042314..e5d353ac 100644
--- a/src/components/rich_content/rich_content.scss
+++ b/src/components/rich_content/rich_content.scss
@@ -1,4 +1,4 @@
-@import '../../variables';
+@import "../../variables";
 
 .RichContent {
   blockquote {
@@ -21,11 +21,11 @@
   }
 
   p {
-    margin: 0 0 1em 0;
+    margin: 0 0 1em;
   }
 
   p:last-child {
-    margin: 0 0 0 0;
+    margin: 0;
   }
 
   h1 {
diff --git a/src/components/scope_selector/scope_selector.vue b/src/components/scope_selector/scope_selector.vue
index f3bee183..d6e7265b 100644
--- a/src/components/scope_selector/scope_selector.vue
+++ b/src/components/scope_selector/scope_selector.vue
@@ -64,10 +64,9 @@
 <script src="./scope_selector.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .ScopeSelector {
-
   .scope {
     display: inline-block;
     cursor: pointer;
diff --git a/src/components/search/search.vue b/src/components/search/search.vue
index 6fc6a0de..19b9c577 100644
--- a/src/components/search/search.vue
+++ b/src/components/search/search.vue
@@ -148,7 +148,7 @@
 <script src="./search.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .search-result-heading {
   color: $fallback--faint;
@@ -176,7 +176,7 @@
 }
 
 .search-result-footer {
-  border-width: 1px 0 0 0;
+  border-width: 1px 0 0;
   border-style: solid;
   border-color: var(--border, $fallback--border);
   padding: 10px;
@@ -229,11 +229,11 @@
     color: $fallback--text;
     color: var(--text, $fallback--text);
   }
-  }
+}
 
-  .more-statuses-button {
-    height: 3.5em;
-    line-height: 3.5em;
-  }
+.more-statuses-button {
+  height: 3.5em;
+  line-height: 3.5em;
+}
 
 </style>
diff --git a/src/components/search_bar/search_bar.vue b/src/components/search_bar/search_bar.vue
index 199a7500..3969d8de 100644
--- a/src/components/search_bar/search_bar.vue
+++ b/src/components/search_bar/search_bar.vue
@@ -56,7 +56,7 @@
 <script src="./search_bar.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .SearchBar {
   display: inline-flex;
diff --git a/src/components/select/select.vue b/src/components/select/select.vue
index 92493b0b..0ce4ea82 100644
--- a/src/components/select/select.vue
+++ b/src/components/select/select.vue
@@ -21,22 +21,20 @@
 <script src="./select.js"> </script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 /* TODO fix order of styles */
 label.Select {
   padding: 0;
 
   select {
-    -webkit-appearance: none;
-    -moz-appearance: none;
     appearance: none;
     background: transparent;
     border: none;
     color: $fallback--text;
     color: var(--inputText, --text, $fallback--text);
     margin: 0;
-    padding: 0 2em 0 .2em;
+    padding: 0 2em 0 0.2em;
     font-family: sans-serif;
     font-family: var(--inputFont, sans-serif);
     font-size: 1em;
@@ -59,6 +57,5 @@ label.Select {
     z-index: 0;
     pointer-events: none;
   }
-
 }
 </style>
diff --git a/src/components/selectable_list/selectable_list.vue b/src/components/selectable_list/selectable_list.vue
index 1f7683ab..14910fc5 100644
--- a/src/components/selectable_list/selectable_list.vue
+++ b/src/components/selectable_list/selectable_list.vue
@@ -51,7 +51,7 @@
 <script src="./selectable_list.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .selectable-list {
   &-item-inner {
@@ -67,6 +67,7 @@
     background-color: $fallback--lightBg;
     background-color: var(--selectedMenu, $fallback--lightBg);
     color: var(--selectedMenuText, $fallback--text);
+
     --faint: var(--selectedMenuFaintText, $fallback--faint);
     --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
     --lightText: var(--selectedMenuLightText, $fallback--lightText);
diff --git a/src/components/settings_modal/helpers/choice_setting.vue b/src/components/settings_modal/helpers/choice_setting.vue
index d141a0d6..8fdbb5d3 100644
--- a/src/components/settings_modal/helpers/choice_setting.vue
+++ b/src/components/settings_modal/helpers/choice_setting.vue
@@ -28,8 +28,3 @@
 </template>
 
 <script src="./choice_setting.js"></script>
-
-<style lang="scss">
-.ChoiceSetting {
-}
-</style>
diff --git a/src/components/settings_modal/helpers/size_setting.vue b/src/components/settings_modal/helpers/size_setting.vue
index 90c9f538..5a78f100 100644
--- a/src/components/settings_modal/helpers/size_setting.vue
+++ b/src/components/settings_modal/helpers/size_setting.vue
@@ -45,10 +45,11 @@
 <script src="./size_setting.js"></script>
 
 <style lang="scss">
-.css-unit-input, .css-unit-input select {
+.css-unit-input,
+.css-unit-input select {
   margin-left: 0.5em;
-  width: 4em !important;
-  max-width: 4em !important;
-  min-width: 4em !important;
+  width: 4em;
+  max-width: 4em;
+  min-width: 4em;
 }
 </style>
diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss
index 13cb0e65..f5861229 100644
--- a/src/components/settings_modal/settings_modal.scss
+++ b/src/components/settings_modal/settings_modal.scss
@@ -1,4 +1,5 @@
-@import 'src/_variables.scss';
+@import "src/variables";
+
 .settings-modal {
   overflow: hidden;
 
@@ -6,32 +7,13 @@
   .option-list {
     list-style-type: none;
     padding-left: 2em;
+
     li {
       margin-bottom: 0.5em;
     }
-    .suboptions {
-      margin-top: 0.3em
-    }
-  }
-
-  &.peek {
-    .settings-modal-panel {
-      /* Explanation:
-       * Modal is positioned vertically centered.
-       * 100vh - 100% = Distance between modal's top+bottom boundaries and screen
-       * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen
-       * + 100% - we move modal completely off-screen, it's top boundary touches
-       *   bottom of the screen
-       * - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible
-       */
-      transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px));
 
-      @media all and (max-width: 800px) {
-        /* For mobile, the modal takes 100% of the available screen.
-           This ensures the minimized modal is always 50px above the browser bottom bar regardless of whether or not it is visible.
-        */
-        transform: translateY(calc(100% - 50px));
-      }
+    .suboptions {
+      margin-top: 0.3em;
     }
   }
 
@@ -63,6 +45,7 @@
 
   .settings-footer {
     display: flex;
+
     >* {
       margin-right: 0.5em;
     }
@@ -72,4 +55,26 @@
       flex-grow: 1;
     }
   }
+
+  &.peek {
+    .settings-modal-panel {
+      /* Explanation:
+       * Modal is positioned vertically centered.
+       * 100vh - 100% = Distance between modal's top+bottom boundaries and screen
+       * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen
+       * + 100% - we move modal completely off-screen, it's top boundary touches
+       *   bottom of the screen
+       * - 50px - leaving tiny amount of space so that titlebar + tiny amount of modal is visible
+       */
+      transform: translateY(calc(((100vh - 100%) / 2 + 100%) - 50px));
+
+      @media all and (max-width: 800px) {
+        /* For mobile, the modal takes 100% of the available screen.
+           This ensures the minimized modal is always 50px above the browser bottom
+           bar regardless of whether or not it is visible.
+        */
+        transform: translateY(calc(100% - 50px));
+      }
+    }
+  }
 }
diff --git a/src/components/settings_modal/settings_modal_content.scss b/src/components/settings_modal/settings_modal_content.scss
index 81ab434b..87df7982 100644
--- a/src/components/settings_modal/settings_modal_content.scss
+++ b/src/components/settings_modal/settings_modal_content.scss
@@ -1,4 +1,5 @@
-@import 'src/_variables.scss';
+@import "src/variables";
+
 .settings_tab-switcher {
   height: 100%;
 
@@ -10,7 +11,8 @@
     > div,
     > label {
       display: block;
-      margin-bottom: .5em;
+      margin-bottom: 0.5em;
+
       &:last-child {
         margin-bottom: 0;
       }
@@ -21,7 +23,7 @@
 
       .option-list {
         margin: 0;
-        padding-left: .5em;
+        padding-left: 0.5em;
       }
     }
 
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index 8561647b..582cb288 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -464,6 +464,7 @@
   justify-content: space-evenly;
   flex-wrap: wrap;
 }
+
 .column-settings .size-label {
   display: block;
   margin-bottom: 0.5em;
diff --git a/src/components/settings_modal/tabs/mutes_and_blocks_tab.scss b/src/components/settings_modal/tabs/mutes_and_blocks_tab.scss
index 2adff847..5fa3a27b 100644
--- a/src/components/settings_modal/tabs/mutes_and_blocks_tab.scss
+++ b/src/components/settings_modal/tabs/mutes_and_blocks_tab.scss
@@ -1,29 +1,29 @@
 .mutes-and-blocks-tab {
-    height: 100%;
+  height: 100%;
 
-    .usersearch-wrapper {
-        padding: 1em;
-    }
+  .usersearch-wrapper {
+    padding: 1em;
+  }
 
-    .bulk-actions {
-        text-align: right;
-        padding: 0 1em;
-        min-height: 2em;
-    }
+  .bulk-actions {
+    text-align: right;
+    padding: 0 1em;
+    min-height: 2em;
+  }
 
-    .bulk-action-button {
-        width: 10em
-    }
+  .bulk-action-button {
+    width: 10em;
+  }
 
-    .domain-mute-form {
-        padding: 1em;
-        display: flex;
-        flex-direction: column
-    }
+  .domain-mute-form {
+    padding: 1em;
+    display: flex;
+    flex-direction: column;
+  }
 
-    .domain-mute-button {
-        align-self: flex-end;
-        margin-top: 1em;
-        width: 10em
-    }
+  .domain-mute-button {
+    align-self: flex-end;
+    margin-top: 1em;
+    width: 10em;
+  }
 }
diff --git a/src/components/settings_modal/tabs/profile_tab.scss b/src/components/settings_modal/tabs/profile_tab.scss
index 201f1a76..73879192 100644
--- a/src/components/settings_modal/tabs/profile_tab.scss
+++ b/src/components/settings_modal/tabs/profile_tab.scss
@@ -1,4 +1,5 @@
-@import '../../../_variables.scss';
+@import "../../../variables";
+
 .profile-tab {
   .bio {
     margin: 0;
@@ -8,7 +9,7 @@
     padding-top: 5px;
   }
 
-  input[type=file] {
+  input[type="file"] {
     padding: 5px;
     height: auto;
   }
@@ -52,7 +53,7 @@
     right: 0.2em;
     border-radius: $fallback--tooltipRadius;
     border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
-    background-color: rgba(0, 0, 0, 0.6);
+    background-color: rgb(0 0 0 / 60%);
     opacity: 0.7;
     width: 1.5em;
     height: 1.5em;
diff --git a/src/components/settings_modal/tabs/security_tab/mfa.vue b/src/components/settings_modal/tabs/security_tab/mfa.vue
index 455d17b6..ee5b6b13 100644
--- a/src/components/settings_modal/tabs/security_tab/mfa.vue
+++ b/src/components/settings_modal/tabs/security_tab/mfa.vue
@@ -137,9 +137,11 @@
 
 <script src="./mfa.js"></script>
 <style lang="scss">
-@import '../../../../_variables.scss';
+@import "../../../../variables";
+
 .mfa-settings {
-  .mfa-heading, .method-item {
+  .mfa-heading,
+  .method-item {
     display: flex;
     flex-wrap: wrap;
     justify-content: space-between;
@@ -155,18 +157,19 @@
     display: flex;
     justify-content: center;
     flex-wrap: wrap;
+
     .qr-code {
       flex: 1;
       padding-right: 10px;
     }
     .verify { flex: 1; }
-    .error { margin: 4px 0 0 0; }
+    .error { margin: 4px 0 0; }
+
     .confirm-otp-actions {
       button {
         width: 15em;
         margin-top: 5px;
       }
-
     }
   }
 }
diff --git a/src/components/settings_modal/tabs/security_tab/mfa_backup_codes.vue b/src/components/settings_modal/tabs/security_tab/mfa_backup_codes.vue
index d7e98b3c..923161b2 100644
--- a/src/components/settings_modal/tabs/security_tab/mfa_backup_codes.vue
+++ b/src/components/settings_modal/tabs/security_tab/mfa_backup_codes.vue
@@ -21,13 +21,14 @@
 </template>
 <script src="./mfa_backup_codes.js"></script>
 <style lang="scss">
-@import '../../../../_variables.scss';
+@import "../../../../variables";
 
 .mfa-backup-codes {
   .warning {
     color: $fallback--cOrange;
     color: var(--cOrange, $fallback--cOrange);
   }
+
   .backup-codes {
     font-family: var(--postCodeFont, monospace);
   }
diff --git a/src/components/settings_modal/tabs/theme_tab/preview.vue b/src/components/settings_modal/tabs/theme_tab/preview.vue
index ba6bd529..d755279a 100644
--- a/src/components/settings_modal/tabs/theme_tab/preview.vue
+++ b/src/components/settings_modal/tabs/theme_tab/preview.vue
@@ -33,10 +33,10 @@
               scope="global"
               keypath="settings.style.preview.text"
             >
-              <code style="font-family: var(--postCodeFont)">
+              <code style="font-family: var(--postCodeFont);">
                 {{ $t('settings.style.preview.mono') }}
               </code>
-              <a style="color: var(--link)">
+              <a style="color: var(--link);">
                 {{ $t('settings.style.preview.link') }}
               </a>
             </i18n-t>
@@ -44,25 +44,25 @@
             <div class="icons">
               <FAIcon
                 fixed-width
-                style="color: var(--cBlue)"
+                style="color: var(--cBlue);"
                 class="fa-scale-110 fa-old-padding"
                 icon="reply"
               />
               <FAIcon
                 fixed-width
-                style="color: var(--cGreen)"
+                style="color: var(--cGreen);"
                 class="fa-scale-110 fa-old-padding"
                 icon="retweet"
               />
               <FAIcon
                 fixed-width
-                style="color: var(--cOrange)"
+                style="color: var(--cOrange);"
                 class="fa-scale-110 fa-old-padding"
                 icon="star"
               />
               <FAIcon
                 fixed-width
-                style="color: var(--cRed)"
+                style="color: var(--cRed);"
                 class="fa-scale-110 fa-old-padding"
                 icon="times"
               />
@@ -81,7 +81,7 @@
               class="faint"
               scope="global"
             >
-              <a style="color: var(--faintLink)">
+              <a style="color: var(--faintLink);">
                 {{ $t('settings.style.preview.faint_link') }}
               </a>
             </i18n-t>
@@ -138,6 +138,7 @@ export default {}
 .preview-container {
   position: relative;
 }
+
 .underlay-preview {
   position: absolute;
   top: 0;
diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
index bad6f51b..9935c2e7 100644
--- a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
+++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
@@ -1,20 +1,17 @@
-@import 'src/_variables.scss';
+@import "src/variables";
+
 .theme-tab {
   padding-bottom: 2em;
-  .theme-warning {
-    display: flex;
-    align-items: baseline;
-    margin-bottom: .5em;
-    .buttons {
-      .btn {
-        margin-bottom: .5em;
-      }
-    }
-  }
+
   .preset-switcher {
     margin-right: 1em;
   }
 
+  .btn {
+    margin-left: 0.25em;
+    margin-right: 0.25em;
+  }
+
   .style-control {
     display: flex;
     align-items: baseline;
@@ -24,35 +21,37 @@
       flex: 1;
     }
 
-    &.disabled {
-      input, select {
-        opacity: .5
-      }
-    }
-
     .opt {
-      margin: .5em;
+      margin: 0.5em;
     }
 
     .color-input {
       flex: 0 0 0;
     }
 
-    input, select {
+    input,
+    select {
       min-width: 3em;
       margin: 0;
       flex: 0;
 
-      &[type=number] {
+      &[type="number"] {
         min-width: 5em;
       }
 
-      &[type=range] {
+      &[type="range"] {
         flex: 1;
         min-width: 3em;
         align-self: flex-start;
       }
     }
+
+    &.disabled {
+      input,
+      select {
+        opacity: 0.5;
+      }
+    }
   }
 
   .reset-container {
@@ -63,8 +62,7 @@
   .reset-container,
   .apply-container,
   .radius-container,
-  .color-container,
-  {
+  .color-container, {
     display: flex;
   }
 
@@ -73,10 +71,11 @@
     flex-direction: column;
   }
 
-  .color-container{
+  .color-container {
     > h4 {
       width: 99%;
     }
+
     flex-wrap: wrap;
     justify-content: space-between;
   }
@@ -100,7 +99,7 @@
     p {
       flex: 1;
       margin: 0;
-      margin-right: .5em;
+      margin-right: 0.5em;
     }
   }
 
@@ -112,15 +111,16 @@
       min-width: 1px;
       flex: 0 auto;
       padding: 0 1em;
-      margin-bottom: .5em;
+      margin-bottom: 0.5em;
     }
   }
 
   .shadow-selector {
     .override {
       flex: 1;
-      margin-left: .5em;
+      margin-left: 0.5em;
     }
+
     .select-container {
       margin-top: -4px;
       margin-bottom: -3px;
@@ -136,7 +136,7 @@
 
     .presets,
     .import-export {
-      margin-bottom: .5em;
+      margin-bottom: 0.5em;
     }
 
     .import-export {
@@ -144,16 +144,17 @@
     }
 
     .override {
-      margin-left: .5em;
+      margin-left: 0.5em;
     }
   }
 
   .save-load-options {
     flex-wrap: wrap;
-    margin-top: .5em;
+    margin-top: 0.5em;
     justify-content: center;
+
     .keep-option {
-      margin: 0 .5em .5em;
+      margin: 0 0.5em 0.5em;
       min-width: 25%;
     }
   }
@@ -179,11 +180,11 @@
           flex: 1;
 
           h4 {
-            margin-bottom: .25em;
+            margin-bottom: 0.25em;
           }
 
           .icons {
-            margin-top: .5em;
+            margin-top: 0.5em;
             display: flex;
 
             i {
@@ -199,8 +200,20 @@
         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%);
+      .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;
@@ -251,33 +264,33 @@
     }
   }
 
+  .radius-item {
+    flex-basis: auto;
+  }
+
   .radius-item,
   .color-item {
     min-width: 20em;
     margin: 5px 6px 0 0;
-    display:flex;
+    display: flex;
     flex-direction: column;
     flex: 1 1 0;
 
     &.wide {
-      min-width: 60%
+      min-width: 60%;
     }
 
     &:not(.wide):nth-child(2n+1) {
       margin-right: 7px;
-
     }
 
-    .color, .opacity {
-      display:flex;
+    .color,
+    .opacity {
+      display: flex;
       align-items: baseline;
     }
   }
 
-  .radius-item {
-    flex-basis: auto;
-  }
-
   .theme-radius-rn,
   .theme-color-cl {
     border: 0;
@@ -295,14 +308,11 @@
 
   .theme-radius-in {
     min-width: 1em;
-  }
-
-  .theme-radius-in {
     max-width: 7em;
     flex: 1;
   }
 
-  .theme-radius-lb{
+  .theme-radius-lb {
     max-width: 50em;
   }
 
@@ -310,9 +320,16 @@
     padding: 20px;
   }
 
-  .btn {
-    margin-left: .25em;
-    margin-right: .25em;
+  .theme-warning {
+    display: flex;
+    align-items: baseline;
+    margin-bottom: 0.5em;
+
+    .buttons {
+      .btn {
+        margin-bottom: 0.5em;
+      }
+    }
   }
 }
 
@@ -323,6 +340,7 @@
     justify-content: space-around;
     flex-grow: 1;
 
+    /* stylelint-disable-next-line no-descending-specificity */
     .btn {
       flex-grow: 1;
       min-height: 2em;
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index 669cac71..7546535d 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -218,7 +218,8 @@
 <script src="./shadow_control.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
+
 .shadow-control {
   display: flex;
   flex-wrap: wrap;
@@ -229,6 +230,7 @@
   .shadow-tweak {
     margin: 5px 6px 0 0;
   }
+
   .shadow-preview-container {
     flex: 0;
     display: flex;
@@ -236,19 +238,19 @@
 
     $side: 15em;
 
-    input[type=number] {
+    input[type="number"] {
       width: 5em;
       min-width: 2em;
     }
+
     .x-shift-control,
     .y-shift-control {
       display: flex;
       flex: 0;
 
-      &[disabled=disabled] *{
-        opacity: .5
+      &[disabled="disabled"] * {
+        opacity: 0.5;
       }
-
     }
 
     .x-shift-control {
@@ -256,37 +258,40 @@
     }
 
     .x-shift-control .wrap,
-    input[type=range] {
+    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] {
+
+      input[type="range"] {
         transform-origin: 1em 1em;
         transform: rotate(90deg);
       }
     }
+
     .preview-window {
       flex: 1;
-      background-color: #999999;
+      background-color: #999;
       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%);
+        linear-gradient(45deg, #666 25%, transparent 25%),
+        linear-gradient(-45deg, #666 25%, transparent 25%),
+        linear-gradient(45deg, transparent 75%, #666 75%),
+        linear-gradient(-45deg, transparent 75%, #666 75%);
       background-size: 20px 20px;
-      background-position:0 0, 0 10px, 10px -10px, -10px 0;
-
+      background-position: 0 0, 0 10px, 10px -10px, -10px 0;
       border-radius: $fallback--inputRadius;
       border-radius: var(--inputRadius, $fallback--inputRadius);
 
@@ -312,14 +317,15 @@
         flex: 1;
       }
 
-      .shadow-switcher, .btn {
+      .shadow-switcher,
+      .btn {
         min-width: 1px;
         margin-right: 5px;
       }
 
       .btn {
-        padding: 0 .4em;
-        margin: 0 .1em;
+        padding: 0 0.4em;
+        margin: 0 0.1em;
       }
     }
   }
diff --git a/src/components/shout_panel/shout_panel.vue b/src/components/shout_panel/shout_panel.vue
index 688c2d61..a7013469 100644
--- a/src/components/shout_panel/shout_panel.vue
+++ b/src/components/shout_panel/shout_panel.vue
@@ -75,7 +75,7 @@
 <script src="./shout_panel.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .floating-shout {
   position: fixed;
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index 887596f8..994ac953 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -73,7 +73,7 @@
         >
           <router-link
             :to="{ name: 'chats', params: { username: currentUser.screen_name } }"
-            style="position: relative"
+            style="position: relative;"
           >
             <FAIcon
               fixed-width
@@ -251,7 +251,7 @@
 <script src="./side_drawer.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .side-drawer-container {
   position: fixed;
@@ -284,11 +284,11 @@
   z-index: -1;
   transition: 0.35s;
   transition-property: background-color;
-  background-color: rgba(0, 0, 0, 0.5);
+  background-color: rgb(0 0 0 / 50%);
 }
 
 .side-drawer-darken-closed {
-  background-color: rgba(0, 0, 0, 0);
+  background-color: rgb(0 0 0 / 0%);
 }
 
 .side-drawer-click-outside {
@@ -297,20 +297,21 @@
 
 .side-drawer {
   overflow-x: hidden;
-  transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
   transition: 0.35s;
+  transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
   transition-property: transform;
   margin: 0 0 0 -100px;
   padding: 0 0 1em 100px;
   width: 80%;
   max-width: 20em;
   flex: 0 0 80%;
-  box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
+  box-shadow: 1px 1px 4px rgb(0 0 0 / 60%);
   box-shadow: var(--panelShadow);
   background-color: $fallback--bg;
   background-color: var(--popover, $fallback--bg);
   color: $fallback--link;
   color: var(--popoverText, $fallback--link);
+
   --faint: var(--popoverFaintText, $fallback--faint);
   --faintLink: var(--popoverFaintLink, $fallback--faint);
   --lightText: var(--popoverLightText, $fallback--lightText);
@@ -360,7 +361,6 @@
   list-style: none;
   margin: 0;
   padding: 0;
-
   border-bottom: 1px solid;
   border-color: $fallback--border;
   border-color: var(--border, $fallback--border);
@@ -373,7 +373,8 @@
 .side-drawer li {
   padding: 0;
 
-  a, button {
+  a,
+  button {
     box-sizing: border-box;
     display: block;
     height: 3em;
@@ -385,6 +386,7 @@
       background-color: var(--selectedMenuPopover, $fallback--lightBg);
       color: $fallback--text;
       color: var(--selectedMenuPopoverText, $fallback--text);
+
       --faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
       --faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
       --lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
diff --git a/src/components/staff_panel/staff_panel.vue b/src/components/staff_panel/staff_panel.vue
index 6b9e61f2..77155e8b 100644
--- a/src/components/staff_panel/staff_panel.vue
+++ b/src/components/staff_panel/staff_panel.vue
@@ -27,7 +27,6 @@
 <script src="./staff_panel.js"></script>
 
 <style lang="scss">
-
 .staff-group {
   padding-left: 1em;
   padding-top: 1em;
diff --git a/src/components/status/status.scss b/src/components/status/status.scss
index ada9841e..44812867 100644
--- a/src/components/status/status.scss
+++ b/src/components/status/status.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Status {
   min-width: 0;
@@ -181,7 +181,7 @@
 
   .reply-to-popover {
     .reply-to:hover::before {
-      content: '';
+      content: "";
       display: block;
       position: absolute;
       bottom: 0;
@@ -197,7 +197,7 @@
 
     &.-strikethrough {
       .reply-to::after {
-        content: '';
+        content: "";
         display: block;
         position: absolute;
         top: 50%;
@@ -336,7 +336,7 @@
       margin-left: 0.2em;
 
       &::before {
-        content: ' ';
+        content: " ";
       }
     }
 
@@ -374,7 +374,7 @@
     align-items: center;
 
     &::before {
-      content: '';
+      content: "";
       position: absolute;
       height: 100%;
       width: 1px;
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 82eb7ac6..fe8778cf 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -261,7 +261,7 @@
                   v-if="!isPreview"
                   :status-id="status.parent_visible && status.in_reply_to_status_id"
                   class="reply-to-popover"
-                  style="min-width: 0"
+                  style="min-width: 0;"
                   :class="{ '-strikethrough': !status.parent_visible }"
                 >
                   <button
diff --git a/src/components/status_body/status_body.scss b/src/components/status_body/status_body.scss
index 039d4c7f..8fd60afc 100644
--- a/src/components/status_body/status_body.scss
+++ b/src/components/status_body/status_body.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .StatusBody {
   display: flex;
@@ -40,7 +40,7 @@
   .summary-wrapper {
     margin-bottom: 0.5em;
     border-style: solid;
-    border-width: 0 0 1px 0;
+    border-width: 0 0 1px;
     border-color: var(--border, $fallback--border);
     flex-grow: 0;
 
@@ -58,8 +58,7 @@
 
   .text-wrapper {
     display: flex;
-    flex-direction: column;
-    flex-wrap: nowrap;
+    flex-flow: column nowrap;
 
     &.-tall-status {
       position: relative;
@@ -75,7 +74,7 @@
           linear-gradient(to top, white, white);
 
         /* Autoprefixed seem to ignore this one, and also syntax is different */
-        -webkit-mask-composite: xor;
+        mask-composite: xor;
         mask-composite: exclude;
       }
     }
@@ -144,7 +143,7 @@
       mask-image: linear-gradient(to bottom, white 2em, transparent 3em);
 
       /* Autoprefixed seem to ignore this one, and also syntax is different */
-      -webkit-mask-composite: xor;
+      mask-composite: xor;
       mask-composite: exclude;
     }
 
@@ -158,7 +157,7 @@
 
     .summary-wrapper {
       .summary::after {
-        content: ': ';
+        content: ": ";
       }
 
       line-height: inherit;
diff --git a/src/components/status_history_modal/status_history_modal.vue b/src/components/status_history_modal/status_history_modal.vue
index 990be35b..79642e9c 100644
--- a/src/components/status_history_modal/status_history_modal.vue
+++ b/src/components/status_history_modal/status_history_modal.vue
@@ -32,6 +32,7 @@
 .modal-view.status-history-modal-view {
   align-items: flex-start;
 }
+
 .status-history-modal-panel {
   flex-shrink: 0;
   margin-top: 25%;
diff --git a/src/components/status_popover/status_popover.vue b/src/components/status_popover/status_popover.vue
index f4ab357b..311ca099 100644
--- a/src/components/status_popover/status_popover.vue
+++ b/src/components/status_popover/status_popover.vue
@@ -40,14 +40,13 @@
 <script src="./status_popover.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 /* popover styles load on-demand, so we need to override */
 .status-popover.popover {
   font-size: 1rem;
   min-width: 15em;
   max-width: 95%;
-
   border-color: $fallback--border;
   border-color: var(--border, $fallback--border);
   border-style: solid;
diff --git a/src/components/sticker_picker/sticker_picker.vue b/src/components/sticker_picker/sticker_picker.vue
index dc449ccb..904853c0 100644
--- a/src/components/sticker_picker/sticker_picker.vue
+++ b/src/components/sticker_picker/sticker_picker.vue
@@ -32,24 +32,29 @@
 <script src="./sticker_picker.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .sticker-picker {
   width: 100%;
+
   .contents {
     min-height: 250px;
+
     .sticker-picker-content {
       display: flex;
       flex-wrap: wrap;
       padding: 0 4px;
+
       .sticker {
         display: flex;
         flex: 1 1 auto;
         margin: 4px;
         width: 56px;
         height: 56px;
+
         img {
           height: 100%;
+
           &:hover {
             filter: drop-shadow(0 0 5px var(--accent, $fallback--link));
           }
diff --git a/src/components/still-image/still-image.vue b/src/components/still-image/still-image.vue
index d015e138..fc46fbe6 100644
--- a/src/components/still-image/still-image.vue
+++ b/src/components/still-image/still-image.vue
@@ -28,7 +28,7 @@
 <script src="./still-image.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .still-image {
   position: relative;
@@ -58,13 +58,13 @@
   &.animated {
     &::before {
       zoom: var(--_still_image-label-scale, 1);
-      content: 'gif';
+      content: "gif";
       position: absolute;
       line-height: 1;
       font-size: 0.7em;
       top: 0.5em;
       left: 0.5em;
-      background: rgba(127, 127, 127, 0.5);
+      background: rgb(127 127 127 / 50%);
       color: #fff;
       display: block;
       padding: 2px 4px;
diff --git a/src/components/tab_switcher/tab_switcher.scss b/src/components/tab_switcher/tab_switcher.scss
index d930368c..705925c8 100644
--- a/src/components/tab_switcher/tab_switcher.scss
+++ b/src/components/tab_switcher/tab_switcher.scss
@@ -1,5 +1,6 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
+/* stylelint-disable no-descending-specificity */
 .tab-switcher {
   display: flex;
 
@@ -19,8 +20,9 @@
       flex-direction: row;
       flex: 0 0 auto;
 
-      &::after, &::before {
-        content: '';
+      &::after,
+      &::before {
+        content: "";
         flex: 1 1 auto;
         border-bottom: 1px solid;
         border-bottom-color: $fallback--border;
@@ -39,6 +41,7 @@
           border-bottom-color: var(--border, $fallback--border);
         }
       }
+
       .tab {
         width: 100%;
         min-width: 1px;
@@ -48,6 +51,7 @@
         margin-bottom: 6px - 99px;
       }
     }
+
     .contents.scrollable-tabs {
       flex-basis: 0;
     }
@@ -70,10 +74,11 @@
       overflow-x: hidden;
       flex-direction: column;
 
-      &::after, &::before {
+      &::after,
+      &::before {
         flex-shrink: 0;
-        flex-basis: .5em;
-        content: '';
+        flex-basis: 0.5em;
+        content: "";
         border-right: 1px solid;
         border-right-color: $fallback--border;
         border-right-color: var(--border, $fallback--border);
@@ -107,7 +112,7 @@
 
         &::before {
           flex: 0 0 6px;
-          content: '';
+          content: "";
           border-right: 1px solid;
           border-right-color: $fallback--border;
           border-right-color: var(--border, $fallback--border);
@@ -131,12 +136,13 @@
         margin-left: 1em;
 
         @media all and (max-width: 800px) {
-          padding-left: .25em;
-          padding-right: calc(.25em + 200px);
-          margin-right: calc(.25em - 200px);
-          margin-left: .25em;
+          padding-left: 0.25em;
+          padding-right: calc(0.25em + 200px);
+          margin-right: calc(0.25em - 200px);
+          margin-left: 0.25em;
+
           .text {
-            display: none
+            display: none;
           }
         }
       }
@@ -145,15 +151,17 @@
 
   .contents {
     flex: 1 0 auto;
-    min-height: 0px;
+    min-height: 0;
 
     .hidden {
       display: none;
     }
+
     .full-height:not(.hidden) {
       height: 100%;
       display: flex;
       flex-direction: column;
+
       > *:not(.mobile-label) {
         flex: 1;
       }
@@ -196,7 +204,8 @@
     position: relative;
     box-sizing: border-box;
 
-    &::after, &::before {
+    &::after,
+    &::before {
       display: block;
       flex: 1 1 auto;
     }
@@ -209,7 +218,7 @@
 
     &:not(.active) {
       &::after {
-        content: '';
+        content: "";
         position: absolute;
         z-index: 7;
       }
@@ -217,11 +226,11 @@
   }
 
   .mobile-label {
-    padding-left: .3em;
-    padding-bottom: .25em;
-    margin-top: .5em;
-    margin-left: .2em;
-    margin-bottom: .25em;
+    padding-left: 0.3em;
+    padding-bottom: 0.25em;
+    margin-top: 0.5em;
+    margin-left: 0.2em;
+    margin-bottom: 0.25em;
     border-bottom: 1px solid var(--border, $fallback--border);
 
     @media all and (min-width: 800px) {
@@ -229,3 +238,4 @@
     }
   }
 }
+/* stylelint-enable no-descending-specificity */
diff --git a/src/components/terms_of_service_panel/terms_of_service_panel.vue b/src/components/terms_of_service_panel/terms_of_service_panel.vue
index 1df41d70..bff0ae74 100644
--- a/src/components/terms_of_service_panel/terms_of_service_panel.vue
+++ b/src/components/terms_of_service_panel/terms_of_service_panel.vue
@@ -17,6 +17,6 @@
 
 <style lang="scss">
 .tos-content {
-  margin: 1em
+  margin: 1em;
 }
 </style>
diff --git a/src/components/thread_tree/thread_tree.vue b/src/components/thread_tree/thread_tree.vue
index c6fffc71..04727278 100644
--- a/src/components/thread_tree/thread_tree.vue
+++ b/src/components/thread_tree/thread_tree.vue
@@ -119,7 +119,8 @@
 <script src="./thread_tree.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
+
 .thread-tree-replies {
   margin-left: var(--status-margin, $status-margin);
   border-left: 2px solid var(--border, $fallback--border);
@@ -127,6 +128,7 @@
 
 .thread-tree-replies-hidden {
   padding: var(--status-margin, $status-margin);
+
   /* Make the button stretch along the whole row */
   display: flex;
   align-items: stretch;
diff --git a/src/components/timeline/timeline.scss b/src/components/timeline/timeline.scss
index c6fb1ca7..4371947d 100644
--- a/src/components/timeline/timeline.scss
+++ b/src/components/timeline/timeline.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Timeline {
   .alert-dot {
@@ -46,10 +46,9 @@
       text-align: center;
       line-height: 2.75em;
       padding: 0 0.5em;
-    }
 
-    .timeline-heading {
-      .button-default, .alert {
+      .button-default,
+      .alert {
         line-height: 2em;
         width: 100%;
       }
diff --git a/src/components/timeline_menu/timeline_menu.vue b/src/components/timeline_menu/timeline_menu.vue
index e7250282..5f1da1f7 100644
--- a/src/components/timeline_menu/timeline_menu.vue
+++ b/src/components/timeline_menu/timeline_menu.vue
@@ -45,56 +45,7 @@
 <script src="./timeline_menu.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
-
-.TimelineMenu {
-  margin-right: auto;
-  min-width: 0;
-
-  .popover-trigger-button {
-    vertical-align: bottom;
-  }
-
-  .panel::after {
-    border-top-right-radius: 0;
-    border-top-left-radius: 0;
-  }
-
-  .timeline-menu-title {
-    margin: 0;
-    cursor: pointer;
-    user-select: none;
-    width: 100%;
-    display: flex;
-
-    .timeline-menu-name {
-      overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
-
-    svg {
-      margin-left: 0.6em;
-      transition: transform 100ms;
-    }
-
-    .click-blocker {
-      cursor: default;
-      flex-grow: 1;
-    }
-  }
-
-  &.open .timeline-menu-title svg {
-    color: $fallback--text;
-    color: var(--panelText, $fallback--text);
-    transform: rotate(180deg);
-  }
-
-  .panel {
-    box-shadow: var(--popoverShadow);
-  }
-
-}
+@import "../../variables";
 
 .timeline-menu-popover {
   min-width: 24rem;
@@ -110,24 +61,6 @@
     padding: 0;
   }
 
-  li {
-    border-bottom: 1px solid;
-    border-color: $fallback--border;
-    border-color: var(--border, $fallback--border);
-    padding: 0;
-
-    &:last-child a {
-      border-bottom-right-radius: $fallback--panelRadius;
-      border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius);
-      border-bottom-left-radius: $fallback--panelRadius;
-      border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius);
-    }
-
-    &:last-child {
-      border: none;
-    }
-  }
-
   a {
     display: block;
     padding: 0 0.65em;
@@ -139,6 +72,7 @@
       background-color: var(--selectedMenu, $fallback--lightBg);
       color: $fallback--link;
       color: var(--selectedMenuText, $fallback--link);
+
       --faint: var(--selectedMenuFaintText, $fallback--faint);
       --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
       --lightText: var(--selectedMenuLightText, $fallback--lightText);
@@ -150,7 +84,9 @@
       background-color: $fallback--lightBg;
       background-color: var(--selectedMenu, $fallback--lightBg);
       color: $fallback--text;
-      color: var(--selectedMenuText, $fallback--text); --faint: var(--selectedMenuFaintText, $fallback--faint);
+      color: var(--selectedMenuText, $fallback--text);
+
+      --faint: var(--selectedMenuFaintText, $fallback--faint);
       --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
       --lightText: var(--selectedMenuLightText, $fallback--lightText);
       --icon: var(--selectedMenuIcon, $fallback--icon);
@@ -165,6 +101,71 @@
       margin-left: -0.2em;
     }
   }
+
+  li {
+    border-bottom: 1px solid;
+    border-color: $fallback--border;
+    border-color: var(--border, $fallback--border);
+    padding: 0;
+
+    &:last-child a {
+      border-bottom-right-radius: $fallback--panelRadius;
+      border-bottom-right-radius: var(--panelRadius, $fallback--panelRadius);
+      border-bottom-left-radius: $fallback--panelRadius;
+      border-bottom-left-radius: var(--panelRadius, $fallback--panelRadius);
+    }
+
+    &:last-child {
+      border: none;
+    }
+  }
 }
 
+.TimelineMenu {
+  margin-right: auto;
+  min-width: 0;
+
+  .popover-trigger-button {
+    vertical-align: bottom;
+  }
+
+  .panel::after {
+    border-top-right-radius: 0;
+    border-top-left-radius: 0;
+  }
+
+  .timeline-menu-title {
+    margin: 0;
+    cursor: pointer;
+    user-select: none;
+    width: 100%;
+    display: flex;
+
+    .timeline-menu-name {
+      overflow: hidden;
+      text-overflow: ellipsis;
+      white-space: nowrap;
+    }
+
+    svg {
+      margin-left: 0.6em;
+      transition: transform 100ms;
+    }
+
+    .click-blocker {
+      cursor: default;
+      flex-grow: 1;
+    }
+  }
+
+  &.open .timeline-menu-title svg {
+    color: $fallback--text;
+    color: var(--panelText, $fallback--text);
+    transform: rotate(180deg);
+  }
+
+  .panel {
+    box-shadow: var(--popoverShadow);
+  }
+}
 </style>
diff --git a/src/components/update_notification/update_notification.scss b/src/components/update_notification/update_notification.scss
index ce8129d0..4337acc4 100644
--- a/src/components/update_notification/update_notification.scss
+++ b/src/components/update_notification/update_notification.scss
@@ -1,4 +1,5 @@
-@import 'src/_variables.scss';
+@import "src/variables";
+
 .UpdateNotification {
   overflow: hidden;
 }
@@ -21,7 +22,8 @@
 
   @media all and (max-width: 800px) {
     /* For mobile, the modal takes 100% of the available screen.
-    This ensures the minimized modal is always 50px above the browser bottom bar regardless of whether or not it is visible.
+       This ensures the minimized modal is always 50px above the browser
+       bottom bar regardless of whether or not it is visible.
    */
     width: 100vw;
   }
@@ -44,7 +46,7 @@
   }
 
   .panel-body {
-    border-width: 0 0 1px 0;
+    border-width: 0 0 1px;
     border-style: solid;
     border-color: var(--border, $fallback--border);
   }
@@ -67,7 +69,7 @@
     z-index: 20;
     position: relative;
     shape-margin: 0.5em;
-    filter: drop-shadow(5px 5px 10px rgba(0,0,0,0.5));
+    filter: drop-shadow(5px 5px 10px rgb(0 0 0 / 50%));
     pointer-events: none;
   }
 
@@ -94,7 +96,7 @@
   }
 
   &.-peek {
-  /* Explanation:
+    /* Explanation:
    * 100vh - 100% = Distance between modal's top+bottom boundaries and screen
    * (100vh - 100%) / 2 = Distance between bottom (or top) boundary and screen
    */
@@ -103,7 +105,7 @@
     .pleroma-tan {
       float: right;
       z-index: 10;
-      shape-image-threshold: 0.7;
+      shape-image-threshold: 70%;
     }
 
     .extra-info-group {
diff --git a/src/components/user_avatar/user_avatar.vue b/src/components/user_avatar/user_avatar.vue
index f4d294df..91c17611 100644
--- a/src/components/user_avatar/user_avatar.vue
+++ b/src/components/user_avatar/user_avatar.vue
@@ -27,7 +27,7 @@
 
 <script src="./user_avatar.js"></script>
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .Avatar {
   --_avatarShadowBox: var(--avatarStatusShadow);
@@ -85,10 +85,9 @@
     right: 0;
     margin: -0.2em;
     padding: 0.2em;
-    background: rgba(127, 127, 127, 0.5);
+    background: rgb(127 127 127 / 50%);
     color: #fff;
     border-radius: var(--tooltipRadius);
   }
-
 }
 </style>
diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss
index cdb8cb57..942673c4 100644
--- a/src/components/user_card/user_card.scss
+++ b/src/components/user_card/user_card.scss
@@ -1,4 +1,4 @@
-@import '../../_variables.scss';
+@import "../../variables";
 
 .user-card {
   position: relative;
@@ -11,7 +11,7 @@
   }
 
   .panel-heading {
-    padding: .5em 0;
+    padding: 0.5em 0;
     text-align: center;
     box-shadow: none;
     background: transparent;
@@ -35,17 +35,19 @@
     left: 0;
     right: 0;
     bottom: 0;
-    mask: linear-gradient(to top, white, transparent) bottom no-repeat,
-          linear-gradient(to top, white, white);
+    mask:
+      linear-gradient(to top, white, transparent) bottom no-repeat,
+      linear-gradient(to top, white, white);
     // Autoprefixer seem to ignore this one, and also syntax is different
-    -webkit-mask-composite: xor;
+    mask-composite: xor;
     mask-composite: exclude;
     background-size: cover;
     mask-size: 100% 60%;
-    border-top-left-radius: calc(var(--__roundnessTop, --panelRadius) - 1px);
-    border-top-right-radius: calc(var(--__roundnessTop, --panelRadius) - 1px);
-    border-bottom-left-radius: calc(var(--__roundnessBottom, --panelRadius) - 1px);
-    border-bottom-right-radius: calc(var(--__roundnessBottom, --panelRadius) - 1px);
+    border-radius:
+      calc(var(--__roundnessTop, --panelRadius) - 1px)
+      calc(var(--__roundnessTop, --panelRadius) - 1px)
+      calc(var(--__roundnessBottom, --panelRadius) - 1px)
+      calc(var(--__roundnessBottom, --panelRadius) - 1px);
     background-color: var(--profileBg);
     z-index: -2;
 
@@ -159,17 +161,17 @@
       top: 0;
       right: 0;
       bottom: 0;
-      background-color: rgba(0, 0, 0, 0.3);
+      background-color: rgb(0 0 0 / 30%);
       display: flex;
       justify-content: center;
       align-items: center;
       border-radius: $fallback--avatarRadius;
       border-radius: var(--avatarRadius, $fallback--avatarRadius);
       opacity: 0;
-      transition: opacity .2s ease;
+      transition: opacity 0.2s ease;
 
       svg {
-        color: #FFF;
+        color: #fff;
       }
     }
 
@@ -178,7 +180,8 @@
     }
   }
 
-  .external-link-button, .edit-profile-button {
+  .external-link-button,
+  .edit-profile-button {
     cursor: pointer;
     width: 2.5em;
     text-align: center;
@@ -191,34 +194,6 @@
     }
   }
 
-  .user-summary {
-    display: block;
-    margin-left: 0.6em;
-    text-align: left;
-    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;
-    line-height: 2em;
-
-    --emoji-size: 1.7em;
-
-    .top-line,
-    .bottom-line {
-      display: flex;
-    }
-  }
-
-  .user-name {
-    text-overflow: ellipsis;
-    overflow: hidden;
-    flex: 1 1 auto;
-    margin-right: 1em;
-    font-size: 1.1em;
-  }
-
   .bottom-line {
     font-weight: light;
     font-size: 1.1em;
@@ -253,8 +228,36 @@
     }
   }
 
+  .user-summary {
+    display: block;
+    margin-left: 0.6em;
+    text-align: left;
+    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;
+    line-height: 2em;
+
+    --emoji-size: 1.7em;
+
+    .top-line,
+    .bottom-line {
+      display: flex;
+    }
+  }
+
+  .user-name {
+    text-overflow: ellipsis;
+    overflow: hidden;
+    flex: 1 1 auto;
+    margin-right: 1em;
+    font-size: 1.1em;
+  }
+
   .user-meta {
-    margin-bottom: .15em;
+    margin-bottom: 0.15em;
     display: flex;
     align-items: baseline;
     line-height: 22px;
@@ -263,7 +266,7 @@
     .following {
       flex: 1 0 auto;
       margin: 0;
-      margin-bottom: .25em;
+      margin-bottom: 0.25em;
       text-align: left;
     }
 
@@ -271,7 +274,7 @@
       flex: 0 1 auto;
       display: flex;
       flex-wrap: wrap;
-      margin-right: -.5em;
+      margin-right: -0.5em;
       align-self: start;
 
       .userHighlightCl {
@@ -294,19 +297,20 @@
       .userHighlightText,
       .userHighlightSel {
         vertical-align: top;
-        margin-right: .5em;
-        margin-bottom: .25em;
+        margin-right: 0.5em;
+        margin-bottom: 0.25em;
       }
     }
   }
+
   .user-interactions {
     position: relative;
     display: flex;
     flex-flow: row wrap;
-    margin-right: -.75em;
+    margin-right: -0.75em;
 
     > * {
-      margin: 0 .75em .6em 0;
+      margin: 0 0.75em 0.6em 0;
       white-space: nowrap;
       min-width: 95px;
     }
@@ -317,7 +321,7 @@
   }
 
   .user-note {
-    margin: 0 .75em .6em 0;
+    margin: 0 0.75em 0.6em 0;
   }
 }
 
@@ -327,8 +331,8 @@
 
 .user-counts {
   display: flex;
-  line-height:16px;
-  padding: .5em 1.5em 0em 1.5em;
+  line-height: 16px;
+  padding: 0.5em 1.5em 0;
   text-align: center;
   justify-content: space-between;
   color: $fallback--lightText;
@@ -338,14 +342,16 @@
 
 .user-count {
   flex: 1 0 auto;
-  padding: .5em 0 .5em 0;
-  margin: 0 .5em;
+  padding: 0.5em 0;
+  margin: 0 0.5em;
 
   h5 {
-    font-size:1em;
+    font-size: 1em;
     font-weight: bolder;
     margin: 0 0 0.25em;
   }
+
+  /* stylelint-disable-next-line no-descending-specificity */
   a {
     text-decoration: none;
   }
diff --git a/src/components/user_list_popover/user_list_popover.vue b/src/components/user_list_popover/user_list_popover.vue
index 635dc7f6..8307cc8a 100644
--- a/src/components/user_list_popover/user_list_popover.vue
+++ b/src/components/user_list_popover/user_list_popover.vue
@@ -48,7 +48,7 @@
 <script src="./user_list_popover.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .user-list-popover {
   padding: 0.5em;
diff --git a/src/components/user_note/user_note.vue b/src/components/user_note/user_note.vue
index 4286e017..4e05951f 100644
--- a/src/components/user_note/user_note.vue
+++ b/src/components/user_note/user_note.vue
@@ -48,7 +48,7 @@
 <script src="./user_note.js"></script>
 
 <style lang="scss">
-@import '../../variables';
+@import "../../variables";
 
 .user-note {
   display: flex;
diff --git a/src/components/user_popover/user_popover.vue b/src/components/user_popover/user_popover.vue
index 53d51fc4..3b2bbc45 100644
--- a/src/components/user_popover/user_popover.vue
+++ b/src/components/user_popover/user_popover.vue
@@ -24,10 +24,12 @@
 <script src="./user_popover.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 /* popover styles load on-demand, so we need to override */
+/* stylelint-disable block-no-empty */
 .user-popover.popover {
 }
+/* stylelint-enable block-no-empty */
 
 </style>
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index d5e8d230..2720f052 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -140,7 +140,7 @@
 <script src="./user_profile.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .user-profile {
   flex: 2;
@@ -186,7 +186,8 @@
         margin: 0 0 0 0.25em;
       }
 
-      .user-profile-field-name, .user-profile-field-value {
+      .user-profile-field-name,
+      .user-profile-field-value {
         line-height: 1.3;
         text-overflow: ellipsis;
         white-space: nowrap;
@@ -204,6 +205,7 @@
     padding: 2em;
   }
 }
+
 .user-profile-placeholder {
   .panel-body {
     display: flex;
diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue
index 8c42ab7b..092c514e 100644
--- a/src/components/user_reporting_modal/user_reporting_modal.vue
+++ b/src/components/user_reporting_modal/user_reporting_modal.vue
@@ -72,7 +72,7 @@
 <script src="./user_reporting_modal.js"></script>
 
 <style lang="scss">
-@import '../../_variables.scss';
+@import "../../variables";
 
 .user-reporting-panel {
   width: 90vw;
@@ -121,7 +121,7 @@
     }
 
     .alert {
-      margin: 1em 0 0 0;
+      margin: 1em 0 0;
       line-height: 1.3em;
     }
   }
diff --git a/src/components/who_to_follow/who_to_follow.vue b/src/components/who_to_follow/who_to_follow.vue
index 3a17d0e2..56543d91 100644
--- a/src/components/who_to_follow/who_to_follow.vue
+++ b/src/components/who_to_follow/who_to_follow.vue
@@ -15,6 +15,3 @@
 </template>
 
 <script src="./who_to_follow.js"></script>
-
-<style lang="scss">
-</style>
diff --git a/src/components/who_to_follow_panel/who_to_follow_panel.vue b/src/components/who_to_follow_panel/who_to_follow_panel.vue
index c1ba6fb1..0fecec0b 100644
--- a/src/components/who_to_follow_panel/who_to_follow_panel.vue
+++ b/src/components/who_to_follow_panel/who_to_follow_panel.vue
@@ -33,24 +33,28 @@
   .who-to-follow * {
     vertical-align: middle;
   }
+
   .who-to-follow img {
     width: 32px;
     height: 32px;
   }
+
   .who-to-follow {
-    padding: 0em 1em;
-    margin: 0px;
+    padding: 0 1em;
+    margin: 0;
   }
+
   .who-to-follow-items {
     white-space: nowrap;
     overflow: hidden;
     text-overflow: ellipsis;
-    padding: 0px;
-    margin: 1em 0em;
+    padding: 0;
+    margin: 1em 0;
   }
+
   .who-to-follow-more {
-    padding: 0px;
-    margin: 1em 0em;
+    padding: 0;
+    margin: 1em 0;
     text-align: center;
   }
 </style>
diff --git a/src/hocs/with_load_more/with_load_more.scss b/src/hocs/with_load_more/with_load_more.scss
index de86ed4a..bad852f4 100644
--- a/src/hocs/with_load_more/with_load_more.scss
+++ b/src/hocs/with_load_more/with_load_more.scss
@@ -1,5 +1,4 @@
-
-@import '../../_variables.scss';
+@import "../../variables";
 
 .with-load-more {
   &-footer {
diff --git a/src/hocs/with_subscription/with_subscription.scss b/src/hocs/with_subscription/with_subscription.scss
index 7fd83802..996045b4 100644
--- a/src/hocs/with_subscription/with_subscription.scss
+++ b/src/hocs/with_subscription/with_subscription.scss
@@ -7,4 +7,4 @@
       font-size: 1rem;
     }
   }
-}
\ No newline at end of file
+}
diff --git a/src/panel.scss b/src/panel.scss
index a53e47c6..9471da11 100644
--- a/src/panel.scss
+++ b/src/panel.scss
@@ -1,3 +1,4 @@
+/* stylelint-disable no-descending-specificity */
 .panel {
   position: relative;
   display: flex;
@@ -12,14 +13,14 @@
   }
 
   &::after {
-    content: '';
+    content: "";
     position: absolute;
     top: 0;
     bottom: 0;
     left: 0;
     right: 0;
     z-index: 5;
-    box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
+    box-shadow: 1px 1px 4px rgb(0 0 0 / 60%);
     box-shadow: var(--panelShadow);
     pointer-events: none;
   }
@@ -87,7 +88,7 @@
 
   &::after,
   &::before {
-    content: '';
+    content: "";
     position: absolute;
     top: 0;
     bottom: 0;
@@ -126,7 +127,7 @@
 .panel-heading {
   border-radius: $fallback--panelRadius $fallback--panelRadius 0 0;
   border-radius: var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius) 0 0;
-  border-width: 0 0 1px 0;
+  border-width: 0 0 1px;
   align-items: start;
   // panel theme
   color: var(--panelText);
@@ -150,7 +151,7 @@
 
   .button-unstyled:hover,
   a:hover {
-    i[class*=icon-],
+    i[class*="icon-"],
     .svg-inline--fa,
     .iconLetter {
       color: var(--panelText);
@@ -173,7 +174,7 @@
       flex-shrink: 0;
 
       &,
-      i[class*=icon-] {
+      i[class*="icon-"] {
         color: $fallback--text;
         color: var(--btnPanelText, $fallback--text);
       }
@@ -234,7 +235,8 @@
   border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
   border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
   align-items: center;
-  border-width: 1px 0 0 0;
+  border-width: 1px 0 0;
   border-style: solid;
   border-color: var(--border, $fallback--border);
 }
+/* stylelint-enable no-descending-specificity */
diff --git a/yarn.lock b/yarn.lock
index c0061cf8..e2e06dec 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5278,7 +5278,7 @@ jest-worker@^27.4.5:
     merge-stream "^2.0.0"
     supports-color "^8.0.0"
 
-jest-worker@^28.0.2:
+jest-worker@^28.0.2, jest-worker@^28.1.0:
   version "28.1.3"
   resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-28.1.3.tgz#7e3c4ce3fa23d1bb6accb169e7f396f98ed4bb98"
   integrity sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==
@@ -8014,6 +8014,17 @@ stylelint-scss@^4.0.0:
     postcss-selector-parser "^6.0.6"
     postcss-value-parser "^4.1.0"
 
+stylelint-webpack-plugin@^3.3.0:
+  version "3.3.0"
+  resolved "https://registry.yarnpkg.com/stylelint-webpack-plugin/-/stylelint-webpack-plugin-3.3.0.tgz#3ba40e2b2b2b7d1802fa53618e01fc28bc21ffb3"
+  integrity sha512-F53bapIZ9zI16ero8IWm6TrUE6SSibZBphJE9b5rR2FxtvmGmm1YmS+a5xjQzn63+cv71GVSCu4byX66fBLpEw==
+  dependencies:
+    globby "^11.1.0"
+    jest-worker "^28.1.0"
+    micromatch "^4.0.5"
+    normalize-path "^3.0.0"
+    schema-utils "^4.0.0"
+
 stylelint@14.16.1:
   version "14.16.1"
   resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.16.1.tgz#b911063530619a1bbe44c2b875fd8181ebdc742d"
-- 
cgit v1.2.3-70-g09d2

