diff --git a/app/controllers/about_controller.rb b/app/controllers/about_controller.rb
index eae7de8c89eb156916e516494c7dbb3184e612d0..0fbc6a800d24ac5a664018cda3781df5ae8b04fe 100644
--- a/app/controllers/about_controller.rb
+++ b/app/controllers/about_controller.rb
@@ -1,63 +1,11 @@
 # frozen_string_literal: true
 
 class AboutController < ApplicationController
-  include RegistrationSpamConcern
+  include WebAppControllerConcern
 
-  layout 'public'
+  skip_before_action :require_functional!
 
-  before_action :require_open_federation!, only: [:more]
-  before_action :set_body_classes, only: :show
-  before_action :set_instance_presenter
-  before_action :set_expires_in, only: [:more]
-
-  skip_before_action :require_functional!, only: [:more]
-
-  def more
-    flash.now[:notice] = I18n.t('about.instance_actor_flash') if params[:instance_actor]
-
-    toc_generator = TOCGenerator.new(@instance_presenter.extended_description)
-
-    @rules             = Rule.ordered
-    @contents          = toc_generator.html
-    @table_of_contents = toc_generator.toc
-    @blocks            = DomainBlock.with_user_facing_limitations.by_severity if display_blocks?
-  end
-
-  helper_method :display_blocks?
-  helper_method :display_blocks_rationale?
-  helper_method :public_fetch_mode?
-  helper_method :new_user
-
-  private
-
-  def require_open_federation!
-    not_found if whitelist_mode?
-  end
-
-  def display_blocks?
-    Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?)
-  end
-
-  def display_blocks_rationale?
-    Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?)
-  end
-
-  def new_user
-    User.new.tap do |user|
-      user.build_account
-      user.build_invite_request
-    end
-  end
-
-  def set_instance_presenter
-    @instance_presenter = InstancePresenter.new
-  end
-
-  def set_body_classes
-    @hide_navbar = true
-  end
-
-  def set_expires_in
-    expires_in 0, public: true
+  def show
+    expires_in 0, public: true unless user_signed_in?
   end
 end
diff --git a/app/controllers/api/v1/instances/domain_blocks_controller.rb b/app/controllers/api/v1/instances/domain_blocks_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..37a6906fb6b5c13e0f316561472437aacb0f5a71
--- /dev/null
+++ b/app/controllers/api/v1/instances/domain_blocks_controller.rb
@@ -0,0 +1,23 @@
+# frozen_string_literal: true
+
+class Api::V1::Instances::DomainBlocksController < Api::BaseController
+  skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
+
+  before_action :require_enabled_api!
+  before_action :set_domain_blocks
+
+  def index
+    expires_in 3.minutes, public: true
+    render json: @domain_blocks, each_serializer: REST::DomainBlockSerializer, with_comment: (Setting.show_domain_blocks_rationale == 'all' || (Setting.show_domain_blocks_rationale == 'users' && user_signed_in?))
+  end
+
+  private
+
+  def require_enabled_api!
+    head 404 unless Setting.show_domain_blocks == 'all' || (Setting.show_domain_blocks == 'users' && user_signed_in?)
+  end
+
+  def set_domain_blocks
+    @domain_blocks = DomainBlock.with_user_facing_limitations.by_severity
+  end
+end
diff --git a/app/controllers/api/v1/instances/extended_descriptions_controller.rb b/app/controllers/api/v1/instances/extended_descriptions_controller.rb
new file mode 100644
index 0000000000000000000000000000000000000000..c72e16cff2c8bc0d99573aef726d4fe6630b3f35
--- /dev/null
+++ b/app/controllers/api/v1/instances/extended_descriptions_controller.rb
@@ -0,0 +1,18 @@
+# frozen_string_literal: true
+
+class Api::V1::Instances::ExtendedDescriptionsController < Api::BaseController
+  skip_before_action :require_authenticated_user!, unless: :whitelist_mode?
+
+  before_action :set_extended_description
+
+  def show
+    expires_in 3.minutes, public: true
+    render json: @extended_description, serializer: REST::ExtendedDescriptionSerializer
+  end
+
+  private
+
+  def set_extended_description
+    @extended_description = ExtendedDescription.current
+  end
+end
diff --git a/app/javascript/fonts/montserrat/Montserrat-Medium.ttf b/app/javascript/fonts/montserrat/Montserrat-Medium.ttf
deleted file mode 100644
index 88d70b89c3f2740e9b9c80881616136b5f697091..0000000000000000000000000000000000000000
Binary files a/app/javascript/fonts/montserrat/Montserrat-Medium.ttf and /dev/null differ
diff --git a/app/javascript/fonts/montserrat/Montserrat-Regular.ttf b/app/javascript/fonts/montserrat/Montserrat-Regular.ttf
deleted file mode 100644
index 29ca85d4a8bcfb20443653e7305c7e981b03eec0..0000000000000000000000000000000000000000
Binary files a/app/javascript/fonts/montserrat/Montserrat-Regular.ttf and /dev/null differ
diff --git a/app/javascript/fonts/montserrat/Montserrat-Regular.woff b/app/javascript/fonts/montserrat/Montserrat-Regular.woff
deleted file mode 100644
index af3b5ec44a985f622e0c236b5ced7ad2fac3e855..0000000000000000000000000000000000000000
Binary files a/app/javascript/fonts/montserrat/Montserrat-Regular.woff and /dev/null differ
diff --git a/app/javascript/fonts/montserrat/Montserrat-Regular.woff2 b/app/javascript/fonts/montserrat/Montserrat-Regular.woff2
deleted file mode 100644
index 3d75434ddf9ae9f5f1eaec11a5fcc2140f283dd9..0000000000000000000000000000000000000000
Binary files a/app/javascript/fonts/montserrat/Montserrat-Regular.woff2 and /dev/null differ
diff --git a/app/javascript/mastodon/actions/server.js b/app/javascript/mastodon/actions/server.js
index af8fef780f39de549ae1622de7575a9efe494730..31d4aea1000c61b00474e6ec0b0516df13d531c3 100644
--- a/app/javascript/mastodon/actions/server.js
+++ b/app/javascript/mastodon/actions/server.js
@@ -5,6 +5,14 @@ export const SERVER_FETCH_REQUEST = 'Server_FETCH_REQUEST';
 export const SERVER_FETCH_SUCCESS = 'Server_FETCH_SUCCESS';
 export const SERVER_FETCH_FAIL    = 'Server_FETCH_FAIL';
 
