diff --git a/app/javascript/flavours/glitch/components/account.jsx b/app/javascript/flavours/glitch/components/account.jsx
index fd7caea6df..7e5209653e 100644
--- a/app/javascript/flavours/glitch/components/account.jsx
+++ b/app/javascript/flavours/glitch/components/account.jsx
@@ -37,10 +37,10 @@ class Account extends ImmutablePureComponent {
   static propTypes = {
     size: PropTypes.number,
     account: ImmutablePropTypes.record,
-    onFollow: PropTypes.func.isRequired,
-    onBlock: PropTypes.func.isRequired,
-    onMute: PropTypes.func.isRequired,
-    onMuteNotifications: PropTypes.func.isRequired,
+    onFollow: PropTypes.func,
+    onBlock: PropTypes.func,
+    onMute: PropTypes.func,
+    onMuteNotifications: PropTypes.func,
     intl: PropTypes.object.isRequired,
     hidden: PropTypes.bool,
     minimal: PropTypes.bool,
diff --git a/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx b/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx
index eb25f5a643..892d068b31 100644
--- a/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx
+++ b/app/javascript/flavours/glitch/components/autosuggest_emoji.jsx
@@ -35,7 +35,7 @@ export default class AutosuggestEmoji extends PureComponent {
           alt={emoji.native || emoji.colons}
         />
 
-        {emoji.colons}
+        <div className='autosuggest-emoji__name'>{emoji.colons}</div>
       </div>
     );
   }
diff --git a/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx b/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx
index 6da6200142..808f303754 100644
--- a/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx
+++ b/app/javascript/flavours/glitch/components/autosuggest_hashtag.tsx
@@ -1,5 +1,3 @@
-import { FormattedMessage } from 'react-intl';
-
 import { ShortNumber } from 'flavours/glitch/components/short_number';
 
 interface Props {
@@ -16,27 +14,18 @@ interface Props {
   };
 }
 
-export const AutosuggestHashtag: React.FC<Props> = ({ tag }) => {
-  const weeklyUses = tag.history && (
-    <ShortNumber
-      value={tag.history.reduce((total, day) => total + day.uses * 1, 0)}
-    />
-  );
-
-  return (
-    <div className='autosuggest-hashtag'>
-      <div className='autosuggest-hashtag__name'>
-        #<strong>{tag.name}</strong>
-      </div>
-      {tag.history !== undefined && (
-        <div className='autosuggest-hashtag__uses'>
-          <FormattedMessage
-            id='autosuggest_hashtag.per_week'
-            defaultMessage='{count} per week'
-            values={{ count: weeklyUses }}
-          />
-        </div>
-      )}
+export const AutosuggestHashtag: React.FC<Props> = ({ tag }) => (
+  <div className='autosuggest-hashtag'>
+    <div className='autosuggest-hashtag__name'>
+      #<strong>{tag.name}</strong>
     </div>
-  );
-};
+
+    {tag.history !== undefined && (
+      <div className='autosuggest-hashtag__uses'>
+        <ShortNumber
+          value={tag.history.reduce((total, day) => total + day.uses * 1, 0)}
+        />
+      </div>
+    )}
+  </div>
+);
diff --git a/app/javascript/flavours/glitch/components/autosuggest_input.jsx b/app/javascript/flavours/glitch/components/autosuggest_input.jsx
index 6d2474b442..97da532ebb 100644
--- a/app/javascript/flavours/glitch/components/autosuggest_input.jsx
+++ b/app/javascript/flavours/glitch/components/autosuggest_input.jsx
@@ -5,6 +5,8 @@ import classNames from 'classnames';
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
+import Overlay from 'react-overlays/Overlay';
+
 import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
 
 import AutosuggestEmoji from './autosuggest_emoji';
@@ -195,34 +197,37 @@ export default class AutosuggestInput extends ImmutablePureComponent {
 
     return (
       <div className='autosuggest-input'>
-        <label>
-          <span style={{ display: 'none' }}>{placeholder}</span>
+        <input
+          type='text'
+          ref={this.setInput}
+          disabled={disabled}
+          placeholder={placeholder}
+          autoFocus={autoFocus}
+          value={value}
+          onChange={this.onChange}
+          onKeyDown={this.onKeyDown}
+          onKeyUp={onKeyUp}
+          onFocus={this.onFocus}
+          onBlur={this.onBlur}
+          dir='auto'
+          aria-autocomplete='list'
+          aria-label={placeholder}
+          id={id}
+          className={className}
+          maxLength={maxLength}
+          lang={lang}
+          spellCheck={spellCheck}
+        />
 
-          <input
-            type='text'
-            ref={this.setInput}
-            disabled={disabled}
-            placeholder={placeholder}
-            autoFocus={autoFocus}
-            value={value}
-            onChange={this.onChange}
-            onKeyDown={this.onKeyDown}
-            onKeyUp={onKeyUp}
-            onFocus={this.onFocus}
-            onBlur={this.onBlur}
-            dir='auto'
-            aria-autocomplete='list'
-            id={id}
-            className={className}
-            maxLength={maxLength}
-            lang={lang}
-            spellCheck={spellCheck}
-          />
-        </label>
-
-        <div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
-          {suggestions.map(this.renderSuggestion)}
-        </div>
+        <Overlay show={!(suggestionsHidden || suggestions.isEmpty())} offset={[0, 0]} placement='bottom' target={this.input} popperConfig={{ strategy: 'fixed' }}>
+          {({ props }) => (
+            <div {...props}>
+              <div className='autosuggest-textarea__suggestions' style={{ width: this.input?.clientWidth }}>
+                {suggestions.map(this.renderSuggestion)}
+              </div>
+            </div>
+          )}
+        </Overlay>
       </div>
     );
   }
diff --git a/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx b/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx
index 28384075c3..9fd199a21c 100644
--- a/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx
+++ b/app/javascript/flavours/glitch/components/autosuggest_textarea.jsx
@@ -5,6 +5,7 @@ import classNames from 'classnames';
 
 import ImmutablePropTypes from 'react-immutable-proptypes';
 
+import Overlay from 'react-overlays/Overlay';
 import Textarea from 'react-textarea-autosize';
 
 import AutosuggestAccountContainer from '../features/compose/containers/autosuggest_account_container';
@@ -52,7 +53,6 @@ const AutosuggestTextarea = forwardRef(({
   onFocus,
   autoFocus = true,
   lang,
-  children,
 }, textareaRef) => {
 
   const [suggestionsHidden, setSuggestionsHidden] = useState(true);
@@ -183,40 +183,38 @@ const AutosuggestTextarea = forwardRef(({
     );
   };
 
-  return [
-    <div className='compose-form__autosuggest-wrapper' key='autosuggest-wrapper'>
-      <div className='autosuggest-textarea'>
-        <label>
-          <span style={{ display: 'none' }}>{placeholder}</span>
+  return (
+    <div className='autosuggest-textarea'>
+      <Textarea
+        ref={textareaRef}
+        className='autosuggest-textarea__textarea'
+        disabled={disabled}
+        placeholder={placeholder}
+        autoFocus={autoFocus}
+        value={value}
+        onChange={handleChange}
+        onKeyDown={handleKeyDown}
+        onKeyUp={onKeyUp}
+        onFocus={handleFocus}
+        onBlur={handleBlur}
+        onPaste={handlePaste}
+        dir='auto'
+        aria-autocomplete='list'
+        aria-label={placeholder}
+        lang={lang}
+      />
 
-          <Textarea
-            ref={textareaRef}
-            className='autosuggest-textarea__textarea'
-            disabled={disabled}
-            placeholder={placeholder}
-            autoFocus={autoFocus}
-            value={value}
-            onChange={handleChange}
-            onKeyDown={handleKeyDown}
-            onKeyUp={onKeyUp}
-            onFocus={handleFocus}
-            onBlur={handleBlur}
-            onPaste={handlePaste}
-            dir='auto'
-            aria-autocomplete='list'
-            lang={lang}
-          />
-        </label>
-      </div>
-      {children}
-    </div>,
-
-    <div className='autosuggest-textarea__suggestions-wrapper' key='suggestions-wrapper'>
-      <div className={`autosuggest-textarea__suggestions ${suggestionsHidden || suggestions.isEmpty() ? '' : 'autosuggest-textarea__suggestions--visible'}`}>
-        {suggestions.map(renderSuggestion)}
-      </div>
-    </div>,
-  ];
+      <Overlay show={!(suggestionsHidden || suggestions.isEmpty())} offset={[0, 0]} placement='bottom' target={textareaRef} popperConfig={{ strategy: 'fixed' }}>
+        {({ props }) => (
+          <div {...props}>
+            <div className='autosuggest-textarea__suggestions' style={{ width: textareaRef.current?.clientWidth }}>
+              {suggestions.map(renderSuggestion)}
+            </div>
+          </div>
+        )}
+      </Overlay>
+    </div>
+  );
 });
 
 AutosuggestTextarea.propTypes = {
@@ -232,7 +230,6 @@ AutosuggestTextarea.propTypes = {
   onKeyDown: PropTypes.func,
   onPaste: PropTypes.func.isRequired,
   onFocus:PropTypes.func,
-  children: PropTypes.node,
   autoFocus: PropTypes.bool,
   lang: PropTypes.string,
 };
diff --git a/app/javascript/flavours/glitch/components/dropdown_menu.jsx b/app/javascript/flavours/glitch/components/dropdown_menu.jsx
index bfaa53f6e5..4d9c34a762 100644
--- a/app/javascript/flavours/glitch/components/dropdown_menu.jsx
+++ b/app/javascript/flavours/glitch/components/dropdown_menu.jsx
@@ -165,7 +165,7 @@ class Dropdown extends PureComponent {
     children: PropTypes.node,
     icon: PropTypes.string,
     iconComponent: PropTypes.func,
-    items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
+    items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]),
     loading: PropTypes.bool,
     size: PropTypes.number,
     title: PropTypes.string,
diff --git a/app/javascript/flavours/glitch/components/visibility_icon.tsx b/app/javascript/flavours/glitch/components/visibility_icon.tsx
index baf134c0ae..dd24c5c927 100644
--- a/app/javascript/flavours/glitch/components/visibility_icon.tsx
+++ b/app/javascript/flavours/glitch/components/visibility_icon.tsx
@@ -1,9 +1,9 @@
 import { defineMessages, useIntl } from 'react-intl';
 
 import LockIcon from '@/material-icons/400-24px/lock.svg?react';
-import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react';
 import MailIcon from '@/material-icons/400-24px/mail.svg?react';
 import PublicIcon from '@/material-icons/400-24px/public.svg?react';
+import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
 
 import { Icon } from './icon';
 
@@ -11,14 +11,17 @@ type Visibility = 'public' | 'unlisted' | 'private' | 'direct';
 
 const messages = defineMessages({
   public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
-  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
+  unlisted_short: {
+    id: 'privacy.unlisted.short',
+    defaultMessage: 'Quiet public',
+  },
   private_short: {
     id: 'privacy.private.short',
-    defaultMessage: 'Followers only',
+    defaultMessage: 'Followers',
   },
   direct_short: {
     id: 'privacy.direct.short',
-    defaultMessage: 'Mentioned people only',
+    defaultMessage: 'Specific people',
   },
 });
 
@@ -35,7 +38,7 @@ export const VisibilityIcon: React.FC<{ visibility: Visibility }> = ({
     },
     unlisted: {
       icon: 'unlock',
-      iconComponent: LockOpenIcon,
+      iconComponent: QuietTimeIcon,
       text: intl.formatMessage(messages.unlisted_short),
     },
     private: {
diff --git a/app/javascript/flavours/glitch/containers/compose_container.jsx b/app/javascript/flavours/glitch/containers/compose_container.jsx
index f76550678e..772ac5fa6b 100644
--- a/app/javascript/flavours/glitch/containers/compose_container.jsx
+++ b/app/javascript/flavours/glitch/containers/compose_container.jsx
@@ -1,14 +1,12 @@
-import { PureComponent } from 'react';
-
 import { Provider } from 'react-redux';
 
-import { fetchCustomEmojis } from '../actions/custom_emojis';
-import { hydrateStore } from '../actions/store';
-import Compose from '../features/standalone/compose';
-import initialState from '../initial_state';
-import { IntlProvider } from '../locales';
-import { store } from '../store';
-
+import { fetchCustomEmojis } from 'flavours/glitch/actions/custom_emojis';
+import { hydrateStore } from 'flavours/glitch/actions/store';
+import { Router } from 'flavours/glitch/components/router';
+import Compose from 'flavours/glitch/features/standalone/compose';
+import initialState from 'flavours/glitch/initial_state';
+import { IntlProvider } from 'flavours/glitch/locales';
+import { store } from 'flavours/glitch/store';
 
 if (initialState) {
   store.dispatch(hydrateStore(initialState));
@@ -16,16 +14,14 @@ if (initialState) {
 
 store.dispatch(fetchCustomEmojis());
 
-export default class ComposeContainer extends PureComponent {
+const ComposeContainer = () => (
+  <IntlProvider>
+    <Provider store={store}>
+      <Router>
+        <Compose />
+      </Router>
+    </Provider>
+  </IntlProvider>
+);
 
-  render () {
-    return (
-      <IntlProvider>
-        <Provider store={store}>
-          <Compose />
-        </Provider>
-      </IntlProvider>
-    );
-  }
-
-}
+export default ComposeContainer;
diff --git a/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx b/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx
index 411ad77c79..7fda25ded5 100644
--- a/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/action_bar.jsx
@@ -1,13 +1,13 @@
-import PropTypes from 'prop-types';
-import { PureComponent } from 'react';
+import { useCallback } from 'react';
 
-import { defineMessages, injectIntl } from 'react-intl';
+import { defineMessages, useIntl } from 'react-intl';
 
-import ImmutablePropTypes from 'react-immutable-proptypes';
+import { useDispatch } from 'react-redux';
 
-import MenuIcon from '@/material-icons/400-24px/menu.svg?react';
-
-import DropdownMenuContainer from '../../../containers/dropdown_menu_container';
+import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
+import { openModal } from 'flavours/glitch/actions/modal';
+import DropdownMenuContainer from 'flavours/glitch/containers/dropdown_menu_container';
+import { logOut } from 'flavours/glitch/utils/log_out';
 
 const messages = defineMessages({
   edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
@@ -23,51 +23,52 @@ const messages = defineMessages({
   filters: { id: 'navigation_bar.filters', defaultMessage: 'Muted words' },
   logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
   bookmarks: { id: 'navigation_bar.bookmarks', defaultMessage: 'Bookmarks' },
+  logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
+  logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
 });
 
-class ActionBar extends PureComponent {
+export const ActionBar = () => {
+  const dispatch = useDispatch();
+  const intl = useIntl();
 
-  static propTypes = {
-    account: ImmutablePropTypes.record.isRequired,
-    onLogout: PropTypes.func.isRequired,
-    intl: PropTypes.object.isRequired,
-  };
+  const handleLogoutClick = useCallback(() => {
+    dispatch(openModal({
+      modalType: 'CONFIRM',
+      modalProps: {
+        message: intl.formatMessage(messages.logoutMessage),
+        confirm: intl.formatMessage(messages.logoutConfirm),
+        closeWhenConfirm: false,
+        onConfirm: () => logOut(),
+      },
+    }));
+  }, [dispatch, intl]);
 
-  handleLogout = () => {
-    this.props.onLogout();
-  };
+  let menu = [];
 
-  render () {
-    const { intl } = this.props;
+  menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });
+  menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' });
+  menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });
+  menu.push(null);
+  menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
+  menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
+  menu.push({ text: intl.formatMessage(messages.bookmarks), to: '/bookmarks' });
+  menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
+  menu.push({ text: intl.formatMessage(messages.followed_tags), to: '/followed_tags' });
+  menu.push(null);
+  menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
+  menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });
+  menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });
+  menu.push({ text: intl.formatMessage(messages.filters), href: '/filters' });
+  menu.push(null);
+  menu.push({ text: intl.formatMessage(messages.logout), action: handleLogoutClick });
 
-    let menu = [];
-
-    menu.push({ text: intl.formatMessage(messages.edit_profile), href: '/settings/profile' });
-    menu.push({ text: intl.formatMessage(messages.preferences), href: '/settings/preferences' });
-    menu.push({ text: intl.formatMessage(messages.pins), to: '/pinned' });
-    menu.push(null);
-    menu.push({ text: intl.formatMessage(messages.follow_requests), to: '/follow_requests' });
-    menu.push({ text: intl.formatMessage(messages.favourites), to: '/favourites' });
-    menu.push({ text: intl.formatMessage(messages.bookmarks), to: '/bookmarks' });
-    menu.push({ text: intl.formatMessage(messages.lists), to: '/lists' });
-    menu.push({ text: intl.formatMessage(messages.followed_tags), to: '/followed_tags' });
-    menu.push(null);
-    menu.push({ text: intl.formatMessage(messages.mutes), to: '/mutes' });
-    menu.push({ text: intl.formatMessage(messages.blocks), to: '/blocks' });
-    menu.push({ text: intl.formatMessage(messages.domain_blocks), to: '/domain_blocks' });
-    menu.push({ text: intl.formatMessage(messages.filters), href: '/filters' });
-    menu.push(null);
-    menu.push({ text: intl.formatMessage(messages.logout), action: this.handleLogout });
-
-    return (
-      <div className='compose__action-bar'>
-        <div className='compose__action-bar-dropdown'>
-          <DropdownMenuContainer items={menu} icon='bars' iconComponent={MenuIcon} size={24} direction='right' />
-        </div>
-      </div>
-    );
-  }
-
-}
-
-export default injectIntl(ActionBar);
+  return (
+    <DropdownMenuContainer
+      items={menu}
+      icon='bars'
+      iconComponent={MoreHorizIcon}
+      size={24}
+      direction='right'
+    />
+  );
+};
diff --git a/app/javascript/flavours/glitch/features/compose/components/autosuggest_account.jsx b/app/javascript/flavours/glitch/features/compose/components/autosuggest_account.jsx
index 0a73bc1020..fe684c1483 100644
--- a/app/javascript/flavours/glitch/features/compose/components/autosuggest_account.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/autosuggest_account.jsx
@@ -15,7 +15,7 @@ export default class AutosuggestAccount extends ImmutablePureComponent {
 
     return (
       <div className='autosuggest-account' title={account.get('acct')}>
-        <div className='autosuggest-account-icon'><Avatar account={account} size={18} /></div>
+        <Avatar account={account} size={24} />
         <DisplayName account={account} />
       </div>
     );
diff --git a/app/javascript/flavours/glitch/features/compose/components/character_counter.jsx b/app/javascript/flavours/glitch/features/compose/components/character_counter.jsx
index 42452b30f6..f400d1fe2f 100644
--- a/app/javascript/flavours/glitch/features/compose/components/character_counter.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/character_counter.jsx
@@ -1,26 +1,18 @@
 import PropTypes from 'prop-types';
-import { PureComponent } from 'react';
 
 import { length } from 'stringz';
 
-export default class CharacterCounter extends PureComponent {
+export const CharacterCounter = ({ text, max }) => {
+  const diff = max - length(text);
 
-  static propTypes = {
-    text: PropTypes.string.isRequired,
-    max: PropTypes.number.isRequired,
-  };
-
-  checkRemainingText (diff) {
-    if (diff < 0) {
-      return <span className='character-counter character-counter--over'>{diff}</span>;
-    }
-
-    return <span className='character-counter'>{diff}</span>;
+  if (diff < 0) {
+    return <span className='character-counter character-counter--over'>{diff}</span>;
   }
 
-  render () {
-    const diff = this.props.max - length(this.props.text);
-    return this.checkRemainingText(diff);
-  }
+  return <span className='character-counter'>{diff}</span>;
+};
 
-}
+CharacterCounter.propTypes = {
+  text: PropTypes.string.isRequired,
+  max: PropTypes.number.isRequired,
+};
diff --git a/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx b/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx
index 1f24828c66..737bbfc126 100644
--- a/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/compose_form.jsx
@@ -10,8 +10,6 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
 
 import { length } from 'stringz';
 
-import LockIcon from '@/material-icons/400-24px/lock.svg?react';
-import { Icon }  from 'flavours/glitch/components/icon';
 import { WithOptionalRouterPropTypes, withOptionalRouter } from 'flavours/glitch/utils/react_router';
 
 import AutosuggestInput from '../../../components/autosuggest_input';
@@ -21,25 +19,27 @@ import { maxChars } from '../../../initial_state';
 import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container';
 import LanguageDropdown from '../containers/language_dropdown_container';
 import PollButtonContainer from '../containers/poll_button_container';
-import PollFormContainer from '../containers/poll_form_container';
 import PrivacyDropdownContainer from '../containers/privacy_dropdown_container';
-import ReplyIndicatorContainer from '../containers/reply_indicator_container';
 import SpoilerButtonContainer from '../containers/spoiler_button_container';
 import UploadButtonContainer from '../containers/upload_button_container';
 import UploadFormContainer from '../containers/upload_form_container';
 import WarningContainer from '../containers/warning_container';
 import { countableText } from '../util/counter';
 
-import CharacterCounter from './character_counter';
+import { CharacterCounter } from './character_counter';
+import { EditIndicator } from './edit_indicator';
+import { NavigationBar } from './navigation_bar';
+import { PollForm } from "./poll_form";
+import { ReplyIndicator } from './reply_indicator';
 
 const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
 
 const messages = defineMessages({
   placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
-  spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
-  publish: { id: 'compose_form.publish', defaultMessage: 'Publish' },
-  publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
-  saveChanges: { id: 'compose_form.save_changes', defaultMessage: 'Save changes' },
+  spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Content warning (optional)' },
+  publish: { id: 'compose_form.publish', defaultMessage: 'Post' },
+  saveChanges: { id: 'compose_form.save_changes', defaultMessage: 'Update' },
+  reply: { id: 'compose_form.reply', defaultMessage: 'Reply' },
 });
 
 class ComposeForm extends ImmutablePureComponent {
@@ -66,6 +66,7 @@ class ComposeForm extends ImmutablePureComponent {
     onPaste: PropTypes.func.isRequired,
     onPickEmoji: PropTypes.func.isRequired,
     autoFocus: PropTypes.bool,
+    withoutNavigation: PropTypes.bool,
     anyMedia: PropTypes.bool,
     isInReply: PropTypes.bool,
     singleColumn: PropTypes.bool,
@@ -224,93 +225,90 @@ class ComposeForm extends ImmutablePureComponent {
   };
 
   render () {
-    const { intl, onPaste, autoFocus } = this.props;
+    const { intl, onPaste, autoFocus, withoutNavigation } = this.props;
     const { highlighted } = this.state;
     const disabled = this.props.isSubmitting;
 
-    let publishText = '';
-
-    if (this.props.isEditing) {
-      publishText = intl.formatMessage(messages.saveChanges);
-    } else if (this.props.privacy === 'private' || this.props.privacy === 'direct') {
-      publishText = <><Icon id='lock' icon={LockIcon} /> {intl.formatMessage(messages.publish)}</>;
-    } else {
-      publishText = this.props.privacy !== 'unlisted' ? intl.formatMessage(messages.publishLoud, { publish: intl.formatMessage(messages.publish) }) : intl.formatMessage(messages.publish);
-    }
-
     return (
       <form className='compose-form' onSubmit={this.handleSubmit}>
+        <ReplyIndicator />
+        {!withoutNavigation && <NavigationBar />}
         <WarningContainer />
 
-        <ReplyIndicatorContainer />
+        <div className={classNames('compose-form__highlightable', { active: highlighted })} ref={this.setRef}>
+          <div className='compose-form__scrollable'>
+            <EditIndicator />
 
-        <div className={`spoiler-input ${this.props.spoiler ? 'spoiler-input--visible' : ''}`} ref={this.setRef} aria-hidden={!this.props.spoiler}>
-          <AutosuggestInput
-            placeholder={intl.formatMessage(messages.spoiler_placeholder)}
-            value={this.props.spoilerText}
-            onChange={this.handleChangeSpoilerText}
-            onKeyDown={this.handleKeyDown}
-            disabled={!this.props.spoiler}
-            ref={this.setSpoilerText}
-            suggestions={this.props.suggestions}
-            onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
-            onSuggestionsClearRequested={this.onSuggestionsClearRequested}
-            onSuggestionSelected={this.onSpoilerSuggestionSelected}
-            searchTokens={[':']}
-            id='cw-spoiler-input'
-            className='spoiler-input__input'
-            lang={this.props.lang}
-            spellCheck
-          />
-        </div>
+            {this.props.spoiler && (
+              <div className='spoiler-input'>
+                <div className='spoiler-input__border' />
 
-        <div className={classNames('compose-form__highlightable', { active: highlighted })}>
-          <AutosuggestTextarea
-            ref={this.textareaRef}
-            placeholder={intl.formatMessage(messages.placeholder)}
-            disabled={disabled}
-            value={this.props.text}
-            onChange={this.handleChange}
-            suggestions={this.props.suggestions}
-            onFocus={this.handleFocus}
-            onKeyDown={this.handleKeyDown}
-            onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
-            onSuggestionsClearRequested={this.onSuggestionsClearRequested}
-            onSuggestionSelected={this.onSuggestionSelected}
-            onPaste={onPaste}
-            autoFocus={autoFocus}
-            lang={this.props.lang}
-          >
-            <div className='compose-form__modifiers'>
-              <UploadFormContainer />
-              <PollFormContainer />
-            </div>
-          </AutosuggestTextarea>
-          <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
+                <AutosuggestInput
+                  placeholder={intl.formatMessage(messages.spoiler_placeholder)}
+                  value={this.props.spoilerText}
+                  disabled={disabled}
+                  onChange={this.handleChangeSpoilerText}
+                  onKeyDown={this.handleKeyDown}
+                  ref={this.setSpoilerText}
+                  suggestions={this.props.suggestions}
+                  onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
+                  onSuggestionsClearRequested={this.onSuggestionsClearRequested}
+                  onSuggestionSelected={this.onSpoilerSuggestionSelected}
+                  searchTokens={[':']}
+                  id='cw-spoiler-input'
+                  className='spoiler-input__input'
+                  lang={this.props.lang}
+                  spellCheck
+                />
 
-          <div className='compose-form__buttons-wrapper'>
-            <div className='compose-form__buttons'>
-              <UploadButtonContainer />
-              <PollButtonContainer />
+                <div className='spoiler-input__border' />
+              </div>
+            )}
+
+            <AutosuggestTextarea
+              ref={this.textareaRef}
+              placeholder={intl.formatMessage(messages.placeholder)}
+              disabled={disabled}
+              value={this.props.text}
+              onChange={this.handleChange}
+              suggestions={this.props.suggestions}
+              onFocus={this.handleFocus}
+              onKeyDown={this.handleKeyDown}
+              onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
+              onSuggestionsClearRequested={this.onSuggestionsClearRequested}
+              onSuggestionSelected={this.onSuggestionSelected}
+              onPaste={onPaste}
+              autoFocus={autoFocus}
+              lang={this.props.lang}
+            />
+          </div>
+
+          <UploadFormContainer />
+          <PollForm />
+
+          <div className='compose-form__footer'>
+            <div className='compose-form__dropdowns'>
               <PrivacyDropdownContainer disabled={this.props.isEditing} />
-              <SpoilerButtonContainer />
               <LanguageDropdown />
             </div>
 
-            <div className='character-counter__wrapper'>
-              <CharacterCounter max={maxChars} text={this.getFulltextForCharacterCounting()} />
-            </div>
-          </div>
-        </div>
+            <div className='compose-form__actions'>
+              <div className='compose-form__buttons'>
+                <UploadButtonContainer />
+                <PollButtonContainer />
+                <SpoilerButtonContainer />
+                <EmojiPickerDropdown onPickEmoji={this.handleEmojiPick} />
+                <CharacterCounter max={maxChars} text={this.getFulltextForCharacterCounting()} />
+              </div>
 
-        <div className='compose-form__publish'>
-          <div className='compose-form__publish-button-wrapper'>
-            <Button
-              type='submit'
-              text={publishText}
-              disabled={!this.canSubmit()}
-              block
-            />
+              <div className='compose-form__submit'>
+                <Button
+                  type='submit'
+                  text={intl.formatMessage(this.props.isEditing ? messages.saveChanges : (this.props.isInReply ? messages.reply : messages.publish))}
+                  disabled={!this.canSubmit()}
+                />
+              </div>
+            </div>
           </div>
         </div>
       </form>
diff --git a/app/javascript/flavours/glitch/features/compose/components/edit_indicator.jsx b/app/javascript/flavours/glitch/features/compose/components/edit_indicator.jsx
new file mode 100644
index 0000000000..4e3d909833
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/compose/components/edit_indicator.jsx
@@ -0,0 +1,62 @@
+import { useCallback } from 'react';
+
+import { defineMessages, useIntl, FormattedMessage } from 'react-intl';
+
+import { Link } from 'react-router-dom';
+
+import { useDispatch, useSelector } from 'react-redux';
+
+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 'flavours/glitch/actions/compose';
+import { Icon } from 'flavours/glitch/components/icon';
+import { IconButton } from 'flavours/glitch/components/icon_button';
+import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
+
+const messages = defineMessages({
+  cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
+});
+
+export const EditIndicator = () => {
+  const intl = useIntl();
+  const dispatch = useDispatch();
+  const id = useSelector(state => state.getIn(['compose', 'id']));
+  const status = useSelector(state => state.getIn(['statuses', id]));
+  const account = useSelector(state => state.getIn(['accounts', status?.get('account')]));
+
+  const handleCancelClick = useCallback(() => {
+    dispatch(cancelReplyCompose());
+  }, [dispatch]);
+
+  if (!status) {
+    return null;
+  }
+
+  const content = { __html: status.get('contentHtml') };
+
+  return (
+    <div className='edit-indicator'>
+      <div className='edit-indicator__header'>
+        <div className='edit-indicator__display-name'>
+          <Link to={`/@${account.get('acct')}`}>@{account.get('acct')}</Link>
+          ยท
+          <Link to={`/@${account.get('acct')}/${status.get('id')}`}><RelativeTimestamp timestamp={status.get('created_at')} /></Link>
+        </div>
+
+        <div className='edit-indicator__cancel'>
+          <IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={handleCancelClick} inverted />
+        </div>
+      </div>
+
+      <div className='edit-indicator__content translate' dangerouslySetInnerHTML={content} />
+
+      {(status.get('poll') || status.get('media_attachments').size > 0) && (
+        <div className='edit-indicator__attachments'>
+          {status.get('poll') && <><Icon icon={BarChart4BarsIcon} /><FormattedMessage id='reply_indicator.poll' defaultMessage='Poll' /></>}
+          {status.get('media_attachments').size > 0 && <><Icon icon={PhotoLibraryIcon} /><FormattedMessage id='reply_indicator.attachments' defaultMessage='{count, plural, one {# attachment} other {# attachments}}' values={{ count: status.get('media_attachments').size }} /></>}
+        </div>
+      )}
+    </div>
+  );
+};
diff --git a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx
index 4195316794..0846468c4e 100644
--- a/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/emoji_picker_dropdown.jsx
@@ -10,6 +10,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import { supportsPassiveEvents } from 'detect-passive-events';
 import Overlay from 'react-overlays/Overlay';
 
+import MoodIcon from '@/material-icons/400-24px/mood.svg?react';
+import { IconButton } from 'flavours/glitch/components/icon_button';
 import { useSystemEmojiFont } from 'flavours/glitch/initial_state';
 import { assetHost } from 'flavours/glitch/utils/config';
 
@@ -323,7 +325,6 @@ class EmojiPickerDropdown extends PureComponent {
     onPickEmoji: PropTypes.func.isRequired,
     onSkinTone: PropTypes.func.isRequired,
     skinTone: PropTypes.number.isRequired,
-    button: PropTypes.node,
   };
 
   state = {
@@ -381,23 +382,24 @@ class EmojiPickerDropdown extends PureComponent {
   };
 
   render () {
-    const { intl, onPickEmoji, onSkinTone, skinTone, frequentlyUsedEmojis, button } = this.props;
+    const { intl, onPickEmoji, onSkinTone, skinTone, frequentlyUsedEmojis } = this.props;
     const title = intl.formatMessage(messages.emoji);
     const { active, loading } = this.state;
 
     return (
-      <div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}>
-        <div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
-          {button || <img
-            className={classNames('emojione', { 'pulse-loading': active && loading })}
-            alt='๐Ÿ™‚'
-            src={`${assetHost}/emoji/1f642.svg`}
-          />}
-        </div>
+      <div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown} ref={this.setTargetRef}>
+        <IconButton
+          title={title}
+          aria-expanded={active}
+          active={active}
+          iconComponent={MoodIcon}
+          onClick={this.onToggle}
+          inverted
+        />
 
         <Overlay show={active} placement={'bottom'} target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
           {({ props, placement })=> (
-            <div {...props} style={{ ...props.style, width: 299 }}>
+            <div {...props} style={{ ...props.style }}>
               <div className={`dropdown-animation ${placement}`}>
                 <EmojiPickerMenu
                   custom_emojis={this.props.custom_emojis}
diff --git a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx
index a067f686e1..db1ce9cece 100644
--- a/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/language_dropdown.jsx
@@ -9,10 +9,11 @@ import { supportsPassiveEvents } from 'detect-passive-events';
 import fuzzysort from 'fuzzysort';
 import Overlay from 'react-overlays/Overlay';
 
+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 'flavours/glitch/components/icon';
 import { languages as preloadedLanguages } from 'flavours/glitch/initial_state';
-import { loupeIcon, deleteIcon } from 'flavours/glitch/utils/icons';
-
-import TextIconButton from './text_icon_button';
 
 const messages = defineMessages({
   changeLanguage: { id: 'compose.language.change', defaultMessage: 'Change language' },
@@ -231,7 +232,7 @@ class LanguageDropdownMenu extends PureComponent {
       <div ref={this.setRef}>
         <div className='emoji-mart-search'>
           <input type='search' value={searchValue} onChange={this.handleSearchChange} onKeyDown={this.handleSearchKeyDown} placeholder={intl.formatMessage(messages.search)} />
-          <button type='button' className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}>{!isSearching ? loupeIcon : deleteIcon}</button>
+          <button type='button' className='emoji-mart-search-icon' disabled={!isSearching} aria-label={intl.formatMessage(messages.clear)} onClick={this.handleClear}><Icon icon={!isSearching ? SearchIcon : CancelIcon} /></button>
         </div>
 
         <div className='language-dropdown__dropdown__results emoji-mart-scroll' role='listbox' ref={this.setListRef}>
@@ -297,20 +298,24 @@ class LanguageDropdown extends PureComponent {
   render () {
     const { value, intl, frequentlyUsedLanguages } = this.props;
     const { open, placement } = this.state;
+    const current = preloadedLanguages.find(lang => lang[0] === value) ?? [];
 
     return (
-      <div className={classNames('privacy-dropdown', placement, { active: open })}>
-        <div className='privacy-dropdown__value' ref={this.setTargetRef} >
-          <TextIconButton
-            className='privacy-dropdown__value-icon'
-            label={value && value.toUpperCase()}
-            title={intl.formatMessage(messages.changeLanguage)}
-            active={open}
-            onClick={this.handleToggle}
-          />
-        </div>
+      <div ref={this.setTargetRef} onKeyDown={this.handleKeyDown}>
+        <button
+          type='button'
+          title={intl.formatMessage(messages.changeLanguage)}
+          aria-expanded={open}
+          onClick={this.handleToggle}
+          onMouseDown={this.handleMouseDown}
+          onKeyDown={this.handleButtonKeyDown}
+          className={classNames('dropdown-button', { active: open })}
+        >
+          <Icon icon={TranslateIcon} />
+          <span className='dropdown-button__label'>{current[2] ?? value}</span>
+        </button>
 
-        <Overlay show={open} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
+        <Overlay show={open} offset={[5, 5]} placement={placement} flip target={this.findTarget} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
           {({ props, placement }) => (
             <div {...props}>
               <div className={`dropdown-animation language-dropdown__dropdown ${placement}`} >
diff --git a/app/javascript/flavours/glitch/features/compose/components/navigation_bar.jsx b/app/javascript/flavours/glitch/features/compose/components/navigation_bar.jsx
index 2f0bb79f89..ef9d01bd20 100644
--- a/app/javascript/flavours/glitch/features/compose/components/navigation_bar.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/navigation_bar.jsx
@@ -1,50 +1,36 @@
-import PropTypes from 'prop-types';
+import { useCallback } from 'react';
 
-import { FormattedMessage } from 'react-intl';
+import { useIntl, defineMessages } from 'react-intl';
 
-import { Link } from 'react-router-dom';
+import { useSelector, useDispatch } from 'react-redux';
 
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
+import CloseIcon from '@/material-icons/400-24px/close.svg?react';
+import { cancelReplyCompose } from 'flavours/glitch/actions/compose';
+import Account from 'flavours/glitch/components/account';
+import { IconButton } from 'flavours/glitch/components/icon_button';
+import { me } from 'flavours/glitch/initial_state';
 
-import { Avatar } from '../../../components/avatar';
+import { ActionBar } from './action_bar';
 
-import ActionBar from './action_bar';
 
-export default class NavigationBar extends ImmutablePureComponent {
+const messages = defineMessages({
+  cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
+});
 
-  static propTypes = {
-    account: ImmutablePropTypes.record.isRequired,
-    onLogout: PropTypes.func.isRequired,
-    onClose: PropTypes.func,
-  };
+export const NavigationBar = () => {
+  const dispatch = useDispatch();
+  const intl = useIntl();
+  const account = useSelector(state => state.getIn(['accounts', me]));
+  const isReplying = useSelector(state => !!state.getIn(['compose', 'in_reply_to']));
 
-  render () {
-    const username = this.props.account.get('acct');
-    return (
-      <div className='navigation-bar'>
-        <Link to={`/@${username}`}>
-          <span style={{ display: 'none' }}>{username}</span>
-          <Avatar account={this.props.account} size={46} />
-        </Link>
+  const handleCancelClick = useCallback(() => {
+    dispatch(cancelReplyCompose());
+  }, [dispatch]);
 
-        <div className='navigation-bar__profile'>
-          <span>
-            <Link to={`/@${username}`}>
-              <strong className='navigation-bar__profile-account'>@{username}</strong>
-            </Link>
-          </span>
-
-          <span>
-            <a href='/settings/profile' className='navigation-bar__profile-edit'><FormattedMessage id='navigation_bar.edit_profile' defaultMessage='Edit profile' /></a>
-          </span>
-        </div>
-
-        <div className='navigation-bar__actions'>
-          <ActionBar account={this.props.account} onLogout={this.props.onLogout} />
-        </div>
-      </div>
-    );
-  }
-
-}
+  return (
+    <div className='navigation-bar'>
+      <Account account={account} minimal />
+      {isReplying ? <IconButton title={intl.formatMessage(messages.cancel)} iconComponent={CloseIcon} onClick={handleCancelClick} /> : <ActionBar />}
+    </div>
+  );
+};
diff --git a/app/javascript/flavours/glitch/features/compose/components/poll_button.jsx b/app/javascript/flavours/glitch/features/compose/components/poll_button.jsx
index 4900d38119..345497abd3 100644
--- a/app/javascript/flavours/glitch/features/compose/components/poll_button.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/poll_button.jsx
@@ -3,11 +3,10 @@ import { PureComponent } from 'react';
 
 import { defineMessages, injectIntl } from 'react-intl';
 
-import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
+import BarChart4BarsIcon from '@/material-icons/400-24px/bar_chart_4_bars.svg?react';
 
 import { IconButton } from '../../../components/icon_button';
 
-
 const messages = defineMessages({
   add_poll: { id: 'poll_button.add_poll', defaultMessage: 'Add a poll' },
   remove_poll: { id: 'poll_button.remove_poll', defaultMessage: 'Remove poll' },
@@ -22,7 +21,6 @@ class PollButton extends PureComponent {
 
   static propTypes = {
     disabled: PropTypes.bool,
-    unavailable: PropTypes.bool,
     active: PropTypes.bool,
     onClick: PropTypes.func.isRequired,
     intl: PropTypes.object.isRequired,
@@ -33,17 +31,13 @@ class PollButton extends PureComponent {
   };
 
   render () {
-    const { intl, active, unavailable, disabled } = this.props;
-
-    if (unavailable) {
-      return null;
-    }
+    const { intl, active, disabled } = this.props;
 
     return (
       <div className='compose-form__poll-button'>
         <IconButton
           icon='tasks'
-          iconComponent={InsertChartIcon}
+          iconComponent={BarChart4BarsIcon}
           title={intl.formatMessage(active ? messages.remove_poll : messages.add_poll)}
           disabled={disabled}
           onClick={this.handleClick}
diff --git a/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx b/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx
index 1ee0a06c62..8964121c57 100644
--- a/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/poll_form.jsx
@@ -1,189 +1,162 @@
 import PropTypes from 'prop-types';
-import { PureComponent } from 'react';
+import { useCallback } from 'react';
 
-import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { defineMessages, useIntl } from 'react-intl';
 
 import classNames from 'classnames';
 
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
+import { useDispatch, useSelector } from 'react-redux';
 
-import AddIcon from '@/material-icons/400-24px/add.svg?react';
-import CloseIcon from '@/material-icons/400-24px/close.svg?react';
+import {
+  changePollSettings,
+  changePollOption,
+  clearComposeSuggestions,
+  fetchComposeSuggestions,
+  selectComposeSuggestion,
+} from 'flavours/glitch/actions/compose';
 import AutosuggestInput from 'flavours/glitch/components/autosuggest_input';
-import { Icon }  from 'flavours/glitch/components/icon';
-import { IconButton } from 'flavours/glitch/components/icon_button';
 
 const messages = defineMessages({
-  option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' },
-  add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' },
-  remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this choice' },
-  poll_duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' },
+  option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Option {number}' },
+  add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add option' },
+  remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this option' },
+  duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll length' },
+  type: { id: 'compose_form.poll.type', defaultMessage: 'Style' },
   switchToMultiple: { id: 'compose_form.poll.switch_to_multiple', defaultMessage: 'Change poll to allow multiple choices' },
   switchToSingle: { id: 'compose_form.poll.switch_to_single', defaultMessage: 'Change poll to allow for a single choice' },
   minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' },
   hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' },
   days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' },
+  singleChoice: { id: 'compose_form.poll.single', defaultMessage: 'Pick one' },
+  multipleChoice: { id: 'compose_form.poll.multiple', defaultMessage: 'Multiple choice' },
 });
 
-class OptionIntl extends PureComponent {
+const Select = ({ label, options, value, onChange }) => {
+  return (
+    <label className='compose-form__poll__select'>
+      <span className='compose-form__poll__select__label'>{label}</span>
 
-  static propTypes = {
-    title: PropTypes.string.isRequired,
-    lang: PropTypes.string,
-    index: PropTypes.number.isRequired,
-    isPollMultiple: PropTypes.bool,
-    autoFocus: PropTypes.bool,
-    onChange: PropTypes.func.isRequired,
-    onRemove: PropTypes.func.isRequired,
-    onToggleMultiple: PropTypes.func.isRequired,
-    suggestions: ImmutablePropTypes.list,
-    onClearSuggestions: PropTypes.func.isRequired,
-    onFetchSuggestions: PropTypes.func.isRequired,
-    onSuggestionSelected: PropTypes.func.isRequired,
-    intl: PropTypes.object.isRequired,
-  };
+      <select className='compose-form__poll__select__value' value={value} onChange={onChange}>
+        {options.map((option, i) => (
+          <option key={i} value={option.value}>{option.label}</option>
+        ))}
+      </select>
+    </label>
+  );
+};
 
-  handleOptionTitleChange = e => {
-    this.props.onChange(this.props.index, e.target.value);
-  };
+Select.propTypes = {
+  label: PropTypes.node,
+  value: PropTypes.any,
+  onChange: PropTypes.func,
+  options: PropTypes.arrayOf(PropTypes.shape({
+    label: PropTypes.node,
+    value: PropTypes.any,
+  })),
+};
 
-  handleOptionRemove = () => {
-    this.props.onRemove(this.props.index);
-  };
+const Option = ({ multipleChoice, index, title, autoFocus }) => {
+  const intl = useIntl();
+  const dispatch = useDispatch();
+  const suggestions = useSelector(state => state.getIn(['compose', 'suggestions']));
+  const lang = useSelector(state => state.getIn(['compose', 'language']));
 
+  const handleChange = useCallback(({ target: { value } }) => {
+    dispatch(changePollOption(index, value));
+  }, [dispatch, index]);
 
-  handleToggleMultiple = e => {
-    this.props.onToggleMultiple();
-    e.preventDefault();
-    e.stopPropagation();
-  };
+  const handleSuggestionsFetchRequested = useCallback(token => {
+    dispatch(fetchComposeSuggestions(token));
+  }, [dispatch]);
 
-  handleCheckboxKeypress = e => {
-    if (e.key === 'Enter' || e.key === ' ') {
-      this.handleToggleMultiple(e);
-    }
-  };
+  const handleSuggestionsClearRequested = useCallback(() => {
+    dispatch(clearComposeSuggestions());
+  }, [dispatch]);
 
-  onSuggestionsClearRequested = () => {
-    this.props.onClearSuggestions();
-  };
+  const handleSuggestionSelected = useCallback((tokenStart, token, value) => {
+    dispatch(selectComposeSuggestion(tokenStart, token, value, ['poll', 'options', index]));
+  }, [dispatch, index]);
 
-  onSuggestionsFetchRequested = (token) => {
-    this.props.onFetchSuggestions(token);
-  };
+  return (
+    <label className={classNames('poll__option editable', { empty: index > 1 && title.length === 0 })}>
+      <span className={classNames('poll__input', { checkbox: multipleChoice })} />
 
-  onSuggestionSelected = (tokenStart, token, value) => {
-    this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]);
-  };
+      <AutosuggestInput
+        placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
+        maxLength={100}
+        value={title}
+        lang={lang}
+        spellCheck
+        onChange={handleChange}
+        suggestions={suggestions}
+        onSuggestionsFetchRequested={handleSuggestionsFetchRequested}
+        onSuggestionsClearRequested={handleSuggestionsClearRequested}
+        onSuggestionSelected={handleSuggestionSelected}
+        searchTokens={[':']}
+        autoFocus={autoFocus}
+      />
+    </label>
+  );
+};
 
-  render () {
-    const { isPollMultiple, title, lang, index, autoFocus, intl } = this.props;
+Option.propTypes = {
+  title: PropTypes.string.isRequired,
+  index: PropTypes.number.isRequired,
+  multipleChoice: PropTypes.bool,
+  autoFocus: PropTypes.bool,
+};
 
-    return (
-      <li>
-        <label className='poll__option editable'>
-          <span
-            className={classNames('poll__input', { checkbox: isPollMultiple })}
-            onClick={this.handleToggleMultiple}
-            onKeyPress={this.handleCheckboxKeypress}
-            role='button'
-            tabIndex={0}
-            title={intl.formatMessage(isPollMultiple ? messages.switchToSingle : messages.switchToMultiple)}
-            aria-label={intl.formatMessage(isPollMultiple ? messages.switchToSingle : messages.switchToMultiple)}
-          />
+export const PollForm = () => {
+  const intl = useIntl();
+  const dispatch = useDispatch();
+  const poll = useSelector(state => state.getIn(['compose', 'poll']));
+  const options = poll?.get('options');
+  const expiresIn = poll?.get('expires_in');
+  const isMultiple = poll?.get('multiple');
 
-          <AutosuggestInput
-            placeholder={intl.formatMessage(messages.option_placeholder, { number: index + 1 })}
-            maxLength={100}
-            value={title}
-            lang={lang}
-            spellCheck
-            onChange={this.handleOptionTitleChange}
-            suggestions={this.props.suggestions}
-            onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
-            onSuggestionsClearRequested={this.onSuggestionsClearRequested}
-            onSuggestionSelected={this.onSuggestionSelected}
-            searchTokens={[':']}
-            autoFocus={autoFocus}
-          />
-        </label>
+  const handleDurationChange = useCallback(({ target: { value } }) => {
+    dispatch(changePollSettings(value, isMultiple));
+  }, [dispatch, isMultiple]);
 
-        <div className='poll__cancel'>
-          <IconButton disabled={index <= 1} title={intl.formatMessage(messages.remove_option)} icon='times' iconComponent={CloseIcon} onClick={this.handleOptionRemove} />
-        </div>
-      </li>
-    );
+  const handleTypeChange = useCallback(({ target: { value } }) => {
+    dispatch(changePollSettings(expiresIn, value === 'true'));
+  }, [dispatch, expiresIn]);
+
+  if (poll === null) {
+    return null;
   }
 
-}
+  return (
+    <div className='compose-form__poll'>
+      {options.map((title, i) => (
+        <Option
+          title={title}
+          key={i}
+          index={i}
+          multipleChoice={isMultiple}
+          autoFocus={i === 0}
+        />
+      ))}
 
-const Option = injectIntl(OptionIntl);
+      <div className='compose-form__poll__footer'>
+        <Select label={intl.formatMessage(messages.duration)} options={[
+          { value: 300, label: intl.formatMessage(messages.minutes, { number: 5 })},
+          { value: 1800, label: intl.formatMessage(messages.minutes, { number: 30 })},
+          { value: 3600, label: intl.formatMessage(messages.hours, { number: 1 })},
+          { value: 21600, label: intl.formatMessage(messages.hours, { number: 6 })},
+          { value: 43200, label: intl.formatMessage(messages.hours, { number: 12 })},
+          { value: 86400, label: intl.formatMessage(messages.days, { number: 1 })},
+          { value: 259200, label: intl.formatMessage(messages.days, { number: 3 })},
+          { value: 604800, label: intl.formatMessage(messages.days, { number: 7 })},
+        ]} value={expiresIn} onChange={handleDurationChange} />
 
-class PollForm extends ImmutablePureComponent {
+        <div className='compose-form__poll__footer__sep' />
 
-  static propTypes = {
-    options: ImmutablePropTypes.list,
-    lang: PropTypes.string,
-    expiresIn: PropTypes.number,
-    isMultiple: PropTypes.bool,
-    onChangeOption: PropTypes.func.isRequired,
-    onAddOption: PropTypes.func.isRequired,
-    onRemoveOption: PropTypes.func.isRequired,
-    onChangeSettings: PropTypes.func.isRequired,
-    suggestions: ImmutablePropTypes.list,
-    onClearSuggestions: PropTypes.func.isRequired,
-    onFetchSuggestions: PropTypes.func.isRequired,
-    onSuggestionSelected: PropTypes.func.isRequired,
-    intl: PropTypes.object.isRequired,
-  };
-
-  handleAddOption = () => {
-    this.props.onAddOption('');
-  };
-
-  handleSelectDuration = e => {
-    this.props.onChangeSettings(e.target.value, this.props.isMultiple);
-  };
-
-  handleToggleMultiple = () => {
-    this.props.onChangeSettings(this.props.expiresIn, !this.props.isMultiple);
-  };
-
-  render () {
-    const { options, lang, expiresIn, isMultiple, onChangeOption, onRemoveOption, intl, ...other } = this.props;
-
-    if (!options) {
-      return null;
-    }
-
-    const autoFocusIndex = options.indexOf('');
-
-    return (
-      <div className='compose-form__poll-wrapper'>
-        <ul>
-          {options.map((title, i) => <Option title={title} lang={lang} key={i} index={i} onChange={onChangeOption} onRemove={onRemoveOption} isPollMultiple={isMultiple} onToggleMultiple={this.handleToggleMultiple} autoFocus={i === autoFocusIndex} {...other} />)}
-        </ul>
-
-        <div className='poll__footer'>
-          <button type='button' disabled={options.size >= 5} className='button button-secondary' onClick={this.handleAddOption}><Icon id='plus' icon={AddIcon} /> <FormattedMessage {...messages.add_option} /></button>
-
-          {/* eslint-disable-next-line jsx-a11y/no-onchange */}
-          <select value={expiresIn} onChange={this.handleSelectDuration}>
-            <option value={300}>{intl.formatMessage(messages.minutes, { number: 5 })}</option>
-            <option value={1800}>{intl.formatMessage(messages.minutes, { number: 30 })}</option>
-            <option value={3600}>{intl.formatMessage(messages.hours, { number: 1 })}</option>
-            <option value={21600}>{intl.formatMessage(messages.hours, { number: 6 })}</option>
-            <option value={43200}>{intl.formatMessage(messages.hours, { number: 12 })}</option>
-            <option value={86400}>{intl.formatMessage(messages.days, { number: 1 })}</option>
-            <option value={259200}>{intl.formatMessage(messages.days, { number: 3 })}</option>
-            <option value={604800}>{intl.formatMessage(messages.days, { number: 7 })}</option>
-          </select>
-        </div>
+        <Select label={intl.formatMessage(messages.type)} options={[
+          { value: false, label: intl.formatMessage(messages.singleChoice) },
+          { value: true, label: intl.formatMessage(messages.multipleChoice) },
+        ]} value={isMultiple} onChange={handleTypeChange} />
       </div>
-    );
-  }
-
-}
-
-export default injectIntl(PollForm);
+    </div>
+  );
+};
diff --git a/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx b/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx
index f7c893f28a..8a49f71511 100644
--- a/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/privacy_dropdown.jsx
@@ -5,28 +5,27 @@ import { injectIntl, defineMessages } from 'react-intl';
 
 import classNames from 'classnames';
 
-
 import { supportsPassiveEvents } from 'detect-passive-events';
 import Overlay from 'react-overlays/Overlay';
 
 import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
+import InfoIcon from '@/material-icons/400-24px/info.svg?react';
 import LockIcon from '@/material-icons/400-24px/lock.svg?react';
-import LockOpenIcon from '@/material-icons/400-24px/lock_open.svg?react';
 import PublicIcon from '@/material-icons/400-24px/public.svg?react';
+import QuietTimeIcon from '@/material-icons/400-24px/quiet_time.svg?react';
 import { Icon }  from 'flavours/glitch/components/icon';
 
-import { IconButton } from '../../../components/icon_button';
-
 const messages = defineMessages({
   public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
-  public_long: { id: 'privacy.public.long', defaultMessage: 'Visible for all' },
-  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
-  unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Visible for all, but opted-out of discovery features' },
-  private_short: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
-  private_long: { id: 'privacy.private.long', defaultMessage: 'Visible for followers only' },
-  direct_short: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
-  direct_long: { id: 'privacy.direct.long', defaultMessage: 'Visible for mentioned users only' },
-  change_privacy: { id: 'privacy.change', defaultMessage: 'Adjust status privacy' },
+  public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' },
+  unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Quiet public' },
+  unlisted_long: { id: 'privacy.unlisted.long', defaultMessage: 'Fewer algorithmic fanfares' },
+  private_short: { id: 'privacy.private.short', defaultMessage: 'Followers' },
+  private_long: { id: 'privacy.private.long', defaultMessage: 'Only your followers' },
+  direct_short: { id: 'privacy.direct.short', defaultMessage: 'Specific people' },
+  direct_long: { id: 'privacy.direct.long', defaultMessage: 'Everyone mentioned in the post' },
+  change_privacy: { id: 'privacy.change', defaultMessage: 'Change post privacy' },
+  unlisted_extra: { id: 'privacy.unlisted.additional', defaultMessage: 'This behaves exactly like public, except the post will not appear in live feeds or hashtags, explore, or Mastodon search, even if you are opted-in account-wide.' },
 });
 
 const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
@@ -135,6 +134,12 @@ class PrivacyDropdownMenu extends PureComponent {
               <strong>{item.text}</strong>
               {item.meta}
             </div>
+
+            {item.extra && (
+              <div className='privacy-dropdown__option__additional' title={item.extra}>
+                <Icon id='info-circle' icon={InfoIcon} />
+              </div>
+            )}
           </div>
         ))}
       </div>
@@ -163,30 +168,11 @@ class PrivacyDropdown extends PureComponent {
   };
 
   handleToggle = () => {
-    if (this.props.isUserTouching && this.props.isUserTouching()) {
-      if (this.state.open) {
-        this.props.onModalClose();
-      } else {
-        this.props.onModalOpen({
-          actions: this.options.map(option => ({ ...option, active: option.value === this.props.value })),
-          onClick: this.handleModalActionClick,
-        });
-      }
-    } else {
-      if (this.state.open && this.activeElement) {
-        this.activeElement.focus({ preventScroll: true });
-      }
-      this.setState({ open: !this.state.open });
+    if (this.state.open && this.activeElement) {
+      this.activeElement.focus({ preventScroll: true });
     }
-  };
 
-  handleModalActionClick = (e) => {
-    e.preventDefault();
-
-    const { value } = this.options[e.currentTarget.getAttribute('data-index')];
-
-    this.props.onModalClose();
-    this.props.onChange(value);
+    this.setState({ open: !this.state.open });
   };
 
   handleKeyDown = e => {
@@ -228,7 +214,7 @@ class PrivacyDropdown extends PureComponent {
 
     this.options = [
       { icon: 'globe', iconComponent: PublicIcon, value: 'public', text: formatMessage(messages.public_short), meta: formatMessage(messages.public_long) },
-      { icon: 'unlock', iconComponent: LockOpenIcon,  value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long) },
+      { icon: 'unlock', iconComponent: QuietTimeIcon,  value: 'unlisted', text: formatMessage(messages.unlisted_short), meta: formatMessage(messages.unlisted_long), extra: formatMessage(messages.unlisted_extra) },
       { icon: 'lock', iconComponent: LockIcon, value: 'private', text: formatMessage(messages.private_short), meta: formatMessage(messages.private_long) },
     ];
 
@@ -259,23 +245,21 @@ class PrivacyDropdown extends PureComponent {
 
     return (
       <div ref={this.setTargetRef} onKeyDown={this.handleKeyDown}>
-        <IconButton
-          className='privacy-dropdown__value-icon'
-          icon={valueOption.icon}
-          iconComponent={valueOption.iconComponent}
+        <button
+          type='button'
           title={intl.formatMessage(messages.change_privacy)}
-          size={18}
-          expanded={open}
-          active={open}
-          inverted
+          aria-expanded={open}
           onClick={this.handleToggle}
           onMouseDown={this.handleMouseDown}
           onKeyDown={this.handleButtonKeyDown}
-          style={{ height: null, lineHeight: '27px' }}
           disabled={disabled}
-        />
+          className={classNames('dropdown-button', { active: open })}
+        >
+          <Icon id={valueOption.icon} icon={valueOption.iconComponent} />
+          <span className='dropdown-button__label'>{valueOption.text}</span>
+        </button>
 
-        <Overlay show={open} placement={placement} flip target={this.findTarget} container={container} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
+        <Overlay show={open} offset={[5, 5]} placement={placement} flip target={this.findTarget} container={container} popperConfig={{ strategy: 'fixed', onFirstUpdate: this.handleOverlayEnter }}>
           {({ props, placement }) => (
             <div {...props}>
               <div className={`dropdown-animation privacy-dropdown__dropdown ${placement}`}>
diff --git a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx
index e3721b6fa9..5c895195a0 100644
--- a/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/reply_indicator.jsx
@@ -1,74 +1,48 @@
-import PropTypes from 'prop-types';
+import { FormattedMessage } from 'react-intl';
 
-import { defineMessages, injectIntl } from 'react-intl';
+import { Link } from 'react-router-dom';
 
-import ImmutablePropTypes from 'react-immutable-proptypes';
-import ImmutablePureComponent from 'react-immutable-pure-component';
+import { useSelector } from 'react-redux';
 
-import CloseIcon from '@/material-icons/400-24px/close.svg?react';
-import AttachmentList from 'flavours/glitch/components/attachment_list';
-import { WithOptionalRouterPropTypes, withOptionalRouter } from 'flavours/glitch/utils/react_router';
+import BarChart4BarsIcon from '@/material-icons/400-24px/bar_chart_4_bars.svg?react';
+import PhotoLibraryIcon from '@/material-icons/400-24px/photo_library.svg?react';
+import { Avatar } from 'flavours/glitch/components/avatar';
+import { DisplayName } from 'flavours/glitch/components/display_name';
+import { Icon } from 'flavours/glitch/components/icon';
 
-import { Avatar } from '../../../components/avatar';
-import { DisplayName } from '../../../components/display_name';
-import { IconButton } from '../../../components/icon_button';
+export const ReplyIndicator = () => {
+  const inReplyToId = useSelector(state => state.getIn(['compose', 'in_reply_to']));
+  const status = useSelector(state => state.getIn(['statuses', inReplyToId]));
+  const account = useSelector(state => state.getIn(['accounts', status?.get('account')]));
 
-const messages = defineMessages({
-  cancel: { id: 'reply_indicator.cancel', defaultMessage: 'Cancel' },
-});
+  if (!status) {
+    return null;
+  }
 
-class ReplyIndicator extends ImmutablePureComponent {
+  const content = { __html: status.get('contentHtml') };
 
-  static propTypes = {
-    status: ImmutablePropTypes.map,
-    onCancel: PropTypes.func.isRequired,
-    intl: PropTypes.object.isRequired,
-    ...WithOptionalRouterPropTypes,
-  };
+  return (
+    <div className='reply-indicator'>
+      <div className='reply-indicator__line' />
 
-  handleClick = () => {
-    this.props.onCancel();
-  };
+      <Link to={`/@${account.get('acct')}`} className='detailed-status__display-avatar'>
+        <Avatar account={account} size={46} />
+      </Link>
 
-  handleAccountClick = (e) => {
-    if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
-      e.preventDefault();
-      this.props.history?.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
-    }
-  };
-
-  render () {
-    const { status, intl } = this.props;
-
-    if (!status) {
-      return null;
-    }
-
-    const content = { __html: status.get('contentHtml') };
-
-    return (
-      <div className='reply-indicator'>
-        <div className='reply-indicator__header'>
-          <div className='reply-indicator__cancel'><IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted /></div>
-
-          <a href={`/@${status.getIn(['account', 'acct'])}`} onClick={this.handleAccountClick} className='reply-indicator__display-name'>
-            <div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
-            <DisplayName account={status.get('account')} />
-          </a>
-        </div>
+      <div className='reply-indicator__main'>
+        <Link to={`/@${account.get('acct')}`} className='detailed-status__display-name'>
+          <DisplayName account={account} />
+        </Link>
 
         <div className='reply-indicator__content translate' dangerouslySetInnerHTML={content} />
 
-        {status.get('media_attachments').size > 0 && (
-          <AttachmentList
-            compact
-            media={status.get('media_attachments')}
-          />
+        {(status.get('poll') || status.get('media_attachments').size > 0) && (
+          <div className='reply-indicator__attachments'>
+            {status.get('poll') && <><Icon icon={BarChart4BarsIcon} /><FormattedMessage id='reply_indicator.poll' defaultMessage='Poll' /></>}
+            {status.get('media_attachments').size > 0 && <><Icon icon={PhotoLibraryIcon} /><FormattedMessage id='reply_indicator.attachments' defaultMessage='{count, plural, one {# attachment} other {# attachments}}' values={{ count: status.get('media_attachments').size }} /></>}
+          </div>
         )}
       </div>
-    );
-  }
-
-}
-
-export default withOptionalRouter(injectIntl(ReplyIndicator));
+    </div>
+  );
+};
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload.jsx b/app/javascript/flavours/glitch/features/compose/components/upload.jsx
index fd2d80e2f2..2568aacb54 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/upload.jsx
@@ -2,6 +2,8 @@ import PropTypes from 'prop-types';
 
 import { FormattedMessage } from 'react-intl';
 
+import classNames from 'classnames';
+
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
@@ -9,7 +11,8 @@ import spring from 'react-motion/lib/spring';
 
 import CloseIcon from '@/material-icons/400-24px/close.svg?react';
 import EditIcon from '@/material-icons/400-24px/edit.svg?react';
-import InfoIcon from '@/material-icons/400-24px/info.svg?react';
+import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
+import { Blurhash } from 'flavours/glitch/components/blurhash';
 import { Icon }  from 'flavours/glitch/components/icon';
 
 import Motion from '../../ui/util/optional_motion';
@@ -18,6 +21,7 @@ export default class Upload extends ImmutablePureComponent {
 
   static propTypes = {
     media: ImmutablePropTypes.map.isRequired,
+    sensitive: PropTypes.bool,
     onUndo: PropTypes.func.isRequired,
     onOpenFocalPoint: PropTypes.func.isRequired,
   };
@@ -33,7 +37,7 @@ export default class Upload extends ImmutablePureComponent {
   };
 
   render () {
-    const { media } = this.props;
+    const { media, sensitive } = this.props;
 
     if (!media) {
       return null;
@@ -43,22 +47,26 @@ export default class Upload extends ImmutablePureComponent {
     const focusY = media.getIn(['meta', 'focus', 'y']);
     const x = ((focusX /  2) + .5) * 100;
     const y = ((focusY / -2) + .5) * 100;
+    const missingDescription = (media.get('description') || '').length === 0;
 
     return (
       <div className='compose-form__upload'>
         <Motion defaultStyle={{ scale: 0.8 }} style={{ scale: spring(1, { stiffness: 180, damping: 12 }) }}>
           {({ scale }) => (
-            <div className='compose-form__upload-thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: `url(${media.get('preview_url')})`, backgroundPosition: `${x}% ${y}%` }}>
+            <div className='compose-form__upload__thumbnail' style={{ transform: `scale(${scale})`, backgroundImage: !sensitive ? `url(${media.get('preview_url')})` : null, backgroundPosition: `${x}% ${y}%` }}>
+              {sensitive && <Blurhash
+                hash={media.get('blurhash')}
+                className='compose-form__upload__preview'
+              />}
+
               <div className='compose-form__upload__actions'>
-                <button type='button' className='icon-button' onClick={this.handleUndoClick}><Icon id='times' icon={CloseIcon} /> <FormattedMessage id='upload_form.undo' defaultMessage='Delete' /></button>
-                <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='pencil' icon={EditIcon} /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
+                <button type='button' className='icon-button compose-form__upload__delete' onClick={this.handleUndoClick}><Icon icon={CloseIcon} /></button>
+                <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon icon={EditIcon} /> <FormattedMessage id='upload_form.edit' defaultMessage='Edit' /></button>
               </div>
 
-              {(media.get('description') || '').length === 0 && (
-                <div className='compose-form__upload__warning'>
-                  <button type='button' className='icon-button' onClick={this.handleFocalPointClick}><Icon id='info-circle' icon={InfoIcon} /> <FormattedMessage id='upload_form.description_missing' defaultMessage='No description added' /></button>
-                </div>
-              )}
+              <div className='compose-form__upload__warning'>
+                <button type='button' className={classNames('icon-button', { active: missingDescription })} onClick={this.handleFocalPointClick}>{missingDescription && <Icon icon={WarningIcon} />} ALT</button>
+              </div>
             </div>
           )}
         </Motion>
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_button.jsx b/app/javascript/flavours/glitch/features/compose/components/upload_button.jsx
index 923d6a3c47..4b8f7213b7 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload_button.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_button.jsx
@@ -6,9 +6,8 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { connect } from 'react-redux';
 
-import AddPhotoAlternateIcon from '@/material-icons/400-24px/add_photo_alternate.svg?react';
-
-import { IconButton } from '../../../components/icon_button';
+import PhotoLibraryIcon from '@/material-icons/400-24px/photo_library.svg?react';
+import { IconButton } from 'flavours/glitch/components/icon_button';
 
 const messages = defineMessages({
   upload: { id: 'upload_button.label', defaultMessage: 'Add images, a video or an audio file' },
@@ -31,7 +30,6 @@ class UploadButton extends ImmutablePureComponent {
 
   static propTypes = {
     disabled: PropTypes.bool,
-    unavailable: PropTypes.bool,
     onSelectFile: PropTypes.func.isRequired,
     style: PropTypes.object,
     resetFileKey: PropTypes.number,
@@ -54,17 +52,13 @@ class UploadButton extends ImmutablePureComponent {
   };
 
   render () {
-    const { intl, resetFileKey, unavailable, disabled, acceptContentTypes } = this.props;
-
-    if (unavailable) {
-      return null;
-    }
+    const { intl, resetFileKey, disabled, acceptContentTypes } = this.props;
 
     const message = intl.formatMessage(messages.upload);
 
     return (
       <div className='compose-form__upload-button'>
-        <IconButton icon='paperclip' iconComponent={AddPhotoAlternateIcon} title={message} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
+        <IconButton icon='paperclip' iconComponent={PhotoLibraryIcon} title={message} disabled={disabled} onClick={this.handleClick} className='compose-form__upload-button-icon' size={18} inverted style={iconStyle} />
         <label>
           <span style={{ display: 'none' }}>{message}</span>
           <input
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_form.jsx b/app/javascript/flavours/glitch/features/compose/components/upload_form.jsx
index cf2e53ad90..46bac7823b 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload_form.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_form.jsx
@@ -1,7 +1,6 @@
 import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 
-import SensitiveButtonContainer from '../containers/sensitive_button_container';
 import UploadContainer from '../containers/upload_container';
 import UploadProgressContainer from '../containers/upload_progress_container';
 
@@ -15,17 +14,17 @@ export default class UploadForm extends ImmutablePureComponent {
     const { mediaIds } = this.props;
 
     return (
-      <div className='compose-form__upload-wrapper'>
+      <>
         <UploadProgressContainer />
 
-        <div className='compose-form__uploads-wrapper'>
-          {mediaIds.map(id => (
-            <UploadContainer id={id} key={id} />
-          ))}
-        </div>
-
-        {!mediaIds.isEmpty() && <SensitiveButtonContainer />}
-      </div>
+        {mediaIds.size > 0 && (
+          <div className='compose-form__uploads'>
+            {mediaIds.map(id => (
+              <UploadContainer id={id} key={id} />
+            ))}
+          </div>
+        )}
+      </>
     );
   }
 
diff --git a/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx b/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx
index f4408b5460..7af5d9090e 100644
--- a/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx
+++ b/app/javascript/flavours/glitch/features/compose/components/upload_progress.jsx
@@ -35,9 +35,7 @@ export default class UploadProgress extends PureComponent {
 
     return (
       <div className='upload-progress'>
-        <div className='upload-progress__icon'>
-          <Icon id='upload' icon={UploadFileIcon} />
-        </div>
+        <Icon id='upload' icon={UploadFileIcon} />
 
         <div className='upload-progress__message'>
           {message}
diff --git a/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js b/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
deleted file mode 100644
index 459fffd910..0000000000
--- a/app/javascript/flavours/glitch/features/compose/containers/navigation_container.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { defineMessages, injectIntl } from 'react-intl';
-
-import { connect }   from 'react-redux';
-
-import { openModal } from 'flavours/glitch/actions/modal';
-import { logOut } from 'flavours/glitch/utils/log_out';
-
-import { me } from '../../../initial_state';
-import NavigationBar from '../components/navigation_bar';
-
-const messages = defineMessages({
-  logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
-  logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
-});
-
-const mapStateToProps = state => {
-  return {
-    account: state.getIn(['accounts', me]),
-  };
-};
-
-const mapDispatchToProps = (dispatch, { intl }) => ({
-  onLogout () {
-    dispatch(openModal({
-      modalType: 'CONFIRM',
-      modalProps: {
-        message: intl.formatMessage(messages.logoutMessage),
-        confirm: intl.formatMessage(messages.logoutConfirm),
-        closeWhenConfirm: false,
-        onConfirm: () => logOut(),
-      },
-    }));
-  },
-});
-
-export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(NavigationBar));
diff --git a/app/javascript/flavours/glitch/features/compose/containers/poll_button_container.js b/app/javascript/flavours/glitch/features/compose/containers/poll_button_container.js
index b7785ecbb4..9de388f64a 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/poll_button_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/poll_button_container.js
@@ -4,7 +4,7 @@ import { addPoll, removePoll } from '../../../actions/compose';
 import PollButton from '../components/poll_button';
 
 const mapStateToProps = state => ({
-  unavailable: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0),
+  disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size > 0),
   active: state.getIn(['compose', 'poll']) !== null,
 });
 
diff --git a/app/javascript/flavours/glitch/features/compose/containers/poll_form_container.js b/app/javascript/flavours/glitch/features/compose/containers/poll_form_container.js
deleted file mode 100644
index 177ffcea6a..0000000000
--- a/app/javascript/flavours/glitch/features/compose/containers/poll_form_container.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import { connect } from 'react-redux';
-
-import {
-  addPollOption,
-  removePollOption,
-  changePollOption,
-  changePollSettings,
-  clearComposeSuggestions,
-  fetchComposeSuggestions,
-  selectComposeSuggestion,
-} from '../../../actions/compose';
-import PollForm from '../components/poll_form';
-
-const mapStateToProps = state => ({
-  suggestions: state.getIn(['compose', 'suggestions']),
-  options: state.getIn(['compose', 'poll', 'options']),
-  lang: state.getIn(['compose', 'language']),
-  expiresIn: state.getIn(['compose', 'poll', 'expires_in']),
-  isMultiple: state.getIn(['compose', 'poll', 'multiple']),
-});
-
-const mapDispatchToProps = dispatch => ({
-  onAddOption(title) {
-    dispatch(addPollOption(title));
-  },
-
-  onRemoveOption(index) {
-    dispatch(removePollOption(index));
-  },
-
-  onChangeOption(index, title) {
-    dispatch(changePollOption(index, title));
-  },
-
-  onChangeSettings(expiresIn, isMultiple) {
-    dispatch(changePollSettings(expiresIn, isMultiple));
-  },
-
-  onClearSuggestions () {
-    dispatch(clearComposeSuggestions());
-  },
-
-  onFetchSuggestions (token) {
-    dispatch(fetchComposeSuggestions(token));
-  },
-
-  onSuggestionSelected (position, token, accountId, path) {
-    dispatch(selectComposeSuggestion(position, token, accountId, path));
-  },
-
-});
-
-export default connect(mapStateToProps, mapDispatchToProps)(PollForm);
diff --git a/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js b/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js
deleted file mode 100644
index 1147e448af..0000000000
--- a/app/javascript/flavours/glitch/features/compose/containers/reply_indicator_container.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { connect } from 'react-redux';
-
-import { cancelReplyCompose } from '../../../actions/compose';
-import { makeGetStatus } from '../../../selectors';
-import ReplyIndicator from '../components/reply_indicator';
-
-const makeMapStateToProps = () => {
-  const getStatus = makeGetStatus();
-
-  const mapStateToProps = state => {
-    let statusId = state.getIn(['compose', 'id'], null);
-    let editing  = true;
-
-    if (statusId === null) {
-      statusId = state.getIn(['compose', 'in_reply_to']);
-      editing  = false;
-    }
-
-    return {
-      status: getStatus(state, { id: statusId }),
-      editing,
-    };
-  };
-
-  return mapStateToProps;
-};
-
-const mapDispatchToProps = dispatch => ({
-
-  onCancel () {
-    dispatch(cancelReplyCompose());
-  },
-
-});
-
-export default connect(makeMapStateToProps, mapDispatchToProps)(ReplyIndicator);
diff --git a/app/javascript/flavours/glitch/features/compose/containers/sensitive_button_container.jsx b/app/javascript/flavours/glitch/features/compose/containers/sensitive_button_container.jsx
deleted file mode 100644
index ad56ff1b92..0000000000
--- a/app/javascript/flavours/glitch/features/compose/containers/sensitive_button_container.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import PropTypes from 'prop-types';
-import { PureComponent } from 'react';
-
-import { injectIntl, defineMessages, FormattedMessage } from 'react-intl';
-
-import classNames from 'classnames';
-
-import { connect } from 'react-redux';
-
-import { changeComposeSensitivity } from 'flavours/glitch/actions/compose';
-
-const messages = defineMessages({
-  marked: {
-    id: 'compose_form.sensitive.marked',
-    defaultMessage: '{count, plural, one {Media is marked as sensitive} other {Media is marked as sensitive}}',
-  },
-  unmarked: {
-    id: 'compose_form.sensitive.unmarked',
-    defaultMessage: '{count, plural, one {Media is not marked as sensitive} other {Media is not marked as sensitive}}',
-  },
-});
-
-const mapStateToProps = state => ({
-  active: state.getIn(['compose', 'sensitive']),
-  disabled: state.getIn(['compose', 'spoiler']),
-  mediaCount: state.getIn(['compose', 'media_attachments']).size,
-});
-
-const mapDispatchToProps = dispatch => ({
-
-  onClick () {
-    dispatch(changeComposeSensitivity());
-  },
-
-});
-
-class SensitiveButton extends PureComponent {
-
-  static propTypes = {
-    active: PropTypes.bool,
-    disabled: PropTypes.bool,
-    mediaCount: PropTypes.number,
-    onClick: PropTypes.func.isRequired,
-    intl: PropTypes.object.isRequired,
-  };
-
-  render () {
-    const { active, disabled, mediaCount, onClick, intl } = this.props;
-
-    return (
-      <div className='compose-form__sensitive-button'>
-        <label className={classNames('icon-button', { active })} title={intl.formatMessage(active ? messages.marked : messages.unmarked, { count: mediaCount })}>
-          <input
-            name='mark-sensitive'
-            type='checkbox'
-            checked={active}
-            onChange={onClick}
-            disabled={disabled}
-          />
-
-          <FormattedMessage
-            id='compose_form.sensitive.hide'
-            defaultMessage='{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}'
-            values={{ count: mediaCount }}
-          />
-        </label>
-      </div>
-    );
-  }
-
-}
-
-export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(SensitiveButton));
diff --git a/app/javascript/flavours/glitch/features/compose/containers/spoiler_button_container.js b/app/javascript/flavours/glitch/features/compose/containers/spoiler_button_container.js
index b3d7a71335..fce1816fe8 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/spoiler_button_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/spoiler_button_container.js
@@ -2,8 +2,10 @@ import { injectIntl, defineMessages } from 'react-intl';
 
 import { connect } from 'react-redux';
 
+import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
+import { IconButton } from 'flavours/glitch/components/icon_button';
+
 import { changeComposeSpoilerness } from '../../../actions/compose';
-import TextIconButton from '../components/text_icon_button';
 
 const messages = defineMessages({
   marked: { id: 'compose_form.spoiler.marked', defaultMessage: 'Text is hidden behind warning' },
@@ -11,10 +13,12 @@ const messages = defineMessages({
 });
 
 const mapStateToProps = (state, { intl }) => ({
-  label: 'CW',
+  iconComponent: WarningIcon,
   title: intl.formatMessage(state.getIn(['compose', 'spoiler']) ? messages.marked : messages.unmarked),
   active: state.getIn(['compose', 'spoiler']),
   ariaControls: 'cw-spoiler-input',
+  size: 18,
+  inverted: true,
 });
 
 const mapDispatchToProps = dispatch => ({
@@ -25,4 +29,4 @@ const mapDispatchToProps = dispatch => ({
 
 });
 
-export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(TextIconButton));
+export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(IconButton));
diff --git a/app/javascript/flavours/glitch/features/compose/containers/upload_button_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_button_container.js
index 42195da617..7c4757b6c3 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/upload_button_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/upload_button_container.js
@@ -4,8 +4,7 @@ import { uploadCompose } from '../../../actions/compose';
 import UploadButton from '../components/upload_button';
 
 const mapStateToProps = state => ({
-  disabled: state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size + state.getIn(['compose', 'pending_media_attachments']) > 3 || state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type')))),
-  unavailable: state.getIn(['compose', 'poll']) !== null,
+  disabled: state.getIn(['compose', 'poll']) !== null || state.getIn(['compose', 'is_uploading']) || (state.getIn(['compose', 'media_attachments']).size + state.getIn(['compose', 'pending_media_attachments']) > 3 || state.getIn(['compose', 'media_attachments']).some(m => ['video', 'audio'].includes(m.get('type')))),
   resetFileKey: state.getIn(['compose', 'resetFileKey']),
 });
 
diff --git a/app/javascript/flavours/glitch/features/compose/containers/upload_container.js b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js
index 77bb90db87..a17a691444 100644
--- a/app/javascript/flavours/glitch/features/compose/containers/upload_container.js
+++ b/app/javascript/flavours/glitch/features/compose/containers/upload_container.js
@@ -5,6 +5,7 @@ import Upload from '../components/upload';
 
 const mapStateToProps = (state, { id }) => ({
   media: state.getIn(['compose', 'media_attachments']).find(item => item.get('id') === id),
+  sensitive: state.getIn(['compose', 'spoiler']),
 });
 
 const mapDispatchToProps = dispatch => ({
diff --git a/app/javascript/flavours/glitch/features/compose/index.jsx b/app/javascript/flavours/glitch/features/compose/index.jsx
index 5bbb7fab96..8d0c194227 100644
--- a/app/javascript/flavours/glitch/features/compose/index.jsx
+++ b/app/javascript/flavours/glitch/features/compose/index.jsx
@@ -30,7 +30,6 @@ import { isMobile } from '../../is_mobile';
 import Motion from '../ui/util/optional_motion';
 
 import ComposeFormContainer from './containers/compose_form_container';
-import NavigationContainer from './containers/navigation_container';
 import SearchContainer from './containers/search_container';
 import SearchResultsContainer from './containers/search_results_container';
 
@@ -129,8 +128,6 @@ class Compose extends PureComponent {
 
           <div className='drawer__pager'>
             <div className='drawer__inner' onFocus={this.onFocus}>
-              <NavigationContainer onClose={this.onBlur} />
-
               <ComposeFormContainer autoFocus={!isMobile(window.innerWidth)} />
 
               <div className='drawer__inner__mastodon'>
@@ -152,7 +149,6 @@ class Compose extends PureComponent {
 
     return (
       <Column onFocus={this.onFocus}>
-        <NavigationContainer onClose={this.onBlur} />
         <ComposeFormContainer />
 
         <Helmet>
diff --git a/app/javascript/flavours/glitch/features/getting_started/index.jsx b/app/javascript/flavours/glitch/features/getting_started/index.jsx
index 866904eafb..a3464f146a 100644
--- a/app/javascript/flavours/glitch/features/getting_started/index.jsx
+++ b/app/javascript/flavours/glitch/features/getting_started/index.jsx
@@ -32,7 +32,7 @@ import { preferencesLink } from 'flavours/glitch/utils/backend_links';
 
 
 import { me, showTrends } from '../../initial_state';
-import NavigationBar from '../compose/components/navigation_bar';
+import { NavigationBar } from '../compose/components/navigation_bar';
 import ColumnLink from '../ui/components/column_link';
 import ColumnSubheading from '../ui/components/column_subheading';
 
diff --git a/app/javascript/flavours/glitch/features/local_settings/page/index.jsx b/app/javascript/flavours/glitch/features/local_settings/page/index.jsx
index dab63c4ce6..849a553e06 100644
--- a/app/javascript/flavours/glitch/features/local_settings/page/index.jsx
+++ b/app/javascript/flavours/glitch/features/local_settings/page/index.jsx
@@ -28,9 +28,9 @@ const messages = defineMessages({
   pop_in_left: { id: 'settings.pop_in_left', defaultMessage: 'Left' },
   pop_in_right: { id: 'settings.pop_in_right', defaultMessage:  'Right' },
   public: { id: 'privacy.public.short', defaultMessage: 'Public' },
-  unlisted: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
-  private: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
-  direct: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
+  unlisted: { id: 'privacy.unlisted.short', defaultMessage: 'Quiet public' },
+  private: { id: 'privacy.private.short', defaultMessage: 'Followers' },
+  direct: { id: 'privacy.direct.short', defaultMessage: 'Specific people' },
 });
 
 class LocalSettingsPage extends PureComponent {
diff --git a/app/javascript/flavours/glitch/features/standalone/compose/index.jsx b/app/javascript/flavours/glitch/features/standalone/compose/index.jsx
index c36e843f5a..a0482c3ce5 100644
--- a/app/javascript/flavours/glitch/features/standalone/compose/index.jsx
+++ b/app/javascript/flavours/glitch/features/standalone/compose/index.jsx
@@ -1,21 +1,15 @@
-import { PureComponent } from 'react';
+import ComposeFormContainer from 'flavours/glitch/features/compose/containers/compose_form_container';
+import LoadingBarContainer from 'flavours/glitch/features/ui/containers/loading_bar_container';
+import ModalContainer from 'flavours/glitch/features/ui/containers/modal_container';
+import NotificationsContainer from 'flavours/glitch/features/ui/containers/notifications_container';
 
-import ComposeFormContainer from '../../compose/containers/compose_form_container';
-import LoadingBarContainer from '../../ui/containers/loading_bar_container';
-import ModalContainer from '../../ui/containers/modal_container';
-import NotificationsContainer from '../../ui/containers/notifications_container';
+const Compose = () => (
+  <>
+    <ComposeFormContainer autoFocus withoutNavigation />
+    <NotificationsContainer />
+    <ModalContainer />
+    <LoadingBarContainer className='loading-bar' />
+  </>
+);
 
-export default class Compose extends PureComponent {
-
-  render () {
-    return (
-      <div>
-        <ComposeFormContainer autoFocus />
-        <NotificationsContainer />
-        <ModalContainer />
-        <LoadingBarContainer className='loading-bar' />
-      </div>
-    );
-  }
-
-}
+export default Compose;
diff --git a/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx b/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx
index 3f9ba99e4f..a99d76c1a4 100644
--- a/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx
+++ b/app/javascript/flavours/glitch/features/ui/components/compose_panel.jsx
@@ -6,7 +6,6 @@ import { connect } from 'react-redux';
 import { mountCompose, unmountCompose } from 'flavours/glitch/actions/compose';
 import ServerBanner from 'flavours/glitch/components/server_banner';
 import ComposeFormContainer from 'flavours/glitch/features/compose/containers/compose_form_container';
-import NavigationContainer from 'flavours/glitch/features/compose/containers/navigation_container';
 import SearchContainer from 'flavours/glitch/features/compose/containers/search_container';
 
 import LinkFooter from './link_footer';
@@ -46,10 +45,7 @@ class ComposePanel extends PureComponent {
         )}
 
         {signedIn && (
-          <>
-            <NavigationContainer />
-            <ComposeFormContainer singleColumn />
-          </>
+          <ComposeFormContainer singleColumn />
         )}
 
         <LinkFooter />
diff --git a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx
index caed29c252..d584277dc3 100644
--- a/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx
+++ b/app/javascript/flavours/glitch/features/ui/components/focal_point_modal.jsx
@@ -21,7 +21,7 @@ import { Button } from 'flavours/glitch/components/button';
 import { GIFV } from 'flavours/glitch/components/gifv';
 import { IconButton } from 'flavours/glitch/components/icon_button';
 import Audio from 'flavours/glitch/features/audio';
-import CharacterCounter from 'flavours/glitch/features/compose/components/character_counter';
+import { CharacterCounter } from 'flavours/glitch/features/compose/components/character_counter';
 import UploadProgress from 'flavours/glitch/features/compose/components/upload_progress';
 import { Tesseract as fetchTesseract } from 'flavours/glitch/features/ui/util/async-components';
 import { me } from 'flavours/glitch/initial_state';
diff --git a/app/javascript/flavours/glitch/features/ui/components/mute_modal.jsx b/app/javascript/flavours/glitch/features/ui/components/mute_modal.jsx
index 2d95cabef8..fa81ea81a3 100644
--- a/app/javascript/flavours/glitch/features/ui/components/mute_modal.jsx
+++ b/app/javascript/flavours/glitch/features/ui/components/mute_modal.jsx
@@ -108,7 +108,6 @@ class MuteModal extends PureComponent {
           <div>
             <span><FormattedMessage id='mute_modal.duration' defaultMessage='Duration' />: </span>
 
-            {/* eslint-disable-next-line jsx-a11y/no-onchange */}
             <select value={muteDuration} onChange={this.changeMuteDuration}>
               <option value={0}>{intl.formatMessage(messages.indefinite)}</option>
               <option value={300}>{intl.formatMessage(messages.minutes, { number: 5 })}</option>
diff --git a/app/javascript/flavours/glitch/locales/en.json b/app/javascript/flavours/glitch/locales/en.json
index 94e7415b03..7321f5ac3d 100644
--- a/app/javascript/flavours/glitch/locales/en.json
+++ b/app/javascript/flavours/glitch/locales/en.json
@@ -5,13 +5,6 @@
   "account.follows_you": "Follows you",
   "account.suspended_disclaimer_full": "This user has been suspended by a moderator.",
   "account.view_full_profile": "View full profile",
-  "advanced_options.icon_title": "Advanced options",
-  "advanced_options.local-only.long": "Do not post to other instances",
-  "advanced_options.local-only.short": "Local-only",
-  "advanced_options.local-only.tooltip": "This post is local-only",
-  "advanced_options.threaded_mode.long": "Automatically opens a reply on posting",
-  "advanced_options.threaded_mode.short": "Threaded mode",
-  "advanced_options.threaded_mode.tooltip": "Threaded mode enabled",
   "boost_modal.missing_description": "This toot contains some media without description",
   "column.favourited_by": "Favourited by",
   "column.heading": "Misc",
@@ -21,26 +14,13 @@
   "column_subheading.lists": "Lists",
   "column_subheading.navigation": "Navigation",
   "community.column_settings.allow_local_only": "Show local-only toots",
-  "compose.attach": "Attach...",
-  "compose.attach.doodle": "Draw something",
-  "compose.attach.upload": "Upload a file",
-  "compose.content-type.html": "HTML",
-  "compose.content-type.markdown": "Markdown",
-  "compose.content-type.plain": "Plain text",
-  "compose_form.poll.multiple_choices": "Allow multiple choices",
-  "compose_form.poll.single_choice": "Allow one choice",
-  "compose_form.spoiler": "Hide text behind warning",
   "confirmation_modal.do_not_ask_again": "Do not ask for confirmation again",
   "confirmations.deprecated_settings.confirm": "Use Mastodon preferences",
   "confirmations.deprecated_settings.message": "Some of the glitch-soc device-specific {app_settings} you are using have been replaced by Mastodon {preferences} and will be overriden:",
-  "confirmations.missing_media_description.confirm": "Send anyway",
-  "confirmations.missing_media_description.edit": "Edit media",
-  "confirmations.missing_media_description.message": "At least one media attachment is lacking a description. Consider describing all media attachments for the visually impaired before sending your toot.",
   "confirmations.unfilter.author": "Author",
   "confirmations.unfilter.confirm": "Show",
   "confirmations.unfilter.edit_filter": "Edit filter",
   "confirmations.unfilter.filters": "Matching {count, plural, one {filter} other {filters}}",
-  "content-type.change": "Content type",
   "direct.group_by_conversations": "Group by conversation",
   "endorsed_accounts_editor.endorsed_accounts": "Featured accounts",
   "favourite_modal.combo": "You can press {combo} to skip this next time",
diff --git a/app/javascript/flavours/glitch/packs/share.jsx b/app/javascript/flavours/glitch/packs/share.jsx
index 21f1da638d..7a4e333653 100644
--- a/app/javascript/flavours/glitch/packs/share.jsx
+++ b/app/javascript/flavours/glitch/packs/share.jsx
@@ -10,10 +10,12 @@ function loaded() {
 
   if (mountNode) {
     const attr = mountNode.getAttribute('data-props');
-    if(!attr) return;
+
+    if (!attr) return;
 
     const props = JSON.parse(attr);
     const root = createRoot(mountNode);
+
     root.render(<ComposeContainer {...props} />);
   }
 }
diff --git a/app/javascript/flavours/glitch/reducers/compose.js b/app/javascript/flavours/glitch/reducers/compose.js
index 8a221e6406..e11a103026 100644
--- a/app/javascript/flavours/glitch/reducers/compose.js
+++ b/app/javascript/flavours/glitch/reducers/compose.js
@@ -44,9 +44,7 @@ import {
   COMPOSE_RESET,
   COMPOSE_POLL_ADD,
   COMPOSE_POLL_REMOVE,
-  COMPOSE_POLL_OPTION_ADD,
   COMPOSE_POLL_OPTION_CHANGE,
-  COMPOSE_POLL_OPTION_REMOVE,
   COMPOSE_POLL_SETTINGS_CHANGE,
   INIT_MEDIA_EDIT_MODAL,
   COMPOSE_CHANGE_MEDIA_DESCRIPTION,
@@ -366,6 +364,18 @@ const updateSuggestionTags = (state, token) => {
   });
 };
 
+const updatePoll = (state, index, value) => state.updateIn(['poll', 'options'], options => {
+  const tmp = options.set(index, value).filterNot(x => x.trim().length === 0);
+
+  if (tmp.size === 0) {
+    return tmp.push('').push('');
+  } else if (tmp.size < 4) {
+    return tmp.push('');
+  }
+
+  return tmp;
+});
+
 export default function compose(state = initialState, action) {
   switch(action.type) {
   case STORE_HYDRATE:
@@ -649,12 +659,8 @@ export default function compose(state = initialState, action) {
     return state.set('poll', initialPoll);
   case COMPOSE_POLL_REMOVE:
     return state.set('poll', null);
-  case COMPOSE_POLL_OPTION_ADD:
-    return state.updateIn(['poll', 'options'], options => options.push(action.title));
   case COMPOSE_POLL_OPTION_CHANGE:
-    return state.setIn(['poll', 'options', action.index], action.title);
-  case COMPOSE_POLL_OPTION_REMOVE:
-    return state.updateIn(['poll', 'options'], options => options.delete(action.index));
+    return updatePoll(state, action.index, action.title);
   case COMPOSE_POLL_SETTINGS_CHANGE:
     return state.update('poll', poll => poll.set('expires_in', action.expiresIn).set('multiple', action.isMultiple));
   case COMPOSE_LANGUAGE_CHANGE:
diff --git a/app/javascript/flavours/glitch/styles/_mixins.scss b/app/javascript/flavours/glitch/styles/_mixins.scss
index ec2a7e7ced..a59bb2d441 100644
--- a/app/javascript/flavours/glitch/styles/_mixins.scss
+++ b/app/javascript/flavours/glitch/styles/_mixins.scss
@@ -24,13 +24,14 @@
   outline: 0;
   box-sizing: border-box;
   width: 100%;
-  border: 0;
   box-shadow: none;
   font-family: inherit;
   background: $ui-base-color;
   color: $darker-text-color;
   border-radius: 4px;
-  font-size: 14px;
+  border: 1px solid lighten($ui-base-color, 8%);
+  font-size: 17px;
+  line-height: normal;
   margin: 0;
 }
 
diff --git a/app/javascript/flavours/glitch/styles/admin.scss b/app/javascript/flavours/glitch/styles/admin.scss
index 2f4027b03f..5963f3ee6e 100644
--- a/app/javascript/flavours/glitch/styles/admin.scss
+++ b/app/javascript/flavours/glitch/styles/admin.scss
@@ -1336,6 +1336,9 @@ a.sparkline {
 
     &__label {
       padding: 15px;
+      display: flex;
+      gap: 8px;
+      align-items: center;
     }
 
     &__rules {
@@ -1346,6 +1349,9 @@ a.sparkline {
   &__rule {
     cursor: pointer;
     padding: 15px;
+    display: flex;
+    gap: 8px;
+    align-items: center;
   }
 }
 
diff --git a/app/javascript/flavours/glitch/styles/basics.scss b/app/javascript/flavours/glitch/styles/basics.scss
index a796bce674..7dc8e340c3 100644
--- a/app/javascript/flavours/glitch/styles/basics.scss
+++ b/app/javascript/flavours/glitch/styles/basics.scss
@@ -8,7 +8,7 @@
 
 body {
   font-family: $font-sans-serif, sans-serif;
-  background: darken($ui-base-color, 7%);
+  background: darken($ui-base-color, 8%);
   font-size: 13px;
   line-height: 18px;
   font-weight: 400;
diff --git a/app/javascript/flavours/glitch/styles/components.scss b/app/javascript/flavours/glitch/styles/components.scss
index 54a119ded7..5be0e85606 100644
--- a/app/javascript/flavours/glitch/styles/components.scss
+++ b/app/javascript/flavours/glitch/styles/components.scss
@@ -373,46 +373,155 @@ body > [data-popper-placement] {
   }
 }
 
-.compose-form {
-  padding: 10px; // glitch: reduced padding
+.autosuggest-textarea {
+  &__textarea {
+    background: transparent;
+    min-height: 100px;
+    padding-bottom: 0;
+    resize: none;
+    scrollbar-color: initial;
 
-  &__sensitive-button {
-    padding: 10px;
-    padding-top: 0;
-    font-size: 14px;
-    font-weight: 500;
-
-    &.active {
-      color: $highlight-text-color;
-    }
-
-    input[type='checkbox'] {
-      appearance: none;
-      display: inline-block;
-      position: relative;
-      border: 1px solid $ui-primary-color;
-      box-sizing: border-box;
-      width: 18px;
-      height: 18px;
-      flex: 0 0 auto;
-      margin-inline-end: 10px;
-      top: -1px;
-      border-radius: 4px;
-      vertical-align: middle;
-      cursor: inherit;
-
-      &:checked {
-        border-color: $highlight-text-color;
-        background: $highlight-text-color
-          url("data:image/svg+xml;utf8,<svg width='18' height='18' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M4.5 8.5L8 12l6-6' stroke='white' stroke-width='1.5'/></svg>")
-          center center no-repeat;
-      }
+    &::-webkit-scrollbar {
+      all: unset;
     }
   }
 
-  .compose-form__warning {
+  &__suggestions {
+    box-shadow: var(--dropdown-shadow);
+    background: $ui-base-color;
+    border: 1px solid lighten($ui-base-color, 14%);
+    border-radius: 0 0 4px 4px;
+    color: $secondary-text-color;
+    font-size: 14px;
+    padding: 0;
+
+    &__item {
+      box-sizing: border-box;
+      display: flex;
+      align-items: center;
+      height: 48px;
+      cursor: pointer;
+      font-size: 14px;
+      line-height: 20px;
+      letter-spacing: 0.25px;
+      color: $secondary-text-color;
+
+      &:last-child {
+        border-radius: 0 0 4px 4px;
+      }
+
+      &:hover,
+      &:focus,
+      &:active,
+      &.selected {
+        background: $ui-highlight-color;
+        color: $primary-text-color;
+
+        .autosuggest-account .display-name__account {
+          color: inherit;
+        }
+      }
+    }
+  }
+}
+
+.autosuggest-account,
+.autosuggest-emoji,
+.autosuggest-hashtag {
+  flex: 1 0 0;
+  display: flex;
+  flex-direction: row;
+  align-items: center;
+  justify-content: flex-start;
+  gap: 12px;
+  padding: 8px 12px;
+  overflow: hidden;
+  text-overflow: ellipsis;
+}
+
+.autosuggest-account {
+  .display-name {
+    font-weight: 400;
+    display: flex;
+    flex-direction: column;
+    flex: 1 0 0;
+  }
+
+  .display-name__account {
+    display: block;
+    line-height: 16px;
+    font-size: 12px;
+    color: $dark-text-color;
+  }
+}
+
+.autosuggest-hashtag {
+  justify-content: space-between;
+
+  &__name {
+    flex: 1 1 auto;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+
+  &__uses {
+    flex: 0 0 auto;
+    text-align: end;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}
+
+.autosuggest-emoji {
+  &__name {
+    flex: 1 0 0;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+  }
+}
+
+.autosuggest-account .account__avatar,
+.autosuggest-emoji img {
+  display: block;
+  width: 24px;
+  height: 24px;
+  flex: 0 0 auto;
+}
+
+.compose-form {
+  display: flex;
+  flex-direction: column;
+  gap: 32px;
+
+  .layout-multiple-columns &,
+  .column & {
+    padding: 15px;
+  }
+
+  &__highlightable {
+    display: flex;
+    flex-direction: column;
+    gap: 16px;
+    flex: 0 1 auto;
+    border-radius: 4px;
+    border: 1px solid lighten($ui-base-color, 8%);
+    transition: border-color 300ms linear;
+    min-height: 0;
+    position: relative;
+    background: $ui-base-color;
+    overflow-y: auto;
+
+    &.active {
+      transition: none;
+      border-color: $ui-highlight-color;
+    }
+  }
+
+  &__warning {
     color: $inverted-text-color;
-    margin-bottom: 10px;
     background: $ui-primary-color;
     box-shadow: 0 2px 6px rgba($base-shadow-color, 0.3);
     padding: 8px 10px;
@@ -444,32 +553,27 @@ body > [data-popper-placement] {
     }
   }
 
-  .emoji-picker-dropdown {
-    position: absolute;
-    top: 0;
-    inset-inline-end: 0;
-  }
-
-  .compose-form__autosuggest-wrapper {
-    position: relative;
-  }
-
-  .autosuggest-textarea,
-  .autosuggest-input,
   .spoiler-input {
-    position: relative;
-    width: 100%;
-  }
+    display: flex;
+    align-items: stretch;
 
-  .spoiler-input {
-    height: 0;
-    transform-origin: bottom;
-    opacity: 0;
+    &__border {
+      background: url('~images/warning-stripes.svg') repeat-y;
+      width: 5px;
+      flex: 0 0 auto;
 
-    &.spoiler-input--visible {
-      height: 36px;
-      margin-bottom: 11px;
-      opacity: 1;
+      &:first-child {
+        border-start-start-radius: 4px;
+      }
+
+      &:last-child {
+        border-start-end-radius: 4px;
+      }
+    }
+
+    .autosuggest-input {
+      flex: 1 1 auto;
+      border-bottom: 1px solid lighten($ui-base-color, 8%);
     }
   }
 
@@ -479,269 +583,303 @@ body > [data-popper-placement] {
     box-sizing: border-box;
     width: 100%;
     margin: 0;
-    color: $inverted-text-color;
-    background: $simple-background-color;
-    padding: 10px;
+    color: $secondary-text-color;
+    background: $ui-base-color;
     font-family: inherit;
     font-size: 14px;
-    resize: vertical;
+    padding: 12px;
+    line-height: normal;
     border: 0;
     outline: 0;
 
-    &::placeholder {
-      color: $dark-text-color;
-    }
-
     &:focus {
       outline: 0;
     }
-
-    @media screen and (width <= 600px) {
-      font-size: 16px;
-    }
   }
 
   .spoiler-input__input {
-    border-radius: 4px;
+    padding: 12px 12px - 5px;
+    background: mix($ui-base-color, $ui-highlight-color, 85%);
+    color: $highlight-text-color;
   }
 
-  .autosuggest-textarea__textarea {
-    min-height: 100px;
-    border-radius: 4px 4px 0 0;
-    padding-bottom: 0;
-    padding-right: 10px + 22px; // Cannot use inline-end because of dir=auto
-    resize: none;
-    scrollbar-color: initial;
-
-    &::-webkit-scrollbar {
-      all: unset;
-    }
-
-    @media screen and (width <= 600px) {
-      height: 100px !important; // Prevent auto-resize textarea
-      resize: vertical;
-    }
-  }
-
-  .autosuggest-textarea__suggestions-wrapper {
-    position: relative;
-    height: 0;
-  }
-
-  .autosuggest-textarea__suggestions {
-    box-sizing: border-box;
-    display: none;
-    position: absolute;
-    top: 100%;
-    width: 100%;
-    z-index: 99;
-    box-shadow: 4px 4px 6px rgba($base-shadow-color, 0.4);
-    background: $ui-secondary-color;
-    border-radius: 0 0 4px 4px;
-    color: $inverted-text-color;
-    font-size: 14px;
-    padding: 6px;
-
-    &.autosuggest-textarea__suggestions--visible {
-      display: block;
-    }
-  }
-
-  .autosuggest-textarea__suggestions__item {
-    padding: 10px;
-    cursor: pointer;
-    border-radius: 4px;
-
-    &:hover,
-    &:focus,
-    &:active,
-    &.selected {
-      background: darken($ui-secondary-color, 10%);
-    }
-  }
-
-  .autosuggest-account,
-  .autosuggest-emoji,
-  .autosuggest-hashtag {
+  &__dropdowns {
     display: flex;
-    flex-direction: row;
     align-items: center;
-    justify-content: flex-start;
-    line-height: 18px;
-    font-size: 14px;
-  }
+    gap: 8px;
 
-  .autosuggest-hashtag {
-    justify-content: space-between;
-
-    &__name {
-      flex: 1 1 auto;
+    & > div {
       overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
-
-    strong {
-      font-weight: 500;
-    }
-
-    &__uses {
-      flex: 0 0 auto;
-      text-align: end;
-      overflow: hidden;
-      text-overflow: ellipsis;
-      white-space: nowrap;
-    }
-  }
-
-  .autosuggest-account-icon,
-  .autosuggest-emoji img {
-    display: block;
-    margin-inline-end: 8px;
-    width: 16px;
-    height: 16px;
-  }
-
-  .autosuggest-account .display-name__account {
-    color: $lighter-text-color;
-  }
-
-  .compose-form__modifiers {
-    color: $inverted-text-color;
-    font-family: inherit;
-    font-size: 14px;
-    background: $simple-background-color;
-
-    .compose-form__upload-wrapper {
-      overflow: hidden;
-    }
-
-    .compose-form__uploads-wrapper {
       display: flex;
-      flex-direction: row;
-      padding: 5px;
-      flex-wrap: wrap;
+    }
+  }
+
+  &__uploads {
+    display: flex;
+    gap: 8px;
+    padding: 0 12px;
+    flex-wrap: wrap;
+    align-self: stretch;
+    align-items: flex-start;
+    align-content: flex-start;
+    justify-content: center;
+  }
+
+  &__upload {
+    flex: 1 1 0;
+    min-width: calc(50% - 8px);
+
+    &__actions {
+      display: flex;
+      align-items: flex-start;
+      justify-content: space-between;
+      padding: 8px;
     }
 
-    .compose-form__upload {
-      flex: 1 1 0;
-      min-width: 40%;
-      margin: 5px;
-
-      &__actions {
-        background: linear-gradient(
-          180deg,
-          rgba($base-shadow-color, 0.8) 0,
-          rgba($base-shadow-color, 0.35) 80%,
-          transparent
-        );
-        display: flex;
-        align-items: flex-start;
-        justify-content: space-between;
-      }
-
-      .icon-button {
-        flex: 0 1 auto;
-        color: $secondary-text-color;
-        font-size: 14px;
-        font-weight: 500;
-        padding: 10px;
-        font-family: inherit;
-
-        .icon {
-          width: 15px;
-          height: 15px;
-        }
-
-        &:hover,
-        &:focus,
-        &:active {
-          color: lighten($secondary-text-color, 7%);
-        }
-      }
-
-      &__warning {
-        position: absolute;
-        z-index: 2;
-        bottom: 0;
-        inset-inline-start: 0;
-        inset-inline-end: 0;
-        box-sizing: border-box;
-        background: linear-gradient(
-          0deg,
-          rgba($base-shadow-color, 0.8) 0,
-          rgba($base-shadow-color, 0.35) 80%,
-          transparent
-        );
-      }
+    &__preview {
+      position: absolute;
+      width: 100%;
+      height: 100%;
+      border-radius: 6px;
+      z-index: -1;
+      top: 0;
+      inset-inline-start: 0;
     }
 
-    .compose-form__upload-thumbnail {
-      border-radius: 4px;
-      background-color: $base-shadow-color;
+    &__thumbnail {
+      width: 100%;
+      height: 144px;
+      border-radius: 6px;
       background-position: center;
       background-size: cover;
       background-repeat: no-repeat;
-      height: 140px;
-      width: 100%;
       overflow: hidden;
     }
+
+    .icon-button {
+      flex: 0 0 auto;
+      color: $white;
+      background: rgba(0, 0, 0, 75%);
+      border-radius: 6px;
+      font-size: 12px;
+      line-height: 16px;
+      font-weight: 500;
+      padding: 4px 8px;
+      font-family: inherit;
+
+      .icon {
+        width: 15px;
+        height: 15px;
+      }
+    }
+
+    .icon-button.compose-form__upload__delete {
+      padding: 3px;
+      border-radius: 50%;
+
+      .icon {
+        width: 18px;
+        height: 18px;
+      }
+    }
+
+    &__warning {
+      position: absolute;
+      z-index: 2;
+      bottom: 0;
+      inset-inline-start: 0;
+      inset-inline-end: 0;
+      padding: 8px;
+
+      .icon-button.active {
+        color: #ffbe2e;
+        background: rgba(0, 0, 0, 75%);
+      }
+    }
   }
 
-  .compose-form__buttons-wrapper {
-    padding: 10px;
-    background: darken($simple-background-color, 8%);
-    border-radius: 0 0 4px 4px;
+  &__footer {
     display: flex;
-    justify-content: space-between;
-    flex: 0 0 auto;
+    flex-direction: column;
+    gap: 12px;
+    padding: 12px;
+    padding-top: 0;
+  }
 
-    .compose-form__buttons {
+  &__submit {
+    display: flex;
+    align-items: center;
+    flex: 1 1 auto;
+    max-width: 100%;
+    overflow: hidden;
+  }
+
+  &__buttons {
+    display: flex;
+    gap: 8px;
+    align-items: center;
+    flex: 1 1 auto;
+
+    & > div {
       display: flex;
-      gap: 2px;
-
-      .icon-button {
-        height: 100%;
-      }
-
-      .compose-form__upload-button-icon {
-        line-height: 27px;
-      }
-
-      .compose-form__sensitive-button {
-        display: none;
-
-        &.compose-form__sensitive-button--visible {
-          display: block;
-        }
-
-        .compose-form__sensitive-button__icon {
-          line-height: 27px;
-        }
-      }
     }
 
-    .icon-button,
-    .text-icon-button {
-      box-sizing: content-box;
-      padding: 0 3px;
+    .icon-button {
+      padding: 3px;
     }
 
-    .character-counter__wrapper {
-      align-self: center;
-      margin-inline-end: 4px;
+    .icon-button .icon {
+      width: 18px;
+      height: 18px;
     }
   }
 
-  .compose-form__publish {
+  &__actions {
     display: flex;
-    justify-content: flex-end;
-    min-width: 0;
+    align-items: center;
     flex: 0 0 auto;
+    gap: 12px;
+    flex-wrap: wrap;
 
-    .compose-form__publish-button-wrapper {
-      padding-top: 15px;
+    .button {
+      display: block; // Otherwise text-ellipsis doesn't work
+      font-size: 14px;
+      line-height: normal;
+      font-weight: 700;
+      flex: 1 1 auto;
+      padding: 5px 12px;
+      border-radius: 4px;
     }
+
+    .icon-button {
+      box-sizing: content-box;
+      color: $highlight-text-color;
+
+      &:hover,
+      &:focus,
+      &:active {
+        color: $highlight-text-color;
+      }
+
+      &.disabled {
+        color: $highlight-text-color;
+        opacity: 0.5;
+      }
+
+      &.active {
+        background: $ui-highlight-color;
+        color: $primary-text-color;
+      }
+    }
+  }
+
+  &__poll {
+    display: flex;
+    flex-direction: column;
+    align-self: stretch;
+    gap: 8px;
+
+    .poll__option {
+      padding: 0 12px;
+      gap: 8px;
+
+      &.empty:not(:focus-within) {
+        opacity: 0.5;
+      }
+    }
+
+    .poll__input {
+      width: 17px;
+      height: 17px;
+      border-color: $darker-text-color;
+    }
+
+    &__footer {
+      display: flex;
+      align-items: center;
+      gap: 16px;
+      padding-inline-start: 37px;
+      padding-inline-end: 40px;
+
+      &__sep {
+        width: 1px;
+        height: 22px;
+        background: lighten($ui-base-color, 8%);
+        flex: 0 0 auto;
+      }
+    }
+
+    &__select {
+      display: flex;
+      flex-direction: column;
+      gap: 2px;
+      flex: 1 1 auto;
+      min-width: 0;
+
+      &__label {
+        flex: 0 0 auto;
+        font-size: 11px;
+        font-weight: 500;
+        line-height: 16px;
+        letter-spacing: 0.5px;
+        color: $darker-text-color;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+      }
+
+      &__value {
+        flex: 0 0 auto;
+        appearance: none;
+        background: transparent;
+        border: none;
+        padding: 0;
+        font-size: 14px;
+        font-weight: 500;
+        line-height: 20px;
+        letter-spacing: 0.1px;
+        color: $highlight-text-color;
+        white-space: nowrap;
+        text-overflow: ellipsis;
+        overflow: hidden;
+      }
+    }
+  }
+}
+
+.dropdown-button {
+  display: flex;
+  align-items: center;
+  gap: 4px;
+  background: transparent;
+  color: $highlight-text-color;
+  border-radius: 6px;
+  border: 1px solid $highlight-text-color;
+  padding: 4px 8px;
+  font-size: 13px;
+  line-height: normal;
+  font-weight: 400;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+
+  .icon {
+    width: 15px;
+    height: 15px;
+    flex: 0 0 auto;
+  }
+
+  &__label {
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+    flex: 1 1 auto;
+  }
+
+  &.active {
+    background: $ui-highlight-color;
+    border-color: $ui-highlight-color;
+    color: $primary-text-color;
   }
 }
 
@@ -749,11 +887,14 @@ body > [data-popper-placement] {
   cursor: default;
   font-family: $font-sans-serif, sans-serif;
   font-size: 14px;
-  font-weight: 600;
-  color: $lighter-text-color;
+  font-weight: 400;
+  line-height: normal;
+  color: $darker-text-color;
+  flex: 1 0 auto;
+  text-align: end;
 
   &.character-counter--over {
-    color: $warning-red;
+    color: $error-red;
   }
 }
 
@@ -799,41 +940,6 @@ body > [data-popper-placement] {
   }
 }
 
-.reply-indicator {
-  border-radius: 4px;
-  margin-bottom: 10px;
-  background: $ui-primary-color;
-  padding: 10px;
-  min-height: 23px;
-  overflow-y: auto;
-  flex: 0 2 auto;
-}
-
-.reply-indicator__header {
-  margin-bottom: 5px;
-  overflow: hidden;
-}
-
-.reply-indicator__cancel {
-  float: right;
-  line-height: 24px;
-}
-
-.reply-indicator__display-name {
-  color: $inverted-text-color;
-  display: block;
-  max-width: 100%;
-  line-height: 24px;
-  overflow: hidden;
-  padding-inline-end: 25px;
-  text-decoration: none;
-}
-
-.reply-indicator__display-avatar {
-  float: left;
-  margin-inline-end: 5px;
-}
-
 .status__content--with-action {
   cursor: pointer;
 }
@@ -843,14 +949,15 @@ body > [data-popper-placement] {
 }
 
 .status__content,
+.edit-indicator__content,
 .reply-indicator__content {
   position: relative;
-  font-size: 15px;
-  line-height: 20px;
   word-wrap: break-word;
   font-weight: 400;
   overflow: hidden;
   text-overflow: ellipsis;
+  font-size: 15px;
+  line-height: 20px;
   padding-top: 2px;
   color: $primary-text-color;
 
@@ -938,6 +1045,174 @@ body > [data-popper-placement] {
   overflow: visible;
 }
 
+.reply-indicator {
+  display: grid;
+  grid-template-columns: 46px minmax(0, 1fr);
+  grid-template-rows: 46px max-content;
+  gap: 0 10px;
+
+  .detailed-status__display-name {
+    margin-bottom: 4px;
+  }
+
+  .detailed-status__display-avatar {
+    grid-column-start: 1;
+    grid-row-start: 1;
+    grid-row-end: span 1;
+  }
+
+  &__main {
+    grid-column-start: 2;
+    grid-row-start: 1;
+    grid-row-end: span 2;
+  }
+
+  .display-name {
+    font-size: 14px;
+    line-height: 16px;
+
+    &__account {
+      display: none;
+    }
+  }
+
+  &__line {
+    grid-column-start: 1;
+    grid-row-start: 2;
+    grid-row-end: span 1;
+    position: relative;
+
+    &::before {
+      display: block;
+      content: '';
+      position: absolute;
+      inset-inline-start: 50%;
+      top: 4px;
+      transform: translateX(-50%);
+      background: lighten($ui-base-color, 8%);
+      width: 2px;
+      height: calc(100% + 32px - 8px); // Account for gap to next element
+    }
+  }
+
+  &__content {
+    font-size: 14px;
+    line-height: 20px;
+    letter-spacing: 0.25px;
+    display: -webkit-box;
+    -webkit-line-clamp: 4;
+    -webkit-box-orient: vertical;
+    padding: 0;
+    max-height: 4 * 20px;
+    overflow: hidden;
+    color: $darker-text-color;
+  }
+
+  &__attachments {
+    margin-top: 4px;
+    color: $darker-text-color;
+    font-size: 12px;
+    line-height: 16px;
+    display: flex;
+    align-items: center;
+    gap: 4px;
+
+    .icon {
+      width: 18px;
+      height: 18px;
+    }
+  }
+}
+
+.edit-indicator {
+  border-radius: 4px 4px 0 0;
+  background: lighten($ui-base-color, 4%);
+  padding: 12px;
+  overflow-y: auto;
+  flex: 0 0 auto;
+  border-bottom: 0.5px solid lighten($ui-base-color, 8%);
+  display: flex;
+  flex-direction: column;
+  gap: 4px;
+
+  &__header {
+    display: flex;
+    justify-content: space-between;
+    align-items: center;
+    color: $darker-text-color;
+    font-size: 12px;
+    line-height: 16px;
+    overflow: hidden;
+    text-overflow: ellipsis;
+  }
+
+  &__cancel {
+    display: flex;
+
+    .icon {
+      width: 18px;
+      height: 18px;
+    }
+  }
+
+  &__display-name {
+    display: flex;
+    gap: 4px;
+
+    a {
+      color: inherit;
+      text-decoration: none;
+
+      &:hover,
+      &:focus,
+      &:active {
+        text-decoration: underline;
+      }
+    }
+  }
+
+  &__content {
+    color: $secondary-text-color;
+    font-size: 14px;
+    line-height: 20px;
+    letter-spacing: 0.25px;
+    padding-top: 0 !important;
+    display: -webkit-box;
+    -webkit-line-clamp: 4;
+    -webkit-box-orient: vertical;
+    max-height: 4 * 20px;
+    overflow: hidden;
+
+    a {
+      color: $highlight-text-color;
+    }
+  }
+
+  &__attachments {
+    color: $darker-text-color;
+    font-size: 12px;
+    line-height: 16px;
+    opacity: 0.75;
+    display: flex;
+    align-items: center;
+    gap: 4px;
+
+    .icon {
+      width: 18px;
+      height: 18px;
+    }
+  }
+}
+
+.edit-indicator__content,
+.reply-indicator__content {
+  .emojione {
+    width: 18px;
+    height: 18px;
+    margin: -3px 0 0;
+  }
+}
+
 .announcements__item__content {
   word-wrap: break-word;
   overflow-y: auto;
@@ -1623,15 +1898,6 @@ body > [data-popper-placement] {
   line-height: 18px;
 }
 
-.reply-indicator__content {
-  color: $inverted-text-color;
-  font-size: 14px;
-
-  a {
-    color: $lighter-text-color;
-  }
-}
-
 .domain {
   padding: 10px;
   border-bottom: 1px solid lighten($ui-base-color, 8%);
@@ -1845,7 +2111,6 @@ a .account__avatar {
 }
 
 .status__display-name,
-.reply-indicator__display-name,
 .detailed-status__display-name,
 a.account__display-name {
   &:hover .display-name strong {
@@ -2104,57 +2369,45 @@ a.account__display-name {
 }
 
 .navigation-bar {
-  padding: 10px; // glitch: reduced padding
   display: flex;
   align-items: center;
   flex-shrink: 0;
   cursor: default;
   gap: 10px;
-  color: $darker-text-color;
 
-  strong {
-    color: $secondary-text-color;
+  .column > & {
+    padding: 15px;
   }
 
-  a {
-    color: inherit;
-    text-decoration: none;
-  }
+  .account {
+    border-bottom: 0;
+    padding: 0;
+    flex: 1 1 auto;
+    min-width: 0;
 
-  .navigation-bar__actions {
-    position: relative;
+    &__display-name {
+      font-size: 16px;
+      line-height: 24px;
+      letter-spacing: 0.15px;
+      font-weight: 500;
 
-    .compose__action-bar .icon-button {
-      pointer-events: auto;
-      transform: scale(1, 1) translate(0, 0);
-      opacity: 1;
-
-      .icon {
-        width: 24px;
-        height: 24px;
+      .display-name__account {
+        font-size: 14px;
+        line-height: 20px;
+        letter-spacing: 0.1px;
       }
     }
   }
-}
 
-.navigation-bar__profile {
-  display: flex;
-  flex-direction: column;
-  flex: 1 1 auto;
-  line-height: 20px;
-}
+  .icon-button {
+    padding: 8px;
+    color: $secondary-text-color;
+  }
 
-.navigation-bar__profile-account {
-  display: inline;
-  font-weight: 500;
-  overflow: hidden;
-  text-overflow: ellipsis;
-}
-
-.navigation-bar__profile-edit {
-  display: inline;
-  color: inherit;
-  text-decoration: none;
+  .icon-button .icon {
+    width: 24px;
+    height: 24px;
+  }
 }
 
 .dropdown-animation {
@@ -2328,6 +2581,7 @@ a.account__display-name {
   &__panels {
     display: flex;
     justify-content: center;
+    gap: 16px;
     width: 100%;
     height: 100%;
     min-height: 100vh;
@@ -2360,7 +2614,6 @@ a.account__display-name {
       flex-direction: column;
 
       @media screen and (min-width: $no-gap-breakpoint) {
-        padding: 0 10px;
         max-width: 600px;
       }
     }
@@ -2610,6 +2863,7 @@ $ui-header-height: 55px;
 
   .columns-area__panels {
     min-height: calc(100vh - $ui-header-height);
+    gap: 0;
   }
 
   .columns-area__panels__pane--navigational {
@@ -3009,21 +3263,6 @@ $ui-header-height: 55px;
   }
 }
 
-.compose-form__highlightable {
-  display: flex;
-  flex-direction: column;
-  flex: 0 1 auto;
-  border-radius: 4px;
-  transition: box-shadow 300ms linear;
-  min-height: 0;
-  position: relative;
-
-  &.active {
-    transition: none;
-    box-shadow: 0 0 0 6px rgba(lighten($highlight-text-color, 8%), 0.7);
-  }
-}
-
 .compose-panel {
   width: 285px;
   margin-top: 10px;
@@ -3052,32 +3291,9 @@ $ui-header-height: 55px;
     }
   }
 
-  .navigation-bar {
-    flex: 0 1 48px;
-  }
-
   .compose-form {
-    flex: 1;
-    display: flex;
-    flex-direction: column;
-    min-height: 310px;
-    padding-bottom: 71px;
-    margin-bottom: -71px;
-  }
-
-  .compose-form__autosuggest-wrapper {
-    overflow-y: auto;
-    background-color: $white;
-    border-radius: 4px 4px 0 0;
-    flex: 0 1 auto;
-  }
-
-  .autosuggest-textarea__textarea {
-    overflow-y: hidden;
-  }
-
-  .compose-form__upload-thumbnail {
-    height: 80px;
+    flex: 1 1 auto;
+    min-height: 0;
   }
 }
 
@@ -3097,6 +3313,10 @@ $ui-header-height: 55px;
     height: 30px;
     width: auto;
   }
+
+  &__logo {
+    margin-bottom: 12px;
+  }
 }
 
 .navigation-panel,
@@ -3128,7 +3348,7 @@ $ui-header-height: 55px;
   position: absolute;
   top: 0;
   inset-inline-start: 0;
-  background: $ui-base-color;
+  background: darken($ui-base-color, 4%);
   box-sizing: border-box;
   padding: 0;
   display: flex;
@@ -3144,7 +3364,7 @@ $ui-header-height: 55px;
 }
 
 .drawer__inner__mastodon {
-  background: $ui-base-color
+  background: darken($ui-base-color, 4%)
     url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>')
     no-repeat bottom / 100% auto;
   flex: 1;
@@ -3174,24 +3394,20 @@ $ui-header-height: 55px;
   }
 }
 
-.pseudo-drawer {
-  background: lighten($ui-base-color, 13%);
-  font-size: 13px;
-  text-align: start;
-}
-
 .drawer__header {
   flex: 0 0 auto;
   font-size: 16px;
-  background: $ui-base-color;
+  background: darken($ui-base-color, 4%);
   margin-bottom: 10px;
   display: flex;
   flex-direction: row;
   border-radius: 4px;
   overflow: hidden;
 
-  a:hover {
-    background: lighten($ui-base-color, 3%);
+  a:hover,
+  a:focus,
+  a:active {
+    background: $ui-base-color;
   }
 }
 
@@ -3437,7 +3653,7 @@ $ui-header-height: 55px;
 
   &--transparent {
     background: transparent;
-    color: $ui-secondary-color;
+    color: $secondary-text-color;
 
     &:hover,
     &:focus,
@@ -4915,10 +5131,7 @@ a.status-card {
 }
 
 .emoji-picker-dropdown__menu {
-  background: $simple-background-color;
   position: relative;
-  box-shadow: var(--dropdown-shadow);
-  border-radius: 4px;
   margin-top: 5px;
   z-index: 2;
 
@@ -4941,11 +5154,12 @@ a.status-card {
 .emoji-picker-dropdown__modifiers__menu {
   position: absolute;
   z-index: 4;
-  top: -4px;
-  inset-inline-start: -8px;
-  background: $simple-background-color;
+  top: -5px;
+  inset-inline-start: -9px;
+  background: var(--dropdown-background-color);
+  border: 1px solid var(--dropdown-border-color);
   border-radius: 4px;
-  box-shadow: 1px 2px 6px rgba($base-shadow-color, 0.2);
+  box-shadow: var(--dropdown-shadow);
   overflow: hidden;
 
   button {
@@ -4958,7 +5172,7 @@ a.status-card {
     &:hover,
     &:focus,
     &:active {
-      background: rgba($ui-secondary-color, 0.4);
+      background: var(--dropdown-border-color);
     }
   }
 
@@ -5027,15 +5241,17 @@ a.status-card {
 }
 
 .upload-progress {
-  padding: 10px;
-  color: $lighter-text-color;
+  color: $darker-text-color;
   overflow: hidden;
   display: flex;
-  gap: 10px;
+  gap: 8px;
+  align-items: center;
+  padding: 0 12px;
 
   .icon {
     width: 24px;
     height: 24px;
+    color: $ui-highlight-color;
   }
 
   span {
@@ -5054,7 +5270,7 @@ a.status-card {
   width: 100%;
   height: 6px;
   border-radius: 6px;
-  background: darken($simple-background-color, 8%);
+  background: darken($ui-base-color, 8%);
   position: relative;
   margin-top: 5px;
 }
@@ -5108,12 +5324,16 @@ a.status-card {
   filter: none;
 }
 
-.privacy-dropdown__dropdown {
-  background: $simple-background-color;
+.privacy-dropdown__dropdown,
+.language-dropdown__dropdown {
   box-shadow: var(--dropdown-shadow);
+  background: var(--dropdown-background-color);
+  border: 1px solid var(--dropdown-border-color);
+  padding: 4px;
   border-radius: 4px;
   overflow: hidden;
   z-index: 2;
+  width: 300px;
 
   &.top {
     transform-origin: 50% 100%;
@@ -5134,29 +5354,41 @@ a.status-card {
 }
 
 .privacy-dropdown__option {
-  color: $inverted-text-color;
-  padding: 10px;
-  align-items: center;
+  font-size: 14px;
+  line-height: 20px;
+  letter-spacing: 0.25px;
+  padding: 8px 12px;
   cursor: pointer;
   display: flex;
+  align-items: center;
+  gap: 12px;
+  border-radius: 4px;
+  color: $primary-text-color;
 
   &:hover,
+  &:active {
+    background: var(--dropdown-border-color);
+  }
+
+  &:focus,
   &.active {
     background: $ui-highlight-color;
     color: $primary-text-color;
     outline: 0;
 
-    .privacy-dropdown__option__content {
+    .privacy-dropdown__option__content,
+    .privacy-dropdown__option__content strong,
+    .privacy-dropdown__option__additional {
       color: $primary-text-color;
-
-      strong {
-        color: $primary-text-color;
-      }
     }
   }
 
-  &.active:hover {
-    background: lighten($ui-highlight-color, 4%);
+  &__additional {
+    display: flex;
+    align-items: center;
+    justify-content: center;
+    color: $darker-text-color;
+    cursor: help;
   }
 }
 
@@ -5164,17 +5396,16 @@ a.status-card {
   display: flex;
   align-items: center;
   justify-content: center;
-  margin-inline-end: 10px;
 }
 
 .privacy-dropdown__option__content {
   flex: 1 1 auto;
-  color: $lighter-text-color;
+  color: $darker-text-color;
 
   strong {
+    color: $primary-text-color;
     font-weight: 500;
     display: block;
-    color: $inverted-text-color;
 
     @each $lang in $cjk-langs {
       &:lang(#{$lang}) {
@@ -5298,64 +5529,78 @@ a.status-card {
 
 .language-dropdown {
   &__dropdown {
-    background: $simple-background-color;
-    box-shadow: var(--dropdown-shadow);
-    border-radius: 4px;
-    overflow: hidden;
-    z-index: 2;
-
-    &.top {
-      transform-origin: 50% 100%;
-    }
-
-    &.bottom {
-      transform-origin: 50% 0;
-    }
+    padding: 0;
 
     .emoji-mart-search {
-      padding-inline-end: 10px;
+      padding: 10px;
+      background: var(--dropdown-background-color);
+
+      input {
+        padding: 8px 12px;
+        background: $ui-base-color;
+        border: 1px solid lighten($ui-base-color, 8%);
+        color: $darker-text-color;
+
+        @media screen and (width <= 600px) {
+          font-size: 16px;
+          line-height: 24px;
+          letter-spacing: 0.5px;
+        }
+      }
     }
 
     .emoji-mart-search-icon {
-      inset-inline-end: 10px + 5px;
+      inset-inline-end: 15px;
+      opacity: 1;
+      color: $darker-text-color;
+
+      .icon {
+        width: 18px;
+        height: 18px;
+      }
+
+      &:disabled {
+        opacity: 0.38;
+      }
     }
 
     .emoji-mart-scroll {
       padding: 0 10px 10px;
+      background: var(--dropdown-background-color);
     }
 
     &__results {
       &__item {
         cursor: pointer;
-        color: $inverted-text-color;
+        color: $primary-text-color;
+        font-size: 14px;
+        line-height: 20px;
+        letter-spacing: 0.25px;
         font-weight: 500;
-        padding: 10px;
+        padding: 8px 12px;
         border-radius: 4px;
-        display: flex;
-        gap: 6px;
-        align-items: center;
-
-        &:focus,
-        &:active,
-        &:hover {
-          background: $ui-secondary-color;
-        }
+        overflow: hidden;
+        white-space: nowrap;
+        text-overflow: ellipsis;
 
         &__common-name {
           color: $darker-text-color;
+          font-weight: 400;
         }
 
+        &:active,
+        &:hover {
+          background: var(--dropdown-border-color);
+        }
+
+        &:focus,
         &.active {
           background: $ui-highlight-color;
           color: $primary-text-color;
           outline: 0;
 
           .language-dropdown__dropdown__results__item__common-name {
-            color: $secondary-text-color;
-          }
-
-          &:hover {
-            background: lighten($ui-highlight-color, 4%);
+            color: $primary-text-color;
           }
         }
       }
@@ -5364,9 +5609,13 @@ a.status-card {
 }
 
 .search {
-  margin-bottom: 10px;
+  margin-bottom: 32px;
   position: relative;
 
+  .layout-multiple-columns & {
+    margin-bottom: 10px;
+  }
+
   &__popout {
     box-sizing: border-box;
     display: none;
@@ -5375,6 +5624,7 @@ a.status-card {
     margin-top: -2px;
     width: 100%;
     background: $ui-base-color;
+    border: 1px solid lighten($ui-base-color, 8%);
     border-radius: 0 0 4px 4px;
     box-shadow: var(--dropdown-shadow);
     z-index: 99;
@@ -5383,7 +5633,7 @@ a.status-card {
 
     h4 {
       text-transform: uppercase;
-      color: $dark-text-color;
+      color: $darker-text-color;
       font-weight: 500;
       padding: 0 10px;
       margin-bottom: 10px;
@@ -5391,6 +5641,7 @@ a.status-card {
 
     .icon-button {
       padding: 0;
+      color: $darker-text-color;
     }
 
     .icon {
@@ -5406,7 +5657,7 @@ a.status-card {
       }
 
       &__message {
-        color: $dark-text-color;
+        color: $darker-text-color;
         padding: 0 10px;
       }
 
@@ -5462,6 +5713,10 @@ a.status-card {
   }
 
   &.active {
+    .search__input {
+      border-radius: 4px 4px 0 0;
+    }
+
     .search__popout {
       display: block;
     }
@@ -5472,14 +5727,9 @@ a.status-card {
   @include search-input;
 
   display: block;
-  padding: 15px;
-  padding-inline-end: 30px;
-  line-height: 18px;
-  font-size: 16px;
-
-  &::placeholder {
-    color: lighten($darker-text-color, 4%);
-  }
+  padding: 12px 16px;
+  padding-inline-start: 16px + 15px + 8px;
+  line-height: normal;
 
   &::-moz-focus-inner {
     border: 0;
@@ -5490,10 +5740,6 @@ a.status-card {
   &:active {
     outline: 0 !important;
   }
-
-  &:focus {
-    background: lighten($ui-base-color, 4%);
-  }
 }
 
 .search__icon {
@@ -5508,21 +5754,21 @@ a.status-card {
 
   .icon {
     position: absolute;
-    top: 13px;
-    inset-inline-end: 10px;
+    top: 12px + 2px;
+    inset-inline-start: 16px - 2px;
     display: inline-block;
     opacity: 0;
     transition: all 100ms linear;
     transition-property: transform, opacity;
-    width: 24px;
-    height: 24px;
-    color: $secondary-text-color;
+    width: 20px;
+    height: 20px;
+    color: $darker-text-color;
     cursor: default;
     pointer-events: none;
 
     &.active {
       pointer-events: auto;
-      opacity: 0.3;
+      opacity: 1;
     }
   }
 
@@ -5537,16 +5783,10 @@ a.status-card {
 
   .icon-times-circle {
     transform: rotate(0deg);
-    color: $action-button-color;
     cursor: pointer;
 
     &.active {
       transform: rotate(90deg);
-      opacity: 1;
-    }
-
-    &:hover {
-      color: lighten($action-button-color, 7%);
     }
   }
 }
@@ -6167,6 +6407,11 @@ a.status-card {
     }
   }
 
+  .dialog-option {
+    align-items: center;
+    gap: 12px;
+  }
+
   .dialog-option .poll__input {
     border-color: $inverted-text-color;
     color: $ui-secondary-color;
@@ -6175,8 +6420,8 @@ a.status-card {
     justify-content: center;
 
     svg {
-      width: 8px;
-      height: auto;
+      width: 15px;
+      height: 15px;
     }
 
     &:active,
@@ -7446,90 +7691,6 @@ noscript {
   }
 }
 
-@media screen and (width <= 630px) and (height <= 400px) {
-  $duration: 400ms;
-  $delay: 100ms;
-
-  .search {
-    will-change: margin-top;
-    transition: margin-top $duration $delay;
-  }
-
-  .navigation-bar {
-    will-change: padding-bottom;
-    transition: padding-bottom $duration $delay;
-  }
-
-  .navigation-bar {
-    & > a:first-child {
-      will-change: margin-top, margin-inline-start, margin-inline-end, width;
-      transition:
-        margin-top $duration $delay,
-        margin-inline-start $duration ($duration + $delay),
-        margin-inline-end $duration ($duration + $delay);
-    }
-
-    & > .navigation-bar__profile-edit {
-      will-change: margin-top;
-      transition: margin-top $duration $delay;
-    }
-
-    .navigation-bar__actions {
-      & > .icon-button.close {
-        will-change: opacity transform;
-        transition:
-          opacity $duration * 0.5 $delay,
-          transform $duration $delay;
-      }
-
-      & > .compose__action-bar .icon-button {
-        will-change: opacity transform;
-        transition:
-          opacity $duration * 0.5 $delay + $duration * 0.5,
-          transform $duration $delay;
-      }
-    }
-  }
-
-  .is-composing {
-    .search {
-      margin-top: -50px;
-    }
-
-    .navigation-bar {
-      padding-bottom: 0;
-
-      & > a:first-child {
-        margin: -100px 10px 0 -50px;
-      }
-
-      .navigation-bar__profile {
-        padding-top: 2px;
-      }
-
-      .navigation-bar__profile-edit {
-        position: absolute;
-        margin-top: -60px;
-      }
-
-      .navigation-bar__actions {
-        .icon-button.close {
-          pointer-events: auto;
-          opacity: 1;
-          transform: scale(1, 1) translate(0, 0);
-          bottom: 5px;
-        }
-
-        .compose__action-bar .icon-button {
-          pointer-events: none;
-          opacity: 0;
-          transform: scale(0, 1) translate(100%, 0);
-        }
-      }
-    }
-  }
-}
-
 .embed-modal {
   width: auto;
   max-width: 80vw;
@@ -9498,11 +9659,14 @@ noscript {
 
 .link-footer {
   flex: 0 0 auto;
-  padding: 10px;
   padding-top: 20px;
   z-index: 1;
   font-size: 13px;
 
+  .column & {
+    padding: 15px;
+  }
+
   p {
     color: $dark-text-color;
     margin-bottom: 20px;
diff --git a/app/javascript/flavours/glitch/styles/containers.scss b/app/javascript/flavours/glitch/styles/containers.scss
index 6d72e43924..632f1da8c7 100644
--- a/app/javascript/flavours/glitch/styles/containers.scss
+++ b/app/javascript/flavours/glitch/styles/containers.scss
@@ -40,13 +40,12 @@
   .compose-form {
     width: 400px;
     margin: 0 auto;
-    padding: 20px 0;
-    margin-top: 40px;
+    padding: 10px 0;
+    padding-bottom: 20px;
     box-sizing: border-box;
 
     @media screen and (width <= 400px) {
       width: 100%;
-      margin-top: 0;
       padding: 20px;
     }
   }
@@ -56,13 +55,15 @@
   width: 400px;
   margin: 0 auto;
   display: flex;
-  font-size: 13px;
-  line-height: 18px;
+  align-items: center;
+  gap: 10px;
+  font-size: 14px;
+  line-height: 20px;
   box-sizing: border-box;
   padding: 20px 0;
   margin-top: 40px;
   margin-bottom: 10px;
-  border-bottom: 1px solid $ui-base-color;
+  border-bottom: 1px solid lighten($ui-base-color, 8%);
 
   @media screen and (width <= 440px) {
     width: 100%;
@@ -73,6 +74,7 @@
   .avatar {
     width: 40px;
     height: 40px;
+    flex: 0 0 auto;
     @include avatar-size(40px);
 
     margin-inline-end: 10px;
@@ -90,13 +92,14 @@
   .name {
     flex: 1 1 auto;
     color: $secondary-text-color;
-    width: calc(100% - 90px);
 
     .username {
       display: block;
-      font-weight: 500;
+      font-size: 16px;
+      line-height: 24px;
       text-overflow: ellipsis;
       overflow: hidden;
+      color: $primary-text-color;
     }
   }
 
@@ -104,7 +107,7 @@
     display: block;
     font-size: 32px;
     line-height: 40px;
-    margin-inline-start: 10px;
+    flex: 0 0 auto;
   }
 }
 
diff --git a/app/javascript/flavours/glitch/styles/contrast/diff.scss b/app/javascript/flavours/glitch/styles/contrast/diff.scss
index 1c2386f02d..ae607f484a 100644
--- a/app/javascript/flavours/glitch/styles/contrast/diff.scss
+++ b/app/javascript/flavours/glitch/styles/contrast/diff.scss
@@ -1,20 +1,7 @@
-.compose-form {
-  .compose-form__modifiers {
-    .compose-form__upload {
-      &-description {
-        input {
-          &::placeholder {
-            opacity: 1;
-          }
-        }
-      }
-    }
-  }
-}
-
 .status__content a,
-.link-footer a,
 .reply-indicator__content a,
+.edit-indicator__content a,
+.link-footer a,
 .status__content__read-more-button,
 .status__content__translate-button {
   text-decoration: underline;
@@ -42,7 +29,9 @@
   }
 }
 
-.status__content a {
+.status__content a,
+.reply-indicator__content a,
+.edit-indicator__content a {
   color: $highlight-text-color;
 }
 
@@ -50,24 +39,10 @@
   color: $darker-text-color;
 }
 
-.compose-form__poll-wrapper .button.button-secondary,
-.compose-form .autosuggest-textarea__textarea::placeholder,
-.compose-form .spoiler-input__input::placeholder,
-.report-dialog-modal__textarea::placeholder,
-.language-dropdown__dropdown__results__item__common-name,
-.compose-form .icon-button {
+.report-dialog-modal__textarea::placeholder {
   color: $inverted-text-color;
 }
 
-.text-icon-button.active {
-  color: $ui-highlight-color;
-}
-
-.language-dropdown__dropdown__results__item.active {
-  background: $ui-highlight-color;
-  font-weight: 500;
-}
-
 .link-button:disabled {
   cursor: not-allowed;
 
diff --git a/app/javascript/flavours/glitch/styles/emoji_picker.scss b/app/javascript/flavours/glitch/styles/emoji_picker.scss
index c7247c3a57..fec0c10ddb 100644
--- a/app/javascript/flavours/glitch/styles/emoji_picker.scss
+++ b/app/javascript/flavours/glitch/styles/emoji_picker.scss
@@ -1,7 +1,6 @@
 .emoji-mart {
   font-size: 13px;
   display: inline-block;
-  color: $inverted-text-color;
 
   &,
   * {
@@ -15,13 +14,13 @@
 }
 
 .emoji-mart-bar {
-  border: 0 solid darken($ui-secondary-color, 8%);
+  border: 0 solid var(--dropdown-border-color);
 
   &:first-child {
     border-bottom-width: 1px;
     border-top-left-radius: 5px;
     border-top-right-radius: 5px;
-    background: $ui-secondary-color;
+    background: var(--dropdown-border-color);
   }
 
   &:last-child {
@@ -36,7 +35,6 @@
   display: flex;
   justify-content: space-between;
   padding: 0 6px;
-  color: $lighter-text-color;
   line-height: 0;
 }
 
@@ -50,9 +48,10 @@
   cursor: pointer;
   background: transparent;
   border: 0;
+  color: $darker-text-color;
 
   &:hover {
-    color: darken($lighter-text-color, 4%);
+    color: lighten($darker-text-color, 4%);
   }
 }
 
@@ -60,7 +59,7 @@
   color: $highlight-text-color;
 
   &:hover {
-    color: darken($highlight-text-color, 4%);
+    color: lighten($highlight-text-color, 4%);
   }
 
   .emoji-mart-anchor-bar {
@@ -95,7 +94,7 @@
   height: 270px;
   max-height: 35vh;
   padding: 0 6px 6px;
-  background: $simple-background-color;
+  background: var(--dropdown-background-color);
   will-change: transform;
 
   &::-webkit-scrollbar-track:hover,
@@ -107,7 +106,7 @@
 .emoji-mart-search {
   padding: 10px;
   padding-inline-end: 45px;
-  background: $simple-background-color;
+  background: var(--dropdown-background-color);
   position: relative;
 
   input {
@@ -118,9 +117,9 @@
     font-family: inherit;
     display: block;
     width: 100%;
-    background: rgba($ui-secondary-color, 0.3);
-    color: $inverted-text-color;
-    border: 1px solid $ui-secondary-color;
+    background: $ui-base-color;
+    color: $darker-text-color;
+    border: 1px solid lighten($ui-base-color, 8%);
     border-radius: 4px;
 
     &::-moz-focus-inner {
@@ -155,11 +154,10 @@
   &:disabled {
     cursor: default;
     pointer-events: none;
-    opacity: 0.3;
   }
 
   svg {
-    fill: $action-button-color;
+    fill: $darker-text-color;
   }
 }
 
@@ -180,7 +178,7 @@
     inset-inline-start: 0;
     width: 100%;
     height: 100%;
-    background-color: rgba($ui-secondary-color, 0.7);
+    background-color: var(--dropdown-border-color);
     border-radius: 100%;
   }
 }
@@ -197,7 +195,7 @@
     width: 100%;
     font-weight: 500;
     padding: 5px 6px;
-    background: $simple-background-color;
+    background: var(--dropdown-background-color);
   }
 }
 
@@ -241,7 +239,7 @@
 
 .emoji-mart-no-results {
   font-size: 14px;
-  color: $light-text-color;
+  color: $dark-text-color;
   text-align: center;
   padding: 5px 6px;
   padding-top: 70px;
diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss
index 0f3a6fa32f..1025a1bbaa 100644
--- a/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss
+++ b/app/javascript/flavours/glitch/styles/mastodon-light/diff.scss
@@ -145,10 +145,6 @@ html {
   }
 }
 
-.compose-form__autosuggest-wrapper,
-.poll__option input[type='text'],
-.compose-form .spoiler-input__input,
-.compose-form__poll-wrapper select,
 .search__input,
 .setting-text,
 .report-dialog-modal__textarea,
@@ -172,28 +168,11 @@ html {
   border-bottom: 0;
 }
 
-.compose-form__poll-wrapper select {
-  background: $simple-background-color
-    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(lighten($ui-base-color, 8%))}'/></svg>")
-    no-repeat right 8px center / auto 16px;
-}
-
-.compose-form__poll-wrapper,
-.compose-form__poll-wrapper .poll__footer {
-  border-top-color: lighten($ui-base-color, 8%);
-}
-
 .notification__filter-bar {
   border: 1px solid lighten($ui-base-color, 8%);
   border-top: 0;
 }
 
-.compose-form .compose-form__buttons-wrapper {
-  background: $ui-base-color;
-  border: 1px solid lighten($ui-base-color, 8%);
-  border-top: 0;
-}
-
 .drawer__header,
 .drawer__inner {
   background: $white;
@@ -206,52 +185,6 @@ html {
     no-repeat bottom / 100% auto;
 }
 
-// Change the colors used in compose-form
-.compose-form {
-  .compose-form__modifiers {
-    .compose-form__upload__actions .icon-button,
-    .compose-form__upload__warning .icon-button {
-      color: lighten($white, 7%);
-
-      &:active,
-      &:focus,
-      &:hover {
-        color: $white;
-      }
-    }
-  }
-
-  .compose-form__buttons-wrapper {
-    background: darken($ui-base-color, 6%);
-  }
-
-  .autosuggest-textarea__suggestions {
-    background: darken($ui-base-color, 6%);
-  }
-
-  .autosuggest-textarea__suggestions__item {
-    &:hover,
-    &:focus,
-    &:active,
-    &.selected {
-      background: lighten($ui-base-color, 4%);
-    }
-  }
-}
-
-.emoji-mart-bar {
-  border-color: lighten($ui-base-color, 4%);
-
-  &:first-child {
-    background: darken($ui-base-color, 6%);
-  }
-}
-
-.emoji-mart-search input {
-  background: rgba($ui-base-color, 0.3);
-  border-color: $ui-base-color;
-}
-
 .upload-progress__backdrop {
   background: $ui-base-color;
 }
@@ -283,46 +216,11 @@ html {
   background: $ui-base-color;
 }
 
-.privacy-dropdown.active .privacy-dropdown__value.active .icon-button {
-  color: $white;
-}
-
 .account-gallery__item a {
   background-color: $ui-base-color;
 }
 
-// Change the colors used in the dropdown menu
-.dropdown-menu {
-  background: $white;
-
-  &__arrow::before {
-    background-color: $white;
-  }
-
-  &__item {
-    color: $darker-text-color;
-
-    &--dangerous {
-      color: $error-value-color;
-    }
-
-    a,
-    button {
-      background: $white;
-    }
-  }
-}
-
 // Change the text colors on inverted background
-.privacy-dropdown__option.active,
-.privacy-dropdown__option:hover,
-.privacy-dropdown__option.active .privacy-dropdown__option__content,
-.privacy-dropdown__option.active .privacy-dropdown__option__content strong,
-.privacy-dropdown__option:hover .privacy-dropdown__option__content,
-.privacy-dropdown__option:hover .privacy-dropdown__option__content strong,
-.dropdown-menu__item:not(.dropdown-menu__item--dangerous) a:active,
-.dropdown-menu__item:not(.dropdown-menu__item--dangerous) a:focus,
-.dropdown-menu__item:not(.dropdown-menu__item--dangerous) a:hover,
 .actions-modal ul li:not(:empty) a.active,
 .actions-modal ul li:not(:empty) a.active button,
 .actions-modal ul li:not(:empty) a:active,
@@ -331,7 +229,6 @@ html {
 .actions-modal ul li:not(:empty) a:focus button,
 .actions-modal ul li:not(:empty) a:hover,
 .actions-modal ul li:not(:empty) a:hover button,
-.language-dropdown__dropdown__results__item.active,
 .admin-wrapper .sidebar ul .simple-navigation-active-leaf a,
 .simple_form .block-button,
 .simple_form .button,
@@ -339,19 +236,6 @@ html {
   color: $white;
 }
 
-.language-dropdown__dropdown__results__item
-  .language-dropdown__dropdown__results__item__common-name {
-  color: lighten($ui-base-color, 8%);
-}
-
-.language-dropdown__dropdown__results__item.active
-  .language-dropdown__dropdown__results__item__common-name {
-  color: darken($ui-base-color, 12%);
-}
-
-.dropdown-menu__separator,
-.dropdown-menu__item.edited-timestamp__history__item,
-.dropdown-menu__container__header,
 .compare-history-modal .report-modal__target,
 .report-dialog-modal .poll__option.dialog-option {
   border-bottom-color: lighten($ui-base-color, 4%);
@@ -385,10 +269,7 @@ html {
 
 .reactions-bar__item:hover,
 .reactions-bar__item:focus,
-.reactions-bar__item:active,
-.language-dropdown__dropdown__results__item:hover,
-.language-dropdown__dropdown__results__item:focus,
-.language-dropdown__dropdown__results__item:active {
+.reactions-bar__item:active {
   background-color: $ui-base-color;
 }
 
@@ -631,11 +512,6 @@ html {
   }
 }
 
-.reply-indicator {
-  background: transparent;
-  border: 1px solid lighten($ui-base-color, 8%);
-}
-
 .status__content,
 .reply-indicator__content {
   a {
@@ -745,3 +621,30 @@ html {
     filter: contrast(75%) brightness(75%) !important;
   }
 }
+
+.compose-form__actions .icon-button.active,
+.dropdown-button.active,
+.privacy-dropdown__option.active,
+.privacy-dropdown__option:focus,
+.language-dropdown__dropdown__results__item:focus,
+.language-dropdown__dropdown__results__item.active,
+.privacy-dropdown__option:focus .privacy-dropdown__option__content,
+.privacy-dropdown__option:focus .privacy-dropdown__option__content strong,
+.privacy-dropdown__option.active .privacy-dropdown__option__content,
+.privacy-dropdown__option.active .privacy-dropdown__option__content strong,
+.language-dropdown__dropdown__results__item:focus
+  .language-dropdown__dropdown__results__item__common-name,
+.language-dropdown__dropdown__results__item.active
+  .language-dropdown__dropdown__results__item__common-name {
+  color: $white;
+}
+
+.compose-form .spoiler-input__input {
+  color: lighten($ui-highlight-color, 8%);
+}
+
+.compose-form .autosuggest-textarea__textarea,
+.compose-form__highlightable,
+.poll__option input[type='text'] {
+  background: darken($ui-base-color, 10%);
+}
diff --git a/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss b/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss
index 250e200fc6..3cf5561ca3 100644
--- a/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss
+++ b/app/javascript/flavours/glitch/styles/mastodon-light/variables.scss
@@ -34,7 +34,7 @@ $ui-button-tertiary-border-color: $blurple-500 !default;
 
 $primary-text-color: $black !default;
 $darker-text-color: $classic-base-color !default;
-$highlight-text-color: darken($ui-highlight-color, 8%) !default;
+$highlight-text-color: $ui-highlight-color !default;
 $dark-text-color: #444b5d;
 $action-button-color: #606984;
 
@@ -55,3 +55,8 @@ $account-background-color: $white !default;
 }
 
 $emojis-requiring-inversion: 'chains';
+
+.theme-mastodon-light {
+  --dropdown-border-color: #d9e1e8;
+  --dropdown-background-color: #fff;
+}
diff --git a/app/javascript/flavours/glitch/styles/modal.scss b/app/javascript/flavours/glitch/styles/modal.scss
index 0b7220b21d..60e7d62245 100644
--- a/app/javascript/flavours/glitch/styles/modal.scss
+++ b/app/javascript/flavours/glitch/styles/modal.scss
@@ -1,5 +1,5 @@
 .modal-layout {
-  background: $ui-base-color
+  background: darken($ui-base-color, 4%)
     url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-lighter-color)}33"/></svg>')
     repeat-x bottom fixed;
   display: flex;
diff --git a/app/javascript/flavours/glitch/styles/polls.scss b/app/javascript/flavours/glitch/styles/polls.scss
index 4566a013a6..f12fd827de 100644
--- a/app/javascript/flavours/glitch/styles/polls.scss
+++ b/app/javascript/flavours/glitch/styles/polls.scss
@@ -58,6 +58,8 @@
   &__option {
     position: relative;
     display: flex;
+    align-items: flex-start;
+    gap: 8px;
     padding: 6px 0;
     line-height: 18px;
     cursor: default;
@@ -84,16 +86,22 @@
       box-sizing: border-box;
       width: 100%;
       font-size: 14px;
-      color: $inverted-text-color;
+      color: $secondary-text-color;
       outline: 0;
       font-family: inherit;
-      background: $simple-background-color;
-      border: 1px solid darken($simple-background-color, 14%);
+      background: $ui-base-color;
+      border: 1px solid $darker-text-color;
       border-radius: 4px;
-      padding: 6px 10px;
+      padding: 8px 12px;
 
       &:focus {
-        border-color: $highlight-text-color;
+        border-color: $ui-highlight-color;
+      }
+
+      @media screen and (width <= 600px) {
+        font-size: 16px;
+        line-height: 24px;
+        letter-spacing: 0.5px;
       }
     }
 
@@ -102,26 +110,20 @@
     }
 
     &.editable {
-      display: flex;
       align-items: center;
       overflow: visible;
     }
   }
 
   &__input {
-    display: inline-block;
+    display: block;
     position: relative;
     border: 1px solid $ui-primary-color;
     box-sizing: border-box;
-    width: 18px;
-    height: 18px;
-    margin-inline-end: 10px;
-    top: -1px;
+    width: 17px;
+    height: 17px;
     border-radius: 50%;
-    vertical-align: middle;
-    margin-top: auto;
-    margin-bottom: auto;
-    flex: 0 0 18px;
+    flex: 0 0 auto;
 
     &.checkbox {
       border-radius: 4px;
@@ -165,6 +167,15 @@
     }
   }
 
+  &__option.editable &__input {
+    &:active,
+    &:focus,
+    &:hover {
+      border-color: $ui-primary-color;
+      border-width: 1px;
+    }
+  }
+
   &__number {
     display: inline-block;
     width: 45px;
@@ -215,92 +226,6 @@
   }
 }
 
-.compose-form__poll-wrapper {
-  border-top: 1px solid darken($simple-background-color, 8%);
-  overflow-x: hidden;
-
-  ul {
-    padding: 10px;
-  }
-
-  .poll__input {
-    &:active,
-    &:focus,
-    &:hover {
-      border-color: $ui-button-focus-background-color;
-    }
-  }
-
-  .poll__footer {
-    border-top: 1px solid darken($simple-background-color, 8%);
-    padding: 10px;
-    display: flex;
-    align-items: center;
-
-    button,
-    select {
-      width: 100%;
-      flex: 1 1 50%;
-
-      &:focus {
-        border-color: $highlight-text-color;
-      }
-    }
-  }
-
-  .button.button-secondary {
-    font-size: 14px;
-    font-weight: 400;
-    padding: 6px 10px;
-    height: auto;
-    line-height: inherit;
-    color: $action-button-color;
-    border-color: $action-button-color;
-    margin-inline-end: 5px;
-
-    &:hover,
-    &:focus,
-    &.active {
-      border-color: $action-button-color;
-      background-color: $action-button-color;
-      color: $ui-button-color;
-    }
-  }
-
-  li {
-    display: flex;
-    align-items: center;
-
-    .poll__option {
-      flex: 0 0 auto;
-      width: calc(100% - (23px + 6px));
-      margin-inline-end: 6px;
-    }
-  }
-
-  select {
-    appearance: none;
-    box-sizing: border-box;
-    font-size: 14px;
-    color: $inverted-text-color;
-    display: inline-block;
-    width: auto;
-    outline: 0;
-    font-family: inherit;
-    background: $simple-background-color
-      url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 14.933 18.467' height='19.698' width='15.929'><path d='M3.467 14.967l-3.393-3.5H14.86l-3.392 3.5c-1.866 1.925-3.666 3.5-4 3.5-.335 0-2.135-1.575-4-3.5zm.266-11.234L7.467 0 11.2 3.733l3.733 3.734H0l3.733-3.734z' fill='#{hex-color(darken($simple-background-color, 14%))}'/></svg>")
-      no-repeat right 8px center / auto 16px;
-    border: 1px solid darken($simple-background-color, 14%);
-    border-radius: 4px;
-    padding: 6px 10px;
-    padding-inline-end: 30px;
-  }
-
-  .icon-button.disabled {
-    color: darken($simple-background-color, 14%);
-  }
-}
-
 .muted .poll {
   color: $dark-text-color;