diff --git a/.husky/pre-commit b/.husky/pre-commit
index d2ae35e84b..3723623171 100755
--- a/.husky/pre-commit
+++ b/.husky/pre-commit
@@ -1,4 +1 @@
-#!/bin/sh
-. "$(dirname "$0")/_/husky.sh"
-
 yarn lint-staged
diff --git a/Gemfile.lock b/Gemfile.lock
index 133a914e9c..8e04953916 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -10,35 +10,35 @@ GIT
 GEM
   remote: https://rubygems.org/
   specs:
-    actioncable (7.1.3)
-      actionpack (= 7.1.3)
-      activesupport (= 7.1.3)
+    actioncable (7.1.3.2)
+      actionpack (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       nio4r (~> 2.0)
       websocket-driver (>= 0.6.1)
       zeitwerk (~> 2.6)
-    actionmailbox (7.1.3)
-      actionpack (= 7.1.3)
-      activejob (= 7.1.3)
-      activerecord (= 7.1.3)
-      activestorage (= 7.1.3)
-      activesupport (= 7.1.3)
+    actionmailbox (7.1.3.2)
+      actionpack (= 7.1.3.2)
+      activejob (= 7.1.3.2)
+      activerecord (= 7.1.3.2)
+      activestorage (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       mail (>= 2.7.1)
       net-imap
       net-pop
       net-smtp
-    actionmailer (7.1.3)
-      actionpack (= 7.1.3)
-      actionview (= 7.1.3)
-      activejob (= 7.1.3)
-      activesupport (= 7.1.3)
+    actionmailer (7.1.3.2)
+      actionpack (= 7.1.3.2)
+      actionview (= 7.1.3.2)
+      activejob (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       mail (~> 2.5, >= 2.5.4)
       net-imap
       net-pop
       net-smtp
       rails-dom-testing (~> 2.2)
-    actionpack (7.1.3)
-      actionview (= 7.1.3)
-      activesupport (= 7.1.3)
+    actionpack (7.1.3.2)
+      actionview (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       nokogiri (>= 1.8.5)
       racc
       rack (>= 2.2.4)
@@ -46,15 +46,15 @@ GEM
       rack-test (>= 0.6.3)
       rails-dom-testing (~> 2.2)
       rails-html-sanitizer (~> 1.6)
-    actiontext (7.1.3)
-      actionpack (= 7.1.3)
-      activerecord (= 7.1.3)
-      activestorage (= 7.1.3)
-      activesupport (= 7.1.3)
+    actiontext (7.1.3.2)
+      actionpack (= 7.1.3.2)
+      activerecord (= 7.1.3.2)
+      activestorage (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       globalid (>= 0.6.0)
       nokogiri (>= 1.8.5)
-    actionview (7.1.3)
-      activesupport (= 7.1.3)
+    actionview (7.1.3.2)
+      activesupport (= 7.1.3.2)
       builder (~> 3.1)
       erubi (~> 1.11)
       rails-dom-testing (~> 2.2)
@@ -64,22 +64,22 @@ GEM
       activemodel (>= 4.1)
       case_transform (>= 0.2)
       jsonapi-renderer (>= 0.1.1.beta1, < 0.3)
-    activejob (7.1.3)
-      activesupport (= 7.1.3)
+    activejob (7.1.3.2)
+      activesupport (= 7.1.3.2)
       globalid (>= 0.3.6)
-    activemodel (7.1.3)
-      activesupport (= 7.1.3)
-    activerecord (7.1.3)
-      activemodel (= 7.1.3)
-      activesupport (= 7.1.3)
+    activemodel (7.1.3.2)
+      activesupport (= 7.1.3.2)
+    activerecord (7.1.3.2)
+      activemodel (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       timeout (>= 0.4.0)
-    activestorage (7.1.3)
-      actionpack (= 7.1.3)
-      activejob (= 7.1.3)
-      activerecord (= 7.1.3)
-      activesupport (= 7.1.3)
+    activestorage (7.1.3.2)
+      actionpack (= 7.1.3.2)
+      activejob (= 7.1.3.2)
+      activerecord (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       marcel (~> 1.0)
-    activesupport (7.1.3)
+    activesupport (7.1.3.2)
       base64
       bigdecimal
       concurrent-ruby (~> 1.0, >= 1.0.2)
@@ -309,7 +309,7 @@ GEM
       activesupport (>= 5.1)
       haml (>= 4.0.6)
       railties (>= 5.1)
-    haml_lint (0.56.0)
+    haml_lint (0.57.0)
       haml (>= 5.0)
       parallel (~> 1.10)
       rainbow
@@ -444,7 +444,7 @@ GEM
       uri
     net-http-persistent (4.0.2)
       connection_pool (~> 2.2)
-    net-imap (0.4.9.1)
+    net-imap (0.4.10)
       date
       net-protocol
     net-ldap (0.19.0)
@@ -532,7 +532,7 @@ GEM
       activesupport (>= 3.0.0)
     raabro (1.4.0)
     racc (1.7.3)
-    rack (2.2.8)
+    rack (2.2.8.1)
     rack-attack (6.7.0)
       rack (>= 1.0, < 4)
     rack-cors (2.0.1)
@@ -554,20 +554,20 @@ GEM
     rackup (1.0.0)
       rack (< 3)
       webrick
-    rails (7.1.3)
-      actioncable (= 7.1.3)
-      actionmailbox (= 7.1.3)
-      actionmailer (= 7.1.3)
-      actionpack (= 7.1.3)
-      actiontext (= 7.1.3)
-      actionview (= 7.1.3)
-      activejob (= 7.1.3)
-      activemodel (= 7.1.3)
-      activerecord (= 7.1.3)
-      activestorage (= 7.1.3)
-      activesupport (= 7.1.3)
+    rails (7.1.3.2)
+      actioncable (= 7.1.3.2)
+      actionmailbox (= 7.1.3.2)
+      actionmailer (= 7.1.3.2)
+      actionpack (= 7.1.3.2)
+      actiontext (= 7.1.3.2)
+      actionview (= 7.1.3.2)
+      activejob (= 7.1.3.2)
+      activemodel (= 7.1.3.2)
+      activerecord (= 7.1.3.2)
+      activestorage (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       bundler (>= 1.15.0)
-      railties (= 7.1.3)
+      railties (= 7.1.3.2)
     rails-controller-testing (1.0.5)
       actionpack (>= 5.0.1.rc1)
       actionview (>= 5.0.1.rc1)
@@ -582,9 +582,9 @@ GEM
     rails-i18n (7.0.8)
       i18n (>= 0.7, < 2)
       railties (>= 6.0.0, < 8)
-    railties (7.1.3)
-      actionpack (= 7.1.3)
-      activesupport (= 7.1.3)
+    railties (7.1.3.2)
+      actionpack (= 7.1.3.2)
+      activesupport (= 7.1.3.2)
       irb
       rackup (>= 1.0.0)
       rake (>= 12.2)
@@ -795,7 +795,7 @@ GEM
     webfinger (1.2.0)
       activesupport
       httpclient (>= 2.4)
-    webmock (3.21.2)
+    webmock (3.22.0)
       addressable (>= 2.8.0)
       crack (>= 0.3.2)
       hashdiff (>= 0.4.0, < 2.0.0)
diff --git a/app/javascript/mastodon/features/compose/components/edit_indicator.jsx b/app/javascript/mastodon/features/compose/components/edit_indicator.jsx
index 6cdaaebea5..cc37d2d7d8 100644
--- a/app/javascript/mastodon/features/compose/components/edit_indicator.jsx
+++ b/app/javascript/mastodon/features/compose/components/edit_indicator.jsx
@@ -6,9 +6,9 @@ import { Link } from 'react-router-dom';
 
 import { useDispatch, useSelector } from 'react-redux';
 
-import BarChart4BarsIcon from 'mastodon/../material-icons/400-24px/bar_chart_4_bars.svg?react';
-import CloseIcon from 'mastodon/../material-icons/400-24px/close.svg?react';
-import PhotoLibraryIcon from 'mastodon/../material-icons/400-24px/photo_library.svg?react';
+import BarChart4BarsIcon from '@/material-icons/400-24px/bar_chart_4_bars.svg?react';
+import CloseIcon from '@/material-icons/400-24px/close.svg?react';
+import PhotoLibraryIcon from '@/material-icons/400-24px/photo_library.svg?react';
 import { cancelReplyCompose } from 'mastodon/actions/compose';
 import { Icon } from 'mastodon/components/icon';
 import { IconButton } from 'mastodon/components/icon_button';
diff --git a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx
index bb2d6a46b6..c270a83652 100644
--- a/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx
+++ b/app/javascript/mastodon/features/compose/components/emoji_picker_dropdown.jsx
@@ -10,7 +10,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import { supportsPassiveEvents } from 'detect-passive-events';
 import Overlay from 'react-overlays/Overlay';
 
-import MoodIcon from 'mastodon/../material-icons/400-24px/mood.svg?react';
+import MoodIcon from '@/material-icons/400-20px/mood.svg?react';
 import { IconButton } from 'mastodon/components/icon_button';
 import { assetHost } from 'mastodon/utils/config';
 
diff --git a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx
index 2783ca8be2..85057799be 100644
--- a/app/javascript/mastodon/features/compose/components/language_dropdown.jsx
+++ b/app/javascript/mastodon/features/compose/components/language_dropdown.jsx
@@ -9,9 +9,9 @@ import { supportsPassiveEvents } from 'detect-passive-events';
 import fuzzysort from 'fuzzysort';
 import Overlay from 'react-overlays/Overlay';
 
-import CancelIcon from 'mastodon/../material-icons/400-24px/cancel-fill.svg?react';
-import SearchIcon from 'mastodon/../material-icons/400-24px/search.svg?react';
-import TranslateIcon from 'mastodon/../material-icons/400-24px/translate.svg?react';
+import CancelIcon from '@/material-icons/400-24px/cancel-fill.svg?react';
+import SearchIcon from '@/material-icons/400-24px/search.svg?react';
+import TranslateIcon from '@/material-icons/400-24px/translate.svg?react';
 import { Icon } from 'mastodon/components/icon';
 import { languages as preloadedLanguages } from 'mastodon/initial_state';
 
diff --git a/app/javascript/mastodon/features/compose/components/navigation_bar.jsx b/app/javascript/mastodon/features/compose/components/navigation_bar.jsx
index ebf59e4c83..ec5578eef3 100644
--- a/app/javascript/mastodon/features/compose/components/navigation_bar.jsx
+++ b/app/javascript/mastodon/features/compose/components/navigation_bar.jsx
@@ -4,7 +4,7 @@ import { useIntl, defineMessages } from 'react-intl';
 
 import { useSelector, useDispatch } from 'react-redux';
 
-import CloseIcon from 'mastodon/../material-icons/400-24px/close.svg?react';
+import CloseIcon from '@/material-icons/400-24px/close.svg?react';
 import { cancelReplyCompose } from 'mastodon/actions/compose';
 import Account from 'mastodon/components/account';
 import { IconButton } from 'mastodon/components/icon_button';
diff --git a/app/javascript/mastodon/features/compose/components/poll_button.jsx b/app/javascript/mastodon/features/compose/components/poll_button.jsx
index 345497abd3..cbaa25cb3c 100644
--- a/app/javascript/mastodon/features/compose/components/poll_button.jsx
+++ b/app/javascript/mastodon/features/compose/components/poll_button.jsx
@@ -3,7 +3,7 @@ import { PureComponent } from 'react';
 
 import { defineMessages, injectIntl } from 'react-intl';
 
-import BarChart4BarsIcon from '@/material-icons/400-24px/bar_chart_4_bars.svg?react';
+import BarChart4BarsIcon from '@/material-icons/400-20px/bar_chart_4_bars.svg?react';
 
 import { IconButton } from '../../../components/icon_button';
 
diff --git a/app/javascript/mastodon/features/compose/components/upload.jsx b/app/javascript/mastodon/features/compose/components/upload.jsx
index 861232d0ec..e8045ae81f 100644
--- a/app/javascript/mastodon/features/compose/components/upload.jsx
+++ b/app/javascript/mastodon/features/compose/components/upload.jsx
@@ -9,7 +9,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 
 import spring from 'react-motion/lib/spring';
 
-import CloseIcon from '@/material-icons/400-24px/close.svg?react';
+import CloseIcon from '@/material-icons/400-20px/close.svg?react';
 import EditIcon from '@/material-icons/400-24px/edit.svg?react';
 import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
 import { Blurhash } from 'mastodon/components/blurhash';
diff --git a/app/javascript/mastodon/features/compose/components/upload_button.jsx b/app/javascript/mastodon/features/compose/components/upload_button.jsx
index 50c9ad6321..20fb20f092 100644
--- a/app/javascript/mastodon/features/compose/components/upload_button.jsx
+++ b/app/javascript/mastodon/features/compose/components/upload_button.jsx
@@ -6,7 +6,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { connect } from 'react-redux';
 
-import PhotoLibraryIcon from '@/material-icons/400-24px/photo_library.svg?react';
+import PhotoLibraryIcon from '@/material-icons/400-20px/photo_library.svg?react';
 import { IconButton } from 'mastodon/components/icon_button';
 
 const messages = defineMessages({
diff --git a/app/javascript/mastodon/features/compose/containers/spoiler_button_container.js b/app/javascript/mastodon/features/compose/containers/spoiler_button_container.js
index a241417735..9acc43437b 100644
--- a/app/javascript/mastodon/features/compose/containers/spoiler_button_container.js
+++ b/app/javascript/mastodon/features/compose/containers/spoiler_button_container.js
@@ -2,7 +2,7 @@ import { injectIntl, defineMessages } from 'react-intl';
 
 import { connect } from 'react-redux';
 
-import WarningIcon from 'mastodon/../material-icons/400-24px/warning.svg?react';
+import WarningIcon from '@/material-icons/400-20px/warning.svg?react';
 import { IconButton } from 'mastodon/components/icon_button';
 
 import { changeComposeSpoilerness } from '../../../actions/compose';
diff --git a/app/javascript/mastodon/locales/ckb.json b/app/javascript/mastodon/locales/ckb.json
index 73910f9b7c..62195b72dc 100644
--- a/app/javascript/mastodon/locales/ckb.json
+++ b/app/javascript/mastodon/locales/ckb.json
@@ -17,9 +17,11 @@
   "account.badges.group": "گرووپ",
   "account.block": "بلۆکی @{name}",
   "account.block_domain": "بلۆکی هەموو شتێک لە {domain}",
+  "account.block_short": "بلۆک",
   "account.blocked": "بلۆککرا",
   "account.browse_more_on_origin_server": "گەڕانی فرەتر لە سەر پرۆفایلی سەرەکی",
   "account.cancel_follow_request": "داواکاری فۆڵۆو بکشێنەوە",
+  "account.copy": "ڕوونووسی بەستەر بۆ توت",
   "account.direct": "بە شێوەیەکی تایبەت باسی @{name} بکە",
   "account.disable_notifications": "ئاگانامە مەنێرە بۆم کاتێک @{name} پۆست دەکرێت",
   "account.domain_blocked": "دۆمەین قەپاتکرا",
@@ -30,6 +32,7 @@
   "account.featured_tags.last_status_never": "هیچ پۆستێک نییە",
   "account.featured_tags.title": "هاشتاگە تایبەتەکانی {name}",
   "account.follow": "بەدواداچوون",
+  "account.follow_back": "فۆڵۆو بکەنەوە",
   "account.followers": "شوێنکەوتووان",
   "account.followers.empty": "کەسێک شوێن ئەم بەکارهێنەرە نەکەوتووە",
   "account.followers_counter": "{count, plural, one {{counter} شوێنکەوتوو} other {{counter} شوێنکەوتوو}}",
@@ -38,6 +41,7 @@
   "account.follows.empty": "ئەم بەکارهێنەرە تا ئێستا شوێن کەس نەکەوتووە.",
   "account.go_to_profile": "بڕۆ بۆ پڕۆفایلی",
   "account.hide_reblogs": "داشاردنی بووستەکان لە @{name}",
+  "account.in_memoriam": "لە یادەوەریدا.",
   "account.joined_short": "بەشداری کردووە",
   "account.languages": "گۆڕینی زمانە بەشداربووەکان",
   "account.link_verified_on": "خاوەنداریەتی ئەم لینکە لە {date} چێک کراوە",
@@ -46,7 +50,11 @@
   "account.mention": "ئاماژە @{name}",
   "account.moved_to": "{name} ئاماژەی بەوە کردووە کە ئەکاونتە نوێیەکەیان ئێستا:",
   "account.mute": "بێدەنگکردن @{name}",
+  "account.mute_notifications_short": "پاڵ بە ئاگادارکردنەوەکانەوە بنێ",
+  "account.mute_short": "بێدەنگ",
   "account.muted": "بێ دەنگ",
+  "account.mutual": "دوولایەنە",
+  "account.no_bio": "هیچ وەسفێک نەخراوەتەڕوو.",
   "account.open_original_page": "لاپەڕەی ئەسڵی بکەرەوە",
   "account.posts": "نووسراوەکان",
   "account.posts_with_replies": "توتس و وەڵامەکان",
@@ -62,6 +70,7 @@
   "account.unendorse": "تایبەتمەندی لەسەر پرۆفایلەکە نیە",
   "account.unfollow": "بەدوادانەچو",
   "account.unmute": "بێدەنگکردنی @{name}",
+  "account.unmute_notifications_short": "ئاگادارکردنەوەکان بێدەنگ بکەرەوە",
   "account.unmute_short": "بێدەنگی مەکە",
   "account_note.placeholder": "کرتەبکە بۆ زیادکردنی تێبینی",
   "admin.dashboard.daily_retention": "ڕێژەی مانەوەی بەکارهێنەر بەپێی ڕۆژ دوای ناو تۆمارکردن",
@@ -69,6 +78,10 @@
   "admin.dashboard.retention.average": "ڕێژە",
   "admin.dashboard.retention.cohort": "چوونەژوورەوەی مانگانە",
   "admin.dashboard.retention.cohort_size": "ئەندامی نوێ",
+  "admin.impact_report.instance_accounts": "پڕۆفایلی هەژمارەکان ئەمە دەسڕێتەوە",
+  "admin.impact_report.instance_followers": "فۆڵۆوەرەکان بەکارهێنەران لەدەست دەدەن",
+  "admin.impact_report.instance_follows": "فۆڵۆوەرەکان ئەمبەکارهێنەرە لەدەست دەدەن",
+  "admin.impact_report.title": "پوختەی کاریگەرییەکان",
   "alert.rate_limited.message": "تکایە هەوڵبدەرەوە دوای {retry_time, time, medium}.",
   "alert.rate_limited.title": "ڕێژەی سنووردار",
   "alert.unexpected.message": "هەڵەیەکی چاوەڕوان نەکراو ڕوویدا.",
@@ -101,6 +114,8 @@
   "column.direct": "ئاماژەی تایبەت",
   "column.directory": "گەڕان لە پرۆفایلەکان",
   "column.domain_blocks": "دۆمەینە داخراوەکان",
+  "column.favourites": "دڵخوازەکان",
+  "column.firehose": "فیدی ڕاستەوخۆ",
   "column.follow_requests": "بەدواداچوی داواکاریەکان بکە",
   "column.home": "سەرەتا",
   "column.lists": "پێرست",
@@ -121,6 +136,9 @@
   "community.column_settings.remote_only": "تەنها بۆ دوور",
   "compose.language.change": "گۆڕینی زمان",
   "compose.language.search": "گەڕان بە زمانەکان...",
+  "compose.published.body": "پۆست بڵاوکراوەتەوە.",
+  "compose.published.open": "بیکەوە",
+  "compose.saved.body": "پۆستەکە سەیڤ کراوە.",
   "compose_form.direct_message_warning_learn_more": "زیاتر فێربه",
   "compose_form.encryption_warning": "Posts on Mastodon are not end-to-end encrypted. Do not share any dangerous information over Mastodon.",
   "compose_form.hashtag_warning": "ئەم بڵاوکراوەیە لە ژێر هیچ هاشتاگێکدا دا نانرێت وەک ئەوەیە، کە گشتی نەبێت. تەنها بڵاوکراوە گشتیەکان دەتوانرێ بە هاشتاگ گەڕانی بۆ بکرێت.",
@@ -128,11 +146,19 @@
   "compose_form.lock_disclaimer.lock": "قفڵ دراوە",
   "compose_form.placeholder": "چی لە مێشکتدایە?",
   "compose_form.poll.duration": "ماوەی ڕاپرسی",
+  "compose_form.poll.multiple": "فرە هەڵبژاردە",
+  "compose_form.poll.option_placeholder": "بژاردەی {number}",
+  "compose_form.poll.single": "یەکێك هەلبژێرە",
   "compose_form.poll.switch_to_multiple": "ڕاپرسی بگۆڕە بۆ ڕێگەدان بە چەند هەڵبژاردنێک",
   "compose_form.poll.switch_to_single": "گۆڕینی ڕاپرسی بۆ ڕێگەدان بە تاکە هەڵبژاردنێک",
+  "compose_form.poll.type": "ستایڵ",
+  "compose_form.publish": "پۆست",
   "compose_form.publish_form": "بڵاوی بکەوە",
+  "compose_form.reply": "وەڵام",
+  "compose_form.save_changes": "نوێکردنەوە",
   "compose_form.spoiler.marked": "دەق لە پشت ئاگاداریدا شاراوەتەوە",
   "compose_form.spoiler.unmarked": "دەق شاراوە نییە",
+  "compose_form.spoiler_placeholder": "ئاگادارکردنەوەی ناوەڕۆک (ئیختیاری)",
   "confirmation_modal.cancel": "هەڵوەشاندنەوه",
   "confirmations.block.block_and_report": "بلۆک & گوزارشت",
   "confirmations.block.confirm": "بلۆک",
@@ -155,6 +181,7 @@
   "confirmations.mute.explanation": "ئەمەش دەبێتە هۆی شاردنەوەی پۆستەکان یان ئەو بابەتانەی کە ئاماژەیان پێ دەکات ، بەڵام هێشتا ڕێگەیان پێ دەدات کە پۆستەکانتان ببینن و شوێنتان بکەون.",
   "confirmations.mute.message": "ئایا دڵنیایت لەوەی دەتەوێت بیلێیت {name}?",
   "confirmations.redraft.confirm": "سڕینەوە & دووبارە ڕەشکردنەوە",
+  "confirmations.redraft.message": "دڵنیای دەتەوێت ئەم پۆستە بسڕیتەوە و دووبارە دایبڕێژیتەوە؟ فەڤۆریت و بووستەکان لەدەست دەچن، وەڵامەکانی پۆستە ئەسڵیەکەش هەتیو دەبن.",
   "confirmations.reply.confirm": "وەڵام",
   "confirmations.reply.message": "وەڵامدانەوە ئێستا ئەو نامەیە ی کە تۆ ئێستا دایڕشتووە، دەنووسێتەوە. ئایا دڵنیایت کە دەتەوێت بەردەوام بیت?",
   "confirmations.unfollow.confirm": "بەدوادانەچو",
@@ -163,7 +190,9 @@
   "conversation.mark_as_read": "نیشانەکردن وەک خوێندراوە",
   "conversation.open": "نیشاندان گفتوگۆ",
   "conversation.with": "لەگەڵ{names}",
+  "copy_icon_button.copied": "کۆپی کراوە بۆ کلیپبۆرد",
   "copypaste.copied": "کۆپی کراوە",
+  "copypaste.copy_to_clipboard": "کۆپی کراوە بۆ کلیپبۆرد",
   "directory.federated": "لە ڕاژەکانی ناسراو",
   "directory.local": "تەنها لە {domain}",
   "directory.new_arrivals": "تازە گەیشتنەکان",
@@ -173,6 +202,7 @@
   "dismissable_banner.community_timeline": "ئەمانە دوایین پۆستی گشتی ئەو کەسانەن کە ئەکاونتەکانیان لەلایەن {domain}ەوە هۆست کراوە.",
   "dismissable_banner.dismiss": "بەلاوە نان",
   "dismissable_banner.explore_links": "ئەم هەواڵانە لە ئێستادا لەلایەن کەسانێکەوە لەسەر ئەم سێرڤەرە و سێرڤەرەکانی تری تۆڕی لامەرکەزی باس دەکرێن.",
+  "dismissable_banner.explore_statuses": "ئەمانە پۆستەکانن لە سەرانسەری وێبی کۆمەڵایەتی کە ئەمڕۆ کێشکردنیان بەدەستهێناوە. پۆستە نوێیەکان کە بووست و فەڤریتی زیاتریان هەیە ڕیزبەندی بەرزتریان هەیە.",
   "dismissable_banner.explore_tags": "ئەم هاشتاگانە لە ئێستادا لە نێو خەڵکی سەر ئەم سێرڤەرە و سێرڤەرەکانی تری تۆڕی لامەرکەزیدا جێگەی خۆیان دەگرن.",
   "embed.instructions": "ئەم توتە بنچین بکە لەسەر وێب سایتەکەت بە کۆپیکردنی کۆدەکەی خوارەوە.",
   "embed.preview": "ئەمە ئەو شتەیە کە لە شێوەی خۆی دەچێت:",
@@ -216,6 +246,7 @@
   "errors.unexpected_crash.copy_stacktrace": "کۆپیکردنی ستێکتراسی بۆ کلیپ بۆرد",
   "errors.unexpected_crash.report_issue": "کێشەی گوزارشت",
   "explore.search_results": "ئەنجامەکانی گەڕان",
+  "explore.suggested_follows": "خەڵک",
   "explore.title": "گەڕان",
   "explore.trending_links": "هەواڵەکان",
   "explore.trending_statuses": "بڵاوکراوەکان",
@@ -236,9 +267,16 @@
   "filter_modal.select_filter.subtitle": "بەکارهێنانی پۆلێنی بەردەست یان دروستکردنی پۆلێنێکی نوێ",
   "filter_modal.select_filter.title": "ئەم بڵاوکراوەیە بپاڵێوە",
   "filter_modal.title.status": "بڵاوکراوەیەک بپاڵێوە",
+  "firehose.all": "هەموو",
+  "firehose.local": "لەسەر ئەم ڕاژەیە",
+  "firehose.remote": "ڕاژەکانی دی",
   "follow_request.authorize": "ده‌سه‌ڵاتپێدراو",
   "follow_request.reject": "ڕەتکردنەوە",
   "follow_requests.unlocked_explanation": "هەرچەندە هەژمارەکەت داخراو نییە، ستافی {domain} وا بیریان کردەوە کە لەوانەیە بتانەوێت پێداچوونەوە بە داواکاریەکانی ئەم هەژمارەدا بکەن بە دەستی.",
+  "follow_suggestions.curated_suggestion": "ستاف هەڵبژاردنی",
+  "follow_suggestions.dismiss": "دوبارە پشانی مەدە",
+  "follow_suggestions.view_all": "بینینی هەموو",
+  "follow_suggestions.who_to_follow": "دواکەوتنی کێ",
   "followed_tags": "هاشتاگە شوێنکەوتووەکان",
   "footer.about": "دەربارە",
   "footer.directory": "ڕابەری پەڕەی ناساندن",
@@ -259,6 +297,7 @@
   "hashtag.column_settings.tag_mode.any": "هەر کام لەمانە",
   "hashtag.column_settings.tag_mode.none": "هیچ کام لەمانە",
   "hashtag.column_settings.tag_toggle": "تاگی زیادە ی ئەم ستوونە لەخۆ بنووسە",
+  "hashtag.counter_by_accounts": "{count, plural, one {{counter} participant} other {{counter} participants}}",
   "hashtag.follow": "شوێنکەوتنی هاشتاگ",
   "hashtag.unfollow": "شوێن نەکەوتنی هاشتاگ",
   "home.column_settings.basic": "بنەڕەتی",
diff --git a/app/javascript/mastodon/locales/es.json b/app/javascript/mastodon/locales/es.json
index b3f8e744f1..25ff1157fd 100644
--- a/app/javascript/mastodon/locales/es.json
+++ b/app/javascript/mastodon/locales/es.json
@@ -171,21 +171,21 @@
   "confirmations.delete_list.message": "¿Seguro que quieres borrar esta lista permanentemente?",
   "confirmations.discard_edit_media.confirm": "Descartar",
   "confirmations.discard_edit_media.message": "Tienes cambios sin guardar en la descripción o vista previa del archivo audiovisual, ¿descartarlos de todos modos?",
-  "confirmations.domain_block.confirm": "Bloquear dominio entero",
-  "confirmations.domain_block.message": "¿Seguro de que quieres bloquear al dominio {domain} entero? En general unos cuantos bloqueos y silenciados concretos es suficiente y preferible.",
+  "confirmations.domain_block.confirm": "Bloquear todo el dominio",
+  "confirmations.domain_block.message": "¿Seguro que quieres bloquear todo el dominio {domain}? En general, unos cuantos bloqueos y silenciados concretos es suficiente y preferible. No verás contenido del dominio en ninguna cronología pública ni en tus notificaciones. Se eliminarán tus seguidores procedentes de ese dominio.",
   "confirmations.edit.confirm": "Editar",
-  "confirmations.edit.message": "Editar ahora reemplazará el mensaje que está escribiendo. ¿Está seguro que quiere proceder?",
+  "confirmations.edit.message": "Editar ahora reemplazará el mensaje que estás escribiendo. ¿Seguro que quieres proceder?",
   "confirmations.logout.confirm": "Cerrar sesión",
-  "confirmations.logout.message": "¿Estás seguro de querer cerrar la sesión?",
+  "confirmations.logout.message": "¿Seguro que quieres cerrar la sesión?",
   "confirmations.mute.confirm": "Silenciar",
-  "confirmations.mute.explanation": "Esto esconderá las publicaciones de ellos y en las que los has mencionado, pero les permitirá ver tus mensajes y seguirte.",
-  "confirmations.mute.message": "¿Estás seguro de que quieres silenciar a {name}?",
+  "confirmations.mute.explanation": "Esto esconderá sus publicaciones y las publicaciones que los mencionen, pero podrán seguir viendo tus mensajes y seguirte.",
+  "confirmations.mute.message": "¿Seguro que quieres silenciar a {name}?",
   "confirmations.redraft.confirm": "Borrar y volver a borrador",
   "confirmations.redraft.message": "¿Estás seguro de querer borrar esta publicación y reescribirla? Los favoritos e impulsos se perderán, y las respuestas a la publicación original quedarán sin contexto.",
   "confirmations.reply.confirm": "Responder",
   "confirmations.reply.message": "Responder sobrescribirá el mensaje que estás escribiendo. ¿Seguro que deseas continuar?",
   "confirmations.unfollow.confirm": "Dejar de seguir",
-  "confirmations.unfollow.message": "¿Estás seguro de que quieres dejar de seguir a {name}?",
+  "confirmations.unfollow.message": "¿Seguro que quieres dejar de seguir a {name}?",
   "conversation.delete": "Borrar conversación",
   "conversation.mark_as_read": "Marcar como leído",
   "conversation.open": "Ver conversación",
@@ -194,7 +194,7 @@
   "copypaste.copied": "Copiado",
   "copypaste.copy_to_clipboard": "Copiar al portapapeles",
   "directory.federated": "Desde el fediverso conocido",
-  "directory.local": "Sólo de {domain}",
+  "directory.local": "Solo de {domain}",
   "directory.new_arrivals": "Recién llegados",
   "directory.recently_active": "Recientemente activo",
   "disabled_account_banner.account_settings": "Ajustes de la cuenta",
@@ -210,11 +210,11 @@
   "emoji_button.activity": "Actividad",
   "emoji_button.clear": "Limpiar",
   "emoji_button.custom": "Personalizado",
-  "emoji_button.flags": "Marcas",
+  "emoji_button.flags": "Banderas",
   "emoji_button.food": "Comida y bebida",
   "emoji_button.label": "Insertar emoji",
   "emoji_button.nature": "Naturaleza",
-  "emoji_button.not_found": "No hay emojis!! ¯\\_(ツ)_/¯",
+  "emoji_button.not_found": "No se encontró ningún emoji coincidente",
   "emoji_button.objects": "Objetos",
   "emoji_button.people": "Personas",
   "emoji_button.recent": "Usados frecuentemente",
@@ -230,8 +230,8 @@
   "empty_column.bookmarked_statuses": "Aún no tienes ninguna publicación guardada como marcador. Cuando guardes una, se mostrará aquí.",
   "empty_column.community": "La línea de tiempo local está vacía. ¡Escribe algo para empezar la fiesta!",
   "empty_column.direct": "Aún no tienes menciones privadas. Cuando envíes o recibas una, aparecerán aquí.",
-  "empty_column.domain_blocks": "Todavía no hay dominios ocultos.",
-  "empty_column.explore_statuses": "Nada está en tendencia en este momento. ¡Revisa más tarde!",
+  "empty_column.domain_blocks": "Todavía no hay dominios bloqueados.",
+  "empty_column.explore_statuses": "No hay nada en tendencia en este momento. ¡Revisa más tarde!",
   "empty_column.favourited_statuses": "Todavía no tienes publicaciones favoritas. Cuando marques una publicación como favorita, se mostrarán aquí.",
   "empty_column.favourites": "Todavía nadie marcó esta publicación como favorita. Cuando alguien lo haga, se mostrarán aquí.",
   "empty_column.follow_requests": "No tienes ninguna petición de seguidor. Cuando recibas una, se mostrará aquí.",
@@ -555,6 +555,7 @@
   "relative_time.minutes": "{number} m",
   "relative_time.seconds": "{number} s",
   "relative_time.today": "hoy",
+  "reply_indicator.attachments": "{count, plural, one {# adjunto} other {# adjuntos}}",
   "reply_indicator.cancel": "Cancelar",
   "reply_indicator.poll": "Encuesta",
   "report.block": "Bloquear",
diff --git a/app/javascript/mastodon/locales/sv.json b/app/javascript/mastodon/locales/sv.json
index 4a15c60ed8..55503ddf50 100644
--- a/app/javascript/mastodon/locales/sv.json
+++ b/app/javascript/mastodon/locales/sv.json
@@ -276,11 +276,18 @@
   "firehose.remote": "Andra servrar",
   "follow_request.authorize": "Godkänn",
   "follow_request.reject": "Avvisa",
-  "follow_requests.unlocked_explanation": "Även om ditt konto inte är låst tror {domain} personalen att du kanske vill granska dessa följares förfrågningar manuellt.",
+  "follow_requests.unlocked_explanation": "Även om ditt konto inte är låst tror {domain}-personalen att du kanske vill granska dessa följares förfrågningar manuellt.",
+  "follow_suggestions.curated_suggestion": "Utvald av personalen",
   "follow_suggestions.dismiss": "Visa inte igen",
+  "follow_suggestions.hints.featured": "Denna profil är handplockad av {domain}-teamet.",
+  "follow_suggestions.hints.friends_of_friends": "Denna profil är populär bland de personer du följer.",
+  "follow_suggestions.hints.most_followed": "Denna profil är en av de mest följda på {domain}.",
+  "follow_suggestions.hints.most_interactions": "Denna profil har nyligen fått mycket uppmärksamhet på {domain}.",
+  "follow_suggestions.hints.similar_to_recently_followed": "Denna profil liknar de profiler som du nyligen har följt.",
   "follow_suggestions.personalized_suggestion": "Personligt förslag",
   "follow_suggestions.popular_suggestion": "Populärt förslag",
   "follow_suggestions.view_all": "Visa alla",
+  "follow_suggestions.who_to_follow": "Rekommenderade profiler",
   "followed_tags": "Följda hashtags",
   "footer.about": "Om",
   "footer.directory": "Profilkatalog",
@@ -486,7 +493,9 @@
   "onboarding.profile.note": "Bio",
   "onboarding.profile.note_hint": "Du kan @nämna andra personer eller #hashtags…",
   "onboarding.profile.save_and_continue": "Spara och fortsätt",
+  "onboarding.profile.title": "Konfiguration av profil",
   "onboarding.profile.upload_avatar": "Ladda upp profilbild",
+  "onboarding.profile.upload_header": "Ladda upp profilbanner",
   "onboarding.share.lead": "Låt folk veta hur de kan hitta dig på Mastodon!",
   "onboarding.share.message": "Jag är {username} på #Mastodon! Följ mig på {url}",
   "onboarding.share.next_steps": "Möjliga nästa steg:",
@@ -521,10 +530,14 @@
   "poll_button.remove_poll": "Ta bort omröstning",
   "privacy.change": "Ändra inläggsintegritet",
   "privacy.direct.long": "Alla som nämns i inlägget",
+  "privacy.direct.short": "Särskilda personer",
   "privacy.private.long": "Endast dina följare",
   "privacy.private.short": "Följare",
   "privacy.public.long": "Alla på och utanför Mastodon",
-  "privacy.public.short": "Publik",
+  "privacy.public.short": "Offentlig",
+  "privacy.unlisted.additional": "Detta fungerar precis som offentlig, förutom att inlägget inte visas i liveflöden eller hashtaggar, utforska eller Mastodon-sökning, även om du har valt detta för hela kontot.",
+  "privacy.unlisted.long": "Mindre beaktat av algoritmen",
+  "privacy.unlisted.short": "Offentlig (begränsad)",
   "privacy_policy.last_updated": "Senast uppdaterad {date}",
   "privacy_policy.title": "Integritetspolicy",
   "recommended": "Rekommenderas",
diff --git a/app/javascript/mastodon/locales/th.json b/app/javascript/mastodon/locales/th.json
index f071a86ba0..7aa54ae8ce 100644
--- a/app/javascript/mastodon/locales/th.json
+++ b/app/javascript/mastodon/locales/th.json
@@ -277,7 +277,13 @@
   "follow_request.authorize": "อนุญาต",
   "follow_request.reject": "ปฏิเสธ",
   "follow_requests.unlocked_explanation": "แม้ว่าไม่มีการล็อคบัญชีของคุณ พนักงานของ {domain} คิดว่าคุณอาจต้องการตรวจทานคำขอติดตามจากบัญชีเหล่านี้ด้วยตนเอง",
+  "follow_suggestions.curated_suggestion": "คัดสรรโดยพนักงาน",
   "follow_suggestions.dismiss": "ไม่ต้องแสดงอีก",
+  "follow_suggestions.hints.featured": "โปรไฟล์นี้ได้รับการคัดสรรโดยทีม {domain}",
+  "follow_suggestions.hints.friends_of_friends": "โปรไฟล์นี้ได้รับความนิยมในหมู่ผู้คนที่คุณติดตาม",
+  "follow_suggestions.hints.most_followed": "โปรไฟล์นี้เป็นหนึ่งในโปรไฟล์ที่ได้รับการติดตามมากที่สุดใน {domain}",
+  "follow_suggestions.hints.most_interactions": "โปรไฟล์นี้เพิ่งได้รับความสนใจอย่างมากใน {domain}",
+  "follow_suggestions.hints.similar_to_recently_followed": "โปรไฟล์นี้คล้ายกับโปรไฟล์ที่คุณได้ติดตามล่าสุด",
   "follow_suggestions.personalized_suggestion": "ข้อเสนอแนะเฉพาะบุคคล",
   "follow_suggestions.popular_suggestion": "ข้อเสนอแนะยอดนิยม",
   "follow_suggestions.view_all": "ดูทั้งหมด",
diff --git a/app/javascript/material-icons/400-20px/bar_chart_4_bars-fill.svg b/app/javascript/material-icons/400-20px/bar_chart_4_bars-fill.svg
new file mode 100644
index 0000000000..78ce147272
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/bar_chart_4_bars-fill.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M96-144v-72h768v72H96Zm48-120v-264h96v264h-96Zm192 0v-456h96v456h-96Zm192 0v-336h96v336h-96Zm192 0v-552h96v552h-96Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/bar_chart_4_bars.svg b/app/javascript/material-icons/400-20px/bar_chart_4_bars.svg
new file mode 100644
index 0000000000..78ce147272
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/bar_chart_4_bars.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M96-144v-72h768v72H96Zm48-120v-264h96v264h-96Zm192 0v-456h96v456h-96Zm192 0v-336h96v336h-96Zm192 0v-552h96v552h-96Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/close-fill.svg b/app/javascript/material-icons/400-20px/close-fill.svg
new file mode 100644
index 0000000000..46d8afd7e1
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/close-fill.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="m291-240-51-51 189-189-189-189 51-51 189 189 189-189 51 51-189 189 189 189-51 51-189-189-189 189Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/close.svg b/app/javascript/material-icons/400-20px/close.svg
new file mode 100644
index 0000000000..46d8afd7e1
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/close.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="m291-240-51-51 189-189-189-189 51-51 189 189 189-189 51 51-189 189 189 189-51 51-189-189-189 189Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/mood-fill.svg b/app/javascript/material-icons/400-20px/mood-fill.svg
new file mode 100644
index 0000000000..ef72aeef6e
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/mood-fill.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M612-516q25 0 42.5-17.5T672-576q0-25-17.5-42.5T612-636q-25 0-42.5 17.5T552-576q0 25 17.5 42.5T612-516Zm-264 0q25 0 42.5-17.5T408-576q0-25-17.5-42.5T348-636q-25 0-42.5 17.5T288-576q0 25 17.5 42.5T348-516Zm132 228q62 0 114.5-29t75.5-86H290q23 57 75.5 86T480-288Zm.276 192Q401-96 331-126q-70-30-122.5-82.5T126-330.958q-30-69.959-30-149.5Q96-560 126-629.5t82.5-122Q261-804 330.958-834q69.959-30 149.5-30Q560-864 629.5-834t122 82.5Q804-699 834-629.276q30 69.725 30 149Q864-401 834-331q-30 70-82.5 122.5T629.276-126q-69.725 30-149 30Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/mood.svg b/app/javascript/material-icons/400-20px/mood.svg
new file mode 100644
index 0000000000..abb44c4663
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/mood.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M612-516q25 0 42.5-17.5T672-576q0-25-17.5-42.5T612-636q-25 0-42.5 17.5T552-576q0 25 17.5 42.5T612-516Zm-264 0q25 0 42.5-17.5T408-576q0-25-17.5-42.5T348-636q-25 0-42.5 17.5T288-576q0 25 17.5 42.5T348-516Zm132 228q60 0 110.5-31t79.5-84H290q29 53 79.5 84T480-288Zm.276 192Q401-96 331-126q-70-30-122.5-82.5T126-330.958q-30-69.959-30-149.5Q96-560 126-629.5t82.5-122Q261-804 330.958-834q69.959-30 149.5-30Q560-864 629.5-834t122 82.5Q804-699 834-629.276q30 69.725 30 149Q864-401 834-331q-30 70-82.5 122.5T629.276-126q-69.725 30-149 30ZM480-480Zm0 312q130 0 221-91t91-221q0-130-91-221t-221-91q-130 0-221 91t-91 221q0 130 91 221t221 91Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/photo_library-fill.svg b/app/javascript/material-icons/400-20px/photo_library-fill.svg
new file mode 100644
index 0000000000..5f5e39fbf9
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/photo_library-fill.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M360-384h384L618-552l-90 120-66-88-102 136Zm-48 144q-29.7 0-50.85-21.15Q240-282.3 240-312v-480q0-29.7 21.15-50.85Q282.3-864 312-864h480q29.7 0 50.85 21.15Q864-821.7 864-792v480q0 29.7-21.15 50.85Q821.7-240 792-240H312ZM168-96q-29.7 0-50.85-21.15Q96-138.3 96-168v-552h72v552h552v72H168Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/photo_library.svg b/app/javascript/material-icons/400-20px/photo_library.svg
new file mode 100644
index 0000000000..5804edb01c
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/photo_library.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M360-384h384L618-552l-90 120-66-88-102 136Zm-48 144q-29.7 0-50.85-21.15Q240-282.3 240-312v-480q0-29.7 21.15-50.85Q282.3-864 312-864h480q29.7 0 50.85 21.15Q864-821.7 864-792v480q0 29.7-21.15 50.85Q821.7-240 792-240H312Zm0-72h480v-480H312v480ZM168-96q-29.7 0-50.85-21.15Q96-138.3 96-168v-552h72v552h552v72H168Zm144-696v480-480Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/warning-fill.svg b/app/javascript/material-icons/400-20px/warning-fill.svg
new file mode 100644
index 0000000000..85dd926d39
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/warning-fill.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="m48-144 432-720 432 720H48Zm431.789-120Q495-264 505.5-274.289q10.5-10.29 10.5-25.5Q516-315 505.711-325.5q-10.29-10.5-25.5-10.5Q465-336 454.5-325.711q-10.5 10.29-10.5 25.5Q444-285 454.289-274.5q10.29 10.5 25.5 10.5ZM444-384h72v-192h-72v192Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-20px/warning.svg b/app/javascript/material-icons/400-20px/warning.svg
new file mode 100644
index 0000000000..d7d45a3211
--- /dev/null
+++ b/app/javascript/material-icons/400-20px/warning.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="m48-144 432-720 432 720H48Zm127-72h610L480-724 175-216Zm304.789-48Q495-264 505.5-274.289q10.5-10.29 10.5-25.5Q516-315 505.711-325.5q-10.29-10.5-25.5-10.5Q465-336 454.5-325.711q-10.5 10.29-10.5 25.5Q444-285 454.289-274.5q10.29 10.5 25.5 10.5ZM444-384h72v-192h-72v192Zm36-86Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-24px/mood-fill.svg b/app/javascript/material-icons/400-24px/mood-fill.svg
deleted file mode 100644
index 9480d0fb92..0000000000
--- a/app/javascript/material-icons/400-24px/mood-fill.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M620-520q25 0 42.5-17.5T680-580q0-25-17.5-42.5T620-640q-25 0-42.5 17.5T560-580q0 25 17.5 42.5T620-520Zm-280 0q25 0 42.5-17.5T400-580q0-25-17.5-42.5T340-640q-25 0-42.5 17.5T280-580q0 25 17.5 42.5T340-520Zm140 260q68 0 123.5-38.5T684-400H276q25 63 80.5 101.5T480-260Zm0 180q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/material-icons/400-24px/mood.svg b/app/javascript/material-icons/400-24px/mood.svg
deleted file mode 100644
index 46cafa7680..0000000000
--- a/app/javascript/material-icons/400-24px/mood.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M620-520q25 0 42.5-17.5T680-580q0-25-17.5-42.5T620-640q-25 0-42.5 17.5T560-580q0 25 17.5 42.5T620-520Zm-280 0q25 0 42.5-17.5T400-580q0-25-17.5-42.5T340-640q-25 0-42.5 17.5T280-580q0 25 17.5 42.5T340-520Zm140 260q68 0 123.5-38.5T684-400H276q25 63 80.5 101.5T480-260Zm0 180q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Z"/></svg>
\ No newline at end of file
diff --git a/app/javascript/packs/admin.jsx b/app/javascript/packs/admin.jsx
index ad263d8192..110437beb6 100644
--- a/app/javascript/packs/admin.jsx
+++ b/app/javascript/packs/admin.jsx
@@ -155,6 +155,10 @@ Rails.delegate(document, '#form_admin_settings_enable_bootstrap_timeline_account
 const onChangeRegistrationMode = (target) => {
   const enabled = target.value === 'approved';
 
+  [].forEach.call(document.querySelectorAll('.form_admin_settings_registrations_mode .warning-hint'), (warning_hint) => {
+    warning_hint.style.display = target.value === 'open' ? 'inline' : 'none';
+  });
+
   [].forEach.call(document.querySelectorAll('#form_admin_settings_require_invite_text'), (input) => {
     input.disabled = !enabled;
     if (enabled) {
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index 7396a986fc..9c60c9d902 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -677,12 +677,12 @@ body > [data-popper-placement] {
     }
 
     .icon-button.compose-form__upload__delete {
-      padding: 3px;
+      padding: 2px;
       border-radius: 50%;
 
       .icon {
-        width: 18px;
-        height: 18px;
+        width: 20px;
+        height: 20px;
       }
     }
 
@@ -732,12 +732,12 @@ body > [data-popper-placement] {
     }
 
     .icon-button {
-      padding: 3px;
+      padding: 2px;
     }
 
     .icon-button .icon {
-      width: 18px;
-      height: 18px;
+      width: 20px;
+      height: 20px;
     }
   }
 
@@ -5480,7 +5480,6 @@ a.status-card {
   .icon {
     position: absolute;
     top: 12px + 2px;
-    inset-inline-start: 16px - 2px;
     display: inline-block;
     opacity: 0;
     transition: all 100ms linear;
@@ -5495,6 +5494,10 @@ a.status-card {
       pointer-events: auto;
       opacity: 1;
     }
+
+    @media screen and (min-width: $no-gap-breakpoint) {
+      inset-inline-start: 16px - 2px;
+    }
   }
 
   .icon-search {
@@ -6250,6 +6253,7 @@ a.status-card {
 .report-modal__comment {
   box-sizing: border-box;
   width: 50%;
+  min-width: 50%;
 
   @media screen and (width <= 480px) {
     width: 100%;
@@ -6318,6 +6322,14 @@ a.status-card {
     min-height: 100px;
     max-height: 50vh;
     border: 0;
+
+    @media screen and (height <= 600px) {
+      max-height: 20vh;
+    }
+
+    @media screen and (max-width: $no-columns-breakpoint) {
+      max-height: 20vh;
+    }
   }
 
   .setting-toggle {
diff --git a/app/services/activitypub/process_account_service.rb b/app/services/activitypub/process_account_service.rb
index c9f17bdd45..ce7c23e567 100644
--- a/app/services/activitypub/process_account_service.rb
+++ b/app/services/activitypub/process_account_service.rb
@@ -246,10 +246,15 @@ class ActivityPub::ProcessAccountService < BaseService
     value = first_of_value(@json[key])
 
     return if value.nil?
-    return value['url'] if value.is_a?(Hash)
 
-    image = fetch_resource_without_id_validation(value)
-    image['url'] if image
+    if value.is_a?(String)
+      value = fetch_resource_without_id_validation(value)
+      return if value.nil?
+    end
+
+    value = first_of_value(value['url']) if value.is_a?(Hash) && value['type'] == 'Image'
+    value = value['href'] if value.is_a?(Hash)
+    value if value.is_a?(String)
   end
 
   def public_key
diff --git a/app/services/verify_link_service.rb b/app/services/verify_link_service.rb
index 707aeb4e08..b317fc31a8 100644
--- a/app/services/verify_link_service.rb
+++ b/app/services/verify_link_service.rb
@@ -19,7 +19,7 @@ class VerifyLinkService < BaseService
 
   def perform_request!
     @body = Request.new(:get, @url).add_headers('Accept' => 'text/html').perform do |res|
-      res.code == 200 ? res.body_with_limit : nil
+      res.code == 200 ? res.truncated_body : nil
     end
   end
 
diff --git a/app/views/admin/settings/registrations/show.html.haml b/app/views/admin/settings/registrations/show.html.haml
index dbf46c5cca..9b55f3cd8f 100644
--- a/app/views/admin/settings/registrations/show.html.haml
+++ b/app/views/admin/settings/registrations/show.html.haml
@@ -10,9 +10,11 @@
 
   %p.lead= t('admin.settings.registrations.preamble')
 
+  .flash-message= t('admin.settings.registrations.moderation_recommandation')
+
   .fields-row
     .fields-row__column.fields-row__column-6.fields-group
-      = f.input :registrations_mode, collection: %w(open approved none), wrapper: :with_label, include_blank: false, label_method: ->(mode) { I18n.t("admin.settings.registrations_mode.modes.#{mode}") }
+      = f.input :registrations_mode, collection: %w(open approved none), wrapper: :with_label, include_blank: false, label_method: ->(mode) { I18n.t("admin.settings.registrations_mode.modes.#{mode}") }, warning_hint: I18n.t('admin.settings.registrations_mode.warning_hint')
 
     .fields-row__column.fields-row__column-6.fields-group
       = f.input :require_invite_text, as: :boolean, wrapper: :with_label, disabled: !approved_registrations?
diff --git a/app/workers/scheduler/auto_close_registrations_scheduler.rb b/app/workers/scheduler/auto_close_registrations_scheduler.rb
index 17516dd23f..6874502915 100644
--- a/app/workers/scheduler/auto_close_registrations_scheduler.rb
+++ b/app/workers/scheduler/auto_close_registrations_scheduler.rb
@@ -26,7 +26,7 @@ class Scheduler::AutoCloseRegistrationsScheduler
   def switch_to_approval_mode!
     Setting.registrations_mode = 'approved'
 
-    User.those_who_can(:view_devops).includes(:account).find_each do |user|
+    User.those_who_can(:manage_settings).includes(:account).find_each do |user|
       AdminMailer.with(recipient: user.account).auto_close_registrations.deliver_later
     end
   end
diff --git a/config/locales/activerecord.es.yml b/config/locales/activerecord.es.yml
index 186104c702..569b783103 100644
--- a/config/locales/activerecord.es.yml
+++ b/config/locales/activerecord.es.yml
@@ -56,4 +56,4 @@ es:
         webhook:
           attributes:
             events:
-              invalid_permissions: no se pueden incluir eventos para los que no tienes derechos
+              invalid_permissions: no puede incluir eventos para los que no tienes permisos
diff --git a/config/locales/ca.yml b/config/locales/ca.yml
index f79d63a459..2f316984b5 100644
--- a/config/locales/ca.yml
+++ b/config/locales/ca.yml
@@ -767,6 +767,7 @@ ca:
         disabled: Per a ningú
         users: Per als usuaris locals en línia
       registrations:
+        moderation_recommandation: Assegureu-vos de tenir un equip de moderadors adient i actiu abans d'obrir l'alta de comptes al públic!
         preamble: Controla qui pot crear un compte en el teu servidor.
         title: Registres
       registrations_mode:
@@ -774,6 +775,7 @@ ca:
           approved: Cal l’aprovació per a registrar-se
           none: No es pot registrar ningú
           open: Qualsevol pot registrar-se
+        warning_hint: Recomanem utilitzar l'opció "Es requereix aprovació per a donar-se d'alta" si no teniu un equip de moderadors que puguin gestionar els enviaments de brossa o maliciosos en un temps raonable.
       security:
         authorized_fetch: Requereix autenticació dels servidors federats
         authorized_fetch_hint: Requerir l'autenticació dels servidors federats permet una aplicació més estricta dels bloqueigs a nivell d'usuari i a nivell de servidor. Tanmateix, això provoca una penalització del rendiment, redueix l'abast de les seves respostes i pot introduir problemes de compatibilitat amb alguns serveis federats. A més, això no impedirà que els actors dedicats busquin les teves publicacions i comptes públics.
@@ -966,6 +968,9 @@ ca:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: A causa de la manca d'activitat recent dels moderadors, les altes a %{instance} han passat automàticament a necessitar una revisió manual, per tal d'evitar que %{instance} es faci servir com a plataforma de potencials mals actuants. Podeu revertir-ho a altes obertes en qualsevol moment.
+      subject: Les altes a %{instance} han passat automàticament a necessitar aprovació
     new_appeal:
       actions:
         delete_statuses: eliminar els seus tuts
diff --git a/config/locales/ckb.yml b/config/locales/ckb.yml
index 7905024381..72a3c08d4d 100644
--- a/config/locales/ckb.yml
+++ b/config/locales/ckb.yml
@@ -521,11 +521,14 @@ ckb:
         all: بۆ هەموو کەسێک
         disabled: بۆ هیچ کەسێک
         users: بۆ چوونە ژوورەوەی بەکارهێنەرانی ناوخۆ
+      registrations:
+        moderation_recommandation: تکایە دڵنیابە پێش ئەوەی ناو تۆمارکردن بۆ هەمووان بکەیتەوە، تیمێکی میانڕەوی گونجاو و کاردانەوەتان هەیە!
       registrations_mode:
         modes:
           approved: پەسەندکردنی داواکراو بۆ ناوتۆمارکردن
           none: کەس ناتوانێت خۆی تۆمار بکات
           open: هەر کەسێک دەتوانێت خۆی تۆمار بکات
+        warning_hint: پێشنیار دەکەین "ڕەزامەندی پێویستە بۆ ناو تۆمارکردن" بەکاربهێنیت مەگەر دڵنیا بیت کە تیمی بەڕێوەبردنەکەت دەتوانێت لە کاتی خۆیدا مامەڵە لەگەڵ سپام و تۆمارکردنی زیانبەخشدا بکات.
     site_uploads:
       delete: سڕینەوەی فایلی بارکراو
       destroyed_msg: بارکردنی ماڵپەڕ بە سەرکەوتوویی سڕدراوەتەوە!
diff --git a/config/locales/cs.yml b/config/locales/cs.yml
index 0c85930a4f..e43f671590 100644
--- a/config/locales/cs.yml
+++ b/config/locales/cs.yml
@@ -795,13 +795,15 @@ cs:
         disabled: Nikomu
         users: Přihlášeným místním uživatelům
       registrations:
+        moderation_recommandation: Před otevřením registrací všem se ujistěte, že máte vhodný a reaktivní moderační tým!
         preamble: Mějte pod kontrolou, kdo může vytvořit účet na vašem serveru.
         title: Registrace
       registrations_mode:
         modes:
-          approved: Pro registraci je vyžadováno schválení
+          approved: Schválení požadované pro registraci
           none: Nikdo se nemůže registrovat
           open: Kdokoliv se může registrovat
+        warning_hint: Doporučujeme použít "Schválení požadované pro registraci", pokud si nejste jistí, že váš moderační tým dokáže včas zpracovat spam a škodlivé registrace.
       security:
         authorized_fetch: Vyžadovat autentizaci od federovaných serverů
         authorized_fetch_hint: Vyžadování ověřování pravosti od federalizovaných serverů umožňuje přísnější prosazování uživatelských i serverních bloků. K tomu však dochází k snížení výkonu, snižení dosah vašich odpovědí a můžou se zavést problémy s kompatibilitou s některými federálními službami. Kromě toho to nebude bránit oddaným uživatelům či robotům v načítání vašich veřejných příspěvků a účtů.
@@ -1002,6 +1004,9 @@ cs:
       title: Webhooky
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Kvůli nedostatku nedávných aktivit od moderátorů byly registrace na %{instance} automaticky přepnuty na vyžadující manuální kontrolu. aby se zabránilo použití %{instance} jako platformy pro potenciálně škodlivých hráčů. Můžete ji kdykoliv přepnout zpět na otevřené registrace.
+      subject: Registrace pro %{instance} byly automaticky přepnuty na vyžadující schválení
     new_appeal:
       actions:
         delete_statuses: smazání jeho příspěvků
diff --git a/config/locales/da.yml b/config/locales/da.yml
index 57899d5f71..43f4b64eef 100644
--- a/config/locales/da.yml
+++ b/config/locales/da.yml
@@ -767,6 +767,7 @@ da:
         disabled: Til ingen
         users: Til indloggede lokale brugere
       registrations:
+        moderation_recommandation: Sørg for, at der er et tilstrækkeligt og reaktivt moderationsteam, før registrering åbnes for alle!
         preamble: Styr, hvem der kan oprette en konto på serveren.
         title: Registreringer
       registrations_mode:
@@ -774,6 +775,7 @@ da:
           approved: Tilmeldingsgodkendelse kræves
           none: Ingen kan tilmelde sig
           open: Alle kan tilmelde sig
+        warning_hint: Brug af "Godkendelse kræves ved tilmelding" anbefales, medmindre man er sikker på, at moderationsteamet kan håndtere spam og ondsindede registreringer i tide.
       security:
         authorized_fetch: Kræver godkendelse fra fødererede servere
         authorized_fetch_hint: Krav om godkendelse fra fødererede servere muliggør strengere håndhævelse af både bruger- og serverniveaublokeringer. Omkostningen er dog en ydelsesreduktion, reduceret udstrækning af dine svar samt potentielle kompatibilitetsproblemer med visse fødererede tjenester. Derudover vil dette ikke hindre målrettede aktører i at hente dine offentlige indlæg og konti.
@@ -966,6 +968,9 @@ da:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Grundet manglende nylig moderatoraktivitet er registreringsproceduren på %{instance} automatisk ændret til at kræve manuel gennemgang for at forhindre, at %{instance} bruges som platform for potentielle dårlige aktører. Proceduren kan til enhver tid ændre igen til åbne registreringer.
+      subject: Registreringsproceduren for %{instance} er automatisk ændret til at kræve godkendelse
     new_appeal:
       actions:
         delete_statuses: for sletning af vedkommendes indlæg
diff --git a/config/locales/de.yml b/config/locales/de.yml
index 57ce5268a8..ae1af7b308 100644
--- a/config/locales/de.yml
+++ b/config/locales/de.yml
@@ -767,6 +767,7 @@ de:
         disabled: Niemandem
         users: Für angemeldete lokale Benutzer*innen
       registrations:
+        moderation_recommandation: Bitte vergewissere dich, dass du ein geeignetes und reaktionsschnelles Moderationsteam hast, bevor du die Registrierungen uneingeschränkt zulässt!
         preamble: Lege fest, wer auf deinem Server ein Konto erstellen darf.
         title: Registrierungen
       registrations_mode:
@@ -774,6 +775,7 @@ de:
           approved: Registrierung muss genehmigt werden
           none: Niemand darf sich registrieren
           open: Alle können sich registrieren
+        warning_hint: Wir empfehlen die Einstellung „Registrierung muss genehmigt werden“ zu verwenden, es sei denn, du bist dir sicher, dass dein Moderationsteam Spam und böswillige Registrierungen rechtzeitig bearbeiten kann.
       security:
         authorized_fetch: Authentisierung von föderierten Servern erforderlich machen
         authorized_fetch_hint: Das Anfordern einer Authentisierung von föderierten Servern ermöglicht ein strengeres Durchsetzen von Sperren sowohl auf Ebene der Benutzer*innen als auch des Servers. Allerdings ist das mit Leistungseinbußen verbunden, reduziert die Reichweite deiner Antworten und kann zu Kompatibilitätsproblemen mit einigen föderierten Diensten führen. Darüber hinaus wird das Abrufen deiner öffentlichen Beiträge und Konten durch spezialisierte Akteur*innen nicht verhindert.
@@ -966,6 +968,9 @@ de:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Aufgrund fehlender Aktivität von Moderator*innen müssen neue Registrierungen auf %{instance} jetzt manuell genehmigt werden. Dies wurde automatisch umgestellt, damit %{instance} nicht als Plattform für Böswillige missbraucht werden kann. Du kannst jederzeit auf uneingeschränkte Registrierungen zurückwechseln.
+      subject: Registrierungen auf %{instance} müssen ab jetzt manuell genehmigt werden (automatisch umgestellt)
     new_appeal:
       actions:
         delete_statuses: das Löschen der Beiträge
diff --git a/config/locales/devise.sv.yml b/config/locales/devise.sv.yml
index 6544f426bd..9300493fa0 100644
--- a/config/locales/devise.sv.yml
+++ b/config/locales/devise.sv.yml
@@ -77,6 +77,7 @@ sv:
         subject: 'Mastodon: Autentisering med säkerhetsnycklar är inaktiverat'
         title: Säkerhetsnycklar inaktiverade
       webauthn_enabled:
+        explanation: Autentisering med säkerhetsnyckel har aktiverats för ditt konto.
         extra: Din säkerhetsnyckel kan nu användas för inloggning.
         subject: 'Mastodon: Autentisering med säkerhetsnyckel är aktiverat'
         title: Säkerhetsnycklar aktiverade
diff --git a/config/locales/doorkeeper.eu.yml b/config/locales/doorkeeper.eu.yml
index 9886e034b0..e7963672fa 100644
--- a/config/locales/doorkeeper.eu.yml
+++ b/config/locales/doorkeeper.eu.yml
@@ -97,7 +97,7 @@ eu:
           unknown: Sarbide token-a baliogabea da
         resource_owner_authenticator_not_configured: Baliabidearen jabearen bilaketak huts egin du Doorkeeper.configure.resource_owner_authenticator konfiguratu gabe dagoelako.
         server_error: Autorizatze zerbitzariak eskaera betetzea eragotzi duen ustekabeko baldintza bat aurkitu du.
-        temporarily_unavailable: Autorizatze zerbitzariak ezin du orain eskaera bete  une batez zerbitzariak gainezka egin duelako edo mantentze lanetan dagoelako.
+        temporarily_unavailable: Baimen-zerbitzariak ezin du orain eskaera bete, une batez zerbitzariak gainezka egin duelako edo mantentze lanetan dagoelako.
         unauthorized_client: Bezeroak ez du eskaera hau metodo hau erabiliz egiteko baimenik.
         unsupported_grant_type: Autorizatze mota ez da onartzen autorizatze zerbitzarian.
         unsupported_response_type: Autorizatze zerbitzari honek ez du onartzen erantzun mota hau.
diff --git a/config/locales/en.yml b/config/locales/en.yml
index c73cdeb827..1e022e7e55 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -899,6 +899,7 @@ en:
         disabled: To no one
         users: To logged-in local users
       registrations:
+        moderation_recommandation: Please make sure you have an adequate and reactive moderation team before you open registrations to everyone!
         preamble: Control who can create an account on your server.
         title: Registrations
       registrations_mode:
@@ -906,6 +907,7 @@ en:
           approved: Approval required for sign up
           none: Nobody can sign up
           open: Anyone can sign up
+        warning_hint: We recommend using “Approval required for sign up” unless you are confident your moderation team can handle spam and malicious registrations in a timely fashion.
       security:
         authorized_fetch: Require authentication from federated servers
         authorized_fetch_hint: Requiring authentication from federated servers enables stricter enforcement of both user-level and server-level blocks. However, this comes at the cost of a performance penalty, reduces the reach of your replies, and may introduce compatibility issues with some federated services. In addition, this will not prevent dedicated actors from fetching your public posts and accounts.
diff --git a/config/locales/es-AR.yml b/config/locales/es-AR.yml
index d1dbdbf0b8..1db8e6ecf8 100644
--- a/config/locales/es-AR.yml
+++ b/config/locales/es-AR.yml
@@ -767,6 +767,7 @@ es-AR:
         disabled: A nadie
         users: A usuarios locales con sesiones abiertas
       registrations:
+        moderation_recommandation: Por favor, ¡asegurate de tener un equipo de moderación adecuado y reactivo antes de abrir los registros a todos!
         preamble: Controlá quién puede crear una cuenta en tu servidor.
         title: Registros
       registrations_mode:
@@ -774,6 +775,7 @@ es-AR:
           approved: Se requiere aprobación para registrarse
           none: Nadie puede registrarse
           open: Cualquiera puede registrarse
+        warning_hint: Recomendamos el uso de la opción “Se requiere aprobación para registrarse”, a menos que estés seguro de que tu equipo de moderación puede manejar el spam y los registros maliciosos de forma oportuna.
       security:
         authorized_fetch: Requiere autenticación de servidores federados
         authorized_fetch_hint: Requerir autenticación de servidores federados permite un cumplimiento más estricto tanto de los bloques de nivel de usuario como de nivel de servidor. Sin embargo, esto se produce a costa de una penalidad en el rendimiento, reduce el alcance de tus respuestas y puede introducir problemas de compatibilidad con algunos servicios federados. Además, esto no impedirá que actores dedicados obtengan tus mensajes y cuentas públicas.
@@ -966,6 +968,9 @@ es-AR:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Debido a la falta de actividad reciente por parte de moderadores, los registros en %{instance} fueron cambiados automáticamente para requerir revisión manual, para evitar que %{instance} se use como una plataforma para potenciales malos actores. Podés volver a cambiar esto para abrir los registros en cualquier momento.
+      subject: Los registros de %{instance} se cambiaron automáticamente para requerir aprobación
     new_appeal:
       actions:
         delete_statuses: para eliminar sus mensajes
diff --git a/config/locales/es-MX.yml b/config/locales/es-MX.yml
index a8b918a8fe..db5c05322b 100644
--- a/config/locales/es-MX.yml
+++ b/config/locales/es-MX.yml
@@ -767,6 +767,7 @@ es-MX:
         disabled: A nadie
         users: Para los usuarios locales que han iniciado sesión
       registrations:
+        moderation_recommandation: Por favor, ¡asegúrate de tener un equipo de moderación adecuado y reactivo antes de abrir los registros a todo el mundo!
         preamble: Controla quién puede crear una cuenta en tu servidor.
         title: Registros
       registrations_mode:
@@ -774,6 +775,7 @@ es-MX:
           approved: Se requiere aprobación para registrarse
           none: Nadie puede registrarse
           open: Cualquiera puede registrarse
+        warning_hint: Recomendamos el uso de “Se requiere aprobación para registrarse” a menos que estés seguro de que tu equipo de moderación puede manejar el spam y los registros maliciosos en un tiempo razonable.
       security:
         authorized_fetch: Requerir autenticación de servidores federados
         authorized_fetch_hint: Requerir autenticación de servidores federados permite un cumplimiento más estricto tanto de los bloqueos a nivel de usuario como a nivel de servidor. Sin embargo, esto se produce a costa de una penalización en el rendimiento, reduce el alcance de tus respuestas y puede introducir problemas de compatibilidad con algunos servicios federados. Además, esto no impedirá que actores dedicados obtengan tus cuentas y publicaciones públicas.
@@ -966,6 +968,9 @@ es-MX:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Debido a la falta de moderadores activos, los registros en %{instance} han sido cambiados automáticamente para requerir revisión manual, para evitar que %{instance} se utilice potencialmente como plataforma por malos actores. Puedes volver a cambiarlo para abrir los registros en cualquier momento.
+      subject: Se ha cambiado automáticamente el registro de %{instance} para requerir aprobación
     new_appeal:
       actions:
         delete_statuses: para eliminar sus mensajes
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 08fc0988e4..f5f65d9b1f 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -31,7 +31,7 @@ es:
       created_msg: "¡Nota de moderación creada con éxito!"
       destroyed_msg: "¡Nota de moderación destruida con éxito!"
     accounts:
-      add_email_domain_block: Poner en lista negra el dominio del correo
+      add_email_domain_block: Bloquear el dominio del correo
       approve: Aprobar
       approved_msg: La solicitud de registro de %{username} ha sido aprobada correctamente
       are_you_sure: "¿Estás seguro?"
@@ -767,6 +767,7 @@ es:
         disabled: A nadie
         users: Para los usuarios locales que han iniciado sesión
       registrations:
+        moderation_recommandation: Por favor, ¡asegúrate de tener un equipo de moderación adecuado y reactivo antes de abrir los registros a todo el mundo!
         preamble: Controla quién puede crear una cuenta en tu servidor.
         title: Registros
       registrations_mode:
@@ -774,6 +775,7 @@ es:
           approved: Se requiere aprobación para registrarse
           none: Nadie puede registrarse
           open: Cualquiera puede registrarse
+        warning_hint: Recomendamos el uso de “Se requiere aprobación para registrarse” a menos que estés seguro de que tu equipo de moderación puede manejar el spam y los registros maliciosos en un tiempo razonable.
       security:
         authorized_fetch: Requerir autenticación de servidores federados
         authorized_fetch_hint: Requerir autenticación de servidores federados permite un cumplimiento más estricto tanto de los bloqueos a nivel de usuario como a nivel de servidor. Sin embargo, esto se produce a costa de una penalización en el rendimiento, reduce el alcance de tus respuestas y puede introducir problemas de compatibilidad con algunos servicios federados. Además, esto no impedirá que actores dedicados obtengan tus cuentas y publicaciones públicas.
@@ -966,6 +968,9 @@ es:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Debido a la falta de moderadores activos, los registros en %{instance} han sido cambiados automáticamente para requerir revisión manual, para evitar que %{instance} se utilice potencialmente como plataforma por malos actores. Puedes volver a cambiarlo para abrir los registros en cualquier momento.
+      subject: Se ha cambiado automáticamente el registro de %{instance} para requerir aprobación
     new_appeal:
       actions:
         delete_statuses: para eliminar sus mensajes
diff --git a/config/locales/eu.yml b/config/locales/eu.yml
index 7acccea006..768a84b7c1 100644
--- a/config/locales/eu.yml
+++ b/config/locales/eu.yml
@@ -597,7 +597,7 @@ eu:
         silence_description_html: Kontua soilik honen jarraitzaile edo espresuki bilatzen dutenentzat izango da ikusgarri, kontuaren irisgarritasuna gogorki mugatzen delarik.
         suspend_description_html: Kontua bera eta honen edukiak eskuraezinak izango dira, eta azkenean, ezabatuak. Kontu honekin erlazionatzea ezinezkoa izango da. Prozesua 30 egunez itzulgarria izango da. Kontu honen aurkako txosten guztiak baztertuko lirateke.
       actions_description_html: Erabaki txosten hau konpontzeko ze ekintza hartu. Salatutako kontuaren aurka zigor ekintza bat hartzen baduzu, eposta jakinarazpen bat bidaliko zaie, <strong>Spam</strong> kategoria hautatzean ezik.
-      actions_description_remote_html: Txosten honi konponbidea aurkitzeko zein ekintza egin hautatu. Hau soilik <strong>zure</strong> zerbitzaria kontu honekin nola komunikatu eta bere edukia nola maneiatzeko da.
+      actions_description_remote_html: Hautatu txosten honi konponbidea aurkitzeko zein neurri hartu. Hau soilik <strong>zure</strong> zerbitzaria urruneko kontu honekin nola komunikatu eta bere edukia nola maneiatzeko da.
       add_to_report: Gehitu gehiago txostenera
       are_you_sure: Ziur zaude?
       assign_to_self: Esleitu niri
@@ -1847,7 +1847,7 @@ eu:
       explanation: Hona hasteko aholku batzuk
       final_action: Hasi bidalketak argitaratzen
       final_step: 'Hasi argitaratzen! Jarraitzailerik ez baduzu ere zure bidalketa publikoak besteek ikusi ditzakete, esaterako denbora-lerro lokalean eta traoletan. Zure burua aurkeztu nahi baduzu #aurkezpenak traola erabili zenezake.'
-      full_handle: Zure erabiltzaile-izen osoa
+      full_handle: Helbide osoa
       full_handle_hint: Hau da lagunei esango zeniekeena beste zerbitzari batetik zu jarraitzeko edo zuri mezuak bidaltzeko.
       subject: Ongi etorri Mastodon-era
       title: Ongi etorri, %{name}!
diff --git a/config/locales/fo.yml b/config/locales/fo.yml
index 10b1e76f5f..0e59783a06 100644
--- a/config/locales/fo.yml
+++ b/config/locales/fo.yml
@@ -966,6 +966,9 @@ fo:
       title: Webhooks/vevhúkar
       webhook: Webhook/vevhúkur
   admin_mailer:
+    auto_close_registrations:
+      body: Vegna avmarkað virksemi hjá umsjónarfólki eru skrásetingar á %{instance} broyttar sjálvvirkandi til at krevja manuella eftirkanning fyri at forða at %{instance} verður brúktur sum ein pallur fyri ringar aktørar. Tú kanst skifta aftur til opnar skrásetingar tá tú vilt.
+      subject: Skrásetingar á %{instance} eru sjálvvirkandi broyttar soleiðis at tær krevja váttan
     new_appeal:
       actions:
         delete_statuses: at strika teirra postar
diff --git a/config/locales/gl.yml b/config/locales/gl.yml
index 7b3fd1a6eb..705f0ef4e9 100644
--- a/config/locales/gl.yml
+++ b/config/locales/gl.yml
@@ -767,6 +767,7 @@ gl:
         disabled: Para ninguén
         users: Para usuarias locais conectadas
       registrations:
+        moderation_recommandation: Por favor, pon interese en crear un equipo de moderación competente e reactivo antes de permitir que calquera poida crear unha conta!
         preamble: Xestiona quen pode crear unha conta no teu servidor.
         title: Rexistros
       registrations_mode:
@@ -774,6 +775,7 @@ gl:
           approved: Precisa aprobación para rexistrarse
           none: Rexistro pechado
           open: Rexistro aberto
+        warning_hint: Recomendamos utilizar "Requerir aprobación para o rexistro" a menos que confíes en que o equipo de moderación é quen de xestionar áxilmente o spam e a creación de contas maliciosas.
       security:
         authorized_fetch: Require autenticación desde os servidores federados
         authorized_fetch_hint: Ao requerir autenticación desde os servidores federados activas un reforzamento das políticas de bloqueo a nivel usuaria e nivel servidor. Este proceder ten un custo no rendemento, reducindo o alcance das túas respostas e podería introducir problemas de compatibilidade con algúns servizos federados. Ademais, non evitará que contas con tal propósito vexan as túas publicacións públicas e contas.
@@ -966,6 +968,9 @@ gl:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Debido á falta de actividade recente de moderación, a creación de contas en %{instance} mudou ao modo de revisión manual das solicitudes, para evitar que %{instance} sexa usada como plataforma por actores maliciosos. Podes volver ao rexistro aberto en calquera momento.
+      subject: O modo de creación de contas en %{instance} mudou automáticamente a aprobación manual
     new_appeal:
       actions:
         delete_statuses: borrar as súas publicacións
diff --git a/config/locales/he.yml b/config/locales/he.yml
index 05b52213a7..fc57f9fd58 100644
--- a/config/locales/he.yml
+++ b/config/locales/he.yml
@@ -1002,6 +1002,9 @@ he:
       title: התליות רשת
       webhook: התליית רשת
   admin_mailer:
+    auto_close_registrations:
+      body: עקב חוסר פעילות מנחים, הרשמות אל %{instance} עברו אוטומטית למצב אישור ידני, כדי למנוע משרת %{instance} לשמש לכר פעילות לגורמים עוינים. ניתן תמיד לחזור להרשמה פתוחה.
+      subject: הרשמות אל %{instance} הועברו אוטומטית לדרישה לאישור ידני
     new_appeal:
       actions:
         delete_statuses: כדי למחוק את הודעותיהם
diff --git a/config/locales/hu.yml b/config/locales/hu.yml
index 34ae9a21c8..b902d0e6c2 100644
--- a/config/locales/hu.yml
+++ b/config/locales/hu.yml
@@ -767,6 +767,7 @@ hu:
         disabled: Senkinek
         users: Bejelentkezett helyi felhasználóknak
       registrations:
+        moderation_recommandation: Győződjünk meg arról, hogy megfelelő és reaktív moderátor csapatunk van, mielőtt mindenki számára megnyitjuk a regisztrációt!
         preamble: Szabályozd, hogy ki hozhat létre fiókot a kiszolgálón.
         title: Regisztrációk
       registrations_mode:
@@ -774,6 +775,7 @@ hu:
           approved: A regisztráció engedélyhez kötött
           none: Senki sem regisztrálhat
           open: Bárki regisztrálhat
+        warning_hint: Célszerű a "Jóváhagyás szükséges a regisztrációhoz” lehetőség használata, hkivéve, ha biztos vagyunk abban, hogy a moderátor csapat időben tudja kezelni a szemetet és a rosszindulatú regisztrációkat.
       security:
         authorized_fetch: Hitelesítés szükséges a föderációs kiszolgálóktól
         authorized_fetch_hint: A föderációs szerverek hitelesítésének szükségessége lehetővé teszi mind a felhasználói mind a szerver szintű blokkok szigorúbb végrehajtását. Ez azonban a teljesítménybüntetés árán jár, csökkenti a válaszok elérhetőségét és kompatibilitási problémákat vethet fel egyes föderációs szolgáltatásokkal. Emellett ez nem akadályozza meg a dedikált szereplőket abban, hogy nyilvános bejegyzéseiket és fiókjaikat letöltsék.
@@ -966,6 +968,9 @@ hu:
       title: Webhookok
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: A közelmúlt moderátori tevékenységének hiánya miatt a %{instance} regisztrációja automatikusan kézi ellenőrzést igénylőre váltott azért, hogy megakadályozzuk, hogy a %{instance} potenciálisan rossz szándékú szereplők számára szolgálhasson platformként. A nyílt regisztrációt bármikor visszakapcsolhatod.
+      subject: "%{instance} regisztrációja automatikusan átállt jóváhagyást igénylőre"
     new_appeal:
       actions:
         delete_statuses: bejegyzések törléséről
diff --git a/config/locales/it.yml b/config/locales/it.yml
index 31de2252d1..a0f1ab7697 100644
--- a/config/locales/it.yml
+++ b/config/locales/it.yml
@@ -767,6 +767,7 @@ it:
         disabled: A nessuno
         users: Agli utenti locali connessi
       registrations:
+        moderation_recommandation: Assicurati di avere un team di moderazione adeguato e reattivo prima di aprire le registrazioni a tutti!
         preamble: Controlla chi può creare un account sul tuo server.
         title: Registrazioni
       registrations_mode:
@@ -774,6 +775,7 @@ it:
           approved: Approvazione richiesta per le iscrizioni
           none: Nessuno può iscriversi
           open: Chiunque può iscriversi
+        warning_hint: Ti consigliamo di utilizzare “Approvazione richiesta per la registrazione” a meno che tu non sia sicuro che il tuo team di moderazione possa gestire lo spam e le registrazioni dannose in modo tempestivo.
       security:
         authorized_fetch: Richiede l'autenticazione dai server federati
         authorized_fetch_hint: La richiesta di autenticazione da server federati consente un'applicazione più rigorosa dei blocchi sia a livello di utente che a livello di server. Tuttavia, ciò comporta una riduzione delle prestazioni, riduce la portata delle tue risposte e potrebbe introdurre problemi di compatibilità con alcuni servizi federati. Inoltre, ciò non impedirà agli attori dedicati di recuperare i tuoi post pubblici e account.
@@ -966,6 +968,9 @@ it:
       title: Webhook
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: A causa della mancanza di attività recente da parte dei moderatori, le registrazioni su %{instance} sono passate automaticamente alla richiesta di revisione manuale, per evitare che %{instance} venga utilizzata come piattaforma per potenziali malintenzionati. Puoi ripristinarlo per aprire le registrazioni in qualsiasi momento.
+      subject: Le registrazioni per %{instance} sono passate automaticamente alla richiesta di approvazione
     new_appeal:
       actions:
         delete_statuses: per cancellare i loro post
diff --git a/config/locales/ja.yml b/config/locales/ja.yml
index e11eb52ce7..30465716db 100644
--- a/config/locales/ja.yml
+++ b/config/locales/ja.yml
@@ -890,6 +890,7 @@ ja:
         disabled: 誰にも許可しない
         users: ログイン済みローカルユーザーのみ許可
       registrations:
+        moderation_recommandation: 登録受付を開始する前に、迅速かつ適切にモデレーションを行うチームを編成しましょう!
         preamble: あなたのサーバー上でアカウントを作成できるユーザーを制御します。
         title: アカウント作成
       registrations_mode:
@@ -897,6 +898,7 @@ ja:
           approved: 登録には承認が必要
           none: 誰にも許可しない
           open: 誰でも登録可
+        warning_hint: モデレーションチームがスパムや悪意のある登録を迅速に処理できる自信がない限り、サインアップを承認制にすることをお勧めします。
       security:
         authorized_fetch: 連合サーバーによる署名なしでの情報取得を拒否する
         authorized_fetch_hint: ほかの連合サーバーから受け付けるリクエストに署名を必須にすることで、ユーザーによるブロックおよびドメインブロック両方の効果をより強力にします。ただし連合の処理コストが増えてパフォーマンス面で不利になるほか、このサーバーから送られた反応が届く範囲が狭まったり、連合における互換性の問題を招く可能性もあります。また、この機能は公開投稿やプロフィールへのアクセスをブロックした相手から完全に遮断できるものではありません。
@@ -1099,6 +1101,9 @@ ja:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: "%{instance} のモデレーターによる活動がしばらくなかったため、%{instance} のアカウント作成は手動での承認を必要とするように自動的に変更されました。これには %{instance} が悪意ある者の踏み台として使われることを防ぐ役割があります。アカウント作成は必要に応じていつでも再び開放できます。"
+      subject: "%{instance} のアカウント作成は自動的に承認制に変更されました"
     new_appeal:
       actions:
         delete_statuses: 投稿を削除する
diff --git a/config/locales/kab.yml b/config/locales/kab.yml
index bd73b4ce0f..f50a357608 100644
--- a/config/locales/kab.yml
+++ b/config/locales/kab.yml
@@ -589,11 +589,13 @@ kab:
       '604800': 1 umalas
       '86400': 1 wass
     expires_in_prompt: Werǧin
+    generate: Slaled aseɣwen n uɛraḍ
     invited_by: 'Tettwaɛraḍeḍ s ɣur:'
     max_uses:
       one: 1 uuseqdec
       other: "%{count} yiseqdac"
     max_uses_prompt: Ulac talast
+    prompt: Slaled rnu bḍu assaɣen d wiyaḍ akken ad kecmen ɣer uqeddac-a
     table:
       expires_at: Ad ifat di
     title: Ɛreḍ-d kra n yimdanen
diff --git a/config/locales/nl.yml b/config/locales/nl.yml
index ea811400a6..4392c2366e 100644
--- a/config/locales/nl.yml
+++ b/config/locales/nl.yml
@@ -767,6 +767,7 @@ nl:
         disabled: Aan niemand
         users: Aan ingelogde lokale gebruikers
       registrations:
+        moderation_recommandation: Zorg ervoor dat je een adequaat en responsief moderatieteam hebt voordat je registraties voor iedereen openstelt!
         preamble: Toezicht houden op wie een account op deze server kan registreren.
         title: Registraties
       registrations_mode:
@@ -774,6 +775,7 @@ nl:
           approved: Goedkeuring vereist om te kunnen registreren
           none: Niemand kan zich registreren
           open: Iedereen kan zich registreren
+        warning_hint: We raden je aan om “Goedkeuring vereist om te kunnen registreren” te gebruiken, tenzij je er zeker van bent dat jouw moderatieteam spam en kwaadwillende registraties tijdig kan afhandelen.
       security:
         authorized_fetch: Verificatie van gefedeerde servers vereisen
         authorized_fetch_hint: Verificatie vereisen van gefedereerde servers maakt een striktere handhaving van blokkades op gebruikersniveau en serverniveau mogelijk. Dit gaat echter ten koste van de prestaties, vermindert het bereik van je reacties en kan compatibiliteitsproblemen met sommige gefedereerde services opleveren. Bovendien zal dit niet voorkomen dat personen met slechte bedoelingen je openbare berichten en accounts kunnen ophalen.
@@ -966,6 +968,9 @@ nl:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: In verband met een gebrek aan recentelijke moderator-activiteit, is de registratie-modus op %{instance} automatisch veranderd naar handmatige beoordeling door moderatoren. Dit om te voorkomen dat %{instance} als platform voor eventueel misbruik kan worden gebruikt. Je kunt op elk gewenst moment veel terugschakelen naar open registraties.
+      subject: De registratie-modus op %{instance} is automatisch veranderd naar handmatige beoordeling door moderatoren
     new_appeal:
       actions:
         delete_statuses: het verwijderen van diens berichten
diff --git a/config/locales/nn.yml b/config/locales/nn.yml
index ffa5198a3a..b1ae928997 100644
--- a/config/locales/nn.yml
+++ b/config/locales/nn.yml
@@ -966,6 +966,9 @@ nn:
       title: Webhooker
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: På grunn av mangel på nyleg moderatoraktivitet, er registreringar på %{instance} automatisk bytt til å krevje manuell gjennomgang, for å hindre at %{instance} vert brukt som ein plattform for potensielle dårlege aktørar. Du kan byte tilbake for å opne registreringar når som helst.
+      subject: Registreringar for %{instance} er automatisk bytt til å krevje godkjenning
     new_appeal:
       actions:
         delete_statuses: å slette sine innlegg
diff --git a/config/locales/pl.yml b/config/locales/pl.yml
index 5bc78a6adf..f0e6a1f60b 100644
--- a/config/locales/pl.yml
+++ b/config/locales/pl.yml
@@ -795,6 +795,7 @@ pl:
         disabled: Nikomu
         users: Zalogowanym lokalnym użytkownikom
       registrations:
+        moderation_recommandation: Upewnij się, że masz adekwatny i szybko reagujący zespół moderacyjny przed otwarciem rejestracji!
         preamble: Kontroluj, kto może utworzyć konto na Twoim serwerze.
         title: Rejestracje
       registrations_mode:
@@ -802,6 +803,7 @@ pl:
           approved: Przyjęcie jest wymagane do rejestracji
           none: Nikt nie może się zarejestrować
           open: Każdy może się zarejestrować
+        warning_hint: Polecamy "Przyjęcie jest wymagane do rejestracji" chyba że masz pewność, że twój zespół moderacyjny może szybko obsłużyć spam i złośliwe rejestracje.
       security:
         authorized_fetch: Wymagaj uwierzytelnienia od sfederowanych serwerów
         authorized_fetch_hint: Wymaganie uwierzytelnienia ze sfederowanych serwerów pozwala na ściślejsze wymuszanie bloków z poziomu użytkowników i serwera, ale jest wolniejsze, redukuje zasięg odpowiedzi, i może być niekompatybilne z niektórymi sfederowanymi usługami. Nie chroni również publicznych kont i wpisów przed oddanymi użytkownikami.
@@ -1002,6 +1004,9 @@ pl:
       title: Webhooki
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Z powodu braku niedawnych działań moderacyjnych, rejestracje na %{instance} wymagają ręcznej weryfikacji (by uniknąć dystrybucji spamu itp.). W dowolnym momencie możesz przywrócić politykę otwartej rejestracji.
+      subject: "%{instance} zostało automatycznie przełączone na zatwierdzanie rejestracji"
     new_appeal:
       actions:
         delete_statuses: aby usunąć ich wpisy
diff --git a/config/locales/pt-PT.yml b/config/locales/pt-PT.yml
index 8a20bc68a1..0ebb032ff9 100644
--- a/config/locales/pt-PT.yml
+++ b/config/locales/pt-PT.yml
@@ -767,6 +767,7 @@ pt-PT:
         disabled: Para ninguém
         users: Para utilizadores locais que se encontrem autenticados
       registrations:
+        moderation_recommandation: Por favor, certifique-se de que você tem uma equipe de moderação adequada e reativa antes de abrir os registros para todos!
         preamble: Controle quem pode criar uma conta no seu servidor.
         title: Inscrições
       registrations_mode:
@@ -774,6 +775,7 @@ pt-PT:
           approved: Registo sujeito a aprovação
           none: Ninguém se pode registar
           open: Qualquer pessoa se pode registar
+        warning_hint: Recomendamos o uso de "Aprovação necessária para se cadastrar", a menos que você esteja confiante de que sua equipe de moderação pode lidar com spam e registros maliciosos em tempo hábil.
       security:
         authorized_fetch: Exigir autenticação de servidores federados
         authorized_fetch_hint: Exigir autenticação de servidores federados permite uma aplicação mais rigorosa de bloqueios tanto ao nível do utilizador como do servidor. No entanto, isso é feito à custa de uma diminuição de desempenho, reduz o alcance das suas respostas e pode introduzir problemas de compatibilidade com alguns serviços federados. Além disso, isso não impede os atores mais empenhados de aceder às suas publicações e contas públicas.
diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml
index b84893083c..8fdb6664af 100644
--- a/config/locales/simple_form.en.yml
+++ b/config/locales/simple_form.en.yml
@@ -39,7 +39,7 @@ en:
         text: You can only appeal a strike once
       defaults:
         autofollow: People who sign up through the invite will automatically follow you
-        avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
+        avatar: WEBP, PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
         bot: Signal to others that the account mainly performs automated actions and might not be monitored
         context: One or multiple contexts where the filter should apply
         current_password: For security purposes please enter the password of the current account
@@ -48,9 +48,7 @@ en:
         discoverable: Allow your account to be discovered by strangers through recommendations, trends and other features
         discoverable_local: Disable the setting on federated servers. The setting is available this server only for avoiding full-text search on other servers
         email: You will be sent a confirmation e-mail
-        group: Reps sent to this account will be automatically BT'd and distributed to all accounts you follow!
-        group_allow_private_message: Posts are duplicated and cannot be edited or deleted by the post
-        header: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
+        header: WEBP, PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
         inbox_url: Copy the URL from the frontpage of the relay you want to use
         irreversible: Filtered posts will disappear irreversibly, even if filter is later removed
         locale: The language of the user interface, e-mails and push notifications
@@ -220,7 +218,6 @@ en:
         expires_in: Expire after
         fields: Extra fields
         group: This is a group account
-        group_allow_private_message: For group accounts, duplicate private or direct message
         header: Header picture
         honeypot: "%{label} (do not fill in)"
         inbox_url: URL of the relay inbox
diff --git a/config/locales/simple_form.ja.yml b/config/locales/simple_form.ja.yml
index d600088ff1..9d275354f4 100644
--- a/config/locales/simple_form.ja.yml
+++ b/config/locales/simple_form.ja.yml
@@ -50,8 +50,6 @@ ja:
         discoverable: レコメンド、トレンド、その他の機能により、あなたのアカウントを他の人から見つけられるようにします。なおkmyblueのローカルユーザーはこの設定をオンにしても全文検索結果には掲載されません。全文検索結果への掲載には、投稿の検索許可設定を変更する必要があります
         discoverable_local: 上記設定を当サーバー内でのみ適用するようにします。他のサーバーの全文検索結果への掲載を回避できますが、レコメンド、トレンドなどその他の機能への掲載も回避されます
         email: 確認のメールが送信されます
-        group: このアカウントに送られたメンションは自動でBTされ、フォローしている全てのアカウントに配信されます
-        group_allow_private_message: 投稿は複製されるため、投稿者が編集・削除することはできません
         header: '%{size}までのPNG、GIF、JPGが利用可能です。 %{dimensions}pxまで縮小されます'
         inbox_url: 使用したいリレーサーバーのトップページからURLをコピーします
         irreversible: フィルターが後で削除されても、除外された投稿は元に戻せなくなります
@@ -231,7 +229,6 @@ ja:
         expires_in: 有効期限
         fields: プロフィール補足情報
         group: これはグループアカウントです
-        group_allow_private_message: グループアカウントの場合、フォロワーのみ・ダイレクトのメンションを複製する
         header: ヘッダー
         honeypot: "%{label} (入力しない)"
         inbox_url: リレーサーバーの inbox URL
diff --git a/config/locales/simple_form.kab.yml b/config/locales/simple_form.kab.yml
index 546336660c..c7370aedf6 100644
--- a/config/locales/simple_form.kab.yml
+++ b/config/locales/simple_form.kab.yml
@@ -55,6 +55,7 @@ kab:
         data: Isefka
         display_name: Isem ara d-yettwaskanen
         email: Tansa imayl
+        expires_in: Ad yemmet
         header: Ixef
         locale: Tutlayt n wegrudem
         max_uses: Amḍan afellay n iseqdacen
diff --git a/config/locales/sk.yml b/config/locales/sk.yml
index 90f8144ea8..66022b10ae 100644
--- a/config/locales/sk.yml
+++ b/config/locales/sk.yml
@@ -634,6 +634,7 @@ sk:
           approved: Pre registráciu je nutné povolenie
           none: Nikto sa nemôže registrovať
           open: Ktokoľvek sa môže zaregistrovať
+        warning_hint: Odporúčame používať "Pre registráciu je potrebné schválenie", pokiaľ si niesi istý/á, že tvoj moderovací tím vie zvládnuť spam a záškodné registrácie včas.
       title: Nastavenia servera
     site_uploads:
       delete: Vymaž nahratý súbor
@@ -739,6 +740,8 @@ sk:
       enabled: Aktívne
       status: Stav
   admin_mailer:
+    auto_close_registrations:
+      subject: Registrácie na %{instance} boli automaticky prepnuté na vyžadujúce schválenie
     new_appeal:
       actions:
         none: varovanie
diff --git a/config/locales/sl.yml b/config/locales/sl.yml
index 54a4da3ea2..915970f805 100644
--- a/config/locales/sl.yml
+++ b/config/locales/sl.yml
@@ -795,6 +795,7 @@ sl:
         disabled: Nikomur
         users: Prijavljenim krajevnim uporabnikom
       registrations:
+        moderation_recommandation: Preden prijave odprete za vse poskrbite, da imate v ekipi moderatorjev zadosti aktivnih članov.
         preamble: Nadzirajte, kdo lahko ustvari račun na vašem strežniku.
         title: Registracije
       registrations_mode:
@@ -802,6 +803,7 @@ sl:
           approved: Potrebna je odobritev za prijavo
           none: Nihče se ne more prijaviti
           open: Vsakdo se lahko prijavi
+        warning_hint: Priporočamo uporabo možnosti »Potrebna je odobritev za prijavo«, razen če ste gotovi, da se bo vaša ekipa moderatorjev res zmožna hitro odzvati na neželene vsebine in škodoželjne prijave.
       security:
         authorized_fetch: Od drugih strežnikov v federaciji zahtevaj overitev pristnosti
         authorized_fetch_hint: Zahtevanje overitve pristnosti od drugih strežnikov v federaciji omogoči strožje uveljavljanje uporabniških in strežniških blokad. Vendar je cena za to počasnejše delovanje, zmanjšanje dosega vaših odgovorov in morebitne težave z združljivostjo z nekaterimi storitvami v federaciji. Poleg tega to odločenim akterjem ne bo preprečilo pridobivanja vaših javnih objav in računov.
@@ -1002,6 +1004,9 @@ sl:
       title: Spletne zanke
       webhook: Spletna zanka
   admin_mailer:
+    auto_close_registrations:
+      body: Zaradi pomanjkanja moderiranja v zadnjem času, se je za strežnik %{instance} samodejno vklopilo ročno preverjanje in potrjevanje prijav. S tem se prepreči morebitno zlorabo strežnika %{instance}. Prijave lahko kadarkoli spet spremenite nazaj v odprte.
+      subject: Za strežnik %{instance} se je samodejno vklopilo ročno potrjevanje prijav
     new_appeal:
       actions:
         delete_statuses: brisanje njihovih objav,
diff --git a/config/locales/sq.yml b/config/locales/sq.yml
index 460fd82dc0..da82dda9cb 100644
--- a/config/locales/sq.yml
+++ b/config/locales/sq.yml
@@ -962,6 +962,9 @@ sq:
       title: Webhook-ë
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Për shkak mungese veprimtarie moderatori së fundi, regjistrimet te %{instance} janë kaluar automatikisht të kërkojnë shqyrtim dorazi, për të penguar përdorimin e %{instance} si një platformë për aktorë të këqij. Mund të kaloni kurdo te regjistrime të hapura.
+      subject: Regjistrimet te %{instance} janë kaluar automatikisht të kërkojnë miratim
     new_appeal:
       actions:
         delete_statuses: fshirje e postimeve të tij
diff --git a/config/locales/tr.yml b/config/locales/tr.yml
index 2b605e5073..f6e00ba520 100644
--- a/config/locales/tr.yml
+++ b/config/locales/tr.yml
@@ -767,6 +767,7 @@ tr:
         disabled: Hiç kimseye
         users: Oturum açan yerel kullanıcılara
       registrations:
+        moderation_recommandation: Lütfen kayıtları herkese açmadan önce yeterli ve duyarlı bir denetleyici ekibine sahip olduğunuzdan emin olun!
         preamble: Sunucunuzda kimin hesap oluşturabileceğini denetleyin.
         title: Kayıtlar
       registrations_mode:
@@ -774,6 +775,7 @@ tr:
           approved: Kayıt için onay gerekli
           none: Hiç kimse kayıt olamaz
           open: Herkes kaydolabilir
+        warning_hint: Denetleyici ekibinizin istenmeyen ve kötü niyetli kayıtları ele alabilecekleri konusunda emin değilseniz "Kayıt için onay gerekli" seçeneğini kullanmanızı öneririz.
       security:
         authorized_fetch: Dağıtık sunuculardan kimlik doğrulama gerektir
         authorized_fetch_hint: Dağıtık sunuculardan kimlik doğrulaması istemek, hem kullanıcı düzeyinde hem de sunucu düzeyinde blokların daha sıkı bir şekilde uygulanmasını sağlar. Ancak bu performans kaybına sebep olur, yanıtlarınızın erişimini azaltır ve bazı dağıtık hizmetlerle uyumluluk sorunları ortaya çıkarabilir. Ayrıca bu, özel aktörlerin herkese açık gönderilerinizi ve hesaplarınızı getirilmesini engellemez.
@@ -966,6 +968,9 @@ tr:
       title: Web kancaları
       webhook: Web kancası
   admin_mailer:
+    auto_close_registrations:
+      body: Son zamanlardaki denetleyi faaliyeti eksikliğinden dolayı, %{instance} üzerindeki kayıtlar, %{instance} sunucusunun olası kötü aktörler tarafından bir platform olarak kullanımını engellemek için otomatik olarak elle onay gerektirecek şekilde değiştirilmiştir. İstediğiniz zaman açık kayıtlara çevirebilirsiniz.
+      subject: "%{instance} üzerindeki kayıtlar otomatik olarak onay gerektirecek şekilde değiştirilmiştir"
     new_appeal:
       actions:
         delete_statuses: gönderilerini silme
diff --git a/config/locales/uk.yml b/config/locales/uk.yml
index 237305c0e9..4d4097d658 100644
--- a/config/locales/uk.yml
+++ b/config/locales/uk.yml
@@ -795,6 +795,7 @@ uk:
         disabled: Нікого
         users: Для авторизованих локальних користувачів
       registrations:
+        moderation_recommandation: Переконайтеся, що у вас є адекватна і швидка команда модерації, перш ніж ви відкриєте реєстрацію для всіх!
         preamble: Контролюйте, хто може створити обліковий запис на вашому сервері.
         title: Реєстрації
       registrations_mode:
@@ -802,6 +803,7 @@ uk:
           approved: Для входу потрібне схвалення
           none: Ніхто не може увійти
           open: Будь-хто може увійти
+        warning_hint: Радимо використовувати "Обов'язкове затвердження", якщо ви не впевнені, що ваша команда модерації може вчасно обробляти спам та зловмисні реєстрації.
       security:
         authorized_fetch: Вимагати аутентифікацію з федеративних серверів
         authorized_fetch_hint: Вимога автентифікації від федеративних серверів забезпечує суворіше застосування блокування як на рівні користувача, так і на рівні сервера. Однак це призводить до зниження продуктивності, зменшує охоплення ваших відповідей і може спричинити проблеми сумісності з деякими федеративними сервісами. Крім того, це не завадить зловмисникам отримувати ваші загальнодоступні дописи та облікові записи.
@@ -1002,6 +1004,9 @@ uk:
       title: Вебхуки
       webhook: Вебхук
   admin_mailer:
+    auto_close_registrations:
+      body: Через нестачу нещодавньої активності модератора реєстрація на %{instance} автоматично перемкнута на обов'язковий розгляд вручну, для запобігання використанню %{instance} платформою для потенційних зловмисників. Ви можете будь-коли перемкнутися на відкриту реєстрацію.
+      subject: Реєстрації для %{instance} автоматично перейшли на такі, що вимагають схвалення
     new_appeal:
       actions:
         delete_statuses: щоб видалити їхні дописи
diff --git a/config/locales/vi.yml b/config/locales/vi.yml
index 045a000e38..99434c3544 100644
--- a/config/locales/vi.yml
+++ b/config/locales/vi.yml
@@ -948,6 +948,9 @@ vi:
       title: Webhook
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: Do gần đây thiếu kiểm duyệt viên nên việc đăng ký trên %{instance} sẽ tự động chuyển thành duyệt thủ công, để tránh %{instance} bị sử dụng làm nền tảng cho những kẻ xấu. Bạn có thể chuyển nó trở lại trạng thái đăng ký mở bất kỳ lúc nào.
+      subject: Đăng ký mới %{instance} đã được tự động chuyển sang duyệt thủ công
     new_appeal:
       actions:
         delete_statuses: xóa tút của họ
diff --git a/config/locales/zh-CN.yml b/config/locales/zh-CN.yml
index 8ccf4c08b3..cf56a2d227 100644
--- a/config/locales/zh-CN.yml
+++ b/config/locales/zh-CN.yml
@@ -753,6 +753,7 @@ zh-CN:
         disabled: 不对任何人
         users: 对本地已登录用户
       registrations:
+        moderation_recommandation: 在向所有人开放注册之前,请确保您拥有一个人手足够且反应迅速的管理团队!
         preamble: 控制谁可以在你的服务器上创建账号。
         title: 注册
       registrations_mode:
@@ -760,6 +761,7 @@ zh-CN:
           approved: 注册时需要批准
           none: 关闭注册
           open: 开放注册
+        warning_hint: 我们建议使用“注册必须经过批准”,除非您确信您的管理团队能够及时处理骚扰和恶意注册。
       security:
         authorized_fetch: 需要跨站认证
         authorized_fetch_hint: 要求外站请求通过验证能够使用户级别与服务器级别的封锁更为严格。然而,这将带来额外的性能负担、减少回复触达范围、并可能导致与一些联邦宇宙服务的兼容性问题。此外,这并不能阻止他人针对性地获取公开嘟文与账户。
@@ -948,6 +950,9 @@ zh-CN:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: 由于近期缺乏管理员活动, %{instance} 上的注册已自动切换为需要手动审核,以防止 %{instance} 被潜在的不良行为者用作平台。您可以随时将其切换回开放注册。
+      subject: "%{instance} 的注册已自动切换为需要批准"
     new_appeal:
       actions:
         delete_statuses: 删除其嘟文
diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml
index 9e8044ebfc..bc8454884c 100644
--- a/config/locales/zh-TW.yml
+++ b/config/locales/zh-TW.yml
@@ -755,6 +755,7 @@ zh-TW:
         disabled: 給沒有人
         users: 套用至所有登入的本站使用者
       registrations:
+        moderation_recommandation: 對所有人開放註冊之前,請確保您有人手充足且反應靈敏的管理員團隊!
         preamble: 控制誰能於您伺服器上建立帳號。
         title: 註冊
       registrations_mode:
@@ -762,6 +763,7 @@ zh-TW:
           approved: 註冊需要審核
           none: 沒有人可註冊
           open: 任何人皆能註冊
+        warning_hint: 建議您使用「需要審核註冊」除非您相信您的管理員團隊能即時處理垃圾訊息與惡意帳號註冊。
       security:
         authorized_fetch: 要求自聯邦宇宙伺服器之驗證
         authorized_fetch_hint: 要求聯邦宇宙伺服器進行驗證將更嚴格地執行使用者層級及伺服器層級之封鎖。然而,這將會帶來一些性能損失、減少您的回嘟觸及量、並可能會引入與某些聯邦宇宙伺服器之相容性問題。 此外,這無法阻止專門服務抓取您的公開嘟文及帳號資料。
@@ -950,6 +952,9 @@ zh-TW:
       title: Webhooks
       webhook: Webhook
   admin_mailer:
+    auto_close_registrations:
+      body: 由於近日缺少管理員活動,%{instance} 上之註冊已自動切換為需要人工審核,以防止 %{instance} 被作為潛在不良行為者之跳板。您隨時能將其切換回開放註冊。
+      subject: "%{instance} 之註冊已自動切換為需要審核"
     new_appeal:
       actions:
         delete_statuses: 要刪除他們的嘟文
diff --git a/config/settings.yml b/config/settings.yml
index 21b7839a4d..b58b4bb966 100644
--- a/config/settings.yml
+++ b/config/settings.yml
@@ -9,7 +9,7 @@ defaults: &defaults
   site_terms: ''
   site_contact_username: ''
   site_contact_email: ''
-  registrations_mode: 'open'
+  registrations_mode: 'none'
   registrations_limit: 0
   registrations_limit_per_day: 0
   registrations_start_hour: 0
diff --git a/lib/tasks/mastodon.rake b/lib/tasks/mastodon.rake
index 7d5cfcf1c9..d64e783188 100644
--- a/lib/tasks/mastodon.rake
+++ b/lib/tasks/mastodon.rake
@@ -544,6 +544,7 @@ namespace :mastodon do
           owner_role = UserRole.find_by(name: 'Owner')
           user = User.new(email: email, password: password, confirmed_at: Time.now.utc, account_attributes: { username: username }, bypass_invite_request_check: true, role: owner_role)
           user.save(validate: false)
+          user.approve!
 
           Setting.site_contact_username = username
 
diff --git a/package.json b/package.json
index c873066a5c..24a28f9d20 100644
--- a/package.json
+++ b/package.json
@@ -31,7 +31,7 @@
     "lint:yml": "prettier --check \"**/*.{yaml,yml}\"",
     "lint": "yarn lint:js && yarn lint:json && yarn lint:sass && yarn lint:yml",
     "postversion": "git push --tags",
-    "prepare": "husky install",
+    "prepare": "husky",
     "start": "node ./streaming/index.js",
     "test": "yarn lint && yarn run typecheck && yarn jest",
     "typecheck": "tsc --noEmit"
@@ -54,7 +54,7 @@
     "@gamestdio/websocket": "^0.3.2",
     "@github/webauthn-json": "^2.1.1",
     "@hello-pangea/dnd": "^16.3.0",
-    "@rails/ujs": "^7.1.1",
+    "@rails/ujs": "7.1.3-2",
     "@reduxjs/toolkit": "^2.0.1",
     "@svgr/webpack": "^5.5.0",
     "arrow-key-navigation": "^1.2.0",
@@ -193,7 +193,7 @@
     "eslint-plugin-promise": "~6.1.1",
     "eslint-plugin-react": "^7.33.2",
     "eslint-plugin-react-hooks": "^4.6.0",
-    "husky": "^8.0.3",
+    "husky": "^9.0.11",
     "jest": "^29.5.0",
     "jest-environment-jsdom": "^29.5.0",
     "lint-staged": "^15.0.0",
diff --git a/spec/services/activitypub/process_account_service_spec.rb b/spec/services/activitypub/process_account_service_spec.rb
index 37817f204a..f26bec6f7e 100644
--- a/spec/services/activitypub/process_account_service_spec.rb
+++ b/spec/services/activitypub/process_account_service_spec.rb
@@ -325,7 +325,7 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
     end
   end
 
-  context 'with property values' do
+  context 'with property values, an avatar, and a profile header' do
     let(:payload) do
       {
         id: 'https://foo.test',
@@ -336,14 +336,30 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
           { type: 'PropertyValue', name: 'Occupation', value: 'Unit test' },
           { type: 'PropertyValue', name: 'non-string', value: %w(foo bar) },
         ],
+        image: {
+          type: 'Image',
+          mediaType: 'image/png',
+          url: 'https://foo.test/image.png',
+        },
+        icon: {
+          type: 'Image',
+          url: [
+            {
+              mediaType: 'image/png',
+              href: 'https://foo.test/icon.png',
+            },
+          ],
+        },
       }.with_indifferent_access
     end
 
     before do
       stub_request(:get, 'https://example.com/.well-known/nodeinfo').to_return(body: '{}')
+      stub_request(:get, 'https://foo.test/image.png').to_return(request_fixture('avatar.txt'))
+      stub_request(:get, 'https://foo.test/icon.png').to_return(request_fixture('avatar.txt'))
     end
 
-    it 'parses out of attachment' do
+    it 'parses property values, avatar and profile header as expected' do
       account = subject.call('alice', 'example.com', payload)
 
       expect(account.fields)
@@ -361,6 +377,10 @@ RSpec.describe ActivityPub::ProcessAccountService, type: :service do
           name: eq('Occupation'),
           value: eq('Unit test')
         )
+      expect(account).to have_attributes(
+        avatar_remote_url: 'https://foo.test/icon.png',
+        header_remote_url: 'https://foo.test/image.png'
+      )
     end
   end
 
diff --git a/spec/services/approve_appeal_service_spec.rb b/spec/services/approve_appeal_service_spec.rb
new file mode 100644
index 0000000000..5707c5d7f4
--- /dev/null
+++ b/spec/services/approve_appeal_service_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe ApproveAppealService do
+  describe '#call' do
+    context 'with an existing appeal' do
+      let(:appeal) { Fabricate(:appeal) }
+      let(:account) { Fabricate(:account) }
+
+      it 'processes the appeal approval' do
+        expect { subject.call(appeal, account) }
+          .to mark_overruled
+          .and record_approver
+      end
+
+      def mark_overruled
+        change(appeal.strike, :overruled_at)
+          .from(nil)
+          .to(be > 1.minute.ago)
+      end
+
+      def record_approver
+        change(appeal, :approved_by_account)
+          .from(nil)
+          .to(account)
+      end
+    end
+  end
+end
diff --git a/spec/services/move_service_spec.rb b/spec/services/move_service_spec.rb
new file mode 100644
index 0000000000..e63818f67e
--- /dev/null
+++ b/spec/services/move_service_spec.rb
@@ -0,0 +1,48 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe MoveService do
+  subject { described_class.new.call(migration) }
+
+  context 'with a valid migration record' do
+    let(:migration) { Fabricate(:account_migration, account: source_account, target_account: target_account) }
+    let(:source_account) { Fabricate(:account) }
+    let(:target_account) { Fabricate(:account, also_known_as: [source_account_uri]) }
+
+    it 'migrates the account to a new account' do
+      expect { subject }
+        .to change_source_moved_value
+        .and process_local_updates
+        .and distribute_updates
+        .and distribute_move
+    end
+  end
+
+  def source_account_uri
+    ActivityPub::TagManager
+      .instance
+      .uri_for(source_account)
+  end
+
+  def change_source_moved_value
+    change(source_account.reload, :moved_to_account)
+      .from(nil)
+      .to(target_account)
+  end
+
+  def process_local_updates
+    enqueue_sidekiq_job(MoveWorker)
+      .with(source_account.id, target_account.id)
+  end
+
+  def distribute_updates
+    enqueue_sidekiq_job(ActivityPub::UpdateDistributionWorker)
+      .with(source_account.id)
+  end
+
+  def distribute_move
+    enqueue_sidekiq_job(ActivityPub::MoveDistributionWorker)
+      .with(migration.id)
+  end
+end
diff --git a/spec/services/remove_domains_from_followers_service_spec.rb b/spec/services/remove_domains_from_followers_service_spec.rb
new file mode 100644
index 0000000000..9e9d6cef2d
--- /dev/null
+++ b/spec/services/remove_domains_from_followers_service_spec.rb
@@ -0,0 +1,28 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe RemoveDomainsFromFollowersService do
+  describe '#call' do
+    context 'with account followers' do
+      let(:account) { Fabricate(:account, domain: nil) }
+      let(:good_domain_account) { Fabricate(:account, domain: 'good.example', protocol: :activitypub) }
+      let(:bad_domain_account) { Fabricate(:account, domain: 'bad.example', protocol: :activitypub) }
+
+      before do
+        Fabricate :follow, target_account: account, account: good_domain_account
+        Fabricate :follow, target_account: account, account: bad_domain_account
+      end
+
+      it 'removes followers from supplied domains and sends a notification' do
+        subject.call(account, ['bad.example'])
+
+        expect(account.followers)
+          .to include(good_domain_account)
+          .and not_include(bad_domain_account)
+        expect(ActivityPub::DeliveryWorker)
+          .to have_enqueued_sidekiq_job(anything, account.id, bad_domain_account.inbox_url)
+      end
+    end
+  end
+end
diff --git a/spec/services/remove_featured_tag_service_spec.rb b/spec/services/remove_featured_tag_service_spec.rb
new file mode 100644
index 0000000000..6cf5388c7f
--- /dev/null
+++ b/spec/services/remove_featured_tag_service_spec.rb
@@ -0,0 +1,37 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe RemoveFeaturedTagService do
+  describe '#call' do
+    context 'with a featured tag' do
+      let(:featured_tag) { Fabricate(:featured_tag) }
+
+      context 'when called by a local account' do
+        let(:account) { Fabricate(:account, domain: nil) }
+
+        it 'destroys the featured tag and sends a distribution' do
+          subject.call(account, featured_tag)
+
+          expect { featured_tag.reload }
+            .to raise_error(ActiveRecord::RecordNotFound)
+          expect(ActivityPub::AccountRawDistributionWorker)
+            .to have_enqueued_sidekiq_job(anything, account.id)
+        end
+      end
+
+      context 'when called by a non local account' do
+        let(:account) { Fabricate(:account, domain: 'host.example') }
+
+        it 'destroys the featured tag and does not send a distribution' do
+          subject.call(account, featured_tag)
+
+          expect { featured_tag.reload }
+            .to raise_error(ActiveRecord::RecordNotFound)
+          expect(ActivityPub::AccountRawDistributionWorker)
+            .to_not have_enqueued_sidekiq_job
+        end
+      end
+    end
+  end
+end
diff --git a/spec/services/unfavourite_service_spec.rb b/spec/services/unfavourite_service_spec.rb
new file mode 100644
index 0000000000..a714cc0675
--- /dev/null
+++ b/spec/services/unfavourite_service_spec.rb
@@ -0,0 +1,36 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe UnfavouriteService do
+  describe '#call' do
+    context 'with a favourited status' do
+      let(:status) { Fabricate(:status, account: account) }
+      let!(:favourite) { Fabricate(:favourite, status: status) }
+
+      context 'when the status account is local' do
+        let(:account) { Fabricate(:account, domain: nil) }
+
+        it 'destroys the favourite' do
+          subject.call(favourite.account, status)
+
+          expect { favourite.reload }
+            .to raise_error(ActiveRecord::RecordNotFound)
+        end
+      end
+
+      context 'when the status account is a remote activitypub account' do
+        let(:account) { Fabricate(:account, domain: 'host.example', protocol: :activitypub) }
+
+        it 'destroys the favourite and sends a notification' do
+          subject.call(favourite.account, status)
+
+          expect { favourite.reload }
+            .to raise_error(ActiveRecord::RecordNotFound)
+          expect(ActivityPub::DeliveryWorker)
+            .to have_enqueued_sidekiq_job(anything, favourite.account.id, status.account.inbox_url)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/services/unmute_service_spec.rb b/spec/services/unmute_service_spec.rb
new file mode 100644
index 0000000000..00135b5ac0
--- /dev/null
+++ b/spec/services/unmute_service_spec.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe UnmuteService do
+  describe '#call' do
+    let!(:account) { Fabricate(:account) }
+    let!(:target_account) { Fabricate(:account) }
+
+    context 'when account is muting target account' do
+      before { Fabricate :mute, account: account, target_account: target_account }
+
+      context 'when account follows target_account' do
+        before { Fabricate :follow, account: account, target_account: target_account }
+
+        it 'removes the account mute and sets up a merge' do
+          expect { subject.call(account, target_account) }
+            .to remove_account_mute
+          expect(MergeWorker).to have_enqueued_sidekiq_job(target_account.id, account.id)
+        end
+      end
+
+      context 'when account does not follow target_account' do
+        it 'removes the account mute and does not create a merge' do
+          expect { subject.call(account, target_account) }
+            .to remove_account_mute
+          expect(MergeWorker).to_not have_enqueued_sidekiq_job
+        end
+      end
+
+      def remove_account_mute
+        change { account.reload.muting?(target_account) }
+          .from(true)
+          .to(false)
+      end
+    end
+
+    context 'when account is not muting target account' do
+      it 'does nothing and returns' do
+        expect { subject.call(account, target_account) }
+          .to_not(change { account.reload.muting?(target_account) })
+        expect(MergeWorker).to_not have_enqueued_sidekiq_job
+      end
+    end
+  end
+end
diff --git a/spec/services/verify_link_service_spec.rb b/spec/services/verify_link_service_spec.rb
index 415788cb58..2895072420 100644
--- a/spec/services/verify_link_service_spec.rb
+++ b/spec/services/verify_link_service_spec.rb
@@ -77,27 +77,28 @@ RSpec.describe VerifyLinkService, type: :service do
 
     context 'when a document is truncated but the link back is valid' do
       let(:html) do
-        "
+        <<-HTML
           <!doctype html>
           <body>
-            <a rel=\"me\" href=\"#{ActivityPub::TagManager.instance.url_for(account)}\"
-        "
+            <a rel="me" href="#{ActivityPub::TagManager.instance.url_for(account)}">
+        HTML
       end
 
-      it 'marks the field as not verified' do
-        expect(field.verified?).to be false
+      it 'marks the field as verified' do
+        expect(field.verified?).to be true
       end
     end
 
-    context 'when a link back might be truncated' do
+    context 'when a link tag might be truncated' do
       let(:html) do
-        "
+        <<-HTML_TRUNCATED
           <!doctype html>
           <body>
-            <a rel=\"me\" href=\"#{ActivityPub::TagManager.instance.url_for(account)}"
+            <a rel="me" href="#{ActivityPub::TagManager.instance.url_for(account)}"
+        HTML_TRUNCATED
       end
 
-      it 'does not mark the field as verified' do
+      it 'marks the field as not verified' do
         expect(field.verified?).to be false
       end
     end
@@ -165,7 +166,11 @@ RSpec.describe VerifyLinkService, type: :service do
       #
       # apparently github allows the user to enter website URLs with a single
       # slash and makes no attempts to correct that.
-      let(:html) { '<a href="http:/unrelated.example">Hello</a>' }
+      let(:html) do
+        <<-HTML
+          <a href="http:/unrelated.example">Hello</a>
+        HTML
+      end
 
       it 'does not crash' do
         # We could probably put more effort into perhaps auto-correcting the
diff --git a/spec/services/vote_service_spec.rb b/spec/services/vote_service_spec.rb
new file mode 100644
index 0000000000..88207b001c
--- /dev/null
+++ b/spec/services/vote_service_spec.rb
@@ -0,0 +1,40 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe VoteService do
+  describe '#call' do
+    subject { described_class.new.call(voter, poll, [0]) }
+
+    context 'with a poll and poll options' do
+      let(:poll) { Fabricate(:poll, account: account, options: %w(Fun UnFun)) }
+      let(:fun_vote) { Fabricate(:poll_vote, poll: poll) }
+      let(:not_fun_vote) { Fabricate(:poll_vote, poll: poll) }
+      let(:voter) { Fabricate(:account, domain: nil) }
+
+      context 'when the poll was created by a local account' do
+        let(:account) { Fabricate(:account, domain: nil) }
+
+        it 'stores the votes and distributes the poll' do
+          expect { subject }
+            .to change(PollVote, :count).by(1)
+
+          expect(ActivityPub::DistributePollUpdateWorker)
+            .to have_enqueued_sidekiq_job(poll.status.id)
+        end
+      end
+
+      context 'when the poll was created by a remote account' do
+        let(:account) { Fabricate(:account, domain: 'host.example') }
+
+        it 'stores the votes and processes delivery' do
+          expect { subject }
+            .to change(PollVote, :count).by(1)
+
+          expect(ActivityPub::DeliveryWorker)
+            .to have_enqueued_sidekiq_job(anything, voter.id, poll.account.inbox_url)
+        end
+      end
+    end
+  end
+end
diff --git a/spec/services/webhook_service_spec.rb b/spec/services/webhook_service_spec.rb
new file mode 100644
index 0000000000..22a60db9f5
--- /dev/null
+++ b/spec/services/webhook_service_spec.rb
@@ -0,0 +1,30 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+
+RSpec.describe WebhookService do
+  describe '#call' do
+    context 'with a relevant event webhook' do
+      let!(:report) { Fabricate(:report) }
+      let!(:webhook) { Fabricate(:webhook, events: ['report.created']) }
+
+      it 'finds and delivers webhook payloads' do
+        expect { subject.call('report.created', report) }
+          .to enqueue_sidekiq_job(Webhooks::DeliveryWorker)
+          .with(
+            webhook.id,
+            anything
+          )
+      end
+    end
+
+    context 'without any relevant event webhooks' do
+      let!(:report) { Fabricate(:report) }
+
+      it 'does not deliver webhook payloads' do
+        expect { subject.call('report.created', report) }
+          .to_not enqueue_sidekiq_job(Webhooks::DeliveryWorker)
+      end
+    end
+  end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 47ded4c6b4..3e4ef03237 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -25,6 +25,12 @@ RSpec.configure do |config|
   config.before :suite do
     Rails.application.load_seed
     Chewy.strategy(:bypass)
+
+    # NOTE: we switched registrations mode to closed by default, but the specs
+    # very heavily rely on having it enabled by default, as it relies on users
+    # being approved by default except in select cases where explicitly testing
+    # other registration modes
+    Setting.registrations_mode = 'open'
   end
 
   config.after :suite do
diff --git a/spec/support/streaming_server_manager.rb b/spec/support/streaming_server_manager.rb
index 39657586f2..3381918299 100644
--- a/spec/support/streaming_server_manager.rb
+++ b/spec/support/streaming_server_manager.rb
@@ -102,6 +102,13 @@ RSpec.configure do |config|
     self.use_transactional_tests = false
 
     DatabaseCleaner.cleaning do
+      # NOTE: we switched registrations mode to closed by default, but the specs
+      # very heavily rely on having it enabled by default, as it relies on users
+      # being approved by default except in select cases where explicitly testing
+      # other registration modes
+      # Also needs to be set per-example here because of the database cleaner.
+      Setting.registrations_mode = 'open'
+
       example.run
     end
 
diff --git a/streaming/errors.js b/streaming/errors.js
new file mode 100644
index 0000000000..9a641180ba
--- /dev/null
+++ b/streaming/errors.js
@@ -0,0 +1,51 @@
+// @ts-check
+
+/**
+ * Typed as a string because otherwise it's a const string, which means we can't
+ * override it in let statements.
+ * @type {string}
+ */
+const UNEXPECTED_ERROR_MESSAGE = 'An unexpected error occurred';
+exports.UNKNOWN_ERROR_MESSAGE = UNEXPECTED_ERROR_MESSAGE;
+
+/**
+ * Extracts the status and message properties from the error object, if
+ * available for public use. The `unknown` is for catch statements
+ * @param {Error | AuthenticationError | RequestError | unknown} err
+ */
+exports.extractStatusAndMessage = function(err) {
+  let statusCode = 500;
+  let errorMessage = UNEXPECTED_ERROR_MESSAGE;
+  if (err instanceof AuthenticationError || err instanceof RequestError) {
+    statusCode = err.status;
+    errorMessage = err.message;
+  }
+
+  return { statusCode, errorMessage };
+};
+
+class RequestError extends Error {
+  /**
+   * @param {string} message
+   */
+  constructor(message) {
+    super(message);
+    this.name = "RequestError";
+    this.status = 400;
+  }
+}
+
+exports.RequestError = RequestError;
+
+class AuthenticationError extends Error {
+  /**
+   * @param {string} message
+   */
+  constructor(message) {
+    super(message);
+    this.name = "AuthenticationError";
+    this.status = 401;
+  }
+}
+
+exports.AuthenticationError = AuthenticationError;
diff --git a/streaming/index.js b/streaming/index.js
index dbe32af23f..a2cd86ce47 100644
--- a/streaming/index.js
+++ b/streaming/index.js
@@ -14,6 +14,8 @@ const pg = require('pg');
 const dbUrlToConfig = require('pg-connection-string').parse;
 const WebSocket = require('ws');
 
+const errors = require('./errors');
+const { AuthenticationError, RequestError } = require('./errors');
 const { logger, httpLogger, initializeLogLevel, attachWebsocketHttpLogger, createWebsocketLogger } = require('./logging');
 const { setupMetrics } = require('./metrics');
 const { isTruthy, normalizeHashtag, firstParam } = require("./utils");
@@ -324,7 +326,7 @@ const startServer = async () => {
       // Unfortunately for using the on('upgrade') setup, we need to manually
       // write a HTTP Response to the Socket to close the connection upgrade
       // attempt, so the following code is to handle all of that.
-      const statusCode = err.status ?? 401;
+      const {statusCode, errorMessage } = errors.extractStatusAndMessage(err);
 
       /** @type {Record<string, string | number | import('pino-http').ReqId>} */
       const headers = {
@@ -332,7 +334,7 @@ const startServer = async () => {
         'Content-Type': 'text/plain',
         'Content-Length': 0,
         'X-Request-Id': request.id,
-        'X-Error-Message': err.status ? err.toString() : 'An unexpected error occurred'
+        'X-Error-Message': errorMessage
       };
 
       // Ensure the socket is closed once we've finished writing to it:
@@ -350,7 +352,7 @@ const startServer = async () => {
           statusCode,
           headers
         }
-      }, err.toString());
+      }, errorMessage);
 
       return;
     }
@@ -535,11 +537,7 @@ const startServer = async () => {
         }
 
         if (result.rows.length === 0) {
-          err = new Error('Invalid access token');
-          // @ts-ignore
-          err.status = 401;
-
-          reject(err);
+          reject(new AuthenticationError('Invalid access token'));
           return;
         }
 
@@ -570,11 +568,7 @@ const startServer = async () => {
     const accessToken   = location.query.access_token || req.headers['sec-websocket-protocol'];
 
     if (!authorization && !accessToken) {
-      const err = new Error('Missing access token');
-      // @ts-ignore
-      err.status = 401;
-
-      reject(err);
+      reject(new AuthenticationError('Missing access token'));
       return;
     }
 
@@ -653,11 +647,7 @@ const startServer = async () => {
       return;
     }
 
-    const err = new Error('Access token does not cover required scopes');
-    // @ts-ignore
-    err.status = 401;
-
-    reject(err);
+    reject(new AuthenticationError('Access token does not have the required scopes'));
   });
 
   /**
@@ -733,11 +723,7 @@ const startServer = async () => {
     // If no channelName can be found for the request, then we should terminate
     // the connection, as there's nothing to stream back
     if (!channelName) {
-      const err = new Error('Unknown channel requested');
-      // @ts-ignore
-      err.status = 400;
-
-      next(err);
+      next(new RequestError('Unknown channel requested'));
       return;
     }
 
@@ -764,10 +750,7 @@ const startServer = async () => {
       return;
     }
 
-    const hasStatusCode = Object.hasOwnProperty.call(err, 'status');
-    // @ts-ignore
-    const statusCode = hasStatusCode ? err.status : 500;
-    const errorMessage = hasStatusCode ? err.toString() : 'An unexpected error occurred';
+    const {statusCode, errorMessage } = errors.extractStatusAndMessage(err);
 
     res.writeHead(statusCode, { 'Content-Type': 'application/json' });
     res.end(JSON.stringify({ error: errorMessage }));
@@ -1197,7 +1180,7 @@ const startServer = async () => {
   };
 
   /**
-   * @param {any} res
+   * @param {http.ServerResponse} res
    */
   const httpNotFound = res => {
     res.writeHead(404, { 'Content-Type': 'application/json' });
@@ -1212,16 +1195,29 @@ const startServer = async () => {
   api.use(errorMiddleware);
 
   api.get('/api/v1/streaming/*', (req, res) => {
-    // @ts-ignore
-    channelNameToIds(req, channelNameFromPath(req), req.query).then(({ channelIds, options }) => {
+    const channelName = channelNameFromPath(req);
+
+    // FIXME: In theory we'd never actually reach here due to
+    // authenticationMiddleware catching this case, however, we need to refactor
+    // how those middlewares work, so I'm adding the extra check in here.
+    if (!channelName) {
+      httpNotFound(res);
+      return;
+    }
+
+    channelNameToIds(req, channelName, req.query).then(({ channelIds, options }) => {
       const onSend = streamToHttp(req, res);
       const onEnd = streamHttpEnd(req, subscriptionHeartbeat(channelIds));
 
       // @ts-ignore
       streamFrom(channelIds, req, req.log, onSend, onEnd, 'eventsource', options.needsFiltering);
     }).catch(err => {
-      res.log.info({ err }, 'Subscription error:', err.toString());
-      httpNotFound(res);
+      const {statusCode, errorMessage } = errors.extractStatusAndMessage(err);
+
+      res.log.info({ err }, 'Eventsource subscription error');
+
+      res.writeHead(statusCode, { 'Content-Type': 'application/json' });
+      res.end(JSON.stringify({ error: errorMessage }));
     });
   });
 
@@ -1323,8 +1319,8 @@ const startServer = async () => {
 
       break;
     case 'hashtag':
-      if (!params.tag || params.tag.length === 0) {
-        reject('No tag for stream provided');
+      if (!params.tag) {
+        reject(new RequestError('Missing tag name parameter'));
       } else {
         resolve({
           channelIds: [`timeline:hashtag:${normalizeHashtag(params.tag)}`],
@@ -1334,8 +1330,8 @@ const startServer = async () => {
 
       break;
     case 'hashtag:local':
-      if (!params.tag || params.tag.length === 0) {
-        reject('No tag for stream provided');
+      if (!params.tag) {
+        reject(new RequestError('Missing tag name parameter'));
       } else {
         resolve({
           channelIds: [`timeline:hashtag:${normalizeHashtag(params.tag)}:local`],
@@ -1345,14 +1341,18 @@ const startServer = async () => {
 
       break;
     case 'list':
-      // @ts-ignore
+      if (!params.list) {
+        reject(new RequestError('Missing list name parameter'));
+        return;
+      }
+
       authorizeListAccess(params.list, req).then(() => {
         resolve({
           channelIds: [`timeline:list:${params.list}`],
           options: { needsFiltering: false },
         });
       }).catch(() => {
-        reject('Not authorized to stream this list');
+        reject(new AuthenticationError('Not authorized to stream this list'));
       });
 
       break;
@@ -1369,7 +1369,7 @@ const startServer = async () => {
 
       break;
     default:
-      reject('Unknown stream type');
+      reject(new RequestError('Unknown stream type'));
     }
   });
 
@@ -1425,8 +1425,17 @@ const startServer = async () => {
         stopHeartbeat,
       };
     }).catch(err => {
-      logger.error({ err }, 'Subscription error');
-      websocket.send(JSON.stringify({ error: err.toString() }));
+      const {statusCode, errorMessage } = errors.extractStatusAndMessage(err);
+
+      logger.error({ err }, 'Websocket subscription error');
+
+      // If we have a socket that is alive and open still, send the error back to the client:
+      if (websocket.isAlive && websocket.readyState === websocket.OPEN) {
+        websocket.send(JSON.stringify({
+          error: errorMessage,
+          status: statusCode
+        }));
+      }
     });
   };
 
@@ -1465,10 +1474,11 @@ const startServer = async () => {
     channelNameToIds(request, channelName, params).then(({ channelIds }) => {
       removeSubscription(session, channelIds);
     }).catch(err => {
-      logger.error({err}, 'Unsubscribe error');
+      logger.error({err}, 'Websocket unsubscribe error');
 
       // If we have a socket that is alive and open still, send the error back to the client:
       if (websocket.isAlive && websocket.readyState === websocket.OPEN) {
+        // TODO: Use a better error response here
         websocket.send(JSON.stringify({ error: "Error unsubscribing from channel" }));
       }
     });
diff --git a/yarn.lock b/yarn.lock
index ffcd32f4bb..cc4a8bf14a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2318,7 +2318,7 @@ __metadata:
     "@gamestdio/websocket": "npm:^0.3.2"
     "@github/webauthn-json": "npm:^2.1.1"
     "@hello-pangea/dnd": "npm:^16.3.0"
-    "@rails/ujs": "npm:^7.1.1"
+    "@rails/ujs": "npm:7.1.3-2"
     "@reduxjs/toolkit": "npm:^2.0.1"
     "@svgr/webpack": "npm:^5.5.0"
     "@testing-library/jest-dom": "npm:^6.0.0"
@@ -2397,7 +2397,7 @@ __metadata:
     history: "npm:^4.10.1"
     hoist-non-react-statics: "npm:^3.3.2"
     http-link-header: "npm:^1.1.1"
-    husky: "npm:^8.0.3"
+    husky: "npm:^9.0.11"
     immutable: "npm:^4.3.0"
     imports-loader: "npm:^1.2.0"
     intl-messageformat: "npm:^10.3.5"
@@ -2619,10 +2619,10 @@ __metadata:
   languageName: node
   linkType: hard
 
-"@rails/ujs@npm:^7.1.1":
-  version: 7.1.3
-  resolution: "@rails/ujs@npm:7.1.3"
-  checksum: 10c0/68112d9add9dbc59b40c2ec1bc095a67445c57d20d0ab7d817ce3de0cd90374e2690af8ad54ce6ecc2d1c748b34c0c44d0fbd2f515ce2c443d7c5d23d00b9ce5
+"@rails/ujs@npm:7.1.3-2":
+  version: 7.1.3-2
+  resolution: "@rails/ujs@npm:7.1.3-2"
+  checksum: 10c0/8bd5b3a409c62f53790ed7e914f1f48235f461a472da7b4ce1d9ad57356fcdeaa7891c946298f7f620ff0ff7c6d5b995bf44057929c4fce796867a8cf4f27c99
   languageName: node
   linkType: hard
 
@@ -6276,18 +6276,18 @@ __metadata:
   languageName: node
   linkType: hard
 
-"cssnano-preset-default@npm:^6.0.3":
-  version: 6.0.3
-  resolution: "cssnano-preset-default@npm:6.0.3"
+"cssnano-preset-default@npm:^6.0.4":
+  version: 6.0.4
+  resolution: "cssnano-preset-default@npm:6.0.4"
   dependencies:
     css-declaration-sorter: "npm:^7.1.1"
     cssnano-utils: "npm:^4.0.1"
     postcss-calc: "npm:^9.0.1"
     postcss-colormin: "npm:^6.0.2"
-    postcss-convert-values: "npm:^6.0.2"
+    postcss-convert-values: "npm:^6.0.3"
     postcss-discard-comments: "npm:^6.0.1"
-    postcss-discard-duplicates: "npm:^6.0.1"
-    postcss-discard-empty: "npm:^6.0.1"
+    postcss-discard-duplicates: "npm:^6.0.2"
+    postcss-discard-empty: "npm:^6.0.2"
     postcss-discard-overridden: "npm:^6.0.1"
     postcss-merge-longhand: "npm:^6.0.2"
     postcss-merge-rules: "npm:^6.0.3"
@@ -6311,7 +6311,7 @@ __metadata:
     postcss-unique-selectors: "npm:^6.0.2"
   peerDependencies:
     postcss: ^8.4.31
-  checksum: 10c0/d100a1f8ab71adbb6df85e00f4a9e5d04ac06fc50343157eef853aded3f75dd0489dd845a5b2fb43ca701bd88c39c5aa88673f842bc1f94f4318c7b38ced1963
+  checksum: 10c0/8a1569756c2189d9db91b2bbd7bc44b39ec6c0bac8cb1a34ab37801b40626b372c2341e696f3a4dfe03ee0490f033299b5e5f9511e2d3572b9b5a2edb7a76e3b
   languageName: node
   linkType: hard
 
@@ -6325,14 +6325,14 @@ __metadata:
   linkType: hard
 
 "cssnano@npm:^6.0.1":
-  version: 6.0.3
-  resolution: "cssnano@npm:6.0.3"
+  version: 6.0.4
+  resolution: "cssnano@npm:6.0.4"
   dependencies:
-    cssnano-preset-default: "npm:^6.0.3"
-    lilconfig: "npm:^3.0.0"
+    cssnano-preset-default: "npm:^6.0.4"
+    lilconfig: "npm:^3.1.1"
   peerDependencies:
     postcss: ^8.4.31
-  checksum: 10c0/d1669eb987fd96159bae262ef2f76c1a64fffefe8fa593918a6bda377977798b60fb4a6a871a9b9a9deb11258130ee254fdb8c3144769b3060ad9f2a95a4ed0a
+  checksum: 10c0/734b8d1a925288a707fa73087b7ae340a93c59a1838ac897f470104bbebf8aa4fb2a24e190e50a4eea592b595bca0a2f25e8aedcf237ea1675c8d1e636f587a5
   languageName: node
   linkType: hard
 
@@ -9074,12 +9074,12 @@ __metadata:
   languageName: node
   linkType: hard
 
-"husky@npm:^8.0.3":
-  version: 8.0.3
-  resolution: "husky@npm:8.0.3"
+"husky@npm:^9.0.11":
+  version: 9.0.11
+  resolution: "husky@npm:9.0.11"
   bin:
-    husky: lib/bin.js
-  checksum: 10c0/6722591771c657b91a1abb082e07f6547eca79144d678e586828ae806499d90dce2a6aee08b66183fd8b085f19d20e0990a2ad396961746b4c8bd5bdb619d668
+    husky: bin.mjs
+  checksum: 10c0/2c787dcf74a837fc9a4fea7da907509d4bd9a289f4ea10ecc9d86279e4d4542b0f5f6443a619bccae19e265f2677172cc2b86aae5c932a35a330cc227d914605
   languageName: node
   linkType: hard
 
@@ -10909,13 +10909,20 @@ __metadata:
   languageName: node
   linkType: hard
 
-"lilconfig@npm:3.0.0, lilconfig@npm:^3.0.0":
+"lilconfig@npm:3.0.0":
   version: 3.0.0
   resolution: "lilconfig@npm:3.0.0"
   checksum: 10c0/7f5ee7a658dc016cacf146815e8d88b06f06f4402823b8b0934e305a57a197f55ccc9c5cd4fb5ea1b2b821c8ccaf2d54abd59602a4931af06eabda332388d3e6
   languageName: node
   linkType: hard
 
+"lilconfig@npm:^3.1.1":
+  version: 3.1.1
+  resolution: "lilconfig@npm:3.1.1"
+  checksum: 10c0/311b559794546894e3fe176663427326026c1c644145be9e8041c58e268aa9328799b8dfe7e4dd8c6a4ae305feae95a1c9e007db3569f35b42b6e1bc8274754c
+  languageName: node
+  linkType: hard
+
 "lines-and-columns@npm:^1.1.6":
   version: 1.2.4
   resolution: "lines-and-columns@npm:1.2.4"
@@ -12745,8 +12752,8 @@ __metadata:
   linkType: hard
 
 "pino@npm:^8.17.1, pino@npm:^8.17.2":
-  version: 8.18.0
-  resolution: "pino@npm:8.18.0"
+  version: 8.19.0
+  resolution: "pino@npm:8.19.0"
   dependencies:
     atomic-sleep: "npm:^1.0.0"
     fast-redact: "npm:^3.1.1"
@@ -12761,7 +12768,7 @@ __metadata:
     thread-stream: "npm:^2.0.0"
   bin:
     pino: bin.js
-  checksum: 10c0/ca73bb31e4656954413b89f48c486b1680fec0c6bb12d4d796c5ccf8eca40f3ee12c9532a0fa61284ed9a800c14eaa0f496f520057ef70cdee0447114813e8eb
+  checksum: 10c0/53e6e9db91e451163e93294b0a7c5c8135742d58909dfc4a6fa1afc155b2b0dc44448ec3d057e08351951f9a3ea67e6ea8e72e952b64a1d889f4d5376cbd1a5d
   languageName: node
   linkType: hard
 
@@ -12834,15 +12841,15 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-convert-values@npm:^6.0.2":
-  version: 6.0.2
-  resolution: "postcss-convert-values@npm:6.0.2"
+"postcss-convert-values@npm:^6.0.3":
+  version: 6.0.3
+  resolution: "postcss-convert-values@npm:6.0.3"
   dependencies:
     browserslist: "npm:^4.22.2"
     postcss-value-parser: "npm:^4.2.0"
   peerDependencies:
     postcss: ^8.4.31
-  checksum: 10c0/882d0b7839ef07ac8ffbf9cb48db0f610939a3496bd0321c7f23096ead676f13e09ab3d9c20ff3dbe2c887e855826051ca7dffeaffce5068cfdc9aaa573a3842
+  checksum: 10c0/614a24d4bc9142f277ed12eefe556eae6ad8292092953c8ebfcf518ef52e8de5dd337a9e915b64e712b8b95175ca0fd8d1b1e9e806d25a8e4f01c75d784f3118
   languageName: node
   linkType: hard
 
@@ -12855,21 +12862,21 @@ __metadata:
   languageName: node
   linkType: hard
 
-"postcss-discard-duplicates@npm:^6.0.1":
-  version: 6.0.1
-  resolution: "postcss-discard-duplicates@npm:6.0.1"
+"postcss-discard-duplicates@npm:^6.0.2":
+  version: 6.0.2
+  resolution: "postcss-discard-duplicates@npm:6.0.2"
   peerDependencies:
     postcss: ^8.4.31
-  checksum: 10c0/b9ea10a3c7528bb1630613c11756f809a95da634822d943fa91b28f2a37787e7cdb9ff96deed9776e2c3753d35e42c8afd5074b630930df7b5150573d4beda23
+  checksum: 10c0/316b8263c3a06d3303288d99e093ed2922757222fe5ea457b70d8d3fccadf0a1a452a6cc3b8296e749e70b0a231b68a742f9e01c606baa7fe3e14327bae3094b
   languageName: node
   linkType: hard
 
-"postcss-discard-empty@npm:^6.0.1":
-  version: 6.0.1
-  resolution: "postcss-discard-empty@npm:6.0.1"
+"postcss-discard-empty@npm:^6.0.2":
+  version: 6.0.2
+  resolution: "postcss-discard-empty@npm:6.0.2"
   peerDependencies:
     postcss: ^8.4.31
-  checksum: 10c0/6b95e588a3e8fb262e56bd313060daf29d7c9d44184bb6c4c5858ae81d6cd2907b15b3e3023b6621d50a67cfc10e6077920ff1e908892b207dee29477376498f
+  checksum: 10c0/abae41eecf93ed7b2b34bb77d319d70093e663ee4b23dc0b1e0007044bbf4315d980539bb67466a8ed24a475afdd52bd465f92433466cf3bf2057591c7124ab1
   languageName: node
   linkType: hard