+          
+            
+          
           
             
           
diff --git a/app/javascript/mastodon/features/account_timeline/index.jsx b/app/javascript/mastodon/features/account_timeline/index.jsx
index 886191e66..a5223275b 100644
--- a/app/javascript/mastodon/features/account_timeline/index.jsx
+++ b/app/javascript/mastodon/features/account_timeline/index.jsx
@@ -7,12 +7,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 import ImmutablePureComponent from 'react-immutable-pure-component';
 import { connect } from 'react-redux';
 
-import { TimelineHint } from 'mastodon/components/timeline_hint';
 import BundleColumnError from 'mastodon/features/ui/components/bundle_column_error';
 import { me } from 'mastodon/initial_state';
 import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
 import { getAccountHidden } from 'mastodon/selectors/accounts';
-import { useAppSelector } from 'mastodon/store';
 
 import { lookupAccount, fetchAccount } from '../../actions/accounts';
 import { fetchFeaturedTags } from '../../actions/featured_tags';
@@ -21,6 +19,7 @@ import { ColumnBackButton } from '../../components/column_back_button';
 import { LoadingIndicator } from '../../components/loading_indicator';
 import StatusList from '../../components/status_list';
 import Column from '../ui/components/column';
+import { RemoteHint } from 'mastodon/components/remote_hint';
 
 import { AccountHeader } from './components/account_header';
 import { LimitedAccountHint } from './components/limited_account_hint';