+export const EXTENDED_DESCRIPTION_REQUEST = 'EXTENDED_DESCRIPTION_REQUEST';
+export const EXTENDED_DESCRIPTION_SUCCESS = 'EXTENDED_DESCRIPTION_SUCCESS';
+export const EXTENDED_DESCRIPTION_FAIL    = 'EXTENDED_DESCRIPTION_FAIL';
+
+export const SERVER_DOMAIN_BLOCKS_FETCH_REQUEST = 'SERVER_DOMAIN_BLOCKS_FETCH_REQUEST';
+export const SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS = 'SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS';
+export const SERVER_DOMAIN_BLOCKS_FETCH_FAIL    = 'SERVER_DOMAIN_BLOCKS_FETCH_FAIL';
+
 export const fetchServer = () => (dispatch, getState) => {
   dispatch(fetchServerRequest());
 
@@ -28,3 +36,56 @@ const fetchServerFail = error => ({
   type: SERVER_FETCH_FAIL,
   error,
 });
+
+export const fetchExtendedDescription = () => (dispatch, getState) => {
+  dispatch(fetchExtendedDescriptionRequest());
+
+  api(getState)
+    .get('/api/v1/instance/extended_description')
+    .then(({ data }) => dispatch(fetchExtendedDescriptionSuccess(data)))
+    .catch(err => dispatch(fetchExtendedDescriptionFail(err)));
+};
+
+const fetchExtendedDescriptionRequest = () => ({
+  type: EXTENDED_DESCRIPTION_REQUEST,
+});
+
+const fetchExtendedDescriptionSuccess = description => ({
+  type: EXTENDED_DESCRIPTION_SUCCESS,
+  description,
+});
+
+const fetchExtendedDescriptionFail = error => ({
+  type: EXTENDED_DESCRIPTION_FAIL,
+  error,
+});
+
+export const fetchDomainBlocks = () => (dispatch, getState) => {
+  dispatch(fetchDomainBlocksRequest());
+
+  api(getState)
+    .get('/api/v1/instance/domain_blocks')
+    .then(({ data }) => dispatch(fetchDomainBlocksSuccess(true, data)))
+    .catch(err => {
+      if (err.response.status === 404) {
+        dispatch(fetchDomainBlocksSuccess(false, []));
+      } else {
+        dispatch(fetchDomainBlocksFail(err));
+      }
+    });
+};
+
+const fetchDomainBlocksRequest = () => ({
+  type: SERVER_DOMAIN_BLOCKS_FETCH_REQUEST,
+});
+
+const fetchDomainBlocksSuccess = (isAvailable, blocks) => ({
+  type: SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS,
+  isAvailable,
+  blocks,
+});
+
+const fetchDomainBlocksFail = error => ({
+  type: SERVER_DOMAIN_BLOCKS_FETCH_FAIL,
+  error,
+});
diff --git a/app/javascript/mastodon/components/image.js b/app/javascript/mastodon/components/image.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e81ddf082cb336007d34d48446a11282533eda8
--- /dev/null
+++ b/app/javascript/mastodon/components/image.js
@@ -0,0 +1,33 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Blurhash from './blurhash';
+import classNames from 'classnames';
+
+export default class Image extends React.PureComponent {
+
+  static propTypes = {
+    src: PropTypes.string,
+    srcSet: PropTypes.string,
+    blurhash: PropTypes.string,
+    className: PropTypes.string,
+  };
+
+  state = {
+    loaded: false,
+  };
+
+  handleLoad = () => this.setState({ loaded: true });
+
+  render () {
+    const { src, srcSet, blurhash, className } = this.props;
+    const { loaded } = this.state;
+
+    return (
+      <div className={classNames('image', { loaded }, className)} role='presentation'>
+        {blurhash && <Blurhash hash={blurhash} className='image__preview' />}
+        <img src={src} srcSet={srcSet} alt='' onLoad={this.handleLoad} />
+      </div>
+    );
+  }
+
+}
diff --git a/app/javascript/mastodon/components/server_banner.js b/app/javascript/mastodon/components/server_banner.js
index ae4e200c340d2ea419b7611519d1aac69e20e45b..c2336e43d3542b3f218792888578b0d3e8b7caf4 100644
--- a/app/javascript/mastodon/components/server_banner.js
+++ b/app/javascript/mastodon/components/server_banner.js
@@ -7,13 +7,15 @@ import ShortNumber from 'mastodon/components/short_number';
 import Skeleton from 'mastodon/components/skeleton';
 import Account from 'mastodon/containers/account_container';
 import { domain } from 'mastodon/initial_state';
+import Image from 'mastodon/components/image';
+import { Link } from 'react-router-dom';
 
 const messages = defineMessages({
   aboutActiveUsers: { id: 'server_banner.about_active_users', defaultMessage: 'People using this server during the last 30 days (Monthly Active Users)' },
 });
 
 const mapStateToProps = state => ({
-  server: state.get('server'),
+  server: state.getIn(['server', 'server']),
 });
 
 export default @connect(mapStateToProps)
@@ -41,7 +43,7 @@ class ServerBanner extends React.PureComponent {
           <FormattedMessage id='server_banner.introduction' defaultMessage='{domain} is part of the decentralized social network powered by {mastodon}.' values={{ domain: <strong>{domain}</strong>, mastodon: <a href='https://joinmastodon.org' target='_blank'>Mastodon</a> }} />
         </div>
 
-        <img src={server.get('thumbnail')} alt={server.get('title')} className='server-banner__hero' />
+        <Image blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} className='server-banner__hero' />
 
         <div className='server-banner__description'>
           {isLoading ? (
@@ -83,7 +85,7 @@ class ServerBanner extends React.PureComponent {
 
         <hr className='spacer' />
 
-        <a className='button button--block button-secondary' href='/about/more' target='_blank'><FormattedMessage id='server_banner.learn_more' defaultMessage='Learn more' /></a>
+        <Link className='button button--block button-secondary' to='/about'><FormattedMessage id='server_banner.learn_more' defaultMessage='Learn more' /></Link>
       </div>
     );
   }
diff --git a/app/javascript/mastodon/components/skeleton.js b/app/javascript/mastodon/components/skeleton.js
index 09093e99c757ad2a9d6f56a5427611ea9f66cb50..6a17ffb261ef16a5d7262bc450f8969959e0bf58 100644
--- a/app/javascript/mastodon/components/skeleton.js
+++ b/app/javascript/mastodon/components/skeleton.js
@@ -4,8 +4,8 @@ import PropTypes from 'prop-types';
 const Skeleton = ({ width, height }) => <span className='skeleton' style={{ width, height }}>&zwnj;</span>;
 
 Skeleton.propTypes = {
-  width: PropTypes.number,
-  height: PropTypes.number,
+  width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
+  height: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
 };
 
 export default Skeleton;
diff --git a/app/javascript/mastodon/features/about/index.js b/app/javascript/mastodon/features/about/index.js
index bc8d3a41b07da4664b0957c664a933ff95bb6009..e9212565acd6bcdfef56de4048570c68c13a3828 100644
--- a/app/javascript/mastodon/features/about/index.js
+++ b/app/javascript/mastodon/features/about/index.js
@@ -1,27 +1,214 @@
 import React from 'react';
-import { defineMessages, injectIntl } from 'react-intl';
+import ImmutablePropTypes from 'react-immutable-proptypes';
+import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
+import { connect } from 'react-redux';
 import PropTypes from 'prop-types';
 import Column from 'mastodon/components/column';
 import LinkFooter from 'mastodon/features/ui/components/link_footer';
 import { Helmet } from 'react-helmet';
+import { fetchServer, fetchExtendedDescription, fetchDomainBlocks } from 'mastodon/actions/server';
+import Account from 'mastodon/containers/account_container';
+import Skeleton from 'mastodon/components/skeleton';
+import Icon from 'mastodon/components/icon';
+import classNames from 'classnames';
+import Image from 'mastodon/components/image';
 
 const messages = defineMessages({
   title: { id: 'column.about', defaultMessage: 'About' },
+  rules: { id: 'about.rules', defaultMessage: 'Server rules' },
+  blocks: { id: 'about.blocks', defaultMessage: 'Moderated servers' },
+  silenced: { id: 'about.domain_blocks.silenced.title', defaultMessage: 'Limited' },
+  silencedExplanation: { id: 'about.domain_blocks.silenced.explanation', defaultMessage: 'You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.' },
+  suspended: { id: 'about.domain_blocks.suspended.title', defaultMessage: 'Suspended' },
+  suspendedExplanation: { id: 'about.domain_blocks.suspended.explanation', defaultMessage: 'No data from this server will be processed, stored or exchanged, making any interaction or communication with users from this server impossible.' },
 });
 
-export default @injectIntl
+const severityMessages = {
+  silence: {
+    title: messages.silenced,
+    explanation: messages.silencedExplanation,
+  },
+
+  suspend: {
+    title: messages.suspended,
+    explanation: messages.suspendedExplanation,
+  },
+};
+
+const mapStateToProps = state => ({
+  server: state.getIn(['server', 'server']),
+  extendedDescription: state.getIn(['server', 'extendedDescription']),
+  domainBlocks: state.getIn(['server', 'domainBlocks']),
+});
+
+class Section extends React.PureComponent {
+
+  static propTypes = {
+    title: PropTypes.string,
+    children: PropTypes.node,
+    open: PropTypes.bool,
+    onOpen: PropTypes.func,
+  };
+
+  state = {
+    collapsed: !this.props.open,
+  };
+
+  handleClick = () => {
+    const { onOpen } = this.props;
+    const { collapsed } = this.state;
+
+    this.setState({ collapsed: !collapsed }, () => onOpen && onOpen());
+  }
+
+  render () {
+    const { title, children } = this.props;
+    const { collapsed } = this.state;
+
+    return (
+      <div className={classNames('about__section', { active: !collapsed })}>
+        <div className='about__section__title' role='button' tabIndex='0' onClick={this.handleClick}>
+          <Icon id={collapsed ? 'chevron-right' : 'chevron-down'} fixedWidth /> {title}
+        </div>
+
+        {!collapsed && (
+          <div className='about__section__body'>{children}</div>
+        )}
+      </div>
+    );
+  }
+
+}
+
+export default @connect(mapStateToProps)
+@injectIntl
 class About extends React.PureComponent {
 
   static propTypes = {
+    server: ImmutablePropTypes.map,
+    extendedDescription: ImmutablePropTypes.map,
+    domainBlocks: ImmutablePropTypes.contains({
+      isLoading: PropTypes.bool,
+      isAvailable: PropTypes.bool,
+      items: ImmutablePropTypes.list,
+    }),
+    dispatch: PropTypes.func.isRequired,
     intl: PropTypes.object.isRequired,
   };
 
+  componentDidMount () {
+    const { dispatch } = this.props;
+    dispatch(fetchServer());
+    dispatch(fetchExtendedDescription());
+  }
+
+  handleDomainBlocksOpen = () => {
+    const { dispatch } = this.props;
+    dispatch(fetchDomainBlocks());
+  }
+
   render () {
-    const { intl } = this.props;
+    const { intl, server, extendedDescription, domainBlocks } = this.props;
+    const isLoading = server.get('isLoading');
 
     return (
       <Column>
-        <LinkFooter />
+        <div className='scrollable about'>
+          <div className='about__header'>
+            <Image blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} srcSet={server.getIn(['thumbnail', 'versions'])?.map((value, key) => `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' />
+            <h1>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</h1>
+            <p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {mastodon}' values={{ mastodon: <a href='https://joinmastodon.org' className='about__mail' target='_blank'>Mastodon</a> }} /></p>
+          </div>
+
+          <div className='about__meta'>
+            <div className='about__meta__column'>
+              <h4><FormattedMessage id='server_banner.administered_by' defaultMessage='Administered by:' /></h4>
+
+              <Account id={server.getIn(['contact', 'account', 'id'])} />
+            </div>
+
+            <hr className='about__meta__divider' />
+
+            <div className='about__meta__column'>
+              <h4><FormattedMessage id='about.contact' defaultMessage='Contact:' /></h4>
+
+              {isLoading ? <Skeleton width='10ch' /> : <a className='about__mail' href={`mailto:${server.getIn(['contact', 'email'])}`}>{server.getIn(['contact', 'email'])}</a>}
+            </div>
+          </div>
+
+          <Section open title={intl.formatMessage(messages.title)}>
+            {extendedDescription.get('isLoading') ? (
+              <>
+                <Skeleton width='100%' />
+                <br />
+                <Skeleton width='100%' />
+                <br />
+                <Skeleton width='100%' />
+                <br />
+                <Skeleton width='70%' />
+              </>
+            ) : (extendedDescription.get('content')?.length > 0 ? (
+              <div
+                className='prose'
+                dangerouslySetInnerHTML={{ __html: extendedDescription.get('content') }}
+              />
+            ) : (
+              <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
+            ))}
+          </Section>
+
+          <Section title={intl.formatMessage(messages.rules)}>
+            {!isLoading && (server.get('rules').isEmpty() ? (
+              <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
+            ) : (
+              <ol className='rules-list'>
+                {server.get('rules').map(rule => (
+                  <li key={rule.get('id')}>
+                    <span className='rules-list__text'>{rule.get('text')}</span>
+                  </li>
+                ))}
+              </ol>
+            ))}
+          </Section>
+
+          <Section title={intl.formatMessage(messages.blocks)} onOpen={this.handleDomainBlocksOpen}>
+            {domainBlocks.get('isLoading') ? (
+              <>
+                <Skeleton width='100%' />
+                <br />
+                <Skeleton width='70%' />
+              </>
+            ) : (domainBlocks.get('isAvailable') ? (
+              <>
+                <p><FormattedMessage id='about.domain_blocks.preamble' defaultMessage='Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.' /></p>
+
+                <table className='about__domain-blocks'>
+                  <thead>
+                    <tr>
+                      <th><FormattedMessage id='about.domain_blocks.domain' defaultMessage='Domain' /></th>
+                      <th><FormattedMessage id='about.domain_blocks.severity' defaultMessage='Severity' /></th>
+                      <th><FormattedMessage id='about.domain_blocks.comment' defaultMessage='Reason' /></th>
+                    </tr>
+                  </thead>
+
+                  <tbody>
+                    {domainBlocks.get('items').map(block => (
+                      <tr key={block.get('domain')}>
+                        <td><span title={`SHA-256: ${block.get('digest')}`}>{block.get('domain')}</span></td>
+                        <td><span title={intl.formatMessage(severityMessages[block.get('severity')].explanation)}>{intl.formatMessage(severityMessages[block.get('severity')].title)}</span></td>
+                        <td>{block.get('comment')}</td>
+                      </tr>
+                    ))}
+                  </tbody>
+                </table>
+              </>
+            ) : (
+              <p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
+            ))}
+          </Section>
+
+          <LinkFooter />
+        </div>
 
         <Helmet>
           <title>{intl.formatMessage(messages.title)}</title>
diff --git a/app/javascript/mastodon/features/privacy_policy/index.js b/app/javascript/mastodon/features/privacy_policy/index.js
index 5fbe340c05cd61c0770fbced599bb37fae4301ec..eee4255f4712a6f31f88f06a7fb4587c05daba2a 100644
--- a/app/javascript/mastodon/features/privacy_policy/index.js
+++ b/app/javascript/mastodon/features/privacy_policy/index.js
@@ -44,7 +44,7 @@ class PrivacyPolicy extends React.PureComponent {
           </div>
 
           <div
-            className='privacy-policy__body'
+            className='privacy-policy__body prose'
             dangerouslySetInnerHTML={{ __html: content }}
           />
         </div>
diff --git a/app/javascript/mastodon/features/report/rules.js b/app/javascript/mastodon/features/report/rules.js
index 2cb4a95b5a93619314770d5c6725ad612664324f..920da68d6382b859daa124085972097259f8bedd 100644
--- a/app/javascript/mastodon/features/report/rules.js
+++ b/app/javascript/mastodon/features/report/rules.js
@@ -7,7 +7,7 @@ import Button from 'mastodon/components/button';
 import Option from './components/option';
 
 const mapStateToProps = state => ({
-  rules: state.getIn(['server', 'rules']),
+  rules: state.getIn(['server', 'server', 'rules']),
 });
 
 export default @connect(mapStateToProps)
diff --git a/app/javascript/mastodon/features/ui/components/link_footer.js b/app/javascript/mastodon/features/ui/components/link_footer.js
index c4ce2a985516c52927ce80916de1a7eca363cf0a..cc3d83572704690802f0283752ec83020c13daf4 100644
--- a/app/javascript/mastodon/features/ui/components/link_footer.js
+++ b/app/javascript/mastodon/features/ui/components/link_footer.js
@@ -51,7 +51,7 @@ class LinkFooter extends React.PureComponent {
     const items = [];
 
     items.push(<a key='apps' href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Get the app' /></a>);
-    items.push(<a key='about' href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About' /></a>);
+    items.push(<Link key='about' to='/about'><FormattedMessage id='navigation_bar.info' defaultMessage='About' /></Link>);
     items.push(<a key='mastodon' href='https://joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.what_is_mastodon' defaultMessage='About Mastodon' /></a>);
     items.push(<a key='docs' href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a>);
     items.push(<Link key='privacy-policy' to='/privacy-policy'><FormattedMessage id='getting_started.privacy_policy' defaultMessage='Privacy Policy' /></Link>);
diff --git a/app/javascript/mastodon/reducers/server.js b/app/javascript/mastodon/reducers/server.js
index 68131c6ddfb2c222aca796ca9f0bebaab99e9acf..db9f2b5e6b61a62fc5b31e4b34d719641a74e978 100644
--- a/app/javascript/mastodon/reducers/server.js
+++ b/app/javascript/mastodon/reducers/server.js
@@ -1,18 +1,52 @@
-import { SERVER_FETCH_REQUEST, SERVER_FETCH_SUCCESS, SERVER_FETCH_FAIL } from 'mastodon/actions/server';
-import { Map as ImmutableMap, fromJS } from 'immutable';
+import {
+  SERVER_FETCH_REQUEST,
+  SERVER_FETCH_SUCCESS,
+  SERVER_FETCH_FAIL,
+  EXTENDED_DESCRIPTION_REQUEST,
+  EXTENDED_DESCRIPTION_SUCCESS,
+  EXTENDED_DESCRIPTION_FAIL,
+  SERVER_DOMAIN_BLOCKS_FETCH_REQUEST,
+  SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS,
+  SERVER_DOMAIN_BLOCKS_FETCH_FAIL,
+} from 'mastodon/actions/server';
+import { Map as ImmutableMap, List as ImmutableList, fromJS } from 'immutable';
 
 const initialState = ImmutableMap({
-  isLoading: true,
+  server: ImmutableMap({
+    isLoading: true,
+  }),
+
+  extendedDescription: ImmutableMap({
+    isLoading: true,
+  }),
+
+  domainBlocks: ImmutableMap({
+    isLoading: true,
+    isAvailable: true,
+    items: ImmutableList(),
+  }),
 });
 
 export default function server(state = initialState, action) {
   switch (action.type) {
   case SERVER_FETCH_REQUEST:
-    return state.set('isLoading', true);
+    return state.setIn(['server', 'isLoading'], true);
   case SERVER_FETCH_SUCCESS:
-    return fromJS(action.server).set('isLoading', false);
+    return state.set('server', fromJS(action.server)).setIn(['server', 'isLoading'], false);
   case SERVER_FETCH_FAIL:
-    return state.set('isLoading', false);
+    return state.setIn(['server', 'isLoading'], false);
+  case EXTENDED_DESCRIPTION_REQUEST:
+    return state.setIn(['extendedDescription', 'isLoading'], true);
+  case EXTENDED_DESCRIPTION_SUCCESS:
+    return state.set('extendedDescription', fromJS(action.description)).setIn(['extendedDescription', 'isLoading'], false);
+  case EXTENDED_DESCRIPTION_FAIL:
+    return state.setIn(['extendedDescription', 'isLoading'], false);
+  case SERVER_DOMAIN_BLOCKS_FETCH_REQUEST:
+    return state.setIn(['domainBlocks', 'isLoading'], true);
+  case SERVER_DOMAIN_BLOCKS_FETCH_SUCCESS:
+    return state.setIn(['domainBlocks', 'items'], fromJS(action.blocks)).setIn(['domainBlocks', 'isLoading'], false).setIn(['domainBlocks', 'isAvailable'], action.isAvailable);
+  case SERVER_DOMAIN_BLOCKS_FETCH_FAIL:
+    return state.setIn(['domainBlocks', 'isLoading'], false);
   default:
     return state;
   }
diff --git a/app/javascript/styles/application.scss b/app/javascript/styles/application.scss
index bbea061957e5d402f903cff3277ad1ce578097d2..e9f596e2fd131a561b9a01d4389d8c5f7e2d76d3 100644
--- a/app/javascript/styles/application.scss
+++ b/app/javascript/styles/application.scss
@@ -2,7 +2,6 @@
 @import 'mastodon/variables';
 @import 'fonts/roboto';
 @import 'fonts/roboto-mono';
-@import 'fonts/montserrat';
 
 @import 'mastodon/reset';
 @import 'mastodon/basics';
@@ -10,7 +9,6 @@
 @import 'mastodon/containers';
 @import 'mastodon/lists';
 @import 'mastodon/footer';
-@import 'mastodon/compact_header';
 @import 'mastodon/widgets';
 @import 'mastodon/forms';
 @import 'mastodon/accounts';
diff --git a/app/javascript/styles/contrast/diff.scss b/app/javascript/styles/contrast/diff.scss
index 841ed66480c6288375f7ce8045bfbab88261e86a..22f5bcc94bbdf34ee0bee30ac3542ab40b8e74f9 100644
--- a/app/javascript/styles/contrast/diff.scss
+++ b/app/javascript/styles/contrast/diff.scss
@@ -13,10 +13,6 @@
   }
 }
 
-.rich-formatting a,
-.rich-formatting p a,
-.rich-formatting li a,
-.landing-page__short-description p a,
 .status__content a,
 .reply-indicator__content a {
   color: lighten($ui-highlight-color, 12%);
diff --git a/app/javascript/styles/fonts/montserrat.scss b/app/javascript/styles/fonts/montserrat.scss
deleted file mode 100644
index 170fe654294d7a7862ccba2178a82cf78d65fc61..0000000000000000000000000000000000000000
--- a/app/javascript/styles/fonts/montserrat.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-@font-face {
-  font-family: mastodon-font-display;
-  src:
-    local('Montserrat'),
-    url('../fonts/montserrat/Montserrat-Regular.woff2') format('woff2'),
-    url('../fonts/montserrat/Montserrat-Regular.woff') format('woff'),
-    url('../fonts/montserrat/Montserrat-Regular.ttf') format('truetype');
-  font-weight: 400;
-  font-display: swap;
-  font-style: normal;
-}
-
-@font-face {
-  font-family: mastodon-font-display;
-  src:
-    local('Montserrat Medium'),
-    url('../fonts/montserrat/Montserrat-Medium.ttf') format('truetype');
-  font-weight: 500;
-  font-display: swap;
-  font-style: normal;
-}
diff --git a/app/javascript/styles/mastodon-light/diff.scss b/app/javascript/styles/mastodon-light/diff.scss
index 0bc6247ef2c8306aca6ef8d8c0692dbafcebad9d..4b27e6b4f3c40660038741f65c013bf2c91236f4 100644
--- a/app/javascript/styles/mastodon-light/diff.scss
+++ b/app/javascript/styles/mastodon-light/diff.scss
@@ -36,6 +36,20 @@ html {
   border-top: 0;
 }
 
+.column > .scrollable.about {
+  border-top: 1px solid lighten($ui-base-color, 8%);
+}
+
+.about__meta,
+.about__section__title {
+  background: $white;
+  border: 1px solid lighten($ui-base-color, 8%);
+}
+
+.rules-list li::before {
+  background: $ui-highlight-color;
+}
+
 .directory__card__img {
   background: lighten($ui-base-color, 12%);
 }
@@ -45,10 +59,6 @@ html {
   border-bottom: 1px solid lighten($ui-base-color, 8%);
 }
 
-.table-of-contents {
-  border: 1px solid lighten($ui-base-color, 8%);
-}
-
 .column-back-button,
 .column-header {
   background: $white;
@@ -138,11 +148,6 @@ html {
 .compose-form__poll-wrapper select,
 .search__input,
 .setting-text,
-.box-widget input[type="text"],
-.box-widget input[type="email"],
-.box-widget input[type="password"],
-.box-widget textarea,
-.statuses-grid .detailed-status,
 .report-dialog-modal__textarea,
 .audio-player {
   border: 1px solid lighten($ui-base-color, 8%);
@@ -480,52 +485,16 @@ html {
   background: $white;
 }
 
-.tabs-bar {
-  background: $white;
-  border: 1px solid lighten($ui-base-color, 8%);
-  border-bottom: 0;
-
-  @media screen and (max-width: $no-gap-breakpoint) {
-    border-top: 0;
-  }
-
-  &__link {
-    padding-bottom: 14px;
-    border-bottom-width: 1px;
-    border-bottom-color: lighten($ui-base-color, 8%);
-
-    &:hover,
-    &:active,
-    &:focus {
-      background: $ui-base-color;
-    }
-
-    &.active {
-      &:hover,
-      &:active,
-      &:focus {
-        background: transparent;
-        border-bottom-color: $ui-highlight-color;
-      }
-    }
-  }
-}
-
 // Change the default colors used on some parts of the profile pages
 .activity-stream-tabs {
   background: $account-background-color;
   border-bottom-color: lighten($ui-base-color, 8%);
 }
 
-.box-widget,
 .nothing-here,
 .page-header,
 .directory__tag > a,
-.directory__tag > div,
-.landing-page__call-to-action,
-.contact-widget,
-.landing .hero-widget__text,
-.landing-page__information.contact-widget {
+.directory__tag > div {
   background: $white;
   border: 1px solid lighten($ui-base-color, 8%);
 
@@ -536,11 +505,6 @@ html {
   }
 }
 
-.landing .hero-widget__text {
-  border-top: 0;
-  border-bottom: 0;
-}
-
 .simple_form {
   input[type="text"],
   input[type="number"],
@@ -553,26 +517,12 @@ html {
   }
 }
 
-.landing .hero-widget__footer {
-  background: $white;
-  border: 1px solid lighten($ui-base-color, 8%);
-  border-top: 0;
-
-  @media screen and (max-width: $no-gap-breakpoint) {
-    border: 0;
-  }
-}
-
 .picture-in-picture-placeholder {
   background: $white;
   border-color: lighten($ui-base-color, 8%);
   color: lighten($ui-base-color, 8%);
 }
 
-.brand__tagline {
-  color: $ui-secondary-color;
-}
-
 .directory__tag > a {
   &:hover,
   &:active,
@@ -666,8 +616,7 @@ html {
   }
 }
 
-.simple_form,
-.table-form {
+.simple_form {
   .warning {
     box-shadow: none;
     background: rgba($error-red, 0.5);
@@ -801,9 +750,6 @@ html {
 }
 
 .hero-widget,
-.box-widget,
-.contact-widget,
-.landing-page__information.contact-widget,
 .moved-account-widget,
 .memoriam-widget,
 .activity-stream,
diff --git a/app/javascript/styles/mastodon/about.scss b/app/javascript/styles/mastodon/about.scss
index 8893e3cf09b81282886fac4aecb26dd166b89088..0183c43d5e75d786cf3da520f42dff67fbe83b49 100644
--- a/app/javascript/styles/mastodon/about.scss
+++ b/app/javascript/styles/mastodon/about.scss
@@ -1,7 +1,5 @@
 $maximum-width: 1235px;
 $fluid-breakpoint: $maximum-width + 20px;
-$column-breakpoint: 700px;
-$small-breakpoint: 960px;
 
 .container {
   box-sizing: border-box;
@@ -15,892 +13,44 @@ $small-breakpoint: 960px;
   }
 }
 
-.rich-formatting {
-  font-family: $font-sans-serif, sans-serif;
-  font-size: 14px;
-  font-weight: 400;
-  line-height: 1.7;
-  word-wrap: break-word;
-  color: $darker-text-color;
-
-  a {
-    color: $highlight-text-color;
-    text-decoration: underline;
-
-    &:hover,
-    &:focus,
-    &:active {
-      text-decoration: none;
-    }
-  }
-
-  p,
-  li {
-    color: $darker-text-color;
-  }
-
-  p {
-    margin-top: 0;
-    margin-bottom: 0.85em;
-
-    &:last-child {
-      margin-bottom: 0;
-    }
-  }
-
-  strong {
-    font-weight: 700;
-    color: $secondary-text-color;
-  }
-
-  em {
-    font-style: italic;
-    color: $secondary-text-color;
-  }
-
-  code {
-    font-size: 0.85em;
-    background: darken($ui-base-color, 8%);
-    border-radius: 4px;
-    padding: 0.2em 0.3em;
-  }
-
-  h1,
-  h2,
-  h3,
-  h4,
-  h5,
-  h6 {
-    font-family: $font-display, sans-serif;
-    margin-top: 1.275em;
-    margin-bottom: 0.85em;
-    font-weight: 500;
-    color: $secondary-text-color;
-  }
-
-  h1 {
-    font-size: 2em;
-  }
-
-  h2 {
-    font-size: 1.75em;
-  }
-
-  h3 {
-    font-size: 1.5em;
-  }
-
-  h4 {
-    font-size: 1.25em;
-  }
-
-  h5,
-  h6 {
-    font-size: 1em;
-  }
-
-  ul {
-    list-style: disc;
-  }
-
-  ol {
-    list-style: decimal;
-  }
-
-  ul,
-  ol {
-    margin: 0;
-    padding: 0;
-    padding-left: 2em;
-    margin-bottom: 0.85em;
-
-    &[type='a'] {
-      list-style-type: lower-alpha;
-    }
-
-    &[type='i'] {
-      list-style-type: lower-roman;
-    }
-  }
-
-  hr {
-    width: 100%;
-    height: 0;
-    border: 0;
-    border-bottom: 1px solid lighten($ui-base-color, 4%);
-    margin: 1.7em 0;
-
-    &.spacer {
-      height: 1px;
-      border: 0;
-    }
-  }
-
-  table {
-    width: 100%;
-    border-collapse: collapse;
-    break-inside: auto;
-    margin-top: 24px;
-    margin-bottom: 32px;
-
-    thead tr,
-    tbody tr {
-      border-bottom: 1px solid lighten($ui-base-color, 4%);
-      font-size: 1em;
-      line-height: 1.625;
-      font-weight: 400;
-      text-align: left;
-      color: $darker-text-color;
-    }
-
-    thead tr {
-      border-bottom-width: 2px;
-      line-height: 1.5;
-      font-weight: 500;
-      color: $dark-text-color;
-    }
-
-    th,
-    td {
-      padding: 8px;
-      align-self: flex-start;
-      align-items: flex-start;
-      word-break: break-all;
-
-      &.nowrap {
-        width: 25%;
-        position: relative;
-
-        &::before {
-          content: '&nbsp;';
-          visibility: hidden;
-        }
-
-        span {
-          position: absolute;
-          left: 8px;
-          right: 8px;
-          white-space: nowrap;
-          overflow: hidden;
-          text-overflow: ellipsis;
-        }
-      }
-    }
-  }
-
-  & > :first-child {
-    margin-top: 0;
-  }
+.brand {
+  position: relative;
+  text-decoration: none;
 }
 
-.information-board {
-  background: darken($ui-base-color, 4%);
-  padding: 20px 0;
-
-  .container-alt {
-    position: relative;
-    padding-right: 280px + 15px;
-  }
-
-  &__sections {
-    display: flex;
-    justify-content: space-between;
-    flex-wrap: wrap;
-  }
-
-  &__section {
-    flex: 1 0 0;
-    font-family: $font-sans-serif, sans-serif;
-    font-size: 16px;
-    line-height: 28px;
-    color: $primary-text-color;
-    text-align: right;
-    padding: 10px 15px;
-
-    span,
-    strong {
-      display: block;
-    }
-
-    span {
-      &:last-child {
-        color: $secondary-text-color;
-      }
-    }
-
-    strong {
-      font-family: $font-display, sans-serif;
-      font-weight: 500;
-      font-size: 32px;
-      line-height: 48px;
-    }
-
-    @media screen and (max-width: $column-breakpoint) {
-      text-align: center;
-    }
-  }
-
-  .panel {
-    position: absolute;
-    width: 280px;
-    box-sizing: border-box;
-    background: darken($ui-base-color, 8%);
-    padding: 20px;
-    padding-top: 10px;
-    border-radius: 4px 4px 0 0;
-    right: 0;
-    bottom: -40px;
-
-    .panel-header {
-      font-family: $font-display, sans-serif;
-      font-size: 14px;
-      line-height: 24px;
-      font-weight: 500;
-      color: $darker-text-color;
-      padding-bottom: 5px;
-      margin-bottom: 15px;
-      border-bottom: 1px solid lighten($ui-base-color, 4%);
-      text-overflow: ellipsis;
-      white-space: nowrap;
-      overflow: hidden;
-
-      a,
-      span {
-        font-weight: 400;
-        color: darken($darker-text-color, 10%);
-      }
-
-      a {
-        text-decoration: none;
-      }
-    }
-  }
-
-  .owner {
-    text-align: center;
-
-    .avatar {
-      width: 80px;
-      height: 80px;
-      margin: 0 auto;
-      margin-bottom: 15px;
-
-      img {
-        display: block;
-        width: 80px;
-        height: 80px;
-        border-radius: 48px;
-      }
-    }
-
-    .name {
-      font-size: 14px;
-
-      a {
-        display: block;
-        color: $primary-text-color;
-        text-decoration: none;
-
-        &:hover {
-          .display_name {
-            text-decoration: underline;
-          }
-        }
-      }
-
-      .username {
-        display: block;
-        color: $darker-text-color;
-      }
-    }
-  }
-}
+.rules-list {
+  font-size: 15px;
+  line-height: 22px;
+  color: $primary-text-color;
+  counter-reset: list-counter;
 
-.landing-page {
-  p,
   li {
-    font-family: $font-sans-serif, sans-serif;
-    font-size: 16px;
-    font-weight: 400;
-    line-height: 30px;
-    margin-bottom: 12px;
-    color: $darker-text-color;
-
-    a {
-      color: $highlight-text-color;
-      text-decoration: underline;
-    }
-  }
-
-  em {
-    display: inline;
-    margin: 0;
-    padding: 0;
-    font-weight: 700;
-    background: transparent;
-    font-family: inherit;
-    font-size: inherit;
-    line-height: inherit;
-    color: lighten($darker-text-color, 10%);
-  }
-
-  h1 {
-    font-family: $font-display, sans-serif;
-    font-size: 26px;
-    line-height: 30px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
-
-    small {
-      font-family: $font-sans-serif, sans-serif;
-      display: block;
-      font-size: 18px;
-      font-weight: 400;
-      color: lighten($darker-text-color, 10%);
-    }
-  }
-
-  h2 {
-    font-family: $font-display, sans-serif;
-    font-size: 22px;
-    line-height: 26px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
-  }
-
-  h3 {
-    font-family: $font-display, sans-serif;
-    font-size: 18px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
-  }
-
-  h4 {
-    font-family: $font-display, sans-serif;
-    font-size: 16px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
-  }
-
-  h5 {
-    font-family: $font-display, sans-serif;
-    font-size: 14px;
-    line-height: 24px;
-    font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
-  }
-
-  h6 {
-    font-family: $font-display, sans-serif;
-    font-size: 12px;
-    line-height: 24px;
+    position: relative;
+    border-bottom: 1px solid lighten($ui-base-color, 8%);
+    padding: 1em 1.75em;
+    padding-left: 3em;
     font-weight: 500;
-    margin-bottom: 20px;
-    color: $secondary-text-color;
-  }
-
-  ul,
-  ol {
-    margin-left: 20px;
-
-    &[type='a'] {
-      list-style-type: lower-alpha;
-    }
-
-    &[type='i'] {
-      list-style-type: lower-roman;
-    }
-  }
-
-  ul {
-    list-style: disc;
-  }
-
-  ol {
-    list-style: decimal;
-  }
-
-  li > ol,
-  li > ul {
-    margin-top: 6px;
-  }
-
-  hr {
-    width: 100%;
-    height: 0;
-    border: 0;
-    border-bottom: 1px solid rgba($ui-base-lighter-color, 0.6);
-    margin: 20px 0;
-
-    &.spacer {
-      height: 1px;
-      border: 0;
-    }
-  }
-
-  &__information,
-  &__forms {
-    padding: 20px;
-  }
-
-  &__call-to-action {
-    background: $ui-base-color;
-    border-radius: 4px;
-    padding: 25px 40px;
-    overflow: hidden;
-    box-sizing: border-box;
-
-    .row {
-      width: 100%;
-      display: flex;
-      flex-direction: row-reverse;
-      flex-wrap: nowrap;
-      justify-content: space-between;
-      align-items: center;
-    }
-
-    .row__information-board {
-      display: flex;
-      justify-content: flex-end;
-      align-items: flex-end;
-
-      .information-board__section {
-        flex: 1 0 auto;
-        padding: 0 10px;
-      }
-
-      @media screen and (max-width: $no-gap-breakpoint) {
-        width: 100%;
-        justify-content: space-between;
-      }
-    }
-
-    .row__mascot {
-      flex: 1;
-      margin: 10px -50px 0 0;
-
-      @media screen and (max-width: $no-gap-breakpoint) {
-        display: none;
-      }
-    }
-  }
-
-  &__logo {
-    margin-right: 20px;
-
-    img {
-      height: 50px;
-      width: auto;
-      mix-blend-mode: lighten;
-    }
-  }
-
-  &__information {
-    padding: 45px 40px;
-    margin-bottom: 10px;
-
-    &:last-child {
-      margin-bottom: 0;
-    }
-
-    strong {
+    counter-increment: list-counter;
+
+    &::before {
+      content: counter(list-counter);
+      position: absolute;
+      left: 0;
+      top: 50%;
+      transform: translateY(-50%);
+      background: $highlight-text-color;
+      color: $ui-base-color;
+      border-radius: 50%;
+      width: 4ch;
+      height: 4ch;
       font-weight: 500;
-      color: lighten($darker-text-color, 10%);
-    }
-
-    .account {
-      border-bottom: 0;
-      padding: 0;
-
-      &__display-name {
-        align-items: center;
-        display: flex;
-        margin-right: 5px;
-      }
-
-      div.account__display-name {
-        &:hover {
-          .display-name strong {
-            text-decoration: none;
-          }
-        }
-
-        .account__avatar {
-          cursor: default;
-        }
-      }
-
-      &__avatar-wrapper {
-        margin-left: 0;
-        flex: 0 0 auto;
-      }
-
-      .display-name {
-        font-size: 15px;
-
-        &__account {
-          font-size: 14px;
-        }
-      }
-    }
-
-    @media screen and (max-width: $small-breakpoint) {
-      .contact {
-        margin-top: 30px;
-      }
-    }
-
-    @media screen and (max-width: $column-breakpoint) {
-      padding: 25px 20px;
-    }
-  }
-
-  &__information,
-  &__forms,
-  #mastodon-timeline {
-    box-sizing: border-box;
-    background: $ui-base-color;
-    border-radius: 4px;
-    box-shadow: 0 0 6px rgba($black, 0.1);
-  }
-
-  &__mascot {
-    height: 104px;
-    position: relative;
-    left: -40px;
-    bottom: 25px;
-
-    img {
-      height: 190px;
-      width: auto;
-    }
-  }
-
-  &__short-description {
-    .row {
       display: flex;
-      flex-wrap: wrap;
+      justify-content: center;
       align-items: center;
-      margin-bottom: 40px;
-    }
-
-    @media screen and (max-width: $column-breakpoint) {
-      .row {
-        margin-bottom: 20px;
-      }
-    }
-
-    p a {
-      color: $secondary-text-color;
-    }
-
-    h1 {
-      font-weight: 500;
-      color: $primary-text-color;
-      margin-bottom: 0;
-
-      small {
-        color: $darker-text-color;
-
-        span {
-          color: $secondary-text-color;
-        }
-      }
-    }
-
-    p:last-child {
-      margin-bottom: 0;
-    }
-  }
-
-  &__hero {
-    margin-bottom: 10px;
-
-    img {
-      display: block;
-      margin: 0;
-      max-width: 100%;
-      height: auto;
-      border-radius: 4px;
-    }
-  }
-
-  @media screen and (max-width: 840px) {
-    .information-board {
-      .container-alt {
-        padding-right: 20px;
-      }
-
-      .panel {
-        position: static;
-        margin-top: 20px;
-        width: 100%;
-        border-radius: 4px;
-
-        .panel-header {
-          text-align: center;
-        }
-      }
-    }
-  }
-
-  @media screen and (max-width: 675px) {
-    .header-wrapper {
-      padding-top: 0;
-
-      &.compact {
-        padding-bottom: 0;
-      }
-
-      &.compact .hero .heading {
-        text-align: initial;
-      }
     }
 
-    .header .container-alt,
-    .features .container-alt {
-      display: block;
-    }
-  }
-
-  .cta {
-    margin: 20px;
-  }
-}
-
-.landing {
-  margin-bottom: 100px;
-
-  @media screen and (max-width: 738px) {
-    margin-bottom: 0;
-  }
-
-  &__brand {
-    display: flex;
-    justify-content: center;
-    align-items: center;
-    padding: 50px;
-
-    .logo {
-      fill: $primary-text-color;
-      height: 52px;
-    }
-
-    @media screen and (max-width: $no-gap-breakpoint) {
-      padding: 0;
-      margin-bottom: 30px;
-    }
-  }
-
-  .directory {
-    margin-top: 30px;
-    background: transparent;
-    box-shadow: none;
-    border-radius: 0;
-  }
-
-  .hero-widget {
-    margin-top: 30px;
-    margin-bottom: 0;
-
-    h4 {
-      padding: 10px;
-      text-transform: uppercase;
-      font-weight: 700;
-      font-size: 13px;
-      color: $darker-text-color;
-    }
-
-    &__text {
-      border-radius: 0;
-      padding-bottom: 0;
-    }
-
-    &__footer {
-      background: $ui-base-color;
-      padding: 10px;
-      border-radius: 0 0 4px 4px;
-      display: flex;
-
-      &__column {
-        flex: 1 1 50%;
-        overflow-x: hidden;
-      }
-    }
-
-    .account {
-      padding: 10px 0;
-      border-bottom: 0;
-
-      .account__display-name {
-        display: flex;
-        align-items: center;
-      }
-    }
-
-    &__counters__wrapper {
-      display: flex;
-    }
-
-    &__counter {
-      padding: 10px;
-      width: 50%;
-
-      strong {
-        font-family: $font-display, sans-serif;
-        font-size: 15px;
-        font-weight: 700;
-        display: block;
-      }
-
-      span {
-        font-size: 14px;
-        color: $darker-text-color;
-      }
-    }
-  }
-
-  .simple_form .user_agreement .label_input > label {
-    font-weight: 400;
-    color: $darker-text-color;
-  }
-
-  .simple_form p.lead {
-    color: $darker-text-color;
-    font-size: 15px;
-    line-height: 20px;
-    font-weight: 400;
-    margin-bottom: 25px;
-  }
-
-  &__grid {
-    max-width: 960px;
-    margin: 0 auto;
-    display: grid;
-    grid-template-columns: minmax(0, 50%) minmax(0, 50%);
-    grid-gap: 30px;
-
-    @media screen and (max-width: 738px) {
-      grid-template-columns: minmax(0, 100%);
-      grid-gap: 10px;
-
-      &__column-login {
-        grid-row: 1;
-        display: flex;
-        flex-direction: column;
-
-        .box-widget {
-          order: 2;
-          flex: 0 0 auto;
-        }
-
-        .hero-widget {
-          margin-top: 0;
-          margin-bottom: 10px;
-          order: 1;
-          flex: 0 0 auto;
-        }
-      }
-
-      &__column-registration {
-        grid-row: 2;
-      }
-
-      .directory {
-        margin-top: 10px;
-      }
-    }
-
-    @media screen and (max-width: $no-gap-breakpoint) {
-      grid-gap: 0;
-
-      .hero-widget {
-        display: block;
-        margin-bottom: 0;
-        box-shadow: none;
-
-        &__img,
-        &__img img,
-        &__footer {
-          border-radius: 0;
-        }
-      }
-
-      .hero-widget,
-      .box-widget,
-      .directory__tag {
-        border-bottom: 1px solid lighten($ui-base-color, 8%);
-      }
-
-      .directory {
-        margin-top: 0;
-
-        &__tag {
-          margin-bottom: 0;
-
-          & > a,
-          & > div {
-            border-radius: 0;
-            box-shadow: none;
-          }
-
-          &:last-child {
-            border-bottom: 0;
-          }
-        }
-      }
-    }
-  }
-}
-
-.brand {
-  position: relative;
-  text-decoration: none;
-}
-
-.brand__tagline {
-  display: block;
-  position: absolute;
-  bottom: -10px;
-  left: 50px;
-  width: 300px;
-  color: $ui-primary-color;
-  text-decoration: none;
-  font-size: 14px;
-
-  @media screen and (max-width: $no-gap-breakpoint) {
-    position: static;
-    width: auto;
-    margin-top: 20px;
-    color: $dark-text-color;
-  }
-}
-
-.rules-list {
-  background: darken($ui-base-color, 2%);
-  border: 1px solid darken($ui-base-color, 8%);
-  border-radius: 4px;
-  padding: 0.5em 2.5em !important;
-  margin-top: 1.85em !important;
-
-  li {
-    border-bottom: 1px solid lighten($ui-base-color, 4%);
-    color: $dark-text-color;
-    padding: 1em;
-
     &:last-child {
       border-bottom: 0;
     }
   }
-
-  &__text {
-    color: $primary-text-color;
-  }
 }
diff --git a/app/javascript/styles/mastodon/compact_header.scss b/app/javascript/styles/mastodon/compact_header.scss
deleted file mode 100644
index 4980ab5f1ac7cd2974e22a5430be63a5343102fc..0000000000000000000000000000000000000000
--- a/app/javascript/styles/mastodon/compact_header.scss
+++ /dev/null
@@ -1,34 +0,0 @@
-.compact-header {
-  h1 {
-    font-size: 24px;
-    line-height: 28px;
-    color: $darker-text-color;
-    font-weight: 500;
-    margin-bottom: 20px;
-    padding: 0 10px;
-    word-wrap: break-word;
-
-    @media screen and (max-width: 740px) {
-      text-align: center;
-      padding: 20px 10px 0;
-    }
-
-    a {
-      color: inherit;
-      text-decoration: none;
-    }
-
-    small {
-      font-weight: 400;
-      color: $secondary-text-color;
-    }
-
-    img {
-      display: inline-block;
-      margin-bottom: -5px;
-      margin-right: 15px;
-      width: 36px;
-      height: 36px;
-    }
-  }
-}
diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss
index a8919b9cbd1c3e3bb4f1b1acb81b0a836ffae74e..d4657d18043b8a75c0fe0401d4f98310126b69d7 100644
--- a/app/javascript/styles/mastodon/components.scss
+++ b/app/javascript/styles/mastodon/components.scss
@@ -3261,6 +3261,7 @@ $ui-header-height: 55px;
     padding: 10px;
     padding-top: 20px;
     z-index: 1;
+    font-size: 13px;
 
     ul {
       margin-bottom: 10px;
@@ -3272,7 +3273,6 @@ $ui-header-height: 55px;
 
     p {
       color: $dark-text-color;
-      font-size: 13px;
       margin-bottom: 20px;
 
       a {
@@ -8266,79 +8266,202 @@ noscript {
 
   &__body {
     margin-top: 20px;
-    color: $secondary-text-color;
-    font-size: 15px;
-    line-height: 22px;
+  }
+}
 
-    h1,
-    p,
-    ul,
-    ol {
-      margin-bottom: 20px;
-    }
+.prose {
+  color: $secondary-text-color;
+  font-size: 15px;
+  line-height: 22px;
 
-    ul {
-      list-style: disc;
-    }
+  p,
+  ul,
+  ol {
+    margin-top: 1.25em;
+    margin-bottom: 1.25em;
+  }
 
-    ol {
-      list-style: decimal;
-    }
+  img {
+    margin-top: 2em;
+    margin-bottom: 2em;
+  }
 
-    ul,
-    ol {
-      padding-left: 1em;
+  video {
+    margin-top: 2em;
+    margin-bottom: 2em;
+  }
+
+  figure {
+    margin-top: 2em;
+    margin-bottom: 2em;
+
+    figcaption {
+      font-size: 0.875em;
+      line-height: 1.4285714;
+      margin-top: 0.8571429em;
     }
+  }
 
-    li {
-      margin-bottom: 10px;
+  figure > * {
+    margin-top: 0;
+    margin-bottom: 0;
+  }
 
-      &::marker {
-        color: $darker-text-color;
-      }
+  h1 {
+    font-size: 1.5em;
+    margin-top: 0;
+    margin-bottom: 1em;
+    line-height: 1.33;
+  }
 
-      &:last-child {
-        margin-bottom: 0;
-      }
-    }
+  h2 {
+    font-size: 1.25em;
+    margin-top: 1.6em;
+    margin-bottom: 0.6em;
+    line-height: 1.6;
+  }
+
+  h3,
+  h4,
+  h5,
+  h6 {
+    margin-top: 1.5em;
+    margin-bottom: 0.5em;
+    line-height: 1.5;
+  }
 
-    h1 {
-      color: $primary-text-color;
-      font-size: 19px;
-      line-height: 24px;
-      font-weight: 700;
-      margin-top: 30px;
+  ol {
+    counter-reset: list-counter;
+  }
 
-      &:first-child {
-        margin-top: 0;
-      }
-    }
+  li {
+    margin-top: 0.5em;
+    margin-bottom: 0.5em;
+  }
 
-    strong {
-      font-weight: 700;
-      color: $primary-text-color;
-    }
+  ol > li {
+    counter-increment: list-counter;
 
-    em {
-      font-style: italic;
+    &::before {
+      content: counter(list-counter) ".";
+      position: absolute;
+      left: 0;
     }
+  }
 
-    a {
-      color: $highlight-text-color;
-      text-decoration: underline;
+  ul > li::before {
+    content: "";
+    position: absolute;
+    background-color: $darker-text-color;
+    border-radius: 50%;
+    width: 0.375em;
+    height: 0.375em;
+    top: 0.5em;
+    left: 0.25em;
+  }
 
-      &:focus,
-      &:hover,
-      &:active {
-        text-decoration: none;
-      }
-    }
+  ul > li,
+  ol > li {
+    position: relative;
+    padding-left: 1.75em;
+  }
 
-    hr {
-      border: 1px solid lighten($ui-base-color, 4%);
-      margin: 30px 0;
+  & > ul > li p {
+    margin-top: 0.75em;
+    margin-bottom: 0.75em;
+  }
+
+  & > ul > li > *:first-child {
+    margin-top: 1.25em;
+  }
+
+  & > ul > li > *:last-child {
+    margin-bottom: 1.25em;
+  }
+
+  & > ol > li > *:first-child {
+    margin-top: 1.25em;
+  }
+
+  & > ol > li > *:last-child {
+    margin-bottom: 1.25em;
+  }
+
+  ul ul,
+  ul ol,
+  ol ul,
+  ol ol {
+    margin-top: 0.75em;
+    margin-bottom: 0.75em;
+  }
+
+  h1,
+  h2,
+  h3,
+  h4,
+  h5,
+  h6,
+  strong,
+  b {
+    color: $primary-text-color;
+    font-weight: 700;
+  }
+
+  em,
+  i {
+    font-style: italic;
+  }
+
+  a {
+    color: $highlight-text-color;
+    text-decoration: underline;
+
+    &:focus,
+    &:hover,
+    &:active {
+      text-decoration: none;
     }
   }
+
+  code {
+    font-size: 0.875em;
+    background: darken($ui-base-color, 8%);
+    border-radius: 4px;
+    padding: 0.2em 0.3em;
+  }
+
+  hr {
+    border: 0;
+    border-top: 1px solid lighten($ui-base-color, 4%);
+    margin-top: 3em;
+    margin-bottom: 3em;
+  }
+
+  hr + * {
+    margin-top: 0;
+  }
+
+  h2 + * {
+    margin-top: 0;
+  }
+
+  h3 + * {
+    margin-top: 0;
+  }
+
+  h4 + *,
+  h5 + *,
+  h6 + * {
+    margin-top: 0;
+  }
+
+  & > :first-child {
+    margin-top: 0;
+  }
+
+  & > :last-child {
+    margin-bottom: 0;
+  }
 }
 
 .dismissable-banner {
@@ -8365,3 +8488,242 @@ noscript {
     justify-content: center;
   }
 }
+
+.image {
+  position: relative;
+  overflow: hidden;
+
+  &__preview {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+  }
+
+  &.loaded &__preview {
+    display: none;
+  }
+
+  img {
+    display: block;
+    width: 100%;
+    height: 100%;
+    object-fit: cover;
+    border: 0;
+    background: transparent;
+    opacity: 0;
+  }
+
+  &.loaded img {
+    opacity: 1;
+  }
+}
+
+.about {
+  padding: 20px;
+
+  @media screen and (min-width: $no-gap-breakpoint) {
+    border-radius: 4px;
+  }
+
+  &__header {
+    margin-bottom: 30px;
+
+    &__hero {
+      width: 100%;
+      height: auto;
+      aspect-ratio: 1.9;
+      background: lighten($ui-base-color, 4%);
+      border-radius: 8px;
+      margin-bottom: 30px;
+    }
+
+    h1,
+    p {
+      text-align: center;
+    }
+
+    h1 {
+      font-size: 24px;
+      line-height: 1.5;
+      font-weight: 700;
+      margin-bottom: 10px;
+    }
+
+    p {
+      font-size: 16px;
+      line-height: 24px;
+      font-weight: 400;
+      color: $darker-text-color;
+    }
+  }
+
+  &__meta {
+    background: lighten($ui-base-color, 4%);
+    border-radius: 4px;
+    display: flex;
+    margin-bottom: 30px;
+    font-size: 15px;
+
+    &__column {
+      box-sizing: border-box;
+      width: 50%;
+      padding: 20px;
+    }
+
+    &__divider {
+      width: 0;
+      border: 0;
+      border-style: solid;
+      border-color: lighten($ui-base-color, 8%);
+      border-left-width: 1px;
+      min-height: calc(100% - 60px);
+      flex: 0 0 auto;
+    }
+
+    h4 {
+      font-size: 15px;
+      text-transform: uppercase;
+      color: $darker-text-color;
+      font-weight: 500;
+      margin-bottom: 20px;
+    }
+
+    @media screen and (max-width: 600px) {
+      display: block;
+
+      h4 {
+        text-align: center;
+      }
+
+      &__column {
+        width: 100%;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+      }
+
+      &__divider {
+        min-height: 0;
+        width: 100%;
+        border-left-width: 0;
+        border-top-width: 1px;
+      }
+    }
+
+    .layout-multiple-columns & {
+      display: block;
+
+      h4 {
+        text-align: center;
+      }
+
+      &__column {
+        width: 100%;
+        display: flex;
+        flex-direction: column;
+        align-items: center;
+      }
+
+      &__divider {
+        min-height: 0;
+        width: 100%;
+        border-left-width: 0;
+        border-top-width: 1px;
+      }
+    }
+  }
+
+  &__mail {
+    color: $primary-text-color;
+    text-decoration: none;
+    font-weight: 500;
+
+    &:hover,
+    &:focus,
+    &:active {
+      text-decoration: underline;
+    }
+  }
+
+  .getting-started__footer {
+    padding: 0;
+    margin-top: 60px;
+    text-align: center;
+    font-size: 15px;
+    line-height: 22px;
+
+    @media screen and (min-width: $no-gap-breakpoint) {
+      display: none;
+    }
+  }
+
+  .account {
+    padding: 0;
+    border: 0;
+  }
+
+  .account__avatar-wrapper {
+    margin-left: 0;
+  }
+
+  .account__relationship {
+    display: none;
+  }
+
+  &__section {
+    margin-bottom: 10px;
+
+    &__title {
+      font-size: 17px;
+      font-weight: 600;
+      line-height: 22px;
+      padding: 20px;
+      border-radius: 4px;
+      background: lighten($ui-base-color, 4%);
+      color: $highlight-text-color;
+      cursor: pointer;
+    }
+
+    &.active &__title {
+      border-radius: 4px 4px 0 0;
+    }
+
+    &__body {
+      border: 1px solid lighten($ui-base-color, 4%);
+      border-top: 0;
+      padding: 20px;
+      font-size: 15px;
+      line-height: 22px;
+    }
+  }
+
+  &__domain-blocks {
+    margin-top: 30px;
+    width: 100%;
+    border-collapse: collapse;
+    break-inside: auto;
+
+    th {
+      text-align: left;
+      font-weight: 500;
+      color: $darker-text-color;
+    }
+
+    thead tr,
+    tbody tr {
+      border-bottom: 1px solid lighten($ui-base-color, 8%);
+    }
+
+    tbody tr:last-child {
+      border-bottom: 0;
+    }
+
+    th,
+    td {
+      padding: 8px;
+    }
+  }
+}
diff --git a/app/javascript/styles/mastodon/containers.scss b/app/javascript/styles/mastodon/containers.scss
index 01ee5621960bf02acb42eff9557579ecddeae314..8e5ed03f07e95aab5aa0b9eac4b84d499d6e8a0d 100644
--- a/app/javascript/styles/mastodon/containers.scss
+++ b/app/javascript/styles/mastodon/containers.scss
@@ -30,7 +30,6 @@
       outline: 0;
       padding: 12px 16px;
       line-height: 32px;
-      font-family: $font-display, sans-serif;
       font-weight: 500;
       font-size: 14px;
     }
diff --git a/app/javascript/styles/mastodon/dashboard.scss b/app/javascript/styles/mastodon/dashboard.scss
index c21fc9eba848c7cc377bcbe387f1c5ef399aa9dd..f25765d1da90aff2ebda759544cf35d89473f3bb 100644
--- a/app/javascript/styles/mastodon/dashboard.scss
+++ b/app/javascript/styles/mastodon/dashboard.scss
@@ -38,7 +38,6 @@
     font-weight: 500;
     font-size: 24px;
     color: $primary-text-color;
-    font-family: $font-display, sans-serif;
     margin-bottom: 20px;
     line-height: 30px;
   }
diff --git a/app/javascript/styles/mastodon/forms.scss b/app/javascript/styles/mastodon/forms.scss
index 3d67f3b567c1c0eb927569c9dd1f03ee1710cf29..69a0b22d6e8a911b921eeed90e98de25dccbcf62 100644
--- a/app/javascript/styles/mastodon/forms.scss
+++ b/app/javascript/styles/mastodon/forms.scss
@@ -139,18 +139,9 @@ code {
   }
 
   .rules-list {
-    list-style: decimal;
     font-size: 17px;
     line-height: 22px;
-    font-weight: 500;
-    background: transparent;
-    border: 0;
-    padding: 0.5em 1em !important;
     margin-bottom: 30px;
-
-    li {
-      border-color: lighten($ui-base-color, 8%);
-    }
   }
 
   .hint {
@@ -603,41 +594,6 @@ code {
       }
     }
   }
-
-  &__overlay-area {
-    position: relative;
-
-    &__blurred form {
-      filter: blur(2px);
-    }
-
-    &__overlay {
-      position: absolute;
-      top: 0;
-      left: 0;
-      width: 100%;
-      height: 100%;
-      display: flex;
-      justify-content: center;
-      align-items: center;
-      background: rgba($ui-base-color, 0.65);
-      border-radius: 4px;
-      margin-left: -4px;
-      margin-top: -4px;
-      padding: 4px;
-
-      &__content {
-        text-align: center;
-
-        &.rich-formatting {
-          &,
-          p {
-            color: $primary-text-color;
-          }
-        }
-      }
-    }
-  }
 }
 
 .block-icon {
@@ -908,24 +864,7 @@ code {
   }
 }
 
-.table-form {
-  p {
-    margin-bottom: 15px;
-
-    strong {
-      font-weight: 500;
-
-      @each $lang in $cjk-langs {
-        &:lang(#{$lang}) {
-          font-weight: 700;
-        }
-      }
-    }
-  }
-}
-
-.simple_form,
-.table-form {
+.simple_form {
   .warning {
     box-sizing: border-box;
     background: rgba($error-value-color, 0.5);
diff --git a/app/javascript/styles/mastodon/widgets.scss b/app/javascript/styles/mastodon/widgets.scss
index 43284eb482b1d958307f8ec9d4652ed4e7dc38a9..260a97c6d22103db220afea5c9d118a3b6645e7c 100644
--- a/app/javascript/styles/mastodon/widgets.scss
+++ b/app/javascript/styles/mastodon/widgets.scss
@@ -112,13 +112,6 @@
   }
 }
 
-.box-widget {
-  padding: 20px;
-  border-radius: 4px;
-  background: $ui-base-color;
-  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
-}
-
 .placeholder-widget {
   padding: 16px;
   border-radius: 4px;
@@ -128,47 +121,6 @@
   margin-bottom: 10px;
 }
 
-.contact-widget {
-  min-height: 100%;
-  font-size: 15px;
-  color: $darker-text-color;
-  line-height: 20px;
-  word-wrap: break-word;
-  font-weight: 400;
-  padding: 0;
-
-  h4 {
-    padding: 10px;
-    text-transform: uppercase;
-    font-weight: 700;
-    font-size: 13px;
-    color: $darker-text-color;
-  }
-
-  .account {
-    border-bottom: 0;
-    padding: 10px 0;
-    padding-top: 5px;
-  }
-
-  & > a {
-    display: inline-block;
-    padding: 10px;
-    padding-top: 0;
-    color: $darker-text-color;
-    text-decoration: none;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-
-    &:hover,
-    &:focus,
-    &:active {
-      text-decoration: underline;
-    }
-  }
-}
-
 .moved-account-widget {
   padding: 15px;
   padding-bottom: 20px;
@@ -249,37 +201,6 @@
   margin-bottom: 10px;
 }
 
-.page-header {
-  background: lighten($ui-base-color, 8%);
-  box-shadow: 0 0 15px rgba($base-shadow-color, 0.2);
-  border-radius: 4px;
-  padding: 60px 15px;
-  text-align: center;
-  margin: 10px 0;
-
-  h1 {
-    color: $primary-text-color;
-    font-size: 36px;
-    line-height: 1.1;
-    font-weight: 700;
-    margin-bottom: 10px;
-  }
-
-  p {
-    font-size: 15px;
-    color: $darker-text-color;
-  }
-
-  @media screen and (max-width: $no-gap-breakpoint) {
-    margin-top: 0;
-    background: lighten($ui-base-color, 4%);
-
-    h1 {
-      font-size: 24px;
-    }
-  }
-}
-
 .directory {
   background: $ui-base-color;
   border-radius: 4px;
@@ -366,34 +287,6 @@
   }
 }
 
-.avatar-stack {
-  display: flex;
-  justify-content: flex-end;
-
-  .account__avatar {
-    flex: 0 0 auto;
-    width: 36px;
-    height: 36px;
-    border-radius: 50%;
-    position: relative;
-    margin-left: -10px;
-    background: darken($ui-base-color, 8%);
-    border: 2px solid $ui-base-color;
-
-    &:nth-child(1) {
-      z-index: 1;
-    }
-
-    &:nth-child(2) {
-      z-index: 2;
-    }
-
-    &:nth-child(3) {
-      z-index: 3;
-    }
-  }
-}
-
 .accounts-table {
   width: 100%;
 
@@ -495,11 +388,7 @@
 
 .moved-account-widget,
 .memoriam-widget,
-.box-widget,
-.contact-widget,
-.landing-page__information.contact-widget,
-.directory,
-.page-header {
+.directory {
   @media screen and (max-width: $no-gap-breakpoint) {
     margin-bottom: 0;
     box-shadow: none;
@@ -507,88 +396,6 @@
   }
 }
 
-$maximum-width: 1235px;
-$fluid-breakpoint: $maximum-width + 20px;
-
-.statuses-grid {
-  min-height: 600px;
-
-  @media screen and (max-width: 640px) {
-    width: 100% !important; // Masonry layout is unnecessary at this width
-  }
-
-  &__item {
-    width: math.div(960px - 20px, 3);
-
-    @media screen and (max-width: $fluid-breakpoint) {
-      width: math.div(940px - 20px, 3);
-    }
-
-    @media screen and (max-width: 640px) {
-      width: 100%;
-    }
-
-    @media screen and (max-width: $no-gap-breakpoint) {
-      width: 100vw;
-    }
-  }
-
-  .detailed-status {
-    border-radius: 4px;
-
-    @media screen and (max-width: $no-gap-breakpoint) {
-      border-top: 1px solid lighten($ui-base-color, 16%);
-    }
-
-    &.compact {
-      .detailed-status__meta {
-        margin-top: 15px;
-      }
-
-      .status__content {
-        font-size: 15px;
-        line-height: 20px;
-
-        .emojione {
-          width: 20px;
-          height: 20px;
-          margin: -3px 0 0;
-        }
-
-        .status__content__spoiler-link {
-          line-height: 20px;
-          margin: 0;
-        }
-      }
-
-      .media-gallery,
-      .status-card,
-      .video-player {
-        margin-top: 15px;
-      }
-    }
-  }
-}
-
-.notice-widget {
-  margin-bottom: 10px;
-  color: $darker-text-color;
-
-  p {
-    margin-bottom: 10px;
-
-    &:last-child {
-      margin-bottom: 0;
-    }
-  }
-
-  a {
-    font-size: 14px;
-    line-height: 20px;
-  }
-}
-
-.notice-widget,
 .placeholder-widget {
   a {
     text-decoration: none;
@@ -602,37 +409,3 @@ $fluid-breakpoint: $maximum-width + 20px;
     }
   }
 }
-
-.table-of-contents {
-  background: darken($ui-base-color, 4%);
-  min-height: 100%;
-  font-size: 14px;
-  border-radius: 4px;
-
-  li a {
-    display: block;
-    font-weight: 500;
-    padding: 15px;
-    white-space: nowrap;
-    overflow: hidden;
-    text-overflow: ellipsis;
-    text-decoration: none;
-    color: $primary-text-color;
-    border-bottom: 1px solid lighten($ui-base-color, 4%);
-
-    &:hover,
-    &:focus,
-    &:active {
-      text-decoration: underline;
-    }
-  }
-
-  li:last-child a {
-    border-bottom: 0;
-  }
-
-  li ul {
-    padding-left: 20px;
-    border-bottom: 1px solid lighten($ui-base-color, 4%);
-  }
-}
diff --git a/app/models/domain_block.rb b/app/models/domain_block.rb
index b08687787cab8d017a1a19681936e602bf7a50bc..ad1dc2a38e9f7cf6054edd72a4d47e7b119e8aaf 100644
--- a/app/models/domain_block.rb
+++ b/app/models/domain_block.rb
@@ -28,8 +28,8 @@ class DomainBlock < ApplicationRecord
   delegate :count, to: :accounts, prefix: true
 
   scope :matches_domain, ->(value) { where(arel_table[:domain].matches("%#{value}%")) }
-  scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]).or(where(reject_media: true)) }
-  scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), reject_media, domain')) }
+  scope :with_user_facing_limitations, -> { where(severity: [:silence, :suspend]) }
+  scope :by_severity, -> { order(Arel.sql('(CASE severity WHEN 0 THEN 1 WHEN 1 THEN 2 WHEN 2 THEN 0 END), domain')) }
 
   def to_log_human_identifier
     domain
diff --git a/app/models/extended_description.rb b/app/models/extended_description.rb
new file mode 100644
index 0000000000000000000000000000000000000000..6e5c0d1b6a797280c7c2df3341f6557dc947419e
--- /dev/null
+++ b/app/models/extended_description.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class ExtendedDescription < ActiveModelSerializers::Model
+  attributes :updated_at, :text
+
+  def self.current
+    custom = Setting.find_by(var: 'site_extended_description')
+
+    if custom&.value.present?
+      new(text: custom.value, updated_at: custom.updated_at)
+    else
+      new
+    end
+  end
+end
diff --git a/app/serializers/rest/domain_block_serializer.rb b/app/serializers/rest/domain_block_serializer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..678463e13b337a0d5b3554252c63b9b62ef00ea2
--- /dev/null
+++ b/app/serializers/rest/domain_block_serializer.rb
@@ -0,0 +1,17 @@
+# frozen_string_literal: true
+
+class REST::DomainBlockSerializer < ActiveModel::Serializer
+  attributes :domain, :digest, :severity, :comment
+
+  def domain
+    object.public_domain
+  end
+
+  def digest
+    object.domain_digest
+  end
+
+  def comment
+    object.public_comment if instance_options[:with_comment]
+  end
+end
diff --git a/app/serializers/rest/extended_description_serializer.rb b/app/serializers/rest/extended_description_serializer.rb
new file mode 100644
index 0000000000000000000000000000000000000000..0c3649033316ce05f752d5b1913d22dbaba023ad
--- /dev/null
+++ b/app/serializers/rest/extended_description_serializer.rb
@@ -0,0 +1,13 @@
+# frozen_string_literal: true
+
+class REST::ExtendedDescriptionSerializer < ActiveModel::Serializer
+  attributes :updated_at, :content
+
+  def updated_at
+    object.updated_at&.iso8601
+  end
+
+  def content
+    object.text
+  end
+end
diff --git a/app/views/about/_domain_blocks.html.haml b/app/views/about/_domain_blocks.html.haml
deleted file mode 100644
index 35a30f16eefd830b3f2cc8dd4154d508d0417609..0000000000000000000000000000000000000000
--- a/app/views/about/_domain_blocks.html.haml
+++ /dev/null
@@ -1,12 +0,0 @@
-%table
-  %thead
-    %tr
-      %th= t('about.unavailable_content_description.domain')
-      %th= t('about.unavailable_content_description.reason')
-  %tbody
-    - domain_blocks.each do |domain_block|
-      %tr
-        %td.nowrap
-          %span{ title: "SHA-256: #{domain_block.domain_digest}" }= domain_block.public_domain
-        %td
-          = domain_block.public_comment if display_blocks_rationale?
diff --git a/app/views/about/more.html.haml b/app/views/about/more.html.haml
deleted file mode 100644
index a5a10b6205949e977e7a76080c5d63661dc13f45..0000000000000000000000000000000000000000
--- a/app/views/about/more.html.haml
+++ /dev/null
@@ -1,96 +0,0 @@
-- content_for :page_title do
-  = site_hostname
-
-- content_for :header_tags do
-  = javascript_pack_tag 'public', crossorigin: 'anonymous'
-  = render partial: 'shared/og'
-
-.grid-4
-  .column-0
-    .public-account-header.public-account-header--no-bar
-      .public-account-header__image
-        = image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.png'), alt: @instance_presenter.title, class: 'parallax'
-
-  .column-1
-    .landing-page__call-to-action{ dir: 'ltr' }
-      .row
-        .row__information-board
-          .information-board__section
-            %span= t 'about.user_count_before'
-            %strong= friendly_number_to_human @instance_presenter.user_count
-            %span= t 'about.user_count_after', count: @instance_presenter.user_count
-          .information-board__section
-            %span= t 'about.status_count_before'
-            %strong= friendly_number_to_human @instance_presenter.status_count
-            %span= t 'about.status_count_after', count: @instance_presenter.status_count
-        .row__mascot
-          .landing-page__mascot
-            = image_tag @instance_presenter.mascot&.file&.url || asset_pack_path('media/images/elephant_ui_plane.svg'), alt: ''
-
-  .column-2
-    .contact-widget
-      %h4= t 'about.administered_by'
-
-      = account_link_to(@instance_presenter.contact.account)
-
-      - if @instance_presenter.contact.email.present?
-        %h4
-          = succeed ':' do
-            = t 'about.contact'
-
-        = mail_to @instance_presenter.contact.email, nil, title: @instance_presenter.contact.email
-
-  .column-3
-    = render 'application/flashes'
-
-    - if @contents.blank? && @rules.empty? && (!display_blocks? || @blocks&.empty?)
-      = nothing_here
-    - else
-      .box-widget
-        .rich-formatting
-          - unless @rules.empty?
-            %h2#rules= t('about.rules')
-
-            %p= t('about.rules_html')
-
-            %ol.rules-list
-              - @rules.each do |rule|
-                %li
-                  .rules-list__text= rule.text
-
-          = @contents.html_safe
-
-          - if display_blocks? && !@blocks.empty?
-            %h2#unavailable-content= t('about.unavailable_content')
-
-            %p= t('about.unavailable_content_html')
-
-            - if (blocks = @blocks.select(&:reject_media?)) && !blocks.empty?
-              %h3= t('about.unavailable_content_description.rejecting_media_title')
-              %p= t('about.unavailable_content_description.rejecting_media')
-              = render partial: 'domain_blocks', locals: { domain_blocks: blocks }
-            - if (blocks = @blocks.select(&:silence?)) && !blocks.empty?
-              %h3= t('about.unavailable_content_description.silenced_title')
-              %p= t('about.unavailable_content_description.silenced')
-              = render partial: 'domain_blocks', locals: { domain_blocks: blocks }
-            - if (blocks = @blocks.select(&:suspend?)) && !blocks.empty?
-              %h3= t('about.unavailable_content_description.suspended_title')
-              %p= t('about.unavailable_content_description.suspended')
-              = render partial: 'domain_blocks', locals: { domain_blocks: blocks }
-
-  .column-4
-    %ul.table-of-contents
-      - unless @rules.empty?
-        %li= link_to t('about.rules'), '#rules'
-
-      - @table_of_contents.each do |item|
-        %li
-          = link_to item.title, "##{item.anchor}"
-
-          - unless item.children.empty?
-            %ul
-              - item.children.each do |sub_item|
-                %li= link_to sub_item.title, "##{sub_item.anchor}"
-
-      - if display_blocks? && !@blocks.empty?
-        %li= link_to t('about.unavailable_content'), '#unavailable-content'
diff --git a/app/views/about/show.html.haml b/app/views/about/show.html.haml
new file mode 100644
index 0000000000000000000000000000000000000000..aff28b9a92154f43beb1103af4836b2ec86b385c
--- /dev/null
+++ b/app/views/about/show.html.haml
@@ -0,0 +1,4 @@
+- content_for :page_title do
+  = t('about.title')
+
+= render partial: 'shared/web_app'
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 8a70bd8caca85b622e35605b9822699b4007dd89..11716234ef346f6cb7da63f794942c094b91db8d 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -2,41 +2,15 @@
 en:
   about:
     about_mastodon_html: 'The social network of the future: No ads, no corporate surveillance, ethical design, and decentralization! Own your data with Mastodon!'
-    about_this: About
-    administered_by: 'Administered by:'
     api: API
     apps: Mobile apps
-    contact: Contact
     contact_missing: Not set
     contact_unavailable: N/A
     documentation: Documentation
     hosted_on: Mastodon hosted on %{domain}
-    instance_actor_flash: |
-      This account is a virtual actor used to represent the server itself and not any individual user.
-      It is used for federation purposes and should not be blocked unless you want to block the whole instance, in which case you should use a domain block.
     privacy_policy: Privacy Policy
-    rules: Server rules
-    rules_html: 'Below is a summary of rules you need to follow if you want to have an account on this server of Mastodon:'
     source_code: Source code
-    status_count_after:
-      one: post
-      other: posts
-    status_count_before: Who published
-    unavailable_content: Moderated servers
-    unavailable_content_description:
-      domain: Server
-      reason: Reason
-      rejecting_media: 'Media files from these servers will not be processed or stored, and no thumbnails will be displayed, requiring manual click-through to the original file:'
-      rejecting_media_title: Filtered media
-      silenced: 'Posts from these servers will be hidden in public timelines and conversations, and no notifications will be generated from their users interactions, unless you are following them:'
-      silenced_title: Limited servers
-      suspended: 'No data from these servers will be processed, stored or exchanged, making any interaction or communication with users from these servers impossible:'
-      suspended_title: Suspended servers
-    unavailable_content_html: Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.
-    user_count_after:
-      one: user
-      other: users
-    user_count_before: Home to
+    title: About
     what_is_mastodon: What is Mastodon?
   accounts:
     choices_html: "%{name}'s choices:"
diff --git a/config/routes.rb b/config/routes.rb
index e6098cd1723948434c02e39bd7e92f4a075655fb..29ec0f8a56f8b11d4378ff895f120327ac65efab 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -487,7 +487,9 @@ Rails.application.routes.draw do
       resource :instance, only: [:show] do
         resources :peers, only: [:index], controller: 'instances/peers'
         resources :rules, only: [:index], controller: 'instances/rules'
+        resources :domain_blocks, only: [:index], controller: 'instances/domain_blocks'
         resource :privacy_policy, only: [:show], controller: 'instances/privacy_policies'
+        resource :extended_description, only: [:show], controller: 'instances/extended_descriptions'
         resource :activity, only: [:show], controller: 'instances/activity'
       end
 
@@ -642,8 +644,8 @@ Rails.application.routes.draw do
 
   get '/web/(*any)', to: 'home#index', as: :web
 
-  get '/about',        to: redirect('/')
-  get '/about/more',   to: 'about#more'
+  get '/about',        to: 'about#show'
+  get '/about/more',   to: redirect('/about')
 
   get '/privacy-policy', to: 'privacy#show', as: :privacy_policy
   get '/terms',          to: redirect('/privacy-policy')
diff --git a/spec/controllers/about_controller_spec.rb b/spec/controllers/about_controller_spec.rb
index 20069e4137e09eb949057df6c49cc45df31cfb98..97143ec4372a72796024c00b5e47b6e83df3a161 100644
--- a/spec/controllers/about_controller_spec.rb
+++ b/spec/controllers/about_controller_spec.rb
@@ -3,13 +3,9 @@ require 'rails_helper'
 RSpec.describe AboutController, type: :controller do
   render_views
 
-  describe 'GET #more' do
+  describe 'GET #show' do
     before do
-      get :more
-    end
-
-    it 'assigns @instance_presenter' do
-      expect(assigns(:instance_presenter)).to be_kind_of InstancePresenter
+      get :show
     end
 
     it 'returns http success' do