@@ -47,11 +46,8 @@ const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = fa
 
   return {
     accountId,
-    remote: !!(state.getIn(['accounts', accountId, 'acct']) !== state.getIn(['accounts', accountId, 'username'])),
-    remoteUrl: state.getIn(['accounts', accountId, 'url']),
     isAccount: !!state.getIn(['accounts', accountId]),
     statusIds: state.getIn(['timelines', `account:${path}`, 'items'], emptyList),
-    featuredStatusIds: withReplies ? ImmutableList() : state.getIn(['timelines', `account:${accountId}:pinned${tagged ? `:${tagged}` : ''}`, 'items'], emptyList),
     isLoading: state.getIn(['timelines', `account:${path}`, 'isLoading']),
     hasMore: state.getIn(['timelines', `account:${path}`, 'hasMore']),
     suspended: state.getIn(['accounts', accountId, 'suspended'], false),
@@ -60,24 +56,6 @@ const mapStateToProps = (state, { params: { acct, id, tagged }, withReplies = fa
   };
 };
 
-const RemoteHint = ({ accountId, url }) => {
-  const acct = useAppSelector(state => state.accounts.get(accountId)?.acct);
-  const domain = acct ? acct.split('@')[1] : undefined;
-
-  return (
-    
}
-      label={
{domain} }} />}
-    />
-  );
-};
-
-RemoteHint.propTypes = {
-  url: PropTypes.string.isRequired,
-  accountId: PropTypes.string.isRequired,
-};
-
 class AccountTimeline extends ImmutablePureComponent {
 
   static propTypes = {
@@ -89,7 +67,6 @@ class AccountTimeline extends ImmutablePureComponent {
     accountId: PropTypes.string,
     dispatch: PropTypes.func.isRequired,
     statusIds: ImmutablePropTypes.list,
-    featuredStatusIds: ImmutablePropTypes.list,
     isLoading: PropTypes.bool,
     hasMore: PropTypes.bool,
     withReplies: PropTypes.bool,
@@ -97,8 +74,6 @@ class AccountTimeline extends ImmutablePureComponent {
     isAccount: PropTypes.bool,
     suspended: PropTypes.bool,
     hidden: PropTypes.bool,
-    remote: PropTypes.bool,
-    remoteUrl: PropTypes.string,
     multiColumn: PropTypes.bool,
   };
 
@@ -161,7 +136,7 @@ class AccountTimeline extends ImmutablePureComponent {
   };
 
   render () {
-    const { accountId, statusIds, featuredStatusIds, isLoading, hasMore, blockedBy, suspended, isAccount, hidden, multiColumn, remote, remoteUrl } = this.props;
+    const { accountId, statusIds, isLoading, hasMore, blockedBy, suspended, isAccount, hidden, multiColumn, remote, remoteUrl } = this.props;
 
     if (isLoading && statusIds.isEmpty()) {
       return (
@@ -191,8 +166,6 @@ class AccountTimeline extends ImmutablePureComponent {
       emptyMessage = ;
     }
 
-    const remoteMessage = remote ?  : null;
-
     return (
       
         
@@ -200,10 +173,9 @@ class AccountTimeline extends ImmutablePureComponent {
         }
           alwaysPrepend
-          append={remoteMessage}
+          append={}
           scrollKey='account_timeline'
           statusIds={forceEmptyState ? emptyList : statusIds}
-          featuredStatusIds={featuredStatusIds}
           isLoading={isLoading}
           hasMore={!forceEmptyState && hasMore}
           onLoadMore={this.handleLoadMore}
diff --git a/app/javascript/mastodon/features/ui/index.jsx b/app/javascript/mastodon/features/ui/index.jsx
index a1cb8212d..bb9720c17 100644
--- a/app/javascript/mastodon/features/ui/index.jsx
+++ b/app/javascript/mastodon/features/ui/index.jsx
@@ -73,6 +73,7 @@ import {
   About,
   PrivacyPolicy,
   TermsOfService,
+  AccountFeatured,
 } from './util/async-components';
 import { ColumnsContextProvider } from './util/columns_context';
 import { WrappedSwitch, WrappedRoute } from './util/react_router_helpers';
@@ -236,6 +237,7 @@ class SwitchingColumnsArea extends PureComponent {
             
 
             
+            
             
             
             
diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js
index 8c3b34277..ec493ae28 100644
--- a/app/javascript/mastodon/features/ui/util/async-components.js
+++ b/app/javascript/mastodon/features/ui/util/async-components.js
@@ -66,6 +66,10 @@ export function AccountGallery () {
   return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery');
 }
 
+export function AccountFeatured() {
+  return import(/* webpackChunkName: "features/account_featured" */'../../account_featured');
+}
+
 export function Followers () {
   return import(/* webpackChunkName: "features/followers" */'../../followers');
 }
diff --git a/app/javascript/mastodon/hooks/useAccountId.ts b/app/javascript/mastodon/hooks/useAccountId.ts
new file mode 100644
index 000000000..1cc819ca5
--- /dev/null
+++ b/app/javascript/mastodon/hooks/useAccountId.ts
@@ -0,0 +1,37 @@
+import { useEffect } from 'react';
+
+import { useParams } from 'react-router';
+
+import { fetchAccount, lookupAccount } from 'mastodon/actions/accounts';
+import { normalizeForLookup } from 'mastodon/reducers/accounts_map';
+import { useAppDispatch, useAppSelector } from 'mastodon/store';
+
+interface Params {
+  acct?: string;
+  id?: string;
+}
+
+export function useAccountId() {
+  const { acct, id } = useParams();
+  const accountId = useAppSelector(
+    (state) =>
+      id ??
+      (state.accounts_map.get(normalizeForLookup(acct)) as string | undefined),
+  );
+
+  const account = useAppSelector((state) =>
+    accountId ? state.accounts.get(accountId) : undefined,
+  );
+  const isAccount = !!account;
+
+  const dispatch = useAppDispatch();
+  useEffect(() => {
+    if (!accountId) {
+      dispatch(lookupAccount(acct));
+    } else if (!isAccount) {
+      dispatch(fetchAccount(accountId));
+    }
+  }, [dispatch, accountId, acct, isAccount]);
+
+  return accountId;
+}
diff --git a/app/javascript/mastodon/hooks/useAccountVisibility.ts b/app/javascript/mastodon/hooks/useAccountVisibility.ts
new file mode 100644
index 000000000..55651af5a
--- /dev/null
+++ b/app/javascript/mastodon/hooks/useAccountVisibility.ts
@@ -0,0 +1,20 @@
+import { getAccountHidden } from 'mastodon/selectors/accounts';
+import { useAppSelector } from 'mastodon/store';
+
+export function useAccountVisibility(accountId?: string) {
+  const blockedBy = useAppSelector(
+    (state) => !!state.relationships.getIn([accountId, 'blocked_by'], false),
+  );
+  const suspended = useAppSelector(
+    (state) => !!state.accounts.getIn([accountId, 'suspended'], false),
+  );
+  const hidden = useAppSelector((state) =>
+    accountId ? Boolean(getAccountHidden(state, accountId)) : false,
+  );
+
+  return {
+    blockedBy,
+    suspended,
+    hidden,
+  };
+}
diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json
index ebd5412cf..0a0f043b4 100644
--- a/app/javascript/mastodon/locales/en.json
+++ b/app/javascript/mastodon/locales/en.json
@@ -27,9 +27,11 @@
   "account.edit_profile": "Edit profile",
   "account.enable_notifications": "Notify me when @{name} posts",
   "account.endorse": "Feature on profile",
+  "account.featured": "Featured",
+  "account.featured.hashtags": "Hashtags",
+  "account.featured.posts": "Posts",
   "account.featured_tags.last_status_at": "Last post on {date}",
   "account.featured_tags.last_status_never": "No posts",
-  "account.featured_tags.title": "{name}'s featured hashtags",
   "account.follow": "Follow",
   "account.follow_back": "Follow back",
   "account.followers": "Followers",
@@ -294,6 +296,7 @@
   "emoji_button.search_results": "Search results",
   "emoji_button.symbols": "Symbols",
   "emoji_button.travel": "Travel & Places",
+  "empty_column.account_featured": "This list is empty",
   "empty_column.account_hides_collections": "This user has chosen to not make this information available",
   "empty_column.account_suspended": "Account suspended",
   "empty_column.account_timeline": "No posts here!",
diff --git a/config/routes.rb b/config/routes.rb
index 5b130c517..2fff44851 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -129,6 +129,7 @@ Rails.application.routes.draw do
   constraints(username: %r{[^@/.]+}) do
     with_options to: 'accounts#show' do
       get '/@:username', as: :short_account
+      get '/@:username/featured'
       get '/@:username/with_replies', as: :short_account_with_replies
       get '/@:username/media', as: :short_account_media
       get '/@:username/tagged/:tag', as: :short_account_tag