diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 989edcda2dc96bfa5a18b27de3c2bb46a2702394..3824d437fe90a09a1fc5583d8610f2fc275f09bc 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -138,7 +138,7 @@ flagAsBotDescription: "このアカウントがプログラムによって運用
 flagAsCat: "Catとして設定"
 flagAsCatDescription: "このアカウントが猫であることを示す場合は、このフラグをオンにします。"
 autoAcceptFollowed: "フォロー中ユーザーからのフォロリクを自動承認"
-addAcount: "アカウント追加"
+addAccount: "アカウントを追加"
 loginFailed: "ログインに失敗しました"
 showOnRemote: "リモートで表示"
 general: "全般"
@@ -183,7 +183,7 @@ clearQueueConfirmTitle: "キューをクリアしますか?"
 clearQueueConfirmText: "未配達の投稿は配送されなくなります。通常この操作を行う必要はありません。"
 clearCachedFiles: "キャッシュをクリア"
 clearCachedFilesConfirm: "キャッシュされたリモートファイルをすべて削除しますか?"
-blockedInstances: "インスタンスブロック"
+blockedInstances: "ブロックしたインスタンス"
 blockedInstancesDescription: "ブロックしたいインスタンスのホストを改行で区切って設定します。ブロックされたインスタンスは、このインスタンスとやり取りできなくなります。"
 muteAndBlock: "ミュートとブロック"
 mutedUsers: "ミュートしたユーザー"
@@ -349,7 +349,6 @@ antennaExcludeKeywords: "除外キーワード"
 antennaKeywordsDescription: "スペースで区切るとAND指定になり、改行で区切るとOR指定になります"
 notifyAntenna: "新しいノートを通知する"
 withFileAntenna: "ファイルが添付されたノートのみ"
-serviceworker: "ServiceWorker"
 enableServiceworker: "ServiceWorkerを有効にする"
 antennaUsersDescription: "ユーザー名を改行で区切って指定します"
 caseSensitive: "大文字小文字を区別する"
@@ -453,7 +452,7 @@ category: "カテゴリ"
 tags: "ã‚¿ã‚°"
 docSource: "このドキュメントのソース"
 createAccount: "アカウントを作成"
-existingAcount: "既存のアカウント"
+existingAccount: "既存のアカウント"
 regenerate: "再生成"
 fontSize: "フォントサイズ"
 noFollowRequests: "フォロー申請はありません"
@@ -568,7 +567,7 @@ pluginTokenRequestedDescription: "このプラグインはここで設定した
 notificationType: "通知の種類"
 edit: "編集"
 useStarForReactionFallback: "リアクション絵文字が不明な場合、代わりに★を使う"
-emailConfig: "メールサーバー設定"
+emailServer: "メールサーバー"
 enableEmail: "メール配信機能を有効化する"
 emailConfigInfo: "メールアドレスの確認やパスワードリセットの際に使います"
 email: "メール"
@@ -728,6 +727,20 @@ hideOnlineStatusDescription: "オンライン状態を隠すと、検索など
 online: "オンライン"
 active: "アクティブ"
 offline: "オフライン"
+notRecommended: "非推奨"
+botProtection: "Bot防御"
+instanceBlocking: "インスタンスブロック"
+selectAccount: "アカウントを選択"
+enabled: "有効"
+disabled: "無効"
+quickAction: "クイックアクション"
+user: "ユーザー"
+administration: "管理"
+accounts: "アカウント"
+switch: "切り替え"
+noMaintainerInformationWarning: "管理者情報が設定されていません。"
+noBotProtectionWarning: "Bot防御が設定されていません。"
+configure: "設定する"
 
 _email:
   _follow:
diff --git a/package.json b/package.json
index f3a4930cc1a68831ad2d405ad10b35e3c77714a6..860a1e149e48a223a80237c9373e91170d82407a 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
 {
 	"name": "misskey",
 	"author": "syuilo <syuilotan@yahoo.co.jp>",
-	"version": "12.77.1",
+	"version": "12.78.0",
 	"codename": "indigo",
 	"repository": {
 		"type": "git",
@@ -39,11 +39,6 @@
 	"dependencies": {
 		"@babel/plugin-transform-runtime": "7.13.15",
 		"@elastic/elasticsearch": "7.11.0",
-		"@fortawesome/fontawesome-svg-core": "1.2.35",
-		"@fortawesome/free-brands-svg-icons": "5.15.3",
-		"@fortawesome/free-regular-svg-icons": "5.15.3",
-		"@fortawesome/free-solid-svg-icons": "5.15.3",
-		"@fortawesome/vue-fontawesome": "3.0.0-3",
 		"@koa/cors": "3.1.0",
 		"@koa/multer": "3.0.0",
 		"@koa/router": "9.0.1",
@@ -140,7 +135,6 @@
 		"eslint-plugin-vue": "7.9.0",
 		"eventemitter3": "4.0.7",
 		"feed": "4.2.2",
-		"fibers": "5.0.0",
 		"file-type": "16.3.0",
 		"fluent-ffmpeg": "2.1.2",
 		"glob": "7.1.6",
@@ -181,7 +175,7 @@
 		"markdown-it": "12.0.5",
 		"markdown-it-anchor": "7.1.0",
 		"matter-js": "0.17.1",
-		"mfm-js": "0.16.0",
+		"mfm-js": "0.16.2",
 		"mocha": "8.3.2",
 		"moji": "0.5.1",
 		"ms": "2.1.3",
diff --git a/src/client/components/abuse-report-window.vue b/src/client/components/abuse-report-window.vue
index df5b594c0b10dd08a1017354fa88d89f971aa4f0..d9e1c3966bd6457d31d181f5da3a134f4f186542 100644
--- a/src/client/components/abuse-report-window.vue
+++ b/src/client/components/abuse-report-window.vue
@@ -1,7 +1,7 @@
 <template>
 <XWindow ref="window" :initial-width="400" :initial-height="500" :can-resize="true" @closed="$emit('closed')">
 	<template #header>
-		<Fa :icon="faExclamationCircle" style="margin-right: 0.5em;"/>
+		<i class="fas fa-exclamation-circle" style="margin-right: 0.5em;"></i>
 		<I18n :src="$ts.reportAbuseOf" tag="span">
 			<template #name>
 				<b><MkAcct :user="user"/></b>
@@ -24,7 +24,6 @@
 
 <script lang="ts">
 import { defineComponent, markRaw } from 'vue';
-import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
 import XWindow from '@client/components/ui/window.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
 import MkButton from '@client/components/ui/button.vue';
@@ -53,7 +52,6 @@ export default defineComponent({
 	data() {
 		return {
 			comment: this.initialComment || '',
-			faExclamationCircle,
 		};
 	},
 
diff --git a/src/client/components/captcha.vue b/src/client/components/captcha.vue
index 710fcd616922bd0fd4b226ee9342c2aa944fb103..26215df09dbb8b5f63d2be3e5be93a6a02067633 100644
--- a/src/client/components/captcha.vue
+++ b/src/client/components/captcha.vue
@@ -18,7 +18,7 @@ type Captcha = {
 	getResponse(id: string): string;
 };
 
-type CaptchaProvider = 'hcaptcha' | 'grecaptcha';
+type CaptchaProvider = 'hcaptcha' | 'recaptcha';
 
 type CaptchaContainer = {
 	readonly [_ in CaptchaProvider]?: Captcha;
@@ -57,7 +57,7 @@ export default defineComponent({
 		src() {
 			const endpoint = ({
 				hcaptcha: 'https://hcaptcha.com/1',
-				grecaptcha: 'https://www.recaptcha.net/recaptcha',
+				recaptcha: 'https://www.recaptcha.net/recaptcha',
 			} as Record<PropertyKey, unknown>)[this.provider];
 
 			return `${typeof endpoint == 'string' ? endpoint : 'about:invalid'}/api.js?render=explicit`;
diff --git a/src/client/components/channel-follow-button.vue b/src/client/components/channel-follow-button.vue
index dc0c0faa1f9b4ba7e0641f4304d9de7fdf71091a..6f9405b97f75bed1b1025882ee2753fe49129cd1 100644
--- a/src/client/components/channel-follow-button.vue
+++ b/src/client/components/channel-follow-button.vue
@@ -6,21 +6,20 @@
 >
 	<template v-if="!wait">
 		<template v-if="isFollowing">
-			<span v-if="full">{{ $ts.unfollow }}</span><Fa :icon="faMinus"/>
+			<span v-if="full">{{ $ts.unfollow }}</span><i class="fas fa-minus"></i>
 		</template>
 		<template v-else>
-			<span v-if="full">{{ $ts.follow }}</span><Fa :icon="faPlus"/>
+			<span v-if="full">{{ $ts.follow }}</span><i class="fas fa-plus"></i>
 		</template>
 	</template>
 	<template v-else>
-		<span v-if="full">{{ $ts.processing }}</span><Fa :icon="faSpinner" pulse fixed-width/>
+		<span v-if="full">{{ $ts.processing }}</span><i class="fas fa-spinner fa-pulse fa-fw"></i>
 	</template>
 </button>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSpinner, faPlus, faMinus, } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -40,7 +39,6 @@ export default defineComponent({
 		return {
 			isFollowing: this.channel.isFollowing,
 			wait: false,
-			faSpinner, faPlus, faMinus,
 		};
 	},
 
diff --git a/src/client/components/channel-preview.vue b/src/client/components/channel-preview.vue
index 4dc633bcb7867fbfdd9daa4ddea0f6bdd4c577e6..eb00052a78c8da536263fc79978214b7f7634ad2 100644
--- a/src/client/components/channel-preview.vue
+++ b/src/client/components/channel-preview.vue
@@ -2,10 +2,10 @@
 <MkA :to="`/channels/${channel.id}`" class="eftoefju _panel" tabindex="-1">
 	<div class="banner" :style="bannerStyle">
 		<div class="fade"></div>
-		<div class="name"><Fa :icon="faSatelliteDish"/> {{ channel.name }}</div>
+		<div class="name"><i class="fas fa-satellite-dish"></i> {{ channel.name }}</div>
 		<div class="status">
 			<div>
-				<Fa :icon="faUsers" fixed-width/>
+				<i class="fas fa-users fa-fw"></i>
 				<I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;">
 					<template #n>
 						<b>{{ channel.usersCount }}</b>
@@ -13,7 +13,7 @@
 				</I18n>
 			</div>
 			<div>
-				<Fa :icon="faPencilAlt" fixed-width/>
+				<i class="fas fa-pencil-alt fa-fw"></i>
 				<I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;">
 					<template #n>
 						<b>{{ channel.notesCount }}</b>
@@ -35,7 +35,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSatelliteDish, faUsers, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
 
 export default defineComponent({
 	props: {
@@ -57,7 +56,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faSatelliteDish, faUsers, faPencilAlt,
 		};
 	},
 });
diff --git a/src/client/components/date-separated-list.vue b/src/client/components/date-separated-list.vue
index 0f2823d3924dc0c4e3fec7a6b7a149df0509e526..2a861adb0910554bdf0743e357f5054f0471fd26 100644
--- a/src/client/components/date-separated-list.vue
+++ b/src/client/components/date-separated-list.vue
@@ -1,7 +1,5 @@
 <script lang="ts">
 import { defineComponent, h, TransitionGroup } from 'vue';
-import { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
 
 export default defineComponent({
 	props: {
@@ -73,17 +71,15 @@ export default defineComponent({
 					class: 'date'
 				}, [
 					h('span', [
-						h(FontAwesomeIcon, {
-							class: 'icon',
-							icon: faAngleUp,
+						h('i', {
+							class: 'fas fa-angle-up icon',
 						}),
 						this.getDateText(item.createdAt)
 					]),
 					h('span', [
 						this.getDateText(this.items[i + 1].createdAt),
-						h(FontAwesomeIcon, {
-							class: 'icon',
-							icon: faAngleDown,
+						h('i', {
+							class: 'fas fa-angle-down icon',
 						})
 					])
 				]));
diff --git a/src/client/components/dialog.vue b/src/client/components/dialog.vue
index ef30715343d86bb0dc9503dac78378a611cf123b..a673e827d612289e9cbecf840a7ae143af23c485 100644
--- a/src/client/components/dialog.vue
+++ b/src/client/components/dialog.vue
@@ -2,15 +2,15 @@
 <MkModal ref="modal" @click="done(true)" @closed="$emit('closed')">
 	<div class="mk-dialog">
 		<div class="icon" v-if="icon">
-			<Fa :icon="icon"/>
+			<i :class="icon"></i>
 		</div>
 		<div class="icon" v-else-if="!input && !select" :class="type">
-			<Fa :icon="faCheck" v-if="type === 'success'"/>
-			<Fa :icon="faTimesCircle" v-if="type === 'error'"/>
-			<Fa :icon="faExclamationTriangle" v-if="type === 'warning'"/>
-			<Fa :icon="faInfoCircle" v-if="type === 'info'"/>
-			<Fa :icon="faQuestionCircle" v-if="type === 'question'"/>
-			<Fa :icon="faSpinner" pulse v-if="type === 'waiting'"/>
+			<i v-if="type === 'success'" class="fas fa-check"></i>
+			<i v-else-if="type === 'error'" class="fas fa-times-circle"></i>
+			<i v-else-if="type === 'warning'" class="fas fa-exclamation-triangle"></i>
+			<i v-else-if="type === 'info'" class="fas fa-info-circle"></i>
+			<i v-else-if="type === 'question'" class="fas fa-question-circle"></i>
+			<i v-else-if="type === 'waiting'" class="fas fa-spinner fa-pulse"></i>
 		</div>
 		<header v-if="title"><Mfm :text="title"/></header>
 		<div class="body" v-if="text"><Mfm :text="text"/></div>
@@ -38,8 +38,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSpinner, faInfoCircle, faExclamationTriangle, faCheck } from '@fortawesome/free-solid-svg-icons';
-import { faTimesCircle, faQuestionCircle } from '@fortawesome/free-regular-svg-icons';
 import MkModal from '@client/components/ui/modal.vue';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -99,7 +97,6 @@ export default defineComponent({
 		return {
 			inputValue: this.input && this.input.default ? this.input.default : null,
 			selectedValue: this.select ? this.select.default ? this.select.default : this.select.items ? this.select.items[0].value : this.select.groupedItems[0].items[0].value : null,
-			faTimesCircle, faQuestionCircle, faSpinner, faInfoCircle, faExclamationTriangle, faCheck
 		};
 	},
 
diff --git a/src/client/components/drive-file-thumbnail.vue b/src/client/components/drive-file-thumbnail.vue
index aadf22ed77cc28a96788738faa38ea68bb75630e..2cb1d986182969c6b35099ef5c0bf830fdd28bf7 100644
--- a/src/client/components/drive-file-thumbnail.vue
+++ b/src/client/components/drive-file-thumbnail.vue
@@ -1,31 +1,21 @@
 <template>
 <div class="zdjebgpv" ref="thumbnail">
 	<ImgWithBlurhash v-if="isThumbnailAvailable" :hash="file.blurhash" :src="file.thumbnailUrl" :alt="file.name" :title="file.name" :style="`object-fit: ${ fit }`"/>
-	<Fa :icon="faFileImage" class="icon" v-else-if="is === 'image'"/>
-	<Fa :icon="faFileVideo" class="icon" v-else-if="is === 'video'"/>
-	<Fa :icon="faMusic" class="icon" v-else-if="is === 'audio' || is === 'midi'"/>
-	<Fa :icon="faFileCsv" class="icon" v-else-if="is === 'csv'"/>
-	<Fa :icon="faFilePdf" class="icon" v-else-if="is === 'pdf'"/>
-	<Fa :icon="faFileAlt" class="icon" v-else-if="is === 'textfile'"/>
-	<Fa :icon="faFileArchive" class="icon" v-else-if="is === 'archive'"/>
-	<Fa :icon="faFile" class="icon" v-else/>
-	<Fa :icon="faFilm" class="icon-sub" v-if="isThumbnailAvailable && is === 'video'"/>
+	<i v-else-if="is === 'image'" class="fas fa-file-image icon"></i>
+	<i v-else-if="is === 'video'" class="fas fa-file-video icon"></i>
+	<i v-else-if="is === 'audio' || is === 'midi'" class="fas fa-music icon"></i>
+	<i v-else-if="is === 'csv'" class="fas fa-file-csv icon"></i>
+	<i v-else-if="is === 'pdf'" class="fas fa-file-pdf icon"></i>
+	<i v-else-if="is === 'textfile'" class="fas fa-file-alt icon"></i>
+	<i v-else-if="is === 'archive'" class="fas fa-file-archive icon"></i>
+	<i v-else class="fas fa-file icon"></i>
+
+	<i v-if="isThumbnailAvailable && is === 'video'" class="fas fa-film icon-sub"></i>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import {
-	faFile,
-	faFileAlt,
-	faFileImage,
-	faMusic,
-	faFileVideo,
-	faFileCsv,
-	faFilePdf,
-	faFileArchive,
-	faFilm
-	} from '@fortawesome/free-solid-svg-icons';
 import ImgWithBlurhash from '@client/components/img-with-blurhash.vue';
 import { ColdDeviceStorage } from '@client/store';
 
@@ -49,15 +39,6 @@ export default defineComponent({
 			isContextmenuShowing: false,
 			isDragging: false,
 
-			faFile,
-			faFileAlt,
-			faFileImage,
-			faMusic,
-			faFileVideo,
-			faFileCsv,
-			faFilePdf,
-			faFileArchive,
-			faFilm
 		};
 	},
 	computed: {
diff --git a/src/client/components/drive.file.vue b/src/client/components/drive.file.vue
index fb8b50d25a5f6d361893d18eb002876ae6726eb8..293465e42854b4158ab959bd75132e8e5b4922ea 100644
--- a/src/client/components/drive.file.vue
+++ b/src/client/components/drive.file.vue
@@ -32,8 +32,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
-import { faDownload, faLink, faICursor, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
 import copyToClipboard from '@client/scripts/copy-to-clipboard';
 import MkDriveFileThumbnail from './drive-file-thumbnail.vue';
 import bytes from '@client/filters/bytes';
@@ -87,22 +85,22 @@ export default defineComponent({
 				action: this.rename
 			}, {
 				text: this.file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,
-				icon: this.file.isSensitive ? faEye : faEyeSlash,
+				icon: this.file.isSensitive ? 'fas fa-eye' : 'fas fa-eye-slash',
 				action: this.toggleSensitive
 			}, null, {
 				text: this.$ts.copyUrl,
-				icon: faLink,
+				icon: 'fas fa-link',
 				action: this.copyUrl
 			}, {
 				type: 'a',
 				href: this.file.url,
 				target: '_blank',
 				text: this.$ts.download,
-				icon: faDownload,
+				icon: 'fas fa-download',
 				download: this.file.name
 			}, null, {
 				text: this.$ts.delete,
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				danger: true,
 				action: this.deleteFile
 			}];
diff --git a/src/client/components/drive.folder.vue b/src/client/components/drive.folder.vue
index 2822c85680a192e562ee2ca558319e91674e0b7e..6ddd392527d5a1f0c99d74cbec44e40b448da138 100644
--- a/src/client/components/drive.folder.vue
+++ b/src/client/components/drive.folder.vue
@@ -15,8 +15,8 @@
 	:title="title"
 >
 	<p class="name">
-		<template v-if="hover"><Fa :icon="faFolderOpen" fixed-width/></template>
-		<template v-if="!hover"><Fa :icon="faFolder" fixed-width/></template>
+		<template v-if="hover"><i class="fas fa-folder-open fa-fw"></i></template>
+		<template v-if="!hover"><i class="fas fa-folder fa-fw"></i></template>
 		{{ folder.name }}
 	</p>
 	<p class="upload" v-if="$store.state.uploadFolder == folder.id">
@@ -28,9 +28,7 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faFolder, faFolderOpen, faTrashAlt, faWindowRestore } from '@fortawesome/free-regular-svg-icons';
 import * as os from '@client/os';
-import { faICursor } from '@fortawesome/free-solid-svg-icons';
 
 export default defineComponent({
 	props: {
@@ -57,7 +55,6 @@ export default defineComponent({
 			hover: false,
 			draghover: false,
 			isDragging: false,
-			faFolder, faFolderOpen
 		};
 	},
 
@@ -241,7 +238,7 @@ export default defineComponent({
 		onContextmenu(e) {
 			os.contextMenu([{
 				text: this.$ts.openInWindow,
-				icon: faWindowRestore,
+				icon: 'fas fa-window-restore',
 				action: () => {
 					os.popup(import('./drive-window.vue'), {
 						initialFolder: this.folder
@@ -254,7 +251,7 @@ export default defineComponent({
 				action: this.rename
 			}, null, {
 				text: this.$ts.delete,
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				danger: true,
 				action: this.deleteFolder
 			}], e);
@@ -312,7 +309,7 @@ export default defineComponent({
 		font-size: 0.9em;
 		color: var(--desktopDriveFolderFg);
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 			margin-left: 2px;
 			text-align: left;
diff --git a/src/client/components/drive.nav-folder.vue b/src/client/components/drive.nav-folder.vue
index 89a267b19f1b6bc390de3979c68547b80ba0adc0..913a1b5f927431f7bb5219310e3ca1a7e0a1970f 100644
--- a/src/client/components/drive.nav-folder.vue
+++ b/src/client/components/drive.nav-folder.vue
@@ -7,14 +7,13 @@
 	@dragleave="onDragleave"
 	@drop.stop="onDrop"
 >
-	<i v-if="folder == null"><Fa :icon="faCloud"/></i>
+	<i v-if="folder == null" class="fas fa-cloud"></i>
 	<span>{{ folder == null ? $ts.drive : folder.name }}</span>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCloud } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -29,7 +28,6 @@ export default defineComponent({
 		return {
 			hover: false,
 			draghover: false,
-			faCloud
 		};
 	},
 
diff --git a/src/client/components/drive.vue b/src/client/components/drive.vue
index 103ae9c11ed3782ea2ee7e0004dcad93c86ae3c6..bd5bd8008bcddb30a17d320897570e5b89913767 100644
--- a/src/client/components/drive.vue
+++ b/src/client/components/drive.vue
@@ -4,10 +4,10 @@
 		<div class="path" @contextmenu.prevent.stop="() => {}">
 			<XNavFolder :class="{ current: folder == null }"/>
 			<template v-for="f in hierarchyFolders">
-				<span class="separator"><Fa :icon="faAngleRight"/></span>
+				<span class="separator"><i class="fas fa-angle-right"></i></span>
 				<XNavFolder :folder="f"/>
 			</template>
-			<span class="separator" v-if="folder != null"><Fa :icon="faAngleRight"/></span>
+			<span class="separator" v-if="folder != null"><i class="fas fa-angle-right"></i></span>
 			<span class="folder current" v-if="folder != null">{{ folder.name }}</span>
 		</div>
 	</nav>
@@ -47,13 +47,11 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAngleRight, faFolderPlus, faICursor, faLink, faUpload } from '@fortawesome/free-solid-svg-icons';
 import XNavFolder from './drive.nav-folder.vue';
 import XFolder from './drive.folder.vue';
 import XFile from './drive.file.vue';
 import MkButton from './ui/button.vue';
 import * as os from '@client/os';
-import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 
 export default defineComponent({
 	components: {
@@ -125,7 +123,6 @@ export default defineComponent({
 			),
 			moreFilesElement: null as Element,
 
-			faAngleRight
 		};
 	},
 
@@ -606,11 +603,11 @@ export default defineComponent({
 				type: 'label'
 			}, {
 				text: this.$ts.upload,
-				icon: faUpload,
+				icon: 'fas fa-upload',
 				action: () => { this.selectLocalFile(); }
 			}, {
 				text: this.$ts.fromUrl,
-				icon: faLink,
+				icon: 'fas fa-link',
 				action: () => { this.urlUpload(); }
 			}, null, {
 				text: this.folder ? this.folder.name : this.$ts.drive,
@@ -621,11 +618,11 @@ export default defineComponent({
 				action: () => { this.renameFolder(this.folder); }
 			} : undefined, this.folder ? {
 				text: this.$ts.deleteFolder,
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				action: () => { this.deleteFolder(this.folder); }
 			} : undefined, {
 				text: this.$ts.createFolder,
-				icon: faFolderPlus,
+				icon: 'fas fa-folder-plus',
 				action: () => { this.createFolder(); }
 			}];
 		},
@@ -693,7 +690,7 @@ export default defineComponent({
 					opacity: 0.5;
 					cursor: default;
 
-					> [data-icon] {
+					> i {
 						margin: 0;
 					}
 				}
diff --git a/src/client/components/emoji-picker.section.vue b/src/client/components/emoji-picker.section.vue
index 944c507bdcfe03b0e1db8487fdea0bed1f11bace..0ea3761429562ebf2b9b0a50405644cac5f71678 100644
--- a/src/client/components/emoji-picker.section.vue
+++ b/src/client/components/emoji-picker.section.vue
@@ -1,7 +1,7 @@
 <template>
 <section>
 	<header class="_acrylic" @click="shown = !shown">
-		<Fa :icon="shown ? faChevronDown : faChevronUp" :key="shown" fixed-width class="toggle"/> <slot></slot> ({{ emojis.length }})
+		<i class="toggle fa-fw" :class="shown ? 'fas fa-chevron-down' : 'fas fa-chevron-up'"></i> <slot></slot> ({{ emojis.length }})
 	</header>
 	<div v-if="shown">
 		<button v-for="emoji in emojis"
@@ -17,7 +17,6 @@
 
 <script lang="ts">
 import { defineComponent, markRaw } from 'vue';
-import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';
 import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
 
 export default defineComponent({
@@ -36,7 +35,6 @@ export default defineComponent({
 		return {
 			getStaticImageUrl,
 			shown: this.initialShown,
-			faChevronUp, faChevronDown,
 		};
 	},
 
diff --git a/src/client/components/emoji-picker.vue b/src/client/components/emoji-picker.vue
index a212c150497aa53d451a9d92e6f862ca0c22000c..9bec319af205cabc83a1992e9eb9f105f2a94de2 100644
--- a/src/client/components/emoji-picker.vue
+++ b/src/client/components/emoji-picker.vue
@@ -42,7 +42,7 @@
 			</section>
 
 			<section>
-				<header class="_acrylic"><Fa :icon="faClock" fixed-width/> {{ $ts.recentUsed }}</header>
+				<header class="_acrylic"><i class="far fa-clock fa-fw"></i> {{ $ts.recentUsed }}</header>
 				<div>
 					<button v-for="emoji in $store.state.recentlyUsedEmojis"
 						class="_button"
@@ -64,10 +64,10 @@
 		</div>
 	</div>
 	<div class="tabs">
-		<button class="_button tab" :class="{ active: tab === 'index' }" @click="tab = 'index'"><Fa :icon="faAsterisk" fixed-width/></button>
-		<button class="_button tab" :class="{ active: tab === 'custom' }" @click="tab = 'custom'"><Fa :icon="faLaugh" fixed-width/></button>
-		<button class="_button tab" :class="{ active: tab === 'unicode' }" @click="tab = 'unicode'"><Fa :icon="faLeaf" fixed-width/></button>
-		<button class="_button tab" :class="{ active: tab === 'tags' }" @click="tab = 'tags'"><Fa :icon="faHashtag" fixed-width/></button>
+		<button class="_button tab" :class="{ active: tab === 'index' }" @click="tab = 'index'"><i class="fas fa-asterisk fa-fw"></i></button>
+		<button class="_button tab" :class="{ active: tab === 'custom' }" @click="tab = 'custom'"><i class="fas fa-laugh fa-fw"></i></button>
+		<button class="_button tab" :class="{ active: tab === 'unicode' }" @click="tab = 'unicode'"><i class="fas fa-leaf fa-fw"></i></button>
+		<button class="_button tab" :class="{ active: tab === 'tags' }" @click="tab = 'tags'"><i class="fas fa-hashtag fa-fw"></i></button>
 	</div>
 </div>
 </template>
@@ -76,8 +76,6 @@
 import { defineComponent, markRaw } from 'vue';
 import { emojilist } from '@/misc/emojilist';
 import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
-import { faAsterisk, faLeaf, faUtensils, faFutbol, faCity, faDice, faGlobe, faClock, faUser, faChevronDown, faShapes, faBicycle, faHashtag } from '@fortawesome/free-solid-svg-icons';
-import { faHeart, faFlag, faLaugh } from '@fortawesome/free-regular-svg-icons';
 import Particle from '@client/components/particle.vue';
 import * as os from '@client/os';
 import { isDeviceTouch } from '@client/scripts/is-device-touch';
@@ -117,7 +115,6 @@ export default defineComponent({
 			searchResultUnicode: [],
 			tab: 'index',
 			categories: ['face', 'people', 'animals_and_nature', 'food_and_drink', 'activity', 'travel_and_places', 'objects', 'symbols', 'flags'],
-			faGlobe, faClock, faChevronDown, faAsterisk, faLaugh, faUtensils, faLeaf, faShapes, faBicycle, faHashtag,
 		};
 	},
 
diff --git a/src/client/components/file-type-icon.vue b/src/client/components/file-type-icon.vue
index 2da9ba0cbda55bf52d9e8fe85bab7f9729e8f870..95200b98c2e89a01db3e266e6c5540e592b0c71f 100644
--- a/src/client/components/file-type-icon.vue
+++ b/src/client/components/file-type-icon.vue
@@ -1,12 +1,11 @@
 <template>
 <span class="mk-file-type-icon">
-	<template v-if="kind == 'image'"><Fa :icon="faFileImage"/></template>
+	<template v-if="kind == 'image'"><i class="fas fa-file-image"></i></template>
 </span>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faFileImage } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -18,7 +17,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faFileImage
 		};
 	},
 	computed: {
diff --git a/src/client/components/follow-button.vue b/src/client/components/follow-button.vue
index d2dc9223bdf6314a34ff0a6a329c733374341c00..7199183c6693154be45ae4491f93306161c8797b 100644
--- a/src/client/components/follow-button.vue
+++ b/src/client/components/follow-button.vue
@@ -6,30 +6,29 @@
 >
 	<template v-if="!wait">
 		<template v-if="hasPendingFollowRequestFromYou && user.isLocked">
-			<span v-if="full">{{ $ts.followRequestPending }}</span><Fa :icon="faHourglassHalf"/>
+			<span v-if="full">{{ $ts.followRequestPending }}</span><i class="fas fa-hourglass-half"></i>
 		</template>
 		<template v-else-if="hasPendingFollowRequestFromYou && !user.isLocked"> <!-- つまりリモートフォローの場合。 -->
-			<span v-if="full">{{ $ts.processing }}</span><Fa :icon="faSpinner" pulse/>
+			<span v-if="full">{{ $ts.processing }}</span><i class="fas fa-spinner fa-pulse"></i>
 		</template>
 		<template v-else-if="isFollowing">
-			<span v-if="full">{{ $ts.unfollow }}</span><Fa :icon="faMinus"/>
+			<span v-if="full">{{ $ts.unfollow }}</span><i class="fas fa-minus"></i>
 		</template>
 		<template v-else-if="!isFollowing && user.isLocked">
-			<span v-if="full">{{ $ts.followRequest }}</span><Fa :icon="faPlus"/>
+			<span v-if="full">{{ $ts.followRequest }}</span><i class="fas fa-plus"></i>
 		</template>
 		<template v-else-if="!isFollowing && !user.isLocked">
-			<span v-if="full">{{ $ts.follow }}</span><Fa :icon="faPlus"/>
+			<span v-if="full">{{ $ts.follow }}</span><i class="fas fa-plus"></i>
 		</template>
 	</template>
 	<template v-else>
-		<span v-if="full">{{ $ts.processing }}</span><Fa :icon="faSpinner" pulse fixed-width/>
+		<span v-if="full">{{ $ts.processing }}</span><i class="fas fa-spinner fa-pulse fa-fw"></i>
 	</template>
 </button>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSpinner, faPlus, faMinus, faHourglassHalf } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -56,7 +55,6 @@ export default defineComponent({
 			hasPendingFollowRequestFromYou: this.user.hasPendingFollowRequestFromYou,
 			wait: false,
 			connection: null,
-			faSpinner, faPlus, faMinus, faHourglassHalf
 		};
 	},
 
diff --git a/src/client/components/form/base.vue b/src/client/components/form/base.vue
index 34deb39465f7e05aa552b82af291c7b63c9feaea..132942d527e002b1d244333911f66efc680dd709 100644
--- a/src/client/components/form/base.vue
+++ b/src/client/components/form/base.vue
@@ -24,6 +24,8 @@ export default defineComponent({
 	--formXPadding: 32px;
 	--formYPadding: 32px;
 
+	--formContentHMargin: 16px;
+
 	font-size: 95%;
 	line-height: 1.3em;
 	background: var(--bg);
diff --git a/src/client/components/form/form.scss b/src/client/components/form/form.scss
index 8c01fad7277f43b4512ec12cb3df252a97ef1956..05994ae65092825b93e16cac29b52cb3c5ad43dc 100644
--- a/src/client/components/form/form.scss
+++ b/src/client/components/form/form.scss
@@ -30,7 +30,7 @@
 	top: var(--stickyTop, 0px);
 	z-index: 2;
 	margin: -8px calc(var(--formXPadding) * -1) 0 calc(var(--formXPadding) * -1);
-	padding: 8px calc(16px + var(--formXPadding)) 8px calc(16px + var(--formXPadding));
+	padding: 8px calc(var(--formContentHMargin) + var(--formXPadding)) 8px calc(var(--formContentHMargin) + var(--formXPadding));
 	background: var(--X17);
 	-webkit-backdrop-filter: blur(10px);
 	backdrop-filter: blur(10px);
@@ -42,7 +42,7 @@
 }
 
 ._formCaption {
-	padding: 8px 16px 0 16px;
+	padding: 8px var(--formContentHMargin) 0 var(--formContentHMargin);
 }
 
 ._formItem {
diff --git a/src/client/components/form/info.vue b/src/client/components/form/info.vue
index a9224c7e6591cff0ab7ffe5c74eea28f550dd10c..9fdcbdca627bd1ac9e878454b4f89558ff5bd897 100644
--- a/src/client/components/form/info.vue
+++ b/src/client/components/form/info.vue
@@ -1,8 +1,8 @@
 <template>
 <div class="fzenkabp _formItem">
 	<div class="_formPanel" :class="{ warn }">
-		<i v-if="warn"><Fa :icon="faExclamationTriangle"/></i>
-		<i v-else><Fa :icon="faInfoCircle"/></i>
+		<i v-if="warn" class="fas fa-exclamation-triangle"></i>
+		<i v-else class="fas fa-info-circle"></i>
 		<slot></slot>
 	</div>
 </div>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 
 export default defineComponent({
 	props: {
@@ -22,7 +21,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faInfoCircle, faExclamationTriangle
 		};
 	}
 });
diff --git a/src/client/components/form/input.vue b/src/client/components/form/input.vue
index c0fa3e716e4417f1adb91068789c263451a06e3c..942ac4dfd2af17d14ee05cbba63b42d7ed368d5a 100644
--- a/src/client/components/form/input.vue
+++ b/src/client/components/form/input.vue
@@ -30,13 +30,12 @@
 	</div>
 	<template #caption><slot name="desc"></slot></template>
 
-	<FormButton v-if="manualSave && changed" @click="updated" primary><Fa :icon="faSave"/> {{ $ts.save }}</FormButton>
+	<FormButton v-if="manualSave && changed" @click="updated" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
 </FormGroup>
 </template>
 
 <script lang="ts">
 import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
-import { faExclamationCircle, faSave } from '@fortawesome/free-solid-svg-icons';
 import './form.scss';
 import FormButton from './button.vue';
 import FormGroup from './group.vue';
@@ -191,7 +190,6 @@ export default defineComponent({
 			onInput,
 			onKeydown,
 			updated,
-			faExclamationCircle, faSave,
 		};
 	},
 });
diff --git a/src/client/components/form/key-value-view.vue b/src/client/components/form/key-value-view.vue
index 85f4febef9d7e083777101caca0f8ece02216a82..ca4c09867fba8ffde40eb7440c640e8fe46a8d93 100644
--- a/src/client/components/form/key-value-view.vue
+++ b/src/client/components/form/key-value-view.vue
@@ -20,7 +20,7 @@ export default defineComponent({
 .anocepby {
 	display: flex;
 	align-items: center;
-	padding: 14px 16px;
+	padding: 14px var(--formContentHMargin);
 
 	> .key {
 		margin-right: 12px;
diff --git a/src/client/components/form/link.vue b/src/client/components/form/link.vue
index af36bcf22c826b6057a8aa3ce1cce363ce8ddfb8..e1d13c64316b863c921a6086a0063ddca39391cd 100644
--- a/src/client/components/form/link.vue
+++ b/src/client/components/form/link.vue
@@ -5,7 +5,7 @@
 		<span class="text"><slot></slot></span>
 		<span class="right">
 			<span class="text"><slot name="suffix"></slot></span>
-			<Fa :icon="faExternalLinkAlt" class="icon"/>
+			<i class="fas fa-external-link-alt icon"></i>
 		</span>
 	</a>
 	<MkA class="main _button _formPanel _formClickable" :class="{ active }" :to="to" :behavior="behavior" v-else>
@@ -13,7 +13,7 @@
 		<span class="text"><slot></slot></span>
 		<span class="right">
 			<span class="text"><slot name="suffix"></slot></span>
-			<Fa :icon="faChevronRight" class="icon"/>
+			<i class="fas fa-chevron-right icon"></i>
 		</span>
 	</MkA>
 </div>
@@ -21,7 +21,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faChevronRight, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
 import './form.scss';
 
 export default defineComponent({
@@ -45,7 +44,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faChevronRight, faExternalLinkAlt
 		};
 	}
 });
diff --git a/src/client/components/form/object-view.vue b/src/client/components/form/object-view.vue
index cbd4186e56d4f39f6d591f310893edd91633ee8b..59fb62b5e695e2d787f2de05e8fdeb76cba46cbc 100644
--- a/src/client/components/form/object-view.vue
+++ b/src/client/components/form/object-view.vue
@@ -75,7 +75,7 @@ export default defineComponent({
 			max-width: 100%;
 			min-height: 130px;
 			margin: 0;
-			padding: 16px;
+			padding: 16px var(--formContentHMargin);
 			box-sizing: border-box;
 			font: inherit;
 			font-weight: normal;
diff --git a/src/client/components/form/radios.vue b/src/client/components/form/radios.vue
index 3daa7e5bbdeff5762383304d2b5538ba3a657be9..4cfb7c247e9453f10537a67ef3a745f14d213bad 100644
--- a/src/client/components/form/radios.vue
+++ b/src/client/components/form/radios.vue
@@ -18,6 +18,9 @@ export default defineComponent({
 		}
 	},
 	watch: {
+		modelValue() {
+			this.value = this.modelValue;
+		},
 		value() {
 			this.$emit('update:modelValue', this.value);
 		}
diff --git a/src/client/components/form/select.vue b/src/client/components/form/select.vue
index 01f28587dc3032ad492863501a84f5c19209058f..1c5a4734510c891597ae5273bd71f03386e8c486 100644
--- a/src/client/components/form/select.vue
+++ b/src/client/components/form/select.vue
@@ -14,7 +14,7 @@
 			<slot></slot>
 		</select>
 		<div class="suffix">
-			<Fa :icon="faChevronDown"/>
+			<i class="fas fa-chevron-down"></i>
 		</div>
 	</div>
 	<div class="_formCaption"><slot name="caption"></slot></div>
@@ -23,7 +23,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
 import './form.scss';
 
 export default defineComponent({
@@ -47,7 +46,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faChevronDown,
 		};
 	},
 	computed: {
diff --git a/src/client/components/form/suspense.vue b/src/client/components/form/suspense.vue
index 6a8282733fd0d0b913be792907c8b84e1627bfd4..d04dc07624a235460b06931d89b4b0cb3b9ba9fc 100644
--- a/src/client/components/form/suspense.vue
+++ b/src/client/components/form/suspense.vue
@@ -5,13 +5,13 @@
 			<MkLoading/>
 		</div>
 	</div>
-	<FormGroup v-else-if="resolved" class="_formItem">
+	<div v-else-if="resolved" class="_formItem">
 		<slot :result="result"></slot>
-	</FormGroup>
+	</div>
 	<div class="_formItem" v-else>
-		<div class="_formPanel">
-			error!
-			<button @click="retry">retry</button>
+		<div class="_formPanel eiurkvay">
+			<div><i class="fas fa-exclamation-triangle"></i> {{ $ts.somethingHappened }}</div>
+			<MkButton inline @click="retry" class="retry"><i class="fas fa-redo-alt"></i> {{ $ts.retry }}</MkButton>
 		</div>
 	</div>
 </transition>
@@ -20,11 +20,11 @@
 <script lang="ts">
 import { defineComponent, PropType, ref, watch } from 'vue';
 import './form.scss';
-import FormGroup from './group.vue';
+import MkButton from '@client/components/ui/button.vue';
 
 export default defineComponent({
 	components: {
-		FormGroup,
+		MkButton
 	},
 
 	props: {
@@ -89,4 +89,13 @@ export default defineComponent({
 .fade-leave-to {
 	opacity: 0;
 }
+
+.eiurkvay {
+	padding: 16px;
+	text-align: center;
+
+	> .retry {
+		margin-top: 16px;
+	}
+}
 </style>
diff --git a/src/client/components/form/textarea.vue b/src/client/components/form/textarea.vue
index 135e16c259184b6600caffe417aba74e238a7268..8f42581a9b1a4a916ca0da100db8a36bb1fdcff7 100644
--- a/src/client/components/form/textarea.vue
+++ b/src/client/components/form/textarea.vue
@@ -18,13 +18,12 @@
 	</div>
 	<template #caption><slot name="desc"></slot></template>
 
-	<FormButton v-if="manualSave && changed" @click="updated" primary><Fa :icon="faSave"/> {{ $ts.save }}</FormButton>
+	<FormButton v-if="manualSave && changed" @click="updated" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
 </FormGroup>
 </template>
 
 <script lang="ts">
 import { defineComponent, ref, toRefs, watch } from 'vue';
-import { faSave } from '@fortawesome/free-solid-svg-icons';
 import './form.scss';
 import FormButton from './button.vue';
 import FormGroup from './group.vue';
@@ -106,7 +105,6 @@ export default defineComponent({
 			changed,
 			focus,
 			onInput,
-			faSave,
 		};
 	}
 });
diff --git a/src/client/components/global/a.vue b/src/client/components/global/a.vue
index 7ad62a731044b158595cc72de57c1b58604bc0cf..952dfb1841d36162b71279ae71fc17cdd374f3e6 100644
--- a/src/client/components/global/a.vue
+++ b/src/client/components/global/a.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExpandAlt, faColumns, faExternalLinkAlt, faLink, faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 import copyToClipboard from '@client/scripts/copy-to-clipboard';
 import { router } from '@client/router';
@@ -57,31 +56,31 @@ export default defineComponent({
 				type: 'label',
 				text: this.to,
 			}, {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts.openInWindow,
 				action: () => {
 					os.pageWindow(this.to);
 				}
 			}, this.sideViewHook ? {
-				icon: faColumns,
+				icon: 'fas fa-columns',
 				text: this.$ts.openInSideView,
 				action: () => {
 					this.sideViewHook(this.to);
 				}
 			} : undefined, {
-				icon: faExpandAlt,
+				icon: 'fas fa-expand-alt',
 				text: this.$ts.showInPage,
 				action: () => {
 					this.$router.push(this.to);
 				}
 			}, null, {
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				text: this.$ts.openInNewTab,
 				action: () => {
 					window.open(this.to, '_blank');
 				}
 			}, {
-				icon: faLink,
+				icon: 'fas fa-link',
 				text: this.$ts.copyLink,
 				action: () => {
 					copyToClipboard(`${url}${this.to}`);
diff --git a/src/client/components/global/error.vue b/src/client/components/global/error.vue
index af989b1c57419d288e333167f166badff7e650c8..05a508a65391026b2b196f47fa0767141227e74a 100644
--- a/src/client/components/global/error.vue
+++ b/src/client/components/global/error.vue
@@ -2,7 +2,7 @@
 <transition :name="$store.state.animation ? 'zoom' : ''" appear>
 	<div class="mjndxjcg">
 		<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
-		<p><Fa :icon="faExclamationTriangle"/> {{ $ts.somethingHappened }}</p>
+		<p><i class="fas fa-exclamation-triangle"></i> {{ $ts.somethingHappened }}</p>
 		<MkButton @click="() => $emit('retry')" class="button">{{ $ts.retry }}</MkButton>
 	</div>
 </transition>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 
 export default defineComponent({
@@ -19,7 +18,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faExclamationTriangle
 		};
 	},
 });
diff --git a/src/client/components/global/url.vue b/src/client/components/global/url.vue
index f68a3c00beac31ea797c5c7ed2ab2223e95868a3..e633a57bd85b657eecc1ef96c4dcd31e42d200b2 100644
--- a/src/client/components/global/url.vue
+++ b/src/client/components/global/url.vue
@@ -15,13 +15,12 @@
 	<span class="pathname" v-if="pathname != ''">{{ self ? pathname.substr(1) : pathname }}</span>
 	<span class="query">{{ query }}</span>
 	<span class="hash">{{ hash }}</span>
-	<Fa :icon="faExternalLinkSquareAlt" v-if="target === '_blank'" class="icon"/>
+	<i v-if="target === '_blank'" class="fas fa-external-link-square-alt icon"></i>
 </component>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
 import { toUnicode as decodePunycode } from 'punycode/';
 import { url as local } from '@client/config';
 import { isDeviceTouch } from '@client/scripts/is-device-touch';
@@ -55,7 +54,6 @@ export default defineComponent({
 			hideTimer: null,
 			checkTimer: null,
 			close: null,
-			faExternalLinkSquareAlt
 		};
 	},
 	created() {
diff --git a/src/client/components/google.vue b/src/client/components/google.vue
index 20dc1f825a72cff999abbcdc926d5b2b39784466..6d8ae0b5bf6ebbfaf8509bca695c0c728da30e49 100644
--- a/src/client/components/google.vue
+++ b/src/client/components/google.vue
@@ -1,13 +1,12 @@
 <template>
 <div class="mk-google">
 	<input type="search" v-model="query" :placeholder="q">
-	<button @click="search"><Fa :icon="faSearch"/> {{ $ts.search }}</button>
+	<button @click="search"><i class="fas fa-search"></i> {{ $ts.search }}</button>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSearch } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -15,7 +14,6 @@ export default defineComponent({
 	data() {
 		return {
 			query: null,
-			faSearch
 		};
 	},
 	mounted() {
diff --git a/src/client/components/instance-stats.vue b/src/client/components/instance-stats.vue
index 75abefc2fe69168cfbe7b37c82013f048e006363..432c9a1bb986df202a60b0fd3ea0df86b7f294eb 100644
--- a/src/client/components/instance-stats.vue
+++ b/src/client/components/instance-stats.vue
@@ -1,129 +1,40 @@
 <template>
-<div class="zbcjwnqg" v-size="{ max: [550, 1000] }">
-	<div class="stats" v-if="info">
-		<div class="_panel">
-			<div>
-				<b><Fa :icon="faUser"/>{{ $ts.users }}</b>
-				<small>{{ $ts.local }}</small>
-			</div>
-			<div>
-				<dl class="total">
-					<dt>{{ $ts.total }}</dt>
-					<dd>{{ number(info.originalUsersCount) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: usersLocalDoD > 0 }">
-					<dt>{{ $ts.dayOverDayChanges }}</dt>
-					<dd>{{ number(usersLocalDoD) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: usersLocalWoW > 0 }">
-					<dt>{{ $ts.weekOverWeekChanges }}</dt>
-					<dd>{{ number(usersLocalWoW) }}</dd>
-				</dl>
-			</div>
-		</div>
-		<div class="_panel">
-			<div>
-				<b><Fa :icon="faUser"/>{{ $ts.users }}</b>
-				<small>{{ $ts.remote }}</small>
-			</div>
-			<div>
-				<dl class="total">
-					<dt>{{ $ts.total }}</dt>
-					<dd>{{ number((info.usersCount - info.originalUsersCount)) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: usersRemoteDoD > 0 }">
-					<dt>{{ $ts.dayOverDayChanges }}</dt>
-					<dd>{{ number(usersRemoteDoD) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: usersRemoteWoW > 0 }">
-					<dt>{{ $ts.weekOverWeekChanges }}</dt>
-					<dd>{{ number(usersRemoteWoW) }}</dd>
-				</dl>
-			</div>
-		</div>
-		<div class="_panel">
-			<div>
-				<b><Fa :icon="faPencilAlt"/>{{ $ts.notes }}</b>
-				<small>{{ $ts.local }}</small>
-			</div>
-			<div>
-				<dl class="total">
-					<dt>{{ $ts.total }}</dt>
-					<dd>{{ number(info.originalNotesCount) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: notesLocalDoD > 0 }">
-					<dt>{{ $ts.dayOverDayChanges }}</dt>
-					<dd>{{ number(notesLocalDoD) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: notesLocalWoW > 0 }">
-					<dt>{{ $ts.weekOverWeekChanges }}</dt>
-					<dd>{{ number(notesLocalWoW) }}</dd>
-				</dl>
-			</div>
-		</div>
-		<div class="_panel">
-			<div>
-				<b><Fa :icon="faPencilAlt"/>{{ $ts.notes }}</b>
-				<small>{{ $ts.remote }}</small>
-			</div>
-			<div>
-				<dl class="total">
-					<dt>{{ $ts.total }}</dt>
-					<dd>{{ number((info.notesCount - info.originalNotesCount)) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: notesRemoteDoD > 0 }">
-					<dt>{{ $ts.dayOverDayChanges }}</dt>
-					<dd>{{ number(notesRemoteDoD) }}</dd>
-				</dl>
-				<dl class="diff" :class="{ inc: notesRemoteWoW > 0 }">
-					<dt>{{ $ts.weekOverWeekChanges }}</dt>
-					<dd>{{ number(notesRemoteWoW) }}</dd>
-				</dl>
-			</div>
-		</div>
+<div class="zbcjwnqg" style="margin-top: -8px;">
+	<div class="selects" style="display: flex;">
+		<MkSelect v-model:value="chartSrc" style="margin: 0; flex: 1;">
+			<optgroup :label="$ts.federation">
+				<option value="federation-instances">{{ $ts._charts.federationInstancesIncDec }}</option>
+				<option value="federation-instances-total">{{ $ts._charts.federationInstancesTotal }}</option>
+			</optgroup>
+			<optgroup :label="$ts.users">
+				<option value="users">{{ $ts._charts.usersIncDec }}</option>
+				<option value="users-total">{{ $ts._charts.usersTotal }}</option>
+				<option value="active-users">{{ $ts._charts.activeUsers }}</option>
+			</optgroup>
+			<optgroup :label="$ts.notes">
+				<option value="notes">{{ $ts._charts.notesIncDec }}</option>
+				<option value="local-notes">{{ $ts._charts.localNotesIncDec }}</option>
+				<option value="remote-notes">{{ $ts._charts.remoteNotesIncDec }}</option>
+				<option value="notes-total">{{ $ts._charts.notesTotal }}</option>
+			</optgroup>
+			<optgroup :label="$ts.drive">
+				<option value="drive-files">{{ $ts._charts.filesIncDec }}</option>
+				<option value="drive-files-total">{{ $ts._charts.filesTotal }}</option>
+				<option value="drive">{{ $ts._charts.storageUsageIncDec }}</option>
+				<option value="drive-total">{{ $ts._charts.storageUsageTotal }}</option>
+			</optgroup>
+		</MkSelect>
+		<MkSelect v-model:value="chartSpan" style="margin: 0;">
+			<option value="hour">{{ $ts.perHour }}</option>
+			<option value="day">{{ $ts.perDay }}</option>
+		</MkSelect>
 	</div>
-
-	<section class="_card">
-		<div class="_title" style="position: relative;"><Fa :icon="faChartBar"/> {{ $ts.statistics }}<button @click="fetchChart" class="_button" style="position: absolute; right: 0; bottom: 0; top: 0; padding: inherit;"><Fa :icon="faSync"/></button></div>
-		<div class="_content" style="margin-top: -8px;">
-			<div class="selects" style="display: flex;">
-				<MkSelect v-model:value="chartSrc" style="margin: 0; flex: 1;">
-					<optgroup :label="$ts.federation">
-						<option value="federation-instances">{{ $ts._charts.federationInstancesIncDec }}</option>
-						<option value="federation-instances-total">{{ $ts._charts.federationInstancesTotal }}</option>
-					</optgroup>
-					<optgroup :label="$ts.users">
-						<option value="users">{{ $ts._charts.usersIncDec }}</option>
-						<option value="users-total">{{ $ts._charts.usersTotal }}</option>
-						<option value="active-users">{{ $ts._charts.activeUsers }}</option>
-					</optgroup>
-					<optgroup :label="$ts.notes">
-						<option value="notes">{{ $ts._charts.notesIncDec }}</option>
-						<option value="local-notes">{{ $ts._charts.localNotesIncDec }}</option>
-						<option value="remote-notes">{{ $ts._charts.remoteNotesIncDec }}</option>
-						<option value="notes-total">{{ $ts._charts.notesTotal }}</option>
-					</optgroup>
-					<optgroup :label="$ts.drive">
-						<option value="drive-files">{{ $ts._charts.filesIncDec }}</option>
-						<option value="drive-files-total">{{ $ts._charts.filesTotal }}</option>
-						<option value="drive">{{ $ts._charts.storageUsageIncDec }}</option>
-						<option value="drive-total">{{ $ts._charts.storageUsageTotal }}</option>
-					</optgroup>
-				</MkSelect>
-				<MkSelect v-model:value="chartSpan" style="margin: 0;">
-					<option value="hour">{{ $ts.perHour }}</option>
-					<option value="day">{{ $ts.perDay }}</option>
-				</MkSelect>
-			</div>
-			<canvas ref="chart"></canvas>
-		</div>
-	</section>
+	<canvas ref="chart"></canvas>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, markRaw } from 'vue';
-import { faChartBar, faUser, faPencilAlt, faSync } from '@fortawesome/free-solid-svg-icons';
 import Chart from 'chart.js';
 import MkSelect from './ui/select.vue';
 import number from '@client/filters/number';
@@ -159,7 +70,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			info: null,
 			notesLocalWoW: 0,
 			notesLocalDoD: 0,
 			notesRemoteWoW: 0,
@@ -173,7 +83,6 @@ export default defineComponent({
 			chartInstance: null,
 			chartSrc: 'notes',
 			chartSpan: 'hour',
-			faChartBar, faUser, faPencilAlt, faSync
 		}
 	},
 
@@ -218,8 +127,6 @@ export default defineComponent({
 	},
 
 	async created() {
-		this.info = await os.api('stats');
-
 		this.now = new Date();
 
 		this.fetchChart();
@@ -258,15 +165,6 @@ export default defineComponent({
 				}
 			};
 
-			this.notesLocalWoW = this.info.originalNotesCount - chart.perDay.notes.local.total[7];
-			this.notesLocalDoD = this.info.originalNotesCount - chart.perDay.notes.local.total[1];
-			this.notesRemoteWoW = (this.info.notesCount - this.info.originalNotesCount) - chart.perDay.notes.remote.total[7];
-			this.notesRemoteDoD = (this.info.notesCount - this.info.originalNotesCount) - chart.perDay.notes.remote.total[1];
-			this.usersLocalWoW = this.info.originalUsersCount - chart.perDay.users.local.total[7];
-			this.usersLocalDoD = this.info.originalUsersCount - chart.perDay.users.local.total[1];
-			this.usersRemoteWoW = (this.info.usersCount - this.info.originalUsersCount) - chart.perDay.users.remote.total[7];
-			this.usersRemoteDoD = (this.info.usersCount - this.info.originalUsersCount) - chart.perDay.users.remote.total[1];
-
 			this.chart = chart;
 
 			this.renderChart();
@@ -302,10 +200,10 @@ export default defineComponent({
 					aspectRatio: 2.5,
 					layout: {
 						padding: {
-							left: 0,
-							right: 0,
+							left: 16,
+							right: 16,
 							top: 16,
-							bottom: 0
+							bottom: 8
 						}
 					},
 					legend: {
@@ -632,90 +530,8 @@ export default defineComponent({
 
 <style lang="scss" scoped>
 .zbcjwnqg {
-	&.max-width_1000px {
-		> .stats {
-			grid-template-columns: 1fr 1fr;
-			grid-template-rows: 1fr 1fr;
-		}
-	}
-
-	&.max-width_550px {
-		> .stats {
-			grid-template-columns: 1fr;
-			grid-template-rows: 1fr 1fr 1fr 1fr;
-		}
-	}
-
-	> .stats {
-		display: grid;
-		grid-template-columns: 1fr 1fr 1fr 1fr;
-		grid-template-rows: 1fr;
-		gap: var(--margin);
-		margin-bottom: var(--margin);
-		font-size: 90%;
-
-		> div {
-			display: flex;
-			box-sizing: border-box;
-			padding: 16px 20px;
-
-			> div {
-				width: 50%;
-
-				&:first-child {
-					> b {
-						display: block;
-
-						> [data-icon] {
-							width: 16px;
-							margin-right: 8px;
-						}
-					}
-
-					> small {
-						margin-left: 16px + 8px;
-						opacity: 0.7;
-					}
-				}
-
-				&:last-child {
-					> dl {
-						display: flex;
-						margin: 0;
-						line-height: 1.5em;
-
-						> dt,
-						> dd {
-							width: 50%;
-							margin: 0;
-						}
-
-						> dd {
-							text-overflow: ellipsis;
-							overflow: hidden;
-							white-space: nowrap;
-						}
-
-						&.total {
-							> dt,
-							> dd {
-								font-weight: bold;
-							}
-						}
-
-						&.diff.inc {
-							> dd {
-								color: #82c11c;
-
-								&:before {
-									content: "+";
-								}
-							}
-						}
-					}
-				}
-			}
-		}
+	> .selects {
+		padding: 8px 16px 0 16px;
 	}
 }
 </style>
diff --git a/src/client/components/launch-pad.vue b/src/client/components/launch-pad.vue
index 7610b44eb57040bb09b296526ce8f45a6255fde8..e3d24c70f25f3e1584162f21c1b6f035a50b9b25 100644
--- a/src/client/components/launch-pad.vue
+++ b/src/client/components/launch-pad.vue
@@ -4,28 +4,28 @@
 		<div class="main">
 			<template v-for="item in items">
 				<button v-if="item.action" class="_button" @click="$event => { item.action($event); close(); }">
-					<Fa :icon="item.icon" class="icon"/>
+					<i class="icon" :class="item.icon"></i>
 					<div class="text">{{ item.text }}</div>
-					<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
+					<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
 				</button>
 				<MkA v-else :to="item.to" @click.passive="close()">
-					<Fa :icon="item.icon" class="icon"/>
+					<i class="icon" :class="item.icon"></i>
 					<div class="text">{{ item.text }}</div>
-					<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
+					<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
 				</MkA>
 			</template>
 		</div>
 		<div class="sub">
 			<MkA to="/docs" @click.passive="close()">
-				<Fa :icon="faQuestionCircle" class="icon"/>
+				<i class="fas fa-question-circle icon"></i>
 				<div class="text">{{ $ts.help }}</div>
 			</MkA>
 			<MkA to="/about" @click.passive="close()">
-				<Fa :icon="faInfoCircle" class="icon"/>
+				<i class="fas fa-info-circle icon"></i>
 				<div class="text">{{ $t('aboutX', { x: instanceName }) }}</div>
 			</MkA>
 			<MkA to="/about-misskey" @click.passive="close()">
-				<Fa :icon="faInfoCircle" class="icon"/>
+				<i class="fas fa-info-circle icon"></i>
 				<div class="text">{{ $ts.aboutMisskey }}</div>
 			</MkA>
 		</div>
@@ -35,7 +35,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faQuestionCircle, faInfoCircle, faCircle } from '@fortawesome/free-solid-svg-icons';
 import MkModal from '@client/components/ui/modal.vue';
 import { sidebarDef } from '@client/sidebar';
 import { instanceName } from '@client/config';
@@ -52,7 +51,6 @@ export default defineComponent({
 			menuDef: sidebarDef,
 			items: [],
 			instanceName,
-			faQuestionCircle, faInfoCircle, faCircle,
 		};
 	},
 
@@ -127,7 +125,7 @@ export default defineComponent({
 				line-height: 1.5em;
 			}
 
-			> i {
+			> .indicator {
 				position: absolute;
 				top: 32px;
 				left: 32px;
diff --git a/src/client/components/link.vue b/src/client/components/link.vue
index cc7db8c2f57e9824cf95243c17bba0ac04f451d7..9712c778a9ef241565b4c31be483de44687e98b0 100644
--- a/src/client/components/link.vue
+++ b/src/client/components/link.vue
@@ -5,13 +5,12 @@
 	:title="url"
 >
 	<slot></slot>
-	<Fa :icon="faExternalLinkSquareAlt" v-if="target === '_blank'" class="icon"/>
+	<i v-if="target === '_blank'" class="fas fa-external-link-square-alt icon"></i>
 </component>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
 import { url as local } from '@client/config';
 import { isDeviceTouch } from '@client/scripts/is-device-touch';
 import * as os from '@client/os';
@@ -38,7 +37,6 @@ export default defineComponent({
 			hideTimer: null,
 			checkTimer: null,
 			close: null,
-			faExternalLinkSquareAlt
 		};
 	},
 	methods: {
diff --git a/src/client/components/media-banner.vue b/src/client/components/media-banner.vue
index 29d7c727f600dcde52c3a7803dd8417ee0961c54..34065557bf43967af218730046984611bf4bf6ee 100644
--- a/src/client/components/media-banner.vue
+++ b/src/client/components/media-banner.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mk-media-banner">
 	<div class="sensitive" v-if="media.isSensitive && hide" @click="hide = false">
-		<span class="icon"><Fa :icon="faExclamationTriangle"/></span>
+		<span class="icon"><i class="fas fa-exclamation-triangle"></i></span>
 		<b>{{ $ts.sensitive }}</b>
 		<span>{{ $ts.clickToShow }}</span>
 	</div>
@@ -19,7 +19,7 @@
 		:title="media.name"
 		:download="media.name"
 	>
-		<span class="icon"><Fa icon="download"/></span>
+		<span class="icon"><i class="fas fa-download"></i></span>
 		<b>{{ media.name }}</b>
 	</a>
 </div>
@@ -27,7 +27,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 import { ColdDeviceStorage } from '@client/store';
 
@@ -41,7 +40,6 @@ export default defineComponent({
 	data() {
 		return {
 			hide: true,
-			faExclamationTriangle
 		};
 	},
 	mounted() {
diff --git a/src/client/components/media-image.vue b/src/client/components/media-image.vue
index 57604661384ef5eefb25eb7b7596a4e1cee5a7f3..0573b2592d352df91c500c21aee2877d44740df0 100644
--- a/src/client/components/media-image.vue
+++ b/src/client/components/media-image.vue
@@ -3,13 +3,13 @@
 	<ImgWithBlurhash class="bg" :hash="image.blurhash" :title="image.name"/>
 	<div class="text">
 		<div>
-			<b><Fa :icon="faExclamationTriangle"/> {{ $ts.sensitive }}</b>
+			<b><i class="fas fa-exclamation-triangle"></i> {{ $ts.sensitive }}</b>
 			<span>{{ $ts.clickToShow }}</span>
 		</div>
 	</div>
 </div>
 <div class="gqnyydlz" :style="{ background: color }" v-else>
-	<i><Fa :icon="faEyeSlash" @click="hide = true"/></i>
+	<i class="fas fa-eye-slash" @click="hide = true"></i>
 	<a
 		:href="image.url"
 		:title="image.name"
@@ -23,7 +23,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
 import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
 import { extractAvgColorFromBlurhash } from '@client/scripts/extract-avg-color-from-blurhash';
 import ImageViewer from './image-viewer.vue';
@@ -47,7 +46,6 @@ export default defineComponent({
 		return {
 			hide: true,
 			color: null,
-			faExclamationTriangle, faEyeSlash,
 		};
 	},
 	computed: {
diff --git a/src/client/components/media-video.vue b/src/client/components/media-video.vue
index b6f63cb65d1f8fa8c87d5c22a203bbaad8e01315..020b5e93a80777f5860b196d038c6f7d48a36836 100644
--- a/src/client/components/media-video.vue
+++ b/src/client/components/media-video.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="icozogqfvdetwohsdglrbswgrejoxbdj" v-if="hide" @click="hide = false">
 	<div>
-		<b><Fa :icon="faExclamationTriangle"/> {{ $ts.sensitive }}</b>
+		<b><i class="fas fa-exclamation-triangle"></i> {{ $ts.sensitive }}</b>
 		<span>{{ $ts.clickToShow }}</span>
 	</div>
 </div>
@@ -18,13 +18,12 @@
 			:type="video.type"
 		>
 	</video>
-	<i><Fa :icon="faEyeSlash" @click="hide = true"/></i>
+	<i class="fas fa-eye-slash" @click="hide = true"></i>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle, faEyeSlash } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -37,8 +36,6 @@ export default defineComponent({
 	data() {
 		return {
 			hide: true,
-			faExclamationTriangle,
-			faEyeSlash
 		};
 	},
 	created() {
diff --git a/src/client/components/modal-page-window.vue b/src/client/components/modal-page-window.vue
index 474a67f98543102ee4a9c7bb89de7475fafc0f53..7be4045a849f2186de9e7b21db85c975beb3da88 100644
--- a/src/client/components/modal-page-window.vue
+++ b/src/client/components/modal-page-window.vue
@@ -1,13 +1,13 @@
 <template>
 <MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
 	<div class="hrmcaedk _popup _narrow_" :style="{ width: `${width}px`, height: (height ? `min(${height}px, 100%)` : '100%') }">
-		<div class="header">
-			<button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button>
+		<div class="header" @contextmenu="onContextmenu">
+			<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
 			<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
 			<span class="title">
 				<XHeader :info="pageInfo" :with-back="false"/>
 			</span>
-			<button class="_button" @click="$refs.modal.close()"><Fa :icon="faTimes"/></button>
+			<button class="_button" @click="$refs.modal.close()"><i class="fas fa-times"></i></button>
 		</div>
 		<div class="body _flat_">
 			<keep-alive>
@@ -20,7 +20,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExternalLinkAlt, faExpandAlt, faLink, faChevronLeft, faColumns, faTimes } from '@fortawesome/free-solid-svg-icons';
 import MkModal from '@client/components/ui/modal.vue';
 import XHeader from '@client/ui/_common_/header.vue';
 import { popout } from '@client/scripts/popout';
@@ -28,6 +27,7 @@ import copyToClipboard from '@client/scripts/copy-to-clipboard';
 import { resolve } from '@client/router';
 import { url } from '@client/config';
 import * as symbols from '@client/symbols';
+import * as os from '@client/os';
 
 export default defineComponent({
 	components: {
@@ -76,7 +76,6 @@ export default defineComponent({
 			component: this.initialComponent,
 			props: this.initialProps,
 			history: [],
-			faChevronLeft, faTimes,
 		};
 	},
 
@@ -90,29 +89,29 @@ export default defineComponent({
 				type: 'label',
 				text: this.path,
 			}, {
-				icon: faExpandAlt,
+				icon: 'fas fa-expand-alt',
 				text: this.$ts.showInPage,
 				action: this.expand
 			}, this.sideViewHook ? {
-				icon: faColumns,
+				icon: 'fas fa-columns',
 				text: this.$ts.openInSideView,
 				action: () => {
 					this.sideViewHook(this.path);
 					this.$refs.window.close();
 				}
 			} : undefined, {
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				text: this.$ts.popout,
 				action: this.popout
 			}, null, {
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				text: this.$ts.openInNewTab,
 				action: () => {
 					window.open(this.url, '_blank');
 					this.$refs.window.close();
 				}
 			}, {
-				icon: faLink,
+				icon: 'fas fa-link',
 				text: this.$ts.copyLink,
 				action: () => {
 					copyToClipboard(this.url);
@@ -150,6 +149,10 @@ export default defineComponent({
 			popout(this.path, this.$el);
 			this.$refs.window.close();
 		},
+
+		onContextmenu(e) {
+			os.contextMenu(this.contextmenu, e);
+		}
 	},
 });
 </script>
diff --git a/src/client/components/note-detailed.vue b/src/client/components/note-detailed.vue
index 50e76e5299b7dc6559676392889bc3d6a3b71de0..6040ad378f712006dc0ec740f7c8a3076e6612cc 100644
--- a/src/client/components/note-detailed.vue
+++ b/src/client/components/note-detailed.vue
@@ -12,7 +12,7 @@
 	<XSub :note="appearNote.reply" class="reply-to" v-if="appearNote.reply"/>
 	<div class="renote" v-if="isRenote">
 		<MkAvatar class="avatar" :user="note.user"/>
-		<Fa :icon="faRetweet"/>
+		<i class="fas fa-retweet"></i>
 		<I18n :src="$ts.renotedBy" tag="span">
 			<template #user>
 				<MkA class="name" :to="userPage(note.user)" v-user-preview="note.userId">
@@ -22,15 +22,15 @@
 		</I18n>
 		<div class="info">
 			<button class="_button time" @click="showRenoteMenu()" ref="renoteTime">
-				<Fa class="dropdownIcon" v-if="isMyRenote" :icon="faEllipsisH"/>
+				<i v-if="isMyRenote" class="fas fa-ellipsis-h dropdownIcon"></i>
 				<MkTime :time="note.createdAt"/>
 			</button>
 			<span class="visibility" v-if="note.visibility !== 'public'">
-				<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
-				<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
-				<Fa v-if="note.visibility === 'specified'" :icon="faEnvelope"/>
+				<i v-if="note.visibility === 'home'" class="fas fa-home"></i>
+				<i v-else-if="note.visibility === 'followers'" class="fas fa-unlock"></i>
+				<i v-else-if="note.visibility === 'specified'" class="fas fa-envelope"></i>
 			</span>
-			<span class="localOnly" v-if="note.localOnly"><Fa :icon="faBiohazard"/></span>
+			<span class="localOnly" v-if="note.localOnly"><i class="fas fa-biohazard"></i></span>
 		</div>
 	</div>
 	<article class="article" @contextmenu.stop="onContextmenu">
@@ -42,14 +42,14 @@
 						<MkUserName :user="appearNote.user"/>
 					</MkA>
 					<span class="is-bot" v-if="appearNote.user.isBot">bot</span>
-					<span class="admin" v-if="appearNote.user.isAdmin"><Fa :icon="faBookmark"/></span>
-					<span class="moderator" v-if="!appearNote.user.isAdmin && appearNote.user.isModerator"><Fa :icon="farBookmark"/></span>
+					<span class="admin" v-if="appearNote.user.isAdmin"><i class="fas fa-bookmark"></i></span>
+					<span class="moderator" v-if="!appearNote.user.isAdmin && appearNote.user.isModerator"><i class="far fa-bookmark"></i></span>
 					<span class="visibility" v-if="appearNote.visibility !== 'public'">
-						<Fa v-if="appearNote.visibility === 'home'" :icon="faHome"/>
-						<Fa v-if="appearNote.visibility === 'followers'" :icon="faUnlock"/>
-						<Fa v-if="appearNote.visibility === 'specified'" :icon="faEnvelope"/>
+						<i v-if="appearNote.visibility === 'home'" class="fas fa-home"></i>
+						<i v-else-if="appearNote.visibility === 'followers'" class="fas fa-unlock"></i>
+						<i v-else-if="appearNote.visibility === 'specified'" class="fas fa-envelope"></i>
 					</span>
-					<span class="localOnly" v-if="appearNote.localOnly"><Fa :icon="faBiohazard"/></span>
+					<span class="localOnly" v-if="appearNote.localOnly"><i class="fas fa-biohazard"></i></span>
 				</div>
 				<div class="username"><MkAcct :user="appearNote.user"/></div>
 				<MkInstanceTicker v-if="showTicker" class="ticker" :instance="appearNote.user.instance"/>
@@ -64,7 +64,7 @@
 				<div class="content" v-show="appearNote.cw == null || showContent">
 					<div class="text">
 						<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
-						<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
+						<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
 						<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
 						<a class="rp" v-if="appearNote.renote != null">RN:</a>
 					</div>
@@ -75,33 +75,33 @@
 					<MkUrlPreview v-for="url in urls" :url="url" :key="url" :compact="true" :detail="true" class="url-preview"/>
 					<div class="renote" v-if="appearNote.renote"><XNotePreview :note="appearNote.renote"/></div>
 				</div>
-				<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</MkA>
+				<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA>
 			</div>
 			<footer class="footer">
 				<div class="info">
-					<span class="mobile" v-if="note.viaMobile"><Fa :icon="faMobileAlt"/></span>
+					<span class="mobile" v-if="note.viaMobile"><i class="fas fa-mobile-alt"></i></span>
 					<MkTime class="created-at" :time="note.createdAt" mode="detail"/>
 				</div>
 				<XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
 				<button @click="reply()" class="button _button">
-					<template v-if="appearNote.reply"><Fa :icon="faReplyAll"/></template>
-					<template v-else><Fa :icon="faReply"/></template>
+					<template v-if="appearNote.reply"><i class="fas fa-reply-all"></i></template>
+					<template v-else><i class="fas fa-reply"></i></template>
 					<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
 				</button>
 				<button v-if="canRenote" @click="renote()" class="button _button" ref="renoteButton">
-					<Fa :icon="faRetweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
+					<i class="fas fa-retweet"></i><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
 				</button>
 				<button v-else class="button _button">
-					<Fa :icon="faBan"/>
+					<i class="fas fa-ban"></i>
 				</button>
 				<button v-if="appearNote.myReaction == null" class="button _button" @click="react()" ref="reactButton">
-					<Fa :icon="faPlus"/>
+					<i class="fas fa-plus"></i>
 				</button>
 				<button v-if="appearNote.myReaction != null" class="button _button reacted" @click="undoReact(appearNote)" ref="reactButton">
-					<Fa :icon="faMinus"/>
+					<i class="fas fa-minus"></i>
 				</button>
 				<button class="button _button" @click="menu()" ref="menuButton">
-					<Fa :icon="faEllipsisH"/>
+					<i class="fas fa-ellipsis-h"></i>
 				</button>
 			</footer>
 		</div>
@@ -121,8 +121,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent, markRaw } from 'vue';
-import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip, faShareAlt } from '@fortawesome/free-solid-svg-icons';
-import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
 import * as mfm from 'mfm-js';
 import { sum } from '../../prelude/array';
 import XSub from './note.sub.vue';
@@ -143,14 +141,6 @@ import { noteActions, noteViewInterruptors } from '@client/store';
 import { reactionPicker } from '@client/scripts/reaction-picker';
 import { extractUrlFromMfm } from '@/misc/extract-url-from-mfm';
 
-function markRawAll(...xs) {
-	for (const x of xs) {
-		markRaw(x);
-	}
-}
-
-markRawAll(faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish);
-
 // TODO: note.vueとほぼ同じなので共通化したい
 export default defineComponent({
 	components: {
@@ -188,7 +178,6 @@ export default defineComponent({
 			showContent: false,
 			isDeleted: false,
 			muted: false,
-			faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish
 		};
 	},
 
@@ -467,7 +456,7 @@ export default defineComponent({
 			this.blur();
 			os.modalMenu([{
 				text: this.$ts.renote,
-				icon: faRetweet,
+				icon: 'fas fa-retweet',
 				action: () => {
 					os.api('notes/create', {
 						renoteId: this.appearNote.id
@@ -475,7 +464,7 @@ export default defineComponent({
 				}
 			}, {
 				text: this.$ts.quote,
-				icon: faQuoteRight,
+				icon: 'fas fa-quote-right',
 				action: () => {
 					os.post({
 						renote: this.appearNote,
@@ -611,62 +600,62 @@ export default defineComponent({
 				});
 
 				menu = [{
-					icon: faCopy,
+					icon: 'fas fa-copy',
 					text: this.$ts.copyContent,
 					action: this.copyContent
 				}, {
-					icon: faLink,
+					icon: 'fas fa-link',
 					text: this.$ts.copyLink,
 					action: this.copyLink
 				}, (this.appearNote.url || this.appearNote.uri) ? {
-					icon: faExternalLinkSquareAlt,
+					icon: 'fas fa-external-link-square-alt',
 					text: this.$ts.showOnRemote,
 					action: () => {
 						window.open(this.appearNote.url || this.appearNote.uri, '_blank');
 					}
 				} : undefined,
 				{
-					icon: faShareAlt,
+					icon: 'fas fa-share-alt',
 					text: this.$ts.share,
 					action: this.share
 				},
 				null,
 				statePromise.then(state => state.isFavorited ? {
-					icon: faStar,
+					icon: 'fas fa-star',
 					text: this.$ts.unfavorite,
 					action: () => this.toggleFavorite(false)
 				} : {
-					icon: faStar,
+					icon: 'fas fa-star',
 					text: this.$ts.favorite,
 					action: () => this.toggleFavorite(true)
 				}),
 				{
-					icon: faPaperclip,
+					icon: 'fas fa-paperclip',
 					text: this.$ts.clip,
 					action: () => this.clip()
 				},
 				(this.appearNote.userId != this.$i.id) ? statePromise.then(state => state.isWatching ? {
-					icon: faEyeSlash,
+					icon: 'fas fa-eye-slash',
 					text: this.$ts.unwatch,
 					action: () => this.toggleWatch(false)
 				} : {
-					icon: faEye,
+					icon: 'fas fa-eye',
 					text: this.$ts.watch,
 					action: () => this.toggleWatch(true)
 				}) : undefined,
 				this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
-					icon: faThumbtack,
+					icon: 'fas fa-thumbtack',
 					text: this.$ts.unpin,
 					action: () => this.togglePin(false)
 				} : {
-					icon: faThumbtack,
+					icon: 'fas fa-thumbtack',
 					text: this.$ts.pin,
 					action: () => this.togglePin(true)
 				} : undefined,
 				...(this.$i.isModerator || this.$i.isAdmin ? [
 					null,
 					{
-						icon: faBullhorn,
+						icon: 'fas fa-bullhorn',
 						text: this.$ts.promote,
 						action: this.promote
 					}]
@@ -675,7 +664,7 @@ export default defineComponent({
 				...(this.appearNote.userId != this.$i.id ? [
 					null,
 					{
-						icon: faExclamationCircle,
+						icon: 'fas fa-exclamation-circle',
 						text: this.$ts.reportAbuse,
 						action: () => {
 							const u = `${url}/notes/${this.appearNote.id}`;
@@ -690,12 +679,12 @@ export default defineComponent({
 				...(this.appearNote.userId == this.$i.id || this.$i.isModerator || this.$i.isAdmin ? [
 					null,
 					this.appearNote.userId == this.$i.id ? {
-						icon: faEdit,
+						icon: 'fas fa-edit',
 						text: this.$ts.deleteAndEdit,
 						action: this.delEdit
 					} : undefined,
 					{
-						icon: faTrashAlt,
+						icon: 'fas fa-trash-alt',
 						text: this.$ts.delete,
 						danger: true,
 						action: this.del
@@ -705,15 +694,15 @@ export default defineComponent({
 				.filter(x => x !== undefined);
 			} else {
 				menu = [{
-					icon: faCopy,
+					icon: 'fas fa-copy',
 					text: this.$ts.copyContent,
 					action: this.copyContent
 				}, {
-					icon: faLink,
+					icon: 'fas fa-link',
 					text: this.$ts.copyLink,
 					action: this.copyLink
 				}, (this.appearNote.url || this.appearNote.uri) ? {
-					icon: faExternalLinkSquareAlt,
+					icon: 'fas fa-external-link-square-alt',
 					text: this.$ts.showOnRemote,
 					action: () => {
 						window.open(this.appearNote.url || this.appearNote.uri, '_blank');
@@ -724,7 +713,7 @@ export default defineComponent({
 
 			if (noteActions.length > 0) {
 				menu = menu.concat([null, ...noteActions.map(action => ({
-					icon: faPlug,
+					icon: 'fas fa-plug',
 					text: action.title,
 					action: () => {
 						action.handler(this.appearNote);
@@ -763,7 +752,7 @@ export default defineComponent({
 			if (!this.isMyRenote) return;
 			os.modalMenu([{
 				text: this.$ts.unrenote,
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				danger: true,
 				action: () => {
 					os.api('notes/delete', {
@@ -806,7 +795,7 @@ export default defineComponent({
 		async clip() {
 			const clips = await os.api('clips/list');
 			os.modalMenu([{
-				icon: faPlus,
+				icon: 'fas fa-plus',
 				text: this.$ts.createNew,
 				action: async () => {
 					const { canceled, result } = await os.form(this.$ts.createNewClip, {
@@ -943,7 +932,7 @@ export default defineComponent({
 			border-radius: 6px;
 		}
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 		}
 
diff --git a/src/client/components/note-header.vue b/src/client/components/note-header.vue
index ab40c5fd4a57c641f9fd925d3fca2850aba597a9..1cd6463f9bfea9b54268e28434635b2e2f5d83e7 100644
--- a/src/client/components/note-header.vue
+++ b/src/client/components/note-header.vue
@@ -5,27 +5,25 @@
 	</MkA>
 	<span class="is-bot" v-if="note.user.isBot">bot</span>
 	<span class="username"><MkAcct :user="note.user"/></span>
-	<span class="admin" v-if="note.user.isAdmin"><Fa :icon="faBookmark"/></span>
-	<span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><Fa :icon="farBookmark"/></span>
+	<span class="admin" v-if="note.user.isAdmin"><i class="fas fa-bookmark"></i></span>
+	<span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><i class="far fa-bookmark"></i></span>
 	<div class="info">
-		<span class="mobile" v-if="note.viaMobile"><Fa :icon="faMobileAlt"/></span>
+		<span class="mobile" v-if="note.viaMobile"><i class="fas fa-mobile-alt"></i></span>
 		<MkA class="created-at" :to="notePage(note)">
 			<MkTime :time="note.createdAt"/>
 		</MkA>
 		<span class="visibility" v-if="note.visibility !== 'public'">
-			<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
-			<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
-			<Fa v-if="note.visibility === 'specified'" :icon="faEnvelope"/>
+			<i v-if="note.visibility === 'home'" class="fas fa-home"></i>
+			<i v-else-if="note.visibility === 'followers'" class="fas fa-unlock"></i>
+			<i v-else-if="note.visibility === 'specified'" class="fas fa-envelope"></i>
 		</span>
-		<span class="localOnly" v-if="note.localOnly"><Fa :icon="faBiohazard"/></span>
+		<span class="localOnly" v-if="note.localOnly"><i class="fas fa-biohazard"></i></span>
 	</div>
 </header>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark, faBiohazard } from '@fortawesome/free-solid-svg-icons';
-import { faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons';
 import notePage from '../filters/note';
 import { userPage } from '../filters/user';
 import * as os from '@client/os';
@@ -40,7 +38,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark, farBookmark, faBiohazard
 		};
 	},
 
diff --git a/src/client/components/note.vue b/src/client/components/note.vue
index 0e153033ca01af1ee053365843a07fa35c4e1ac9..504d07c0eb53c0ebfcf0771542293a369dd8a2a4 100644
--- a/src/client/components/note.vue
+++ b/src/client/components/note.vue
@@ -9,12 +9,12 @@
 	v-size="{ max: [500, 450, 350, 300] }"
 >
 	<XSub :note="appearNote.reply" class="reply-to" v-if="appearNote.reply"/>
-	<div class="info" v-if="pinned"><Fa :icon="faThumbtack"/> {{ $ts.pinnedNote }}</div>
-	<div class="info" v-if="appearNote._prId_"><Fa :icon="faBullhorn"/> {{ $ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ $ts.hideThisNote }} <Fa :icon="faTimes"/></button></div>
-	<div class="info" v-if="appearNote._featuredId_"><Fa :icon="faBolt"/> {{ $ts.featured }}</div>
+	<div class="info" v-if="pinned"><i class="fas fa-thumbtack"></i> {{ $ts.pinnedNote }}</div>
+	<div class="info" v-if="appearNote._prId_"><i class="fas fa-bullhorn"></i> {{ $ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ $ts.hideThisNote }} <i class="fas fa-times"></i></button></div>
+	<div class="info" v-if="appearNote._featuredId_"><i class="fas fa-bolt"></i> {{ $ts.featured }}</div>
 	<div class="renote" v-if="isRenote">
 		<MkAvatar class="avatar" :user="note.user"/>
-		<Fa :icon="faRetweet"/>
+		<i class="fas fa-retweet"></i>
 		<I18n :src="$ts.renotedBy" tag="span">
 			<template #user>
 				<MkA class="name" :to="userPage(note.user)" v-user-preview="note.userId">
@@ -24,15 +24,15 @@
 		</I18n>
 		<div class="info">
 			<button class="_button time" @click="showRenoteMenu()" ref="renoteTime">
-				<Fa class="dropdownIcon" v-if="isMyRenote" :icon="faEllipsisH"/>
+				<i v-if="isMyRenote" class="fas fa-ellipsis-h dropdownIcon"></i>
 				<MkTime :time="note.createdAt"/>
 			</button>
 			<span class="visibility" v-if="note.visibility !== 'public'">
-				<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
-				<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
-				<Fa v-if="note.visibility === 'specified'" :icon="faEnvelope"/>
+				<i v-if="note.visibility === 'home'" class="fas fa-home"></i>
+				<i v-else-if="note.visibility === 'followers'" class="fas fa-unlock"></i>
+				<i v-else-if="note.visibility === 'specified'" class="fas fa-envelope"></i>
 			</span>
-			<span class="localOnly" v-if="note.localOnly"><Fa :icon="faBiohazard"/></span>
+			<span class="localOnly" v-if="note.localOnly"><i class="fas fa-biohazard"></i></span>
 		</div>
 	</div>
 	<article class="article" @contextmenu.stop="onContextmenu">
@@ -48,7 +48,7 @@
 				<div class="content" :class="{ collapsed }" v-show="appearNote.cw == null || showContent">
 					<div class="text">
 						<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
-						<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
+						<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
 						<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
 						<a class="rp" v-if="appearNote.renote != null">RN:</a>
 					</div>
@@ -62,29 +62,29 @@
 						<span>{{ $ts.showMore }}</span>
 					</button>
 				</div>
-				<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</MkA>
+				<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA>
 			</div>
 			<footer class="footer">
 				<XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
 				<button @click="reply()" class="button _button">
-					<template v-if="appearNote.reply"><Fa :icon="faReplyAll"/></template>
-					<template v-else><Fa :icon="faReply"/></template>
+					<template v-if="appearNote.reply"><i class="fas fa-reply-all"></i></template>
+					<template v-else><i class="fas fa-reply"></i></template>
 					<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
 				</button>
 				<button v-if="canRenote" @click="renote()" class="button _button" ref="renoteButton">
-					<Fa :icon="faRetweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
+					<i class="fas fa-retweet"></i><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
 				</button>
 				<button v-else class="button _button">
-					<Fa :icon="faBan"/>
+					<i class="fas fa-ban"></i>
 				</button>
 				<button v-if="appearNote.myReaction == null" class="button _button" @click="react()" ref="reactButton">
-					<Fa :icon="faPlus"/>
+					<i class="fas fa-plus"></i>
 				</button>
 				<button v-if="appearNote.myReaction != null" class="button _button reacted" @click="undoReact(appearNote)" ref="reactButton">
-					<Fa :icon="faMinus"/>
+					<i class="fas fa-minus"></i>
 				</button>
 				<button class="button _button" @click="menu()" ref="menuButton">
-					<Fa :icon="faEllipsisH"/>
+					<i class="fas fa-ellipsis-h"></i>
 				</button>
 			</footer>
 		</div>
@@ -103,8 +103,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent, markRaw } from 'vue';
-import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip, faShareAlt } from '@fortawesome/free-solid-svg-icons';
-import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
 import * as mfm from 'mfm-js';
 import { sum } from '../../prelude/array';
 import XSub from './note.sub.vue';
@@ -125,14 +123,6 @@ import { noteActions, noteViewInterruptors } from '@client/store';
 import { reactionPicker } from '@client/scripts/reaction-picker';
 import { extractUrlFromMfm } from '@/misc/extract-url-from-mfm';
 
-function markRawAll(...xs) {
-	for (const x of xs) {
-		markRaw(x);
-	}
-}
-
-markRawAll(faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish);
-
 export default defineComponent({
 	components: {
 		XSub,
@@ -174,7 +164,6 @@ export default defineComponent({
 			collapsed: false,
 			isDeleted: false,
 			muted: false,
-			faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish
 		};
 	},
 
@@ -442,7 +431,7 @@ export default defineComponent({
 			this.blur();
 			os.modalMenu([{
 				text: this.$ts.renote,
-				icon: faRetweet,
+				icon: 'fas fa-retweet',
 				action: () => {
 					os.api('notes/create', {
 						renoteId: this.appearNote.id
@@ -450,7 +439,7 @@ export default defineComponent({
 				}
 			}, {
 				text: this.$ts.quote,
-				icon: faQuoteRight,
+				icon: 'fas fa-quote-right',
 				action: () => {
 					os.post({
 						renote: this.appearNote,
@@ -586,62 +575,62 @@ export default defineComponent({
 				});
 
 				menu = [{
-					icon: faCopy,
+					icon: 'fas fa-copy',
 					text: this.$ts.copyContent,
 					action: this.copyContent
 				}, {
-					icon: faLink,
+					icon: 'fas fa-link',
 					text: this.$ts.copyLink,
 					action: this.copyLink
 				}, (this.appearNote.url || this.appearNote.uri) ? {
-					icon: faExternalLinkSquareAlt,
+					icon: 'fas fa-external-link-square-alt',
 					text: this.$ts.showOnRemote,
 					action: () => {
 						window.open(this.appearNote.url || this.appearNote.uri, '_blank');
 					}
 				} : undefined,
 				{
-					icon: faShareAlt,
+					icon: 'fas fa-share-alt',
 					text: this.$ts.share,
 					action: this.share
 				},
 				null,
 				statePromise.then(state => state.isFavorited ? {
-					icon: faStar,
+					icon: 'fas fa-star',
 					text: this.$ts.unfavorite,
 					action: () => this.toggleFavorite(false)
 				} : {
-					icon: faStar,
+					icon: 'fas fa-star',
 					text: this.$ts.favorite,
 					action: () => this.toggleFavorite(true)
 				}),
 				{
-					icon: faPaperclip,
+					icon: 'fas fa-paperclip',
 					text: this.$ts.clip,
 					action: () => this.clip()
 				},
 				(this.appearNote.userId != this.$i.id) ? statePromise.then(state => state.isWatching ? {
-					icon: faEyeSlash,
+					icon: 'fas fa-eye-slash',
 					text: this.$ts.unwatch,
 					action: () => this.toggleWatch(false)
 				} : {
-					icon: faEye,
+					icon: 'fas fa-eye',
 					text: this.$ts.watch,
 					action: () => this.toggleWatch(true)
 				}) : undefined,
 				this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
-					icon: faThumbtack,
+					icon: 'fas fa-thumbtack',
 					text: this.$ts.unpin,
 					action: () => this.togglePin(false)
 				} : {
-					icon: faThumbtack,
+					icon: 'fas fa-thumbtack',
 					text: this.$ts.pin,
 					action: () => this.togglePin(true)
 				} : undefined,
 				...(this.$i.isModerator || this.$i.isAdmin ? [
 					null,
 					{
-						icon: faBullhorn,
+						icon: 'fas fa-bullhorn',
 						text: this.$ts.promote,
 						action: this.promote
 					}]
@@ -650,7 +639,7 @@ export default defineComponent({
 				...(this.appearNote.userId != this.$i.id ? [
 					null,
 					{
-						icon: faExclamationCircle,
+						icon: 'fas fa-exclamation-circle',
 						text: this.$ts.reportAbuse,
 						action: () => {
 							const u = `${url}/notes/${this.appearNote.id}`;
@@ -665,12 +654,12 @@ export default defineComponent({
 				...(this.appearNote.userId == this.$i.id || this.$i.isModerator || this.$i.isAdmin ? [
 					null,
 					this.appearNote.userId == this.$i.id ? {
-						icon: faEdit,
+						icon: 'fas fa-edit',
 						text: this.$ts.deleteAndEdit,
 						action: this.delEdit
 					} : undefined,
 					{
-						icon: faTrashAlt,
+						icon: 'fas fa-trash-alt',
 						text: this.$ts.delete,
 						danger: true,
 						action: this.del
@@ -680,15 +669,15 @@ export default defineComponent({
 				.filter(x => x !== undefined);
 			} else {
 				menu = [{
-					icon: faCopy,
+					icon: 'fas fa-copy',
 					text: this.$ts.copyContent,
 					action: this.copyContent
 				}, {
-					icon: faLink,
+					icon: 'fas fa-link',
 					text: this.$ts.copyLink,
 					action: this.copyLink
 				}, (this.appearNote.url || this.appearNote.uri) ? {
-					icon: faExternalLinkSquareAlt,
+					icon: 'fas fa-external-link-square-alt',
 					text: this.$ts.showOnRemote,
 					action: () => {
 						window.open(this.appearNote.url || this.appearNote.uri, '_blank');
@@ -699,7 +688,7 @@ export default defineComponent({
 
 			if (noteActions.length > 0) {
 				menu = menu.concat([null, ...noteActions.map(action => ({
-					icon: faPlug,
+					icon: 'fas fa-plug',
 					text: action.title,
 					action: () => {
 						action.handler(this.appearNote);
@@ -738,7 +727,7 @@ export default defineComponent({
 			if (!this.isMyRenote) return;
 			os.modalMenu([{
 				text: this.$ts.unrenote,
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				danger: true,
 				action: () => {
 					os.api('notes/delete', {
@@ -781,7 +770,7 @@ export default defineComponent({
 		async clip() {
 			const clips = await os.api('clips/list');
 			os.modalMenu([{
-				icon: faPlus,
+				icon: 'fas fa-plus',
 				text: this.$ts.createNew,
 				action: async () => {
 					const { canceled, result } = await os.form(this.$ts.createNewClip, {
@@ -909,7 +898,7 @@ export default defineComponent({
 		white-space: pre;
 		color: #d28a3f;
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 		}
 
@@ -945,7 +934,7 @@ export default defineComponent({
 			border-radius: 6px;
 		}
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 		}
 
diff --git a/src/client/components/notification.vue b/src/client/components/notification.vue
index 2b8b440ced0b09942a9cbfa2013a333a3e8a8883..9badd7a70864327b1acdec5155d2819f68df5127 100644
--- a/src/client/components/notification.vue
+++ b/src/client/components/notification.vue
@@ -4,15 +4,15 @@
 		<MkAvatar v-if="notification.user" class="icon" :user="notification.user"/>
 		<img v-else-if="notification.icon" class="icon" :src="notification.icon" alt=""/>
 		<div class="sub-icon" :class="notification.type">
-			<Fa :icon="faPlus" v-if="notification.type === 'follow'"/>
-			<Fa :icon="faClock" v-else-if="notification.type === 'receiveFollowRequest'"/>
-			<Fa :icon="faCheck" v-else-if="notification.type === 'followRequestAccepted'"/>
-			<Fa :icon="faIdCardAlt" v-else-if="notification.type === 'groupInvited'"/>
-			<Fa :icon="faRetweet" v-else-if="notification.type === 'renote'"/>
-			<Fa :icon="faReply" v-else-if="notification.type === 'reply'"/>
-			<Fa :icon="faAt" v-else-if="notification.type === 'mention'"/>
-			<Fa :icon="faQuoteLeft" v-else-if="notification.type === 'quote'"/>
-			<Fa :icon="faPollH" v-else-if="notification.type === 'pollVote'"/>
+			<i v-if="notification.type === 'follow'" class="fas fa-plus"></i>
+			<i v-else-if="notification.type === 'receiveFollowRequest'" class="fas fa-clock"></i>
+			<i v-else-if="notification.type === 'followRequestAccepted'" class="fas fa-check"></i>
+			<i v-else-if="notification.type === 'groupInvited'" class="fas fa-id-card-alt"></i>
+			<i v-else-if="notification.type === 'renote'" class="fas fa-retweet"></i>
+			<i v-else-if="notification.type === 'reply'" class="fas fa-reply"></i>
+			<i v-else-if="notification.type === 'mention'" class="fas fa-at"></i>
+			<i v-else-if="notification.type === 'quote'" class="fas fa-quote-left"></i>
+			<i v-else-if="notification.type === 'pollVote'" class="fas fa-poll-h"></i>
 			<XReactionIcon v-else-if="notification.type === 'reaction'" :reaction="notification.reaction" :custom-emojis="notification.note.emojis" :no-style="true"/>
 		</div>
 	</div>
@@ -23,14 +23,14 @@
 			<MkTime :time="notification.createdAt" v-if="withTime" class="time"/>
 		</header>
 		<MkA v-if="notification.type === 'reaction'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
-			<Fa :icon="faQuoteLeft"/>
+			<i class="fas fa-quote-left"></i>
 			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
-			<Fa :icon="faQuoteRight"/>
+			<i class="fas fa-quote-right"></i>
 		</MkA>
 		<MkA v-if="notification.type === 'renote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note.renote)">
-			<Fa :icon="faQuoteLeft"/>
+			<i class="fas fa-quote-left"></i>
 			<Mfm :text="getNoteSummary(notification.note.renote)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.renote.emojis"/>
-			<Fa :icon="faQuoteRight"/>
+			<i class="fas fa-quote-right"></i>
 		</MkA>
 		<MkA v-if="notification.type === 'reply'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
 			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
@@ -42,9 +42,9 @@
 			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
 		</MkA>
 		<MkA v-if="notification.type === 'pollVote'" class="text" :to="notePage(notification.note)" :title="getNoteSummary(notification.note)">
-			<Fa :icon="faQuoteLeft"/>
+			<i class="fas fa-quote-left"></i>
 			<Mfm :text="getNoteSummary(notification.note)" :plain="true" :nowrap="!full" :custom-emojis="notification.note.emojis"/>
-			<Fa :icon="faQuoteRight"/>
+			<i class="fas fa-quote-right"></i>
 		</MkA>
 		<span v-if="notification.type === 'follow'" class="text" style="opacity: 0.6;">{{ $ts.youGotNewFollower }}<div v-if="full"><MkFollowButton :user="notification.user" :full="true"/></div></span>
 		<span v-if="notification.type === 'followRequestAccepted'" class="text" style="opacity: 0.6;">{{ $ts.followRequestAccepted }}</span>
@@ -59,8 +59,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faIdCardAlt, faPlus, faQuoteLeft, faQuoteRight, faRetweet, faReply, faAt, faCheck, faPollH } from '@fortawesome/free-solid-svg-icons';
-import { faClock } from '@fortawesome/free-regular-svg-icons';
 import { getNoteSummary } from '@/misc/get-note-summary';
 import XReactionIcon from './reaction-icon.vue';
 import MkFollowButton from './follow-button.vue';
@@ -96,7 +94,6 @@ export default defineComponent({
 			groupInviteDone: false,
 			connection: null,
 			readObserver: null,
-			faIdCardAlt, faPlus, faQuoteLeft, faQuoteRight, faRetweet, faReply, faAt, faClock, faCheck, faPollH
 		};
 	},
 
@@ -271,17 +268,17 @@ export default defineComponent({
 			overflow: hidden;
 			text-overflow: ellipsis;
 
-			> [data-icon] {
+			> i {
 				vertical-align: super;
 				font-size: 50%;
 				opacity: 0.5;
 			}
 
-			> [data-icon]:first-child {
+			> i:first-child {
 				margin-right: 4px;
 			}
 
-			> [data-icon]:last-child {
+			> i:last-child {
 				margin-left: 4px;
 			}
 		}
diff --git a/src/client/components/page-window.vue b/src/client/components/page-window.vue
index 1afde255010129dbe561c5257dcfdd38d1028908..26499f7054b29164f3d8b2283570839a829acbc6 100644
--- a/src/client/components/page-window.vue
+++ b/src/client/components/page-window.vue
@@ -11,7 +11,7 @@
 		<XHeader :info="pageInfo" :with-back="false"/>
 	</template>
 	<template #buttons>
-		<button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button>
+		<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
 		<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
 	</template>
 	<div class="yrolvcoq _flat_">
@@ -22,7 +22,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExternalLinkAlt, faExpandAlt, faLink, faChevronLeft, faColumns } from '@fortawesome/free-solid-svg-icons';
 import XWindow from '@client/components/ui/window.vue';
 import XHeader from '@client/ui/_common_/header.vue';
 import { popout } from '@client/scripts/popout';
@@ -76,7 +75,6 @@ export default defineComponent({
 			component: this.initialComponent,
 			props: this.initialProps,
 			history: [],
-			faChevronLeft,
 		};
 	},
 
@@ -90,29 +88,29 @@ export default defineComponent({
 				type: 'label',
 				text: this.path,
 			}, {
-				icon: faExpandAlt,
+				icon: 'fas fa-expand-alt',
 				text: this.$ts.showInPage,
 				action: this.expand
 			}, this.sideViewHook ? {
-				icon: faColumns,
+				icon: 'fas fa-columns',
 				text: this.$ts.openInSideView,
 				action: () => {
 					this.sideViewHook(this.path);
 					this.$refs.window.close();
 				}
 			} : undefined, {
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				text: this.$ts.popout,
 				action: this.popout
 			}, null, {
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				text: this.$ts.openInNewTab,
 				action: () => {
 					window.open(this.url, '_blank');
 					this.$refs.window.close();
 				}
 			}, {
-				icon: faLink,
+				icon: 'fas fa-link',
 				text: this.$ts.copyLink,
 				action: () => {
 					copyToClipboard(this.url);
diff --git a/src/client/components/page/page.post.vue b/src/client/components/page/page.post.vue
index 926d06ae808d473a919b331d841c55b2098a7f13..1dfb506d5f8f8ff622e847ceaf95cf9e7d451f81 100644
--- a/src/client/components/page/page.post.vue
+++ b/src/client/components/page/page.post.vue
@@ -1,13 +1,15 @@
 <template>
 <div class="ngbfujlo">
 	<MkTextarea :value="text" readonly style="margin: 0;"></MkTextarea>
-	<MkButton class="button" primary @click="post()" :disabled="posting || posted"><Fa v-if="posted" :icon="faCheck"/><Fa v-else :icon="faPaperPlane"/></MkButton>
+	<MkButton class="button" primary @click="post()" :disabled="posting || posted">
+		<i v-if="posted" class="fas fa-check"></i>
+		<i v-else class="fas fa-paper-plane"></i>
+	</MkButton>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, PropType } from 'vue';
-import { faCheck, faPaperPlane } from '@fortawesome/free-solid-svg-icons';
 import MkTextarea from '../ui/textarea.vue';
 import MkButton from '../ui/button.vue';
 import { apiUrl } from '@client/config';
@@ -35,7 +37,6 @@ export default defineComponent({
 			text: this.hpml.interpolate(this.block.text),
 			posted: false,
 			posting: false,
-			faCheck, faPaperPlane
 		};
 	},
 	watch: {
diff --git a/src/client/components/poll-editor.vue b/src/client/components/poll-editor.vue
index 3503d3df7165edd0a7caf86acdadca016ef70eb3..0ade2c3ba0d83378f6e8c47556b0723c3df25cc2 100644
--- a/src/client/components/poll-editor.vue
+++ b/src/client/components/poll-editor.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="zmdxowus">
 	<p class="caution" v-if="choices.length < 2">
-		<Fa :icon="faExclamationTriangle"/>{{ $ts._poll.noOnlyOneChoice }}
+		<i class="fas fa-exclamation-triangle"></i>{{ $ts._poll.noOnlyOneChoice }}
 	</p>
 	<ul ref="choices">
 		<li v-for="(choice, i) in choices" :key="i">
@@ -9,7 +9,7 @@
 				<span>{{ $t('_poll.choiceN', { n: i + 1 }) }}</span>
 			</MkInput>
 			<button @click="remove(i)" class="_button">
-				<Fa :icon="faTimes"/>
+				<i class="fas fa-times"></i>
 			</button>
 		</li>
 	</ul>
@@ -50,7 +50,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle, faTimes } from '@fortawesome/free-solid-svg-icons';
 import { addTime } from '../../prelude/time';
 import { formatDateTimeString } from '@/misc/format-time-string';
 import MkInput from './ui/input.vue';
@@ -84,7 +83,6 @@ export default defineComponent({
 			atTime: '00:00',
 			after: 0,
 			unit: 'second',
-			faExclamationTriangle, faTimes
 		};
 	},
 
@@ -190,7 +188,7 @@ export default defineComponent({
 		font-size: 0.8em;
 		color: #f00;
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 		}
 	}
diff --git a/src/client/components/poll.vue b/src/client/components/poll.vue
index 6cf6a8e9180877a998252bf7be8cb69a2e9b6d9a..463ddab7211806ae1760f3ce55fbfc50461c517f 100644
--- a/src/client/components/poll.vue
+++ b/src/client/components/poll.vue
@@ -4,7 +4,7 @@
 		<li v-for="(choice, i) in poll.choices" :key="i" @click="vote(i)" :class="{ voted: choice.voted }">
 			<div class="backdrop" :style="{ 'width': `${showResult ? (choice.votes / total * 100) : 0}%` }"></div>
 			<span>
-				<template v-if="choice.isVoted"><Fa :icon="faCheck"/></template>
+				<template v-if="choice.isVoted"><i class="fas fa-check"></i></template>
 				<Mfm :text="choice.text" :plain="true" :custom-emojis="note.emojis"/>
 				<span class="votes" v-if="showResult">({{ $t('_poll.votesCount', { n: choice.votes }) }})</span>
 			</span>
@@ -23,7 +23,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCheck } from '@fortawesome/free-solid-svg-icons';
 import { sum } from '../../prelude/array';
 import * as os from '@client/os';
 
@@ -38,7 +37,6 @@ export default defineComponent({
 		return {
 			remaining: -1,
 			showResult: false,
-			faCheck
 		};
 	},
 	computed: {
@@ -135,7 +133,7 @@ export default defineComponent({
 			> span {
 				position: relative;
 
-				> [data-icon] {
+				> i {
 					margin-right: 4px;
 				}
 
diff --git a/src/client/components/post-form-attaches.vue b/src/client/components/post-form-attaches.vue
index f2eed304419527d0bfc86855ca726247752e9c17..eba7e7af366cbc606b593b5defb6aa1f402026cf 100644
--- a/src/client/components/post-form-attaches.vue
+++ b/src/client/components/post-form-attaches.vue
@@ -5,7 +5,7 @@
 			<div @click="showFileMenu(element, $event)" @contextmenu.prevent="showFileMenu(element, $event)">
 				<MkDriveFileThumbnail :data-id="element.id" class="thumbnail" :file="element" fit="cover"/>
 				<div class="sensitive" v-if="element.isSensitive">
-					<Fa class="icon" :icon="faExclamationTriangle"/>
+					<i class="fas fa-exclamation-triangle icon"></i>
 				</div>
 			</div>
 		</template>
@@ -16,8 +16,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faTimesCircle, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
-import { faExclamationTriangle, faICursor } from '@fortawesome/free-solid-svg-icons';
 import MkDriveFileThumbnail from './drive-file-thumbnail.vue'
 import * as os from '@client/os';
 
@@ -44,7 +42,6 @@ export default defineComponent({
 		return {
 			menu: null as Promise<null> | null,
 
-			faExclamationTriangle
 		};
 	},
 
@@ -100,11 +97,11 @@ export default defineComponent({
 				action: () => { this.rename(file) }
 			}, {
 				text: file.isSensitive ? this.$ts.unmarkAsSensitive : this.$ts.markAsSensitive,
-				icon: file.isSensitive ? faEyeSlash : faEye,
+				icon: file.isSensitive ? 'fas fa-eye-slash' : 'fas fa-eye',
 				action: () => { this.toggleSensitive(file) }
 			}, {
 				text: this.$ts.attachCancel,
-				icon: faTimesCircle,
+				icon: 'fas fa-times-circle',
 				action: () => { this.detachMedia(file.id) }
 			}], ev.currentTarget || ev.target).then(() => this.menu = null);
 		}
diff --git a/src/client/components/post-form.vue b/src/client/components/post-form.vue
index 4c6a9ebc95239e74ccc396b587a577f47e2b125d..c5186577f37c2a58c54c3b78b5d2c79f2ebb752f 100644
--- a/src/client/components/post-form.vue
+++ b/src/client/components/post-form.vue
@@ -7,31 +7,31 @@
 	@drop.stop="onDrop"
 >
 	<header>
-		<button v-if="!fixed" class="cancel _button" @click="cancel"><Fa :icon="faTimes"/></button>
+		<button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button>
 		<div>
 			<span class="text-count" :class="{ over: textLength > max }">{{ max - textLength }}</span>
-			<span class="local-only" v-if="localOnly"><Fa :icon="faBiohazard"/></span>
+			<span class="local-only" v-if="localOnly"><i class="fas fa-biohazard"></i></span>
 			<button class="_button visibility" @click="setVisibility" ref="visibilityButton" v-tooltip="$ts.visibility" :disabled="channel != null">
-				<span v-if="visibility === 'public'"><Fa :icon="faGlobe"/></span>
-				<span v-if="visibility === 'home'"><Fa :icon="faHome"/></span>
-				<span v-if="visibility === 'followers'"><Fa :icon="faUnlock"/></span>
-				<span v-if="visibility === 'specified'"><Fa :icon="faEnvelope"/></span>
+				<span v-if="visibility === 'public'"><i class="fas fa-globe"></i></span>
+				<span v-if="visibility === 'home'"><i class="fas fa-home"></i></span>
+				<span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span>
+				<span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span>
 			</button>
-			<button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<Fa :icon="reply ? faReply : renote ? faQuoteRight : faPaperPlane"/></button>
+			<button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
 		</div>
 	</header>
 	<div class="form" :class="{ fixed }">
 		<XNotePreview class="preview" v-if="reply" :note="reply"/>
 		<XNotePreview class="preview" v-if="renote" :note="renote"/>
-		<div class="with-quote" v-if="quoteId"><Fa icon="quote-left"/> {{ $ts.quoteAttached }}<button @click="quoteId = null"><Fa icon="times"/></button></div>
+		<div class="with-quote" v-if="quoteId"><i class="fas fa-quote-left"></i> {{ $ts.quoteAttached }}<button @click="quoteId = null"><i class="fas fa-times"></i></button></div>
 		<div v-if="visibility === 'specified'" class="to-specified">
 			<span style="margin-right: 8px;">{{ $ts.recipient }}</span>
 			<div class="visibleUsers">
 				<span v-for="u in visibleUsers" :key="u.id">
 					<MkAcct :user="u"/>
-					<button class="_button" @click="removeVisibleUser(u)"><Fa :icon="faTimes"/></button>
+					<button class="_button" @click="removeVisibleUser(u)"><i class="fas fa-times"></i></button>
 				</span>
-				<button @click="addVisibleUser" class="_buttonPrimary"><Fa :icon="faPlus" fixed-width/></button>
+				<button @click="addVisibleUser" class="_buttonPrimary"><i class="fas fa-plus fa-fw"></i></button>
 			</div>
 		</div>
 		<MkInfo warn v-if="hasNotSpecifiedMentions" class="hasNotSpecifiedMentions">{{ $ts.notSpecifiedMentionWarning }} - <button class="_textButton" @click="addMissingMention()">{{ $ts.add }}</button></MkInfo>
@@ -40,12 +40,12 @@
 		<XPostFormAttaches class="attaches" :files="files" @updated="updateFiles" @detach="detachFile" @changeSensitive="updateFileSensitive" @changeName="updateFileName"/>
 		<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
 		<footer>
-			<button class="_button" @click="chooseFileFrom" v-tooltip="$ts.attachFile"><Fa :icon="faPhotoVideo"/></button>
-			<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><Fa :icon="faPollH"/></button>
-			<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$ts.useCw"><Fa :icon="faEyeSlash"/></button>
-			<button class="_button" @click="insertMention" v-tooltip="$ts.mention"><Fa :icon="faAt"/></button>
-			<button class="_button" @click="insertEmoji" v-tooltip="$ts.emoji"><Fa :icon="faLaughSquint"/></button>
-			<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><Fa :icon="faPlug"/></button>
+			<button class="_button" @click="chooseFileFrom" v-tooltip="$ts.attachFile"><i class="fas fa-photo-video"></i></button>
+			<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><i class="fas fa-poll-h"></i></button>
+			<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$ts.useCw"><i class="fas fa-eye-slash"></i></button>
+			<button class="_button" @click="insertMention" v-tooltip="$ts.mention"><i class="fas fa-at"></i></button>
+			<button class="_button" @click="insertEmoji" v-tooltip="$ts.emoji"><i class="fas fa-laugh-squint"></i></button>
+			<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><i class="fas fa-plug"></i></button>
 		</footer>
 	</div>
 </div>
@@ -53,8 +53,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faAt, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
-import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons';
 import insertTextAtCursor from 'insert-text-at-cursor';
 import { length } from 'stringz';
 import { toASCII } from 'punycode/';
@@ -155,7 +153,6 @@ export default defineComponent({
 				}
 			}),
 			postFormActions,
-			faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faAt, faBiohazard, faPlug
 		};
 	},
 
@@ -724,7 +721,7 @@ export default defineComponent({
 					opacity: 0.7;
 				}
 
-				> [data-icon] {
+				> i {
 					margin-left: 6px;
 				}
 			}
diff --git a/src/client/components/remote-caution.vue b/src/client/components/remote-caution.vue
index c9c5ceea4c1f8948e83c9a2c37fbe11ad0900ff2..985ae446942f6e85be96fe824f39928131533fdc 100644
--- a/src/client/components/remote-caution.vue
+++ b/src/client/components/remote-caution.vue
@@ -1,10 +1,9 @@
 <template>
-<div class="jmgmzlwq _block"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/>{{ $ts.remoteUserCaution }}<a :href="href" rel="nofollow noopener" target="_blank">{{ $ts.showOnRemote }}</a></div>
+<div class="jmgmzlwq _block"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i>{{ $ts.remoteUserCaution }}<a :href="href" rel="nofollow noopener" target="_blank">{{ $ts.showOnRemote }}</a></div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -16,7 +15,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faExclamationTriangle
 		};
 	}
 });
diff --git a/src/client/components/signin.vue b/src/client/components/signin.vue
index 1cd79bac1d697579e85c184f2d758121a71940ce..2c883e0c32c0cf07c77984b57e6161ec3b6ad946 100755
--- a/src/client/components/signin.vue
+++ b/src/client/components/signin.vue
@@ -10,7 +10,7 @@
 			</MkInput>
 			<MkInput v-model:value="password" type="password" :with-password-toggle="true" v-if="!user || user && !user.usePasswordLessLogin" required>
 				<span>{{ $ts.password }}</span>
-				<template #prefix><Fa :icon="faLock"/></template>
+				<template #prefix><i class="fas fa-lock"></i></template>
 			</MkInput>
 			<MkButton type="submit" primary :disabled="signing" style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
 		</div>
@@ -28,20 +28,20 @@
 				<p style="margin-bottom:0;">{{ $ts.twoStepAuthentication }}</p>
 				<MkInput v-model:value="password" type="password" :with-password-toggle="true" v-if="user && user.usePasswordLessLogin" required>
 					<span>{{ $ts.password }}</span>
-					<template #prefix><Fa :icon="faLock"/></template>
+					<template #prefix><i class="fas fa-lock"></i></template>
 				</MkInput>
 				<MkInput v-model:value="token" type="text" pattern="^[0-9]{6}$" autocomplete="off" spellcheck="false" required>
 					<span>{{ $ts.token }}</span>
-					<template #prefix><Fa :icon="faGavel"/></template>
+					<template #prefix><i class="fas fa-gavel"></i></template>
 				</MkInput>
 				<MkButton type="submit" :disabled="signing" primary style="margin: 0 auto;">{{ signing ? $ts.loggingIn : $ts.login }}</MkButton>
 			</div>
 		</div>
 	</div>
 	<div class="social _section">
-		<a class="_borderButton _gap" v-if="meta && meta.enableTwitterIntegration" :href="`${apiUrl}/signin/twitter`"><Fa :icon="faTwitter" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Twitter' }) }}</a>
-		<a class="_borderButton _gap" v-if="meta && meta.enableGithubIntegration" :href="`${apiUrl}/signin/github`"><Fa :icon="faGithub" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'GitHub' }) }}</a>
-		<a class="_borderButton _gap" v-if="meta && meta.enableDiscordIntegration" :href="`${apiUrl}/signin/discord`"><Fa :icon="faDiscord" style="margin-right: 4px;"/>{{ $t('signinWith', { x: 'Discord' }) }}</a>
+		<a class="_borderButton _gap" v-if="meta && meta.enableTwitterIntegration" :href="`${apiUrl}/signin/twitter`"><i class="fab fa-twitter" style="margin-right: 4px;"></i>{{ $t('signinWith', { x: 'Twitter' }) }}</a>
+		<a class="_borderButton _gap" v-if="meta && meta.enableGithubIntegration" :href="`${apiUrl}/signin/github`"><i class="fab fa-github" style="margin-right: 4px;"></i>{{ $t('signinWith', { x: 'GitHub' }) }}</a>
+		<a class="_borderButton _gap" v-if="meta && meta.enableDiscordIntegration" :href="`${apiUrl}/signin/discord`"><i class="fab fa-discord" style="margin-right: 4px;"></i>{{ $t('signinWith', { x: 'Discord' }) }}</a>
 	</div>
 </form>
 </template>
@@ -49,8 +49,6 @@
 <script lang="ts">
 import { defineComponent } from 'vue';
 import { toUnicode } from 'punycode/';
-import { faLock, faGavel } from '@fortawesome/free-solid-svg-icons';
-import { faTwitter, faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons';
 import MkButton from './ui/button.vue';
 import MkInput from './ui/input.vue';
 import { apiUrl, host } from '@client/config';
@@ -92,7 +90,6 @@ export default defineComponent({
 			credential: null,
 			challengeData: null,
 			queryingKey: false,
-			faLock, faGavel, faTwitter, faDiscord, faGithub
 		};
 	},
 
diff --git a/src/client/components/signup.vue b/src/client/components/signup.vue
index 66d01213bc8fbef8a678e8590224d442e24ae5c2..671642b2915b289976d6be6372b5f315392818db 100644
--- a/src/client/components/signup.vue
+++ b/src/client/components/signup.vue
@@ -3,37 +3,37 @@
 	<template v-if="meta">
 		<MkInput v-if="meta.disableRegistration" v-model:value="invitationCode" type="text" :autocomplete="Math.random()" spellcheck="false" required>
 			<span>{{ $ts.invitationCode }}</span>
-			<template #prefix><Fa :icon="faKey"/></template>
+			<template #prefix><i class="fas fa-key"></i></template>
 		</MkInput>
 		<MkInput v-model:value="username" type="text" pattern="^[a-zA-Z0-9_]{1,20}$" :autocomplete="Math.random()" spellcheck="false" required @update:value="onChangeUsername">
 			<span>{{ $ts.username }}</span>
 			<template #prefix>@</template>
 			<template #suffix>@{{ host }}</template>
 			<template #desc>
-				<span v-if="usernameState == 'wait'" style="color:#999"><Fa :icon="faSpinner" pulse fixed-width/> {{ $ts.checking }}</span>
-				<span v-if="usernameState == 'ok'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.available }}</span>
-				<span v-if="usernameState == 'unavailable'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.unavailable }}</span>
-				<span v-if="usernameState == 'error'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.error }}</span>
-				<span v-if="usernameState == 'invalid-format'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.usernameInvalidFormat }}</span>
-				<span v-if="usernameState == 'min-range'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.tooShort }}</span>
-				<span v-if="usernameState == 'max-range'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.tooLong }}</span>
+				<span v-if="usernameState == 'wait'" style="color:#999"><i class="fas fa-spinner fa-pulse fa-fw"></i> {{ $ts.checking }}</span>
+				<span v-if="usernameState == 'ok'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.available }}</span>
+				<span v-if="usernameState == 'unavailable'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.unavailable }}</span>
+				<span v-if="usernameState == 'error'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.error }}</span>
+				<span v-if="usernameState == 'invalid-format'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.usernameInvalidFormat }}</span>
+				<span v-if="usernameState == 'min-range'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooShort }}</span>
+				<span v-if="usernameState == 'max-range'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.tooLong }}</span>
 			</template>
 		</MkInput>
 		<MkInput v-model:value="password" type="password" :autocomplete="Math.random()" required @update:value="onChangePassword">
 			<span>{{ $ts.password }}</span>
-			<template #prefix><Fa :icon="faLock"/></template>
+			<template #prefix><i class="fas fa-lock"></i></template>
 			<template #desc>
-				<p v-if="passwordStrength == 'low'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.weakPassword }}</p>
-				<p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.normalPassword }}</p>
-				<p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.strongPassword }}</p>
+				<p v-if="passwordStrength == 'low'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.weakPassword }}</p>
+				<p v-if="passwordStrength == 'medium'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.normalPassword }}</p>
+				<p v-if="passwordStrength == 'high'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.strongPassword }}</p>
 			</template>
 		</MkInput>
 		<MkInput v-model:value="retypedPassword" type="password" :autocomplete="Math.random()" required @update:value="onChangePasswordRetype">
 			<span>{{ $ts.password }} ({{ $ts.retype }})</span>
-			<template #prefix><Fa :icon="faLock"/></template>
+			<template #prefix><i class="fas fa-lock"></i></template>
 			<template #desc>
-				<p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><Fa :icon="faCheck" fixed-width/> {{ $ts.passwordMatched }}</p>
-				<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><Fa :icon="faExclamationTriangle" fixed-width/> {{ $ts.passwordNotMatched }}</p>
+				<p v-if="passwordRetypeState == 'match'" style="color:#3CB7B5"><i class="fas fa-check fa-fw"></i> {{ $ts.passwordMatched }}</p>
+				<p v-if="passwordRetypeState == 'not-match'" style="color:#FF1161"><i class="fas fa-exclamation-triangle fa-fw"></i> {{ $ts.passwordNotMatched }}</p>
 			</template>
 		</MkInput>
 		<label v-if="meta.tosUrl" class="tou">
@@ -45,7 +45,7 @@
 			</I18n>
 		</label>
 		<captcha v-if="meta.enableHcaptcha" class="captcha" provider="hcaptcha" ref="hcaptcha" v-model:value="hCaptchaResponse" :sitekey="meta.hcaptchaSiteKey"/>
-		<captcha v-if="meta.enableRecaptcha" class="captcha" provider="grecaptcha" ref="recaptcha" v-model:value="reCaptchaResponse" :sitekey="meta.recaptchaSiteKey"/>
+		<captcha v-if="meta.enableRecaptcha" class="captcha" provider="recaptcha" ref="recaptcha" v-model:value="reCaptchaResponse" :sitekey="meta.recaptchaSiteKey"/>
 		<MkButton type="submit" :disabled="shouldDisableSubmitting" primary>{{ $ts.start }}</MkButton>
 	</template>
 </form>
@@ -53,7 +53,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faLock, faExclamationTriangle, faSpinner, faCheck, faKey } from '@fortawesome/free-solid-svg-icons';
 const getPasswordStrength = require('syuilo-password-strength');
 import { toUnicode } from 'punycode/';
 import { host, url } from '@client/config';
@@ -96,7 +95,6 @@ export default defineComponent({
 			ToSAgreement: false,
 			hCaptchaResponse: null,
 			reCaptchaResponse: null,
-			faLock, faExclamationTriangle, faSpinner, faCheck, faKey
 		}
 	},
 
diff --git a/src/client/components/sub-note-content.vue b/src/client/components/sub-note-content.vue
index 384bcb4563c0f53c1017c3d80e7f018216898ae7..ff89a9887b1ee02a3f85845977de12d0e380e921 100644
--- a/src/client/components/sub-note-content.vue
+++ b/src/client/components/sub-note-content.vue
@@ -3,7 +3,7 @@
 	<div class="body">
 		<span v-if="note.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
 		<span v-if="note.deletedAt" style="opacity: 0.5">({{ $ts.deleted }})</span>
-		<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></MkA>
+		<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><i class="fas fa-reply"></i></MkA>
 		<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
 		<MkA class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
 	</div>
@@ -20,7 +20,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faReply } from '@fortawesome/free-solid-svg-icons';
 import XPoll from './poll.vue';
 import XMediaList from './media-list.vue';
 import * as os from '@client/os';
@@ -38,7 +37,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faReply
 		};
 	}
 });
diff --git a/src/client/components/tab.vue b/src/client/components/tab.vue
index aca4d32a220f47fa9fcf2416abf41cbd30ef8c63..96cbe50fb194ae5db5f1683b78eb73918b95c000 100644
--- a/src/client/components/tab.vue
+++ b/src/client/components/tab.vue
@@ -29,6 +29,7 @@ export default defineComponent({
 <style lang="scss">
 .pxhvhrfw {
 	display: flex;
+	font-size: 90%;
 
 	> button {
 		flex: 1;
diff --git a/src/client/components/taskmanager.vue b/src/client/components/taskmanager.vue
index 1339e2e35291538bc00770b5f7129ea9664889c6..cb8cb7874871ed9bc30a73eff90ef7cbc34c7d1b 100644
--- a/src/client/components/taskmanager.vue
+++ b/src/client/components/taskmanager.vue
@@ -1,7 +1,7 @@
 <template>
 <XWindow ref="window" :initial-width="650" :initial-height="420" :can-resize="true" @closed="$emit('closed')">
 	<template #header>
-		<Fa :icon="faTerminal" style="margin-right: 0.5em;"/>Task Manager
+		<i class="fas fa-terminal" style="margin-right: 0.5em;"></i>Task Manager
 	</template>
 	<div class="qljqmnzj _monospace">
 		<MkTab v-model:value="tab" style="border-bottom: solid 0.5px var(--divider);">
@@ -78,7 +78,6 @@
 
 <script lang="ts">
 import { defineComponent, markRaw, onBeforeUnmount, ref, shallowRef } from 'vue';
-import { faTerminal } from '@fortawesome/free-solid-svg-icons';
 import XWindow from '@client/components/ui/window.vue';
 import MkTab from '@client/components/tab.vue';
 import MkButton from '@client/components/ui/button.vue';
@@ -139,7 +138,6 @@ export default defineComponent({
 			pools,
 			killPopup,
 			showReq,
-			faTerminal,
 		};
 	},
 });
diff --git a/src/client/components/ui/container.vue b/src/client/components/ui/container.vue
index ecd48876e826b84d47ad354a9287cc57c6bfd151..cfd928518e45e59e47aeddae825d4a46138acbc5 100644
--- a/src/client/components/ui/container.vue
+++ b/src/client/components/ui/container.vue
@@ -5,8 +5,8 @@
 		<div class="sub">
 			<slot name="func"></slot>
 			<button class="_button" v-if="foldable" @click="() => showBody = !showBody">
-				<template v-if="showBody"><Fa :icon="faAngleUp"/></template>
-				<template v-else><Fa :icon="faAngleDown"/></template>
+				<template v-if="showBody"><i class="fas fa-angle-up"></i></template>
+				<template v-else><i class="fas fa-angle-down"></i></template>
 			</button>
 		</div>
 	</header>
@@ -28,7 +28,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
 
 export default defineComponent({
 	props: {
@@ -68,7 +67,6 @@ export default defineComponent({
 			showBody: this.expanded,
 			omitted: null,
 			ignoreOmit: false,
-			faAngleUp, faAngleDown
 		};
 	},
 	mounted() {
@@ -169,7 +167,7 @@ export default defineComponent({
 			margin: 0;
 			padding: 12px 16px;
 
-			> ::v-deep([data-icon]) {
+			> ::v-deep(i) {
 				margin-right: 6px;
 			}
 
diff --git a/src/client/components/ui/folder.vue b/src/client/components/ui/folder.vue
index aee3c0ccaa392ab317cdd4a769fed67cf7386a6d..4281ec77788cfa73bc44c0061100ef207db3d4c9 100644
--- a/src/client/components/ui/folder.vue
+++ b/src/client/components/ui/folder.vue
@@ -4,8 +4,8 @@
 		<div class="title"><slot name="header"></slot></div>
 		<div class="divider"></div>
 		<button class="_button">
-			<template v-if="showBody"><Fa :icon="faAngleUp"/></template>
-			<template v-else><Fa :icon="faAngleDown"/></template>
+			<template v-if="showBody"><i class="fas fa-angle-up"></i></template>
+			<template v-else><i class="fas fa-angle-down"></i></template>
 		</button>
 	</header>
 	<transition name="folder-toggle"
@@ -23,7 +23,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
 
 const localStoragePrefix = 'ui:folder:';
 
@@ -43,7 +42,6 @@ export default defineComponent({
 	data() {
 		return {
 			showBody: (this.persistKey && localStorage.getItem(localStoragePrefix + this.persistKey)) ? localStorage.getItem(localStoragePrefix + this.persistKey) === 't' : this.expanded,
-			faAngleUp, faAngleDown
 		};
 	},
 	watch: {
@@ -109,7 +107,7 @@ export default defineComponent({
 			margin: 0;
 			padding: 12px 16px 12px 0;
 
-			> [data-icon] {
+			> i {
 				margin-right: 6px;
 			}
 
diff --git a/src/client/components/ui/info.vue b/src/client/components/ui/info.vue
index ad1b9ebb5855ffce2c289b5bc9113636a6204212..513682ef55ce224e9dd2cf0079c25aabc3536b53 100644
--- a/src/client/components/ui/info.vue
+++ b/src/client/components/ui/info.vue
@@ -1,14 +1,13 @@
 <template>
 <div class="fpezltsf" :class="{ warn }">
-	<i v-if="warn"><Fa :icon="faExclamationTriangle"/></i>
-	<i v-else><Fa :icon="faInfoCircle"/></i>
+	<i v-if="warn" class="fas fa-exclamation-triangle"></i>
+	<i v-else class="fas fa-info-circle"></i>
 	<slot></slot>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faInfoCircle, faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -21,7 +20,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faInfoCircle, faExclamationTriangle
 		};
 	}
 });
diff --git a/src/client/components/ui/input.vue b/src/client/components/ui/input.vue
index 302d96d026899beaac99f70e4b50950f08d2ac65..7415d9896b93c5b43c275bd6b63d9554c8e2a3ae 100644
--- a/src/client/components/ui/input.vue
+++ b/src/client/components/ui/input.vue
@@ -5,7 +5,7 @@
 		<span class="label" ref="labelEl"><slot></slot></span>
 		<span class="title" ref="title">
 			<slot name="title"></slot>
-			<span class="warning" v-if="invalid"><Fa :icon="faExclamationCircle"/>{{ $refs.input.validationMessage }}</span>
+			<span class="warning" v-if="invalid"><i class="fas fa-exclamation-circle"></i>{{ $refs.input.validationMessage }}</span>
 		</span>
 		<div class="prefix" ref="prefixEl"><slot name="prefix"></slot></div>
 		<input v-if="debounce" ref="inputEl"
@@ -56,7 +56,6 @@
 <script lang="ts">
 import { defineComponent, onMounted, onUnmounted, nextTick, ref, watch, computed, toRefs } from 'vue';
 import debounce from 'v-debounce';
-import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
@@ -205,7 +204,6 @@ export default defineComponent({
 			focus,
 			onInput,
 			onKeydown,
-			faExclamationCircle,
 		};
 	},
 });
diff --git a/src/client/components/ui/menu.vue b/src/client/components/ui/menu.vue
index 1550fe40c7361b0dc8cc7be5ee2b41826baabaac..eb9645077429f6ce59ef6f398ced0c012169a723 100644
--- a/src/client/components/ui/menu.vue
+++ b/src/client/components/ui/menu.vue
@@ -13,25 +13,25 @@
 			<span><MkEllipsis/></span>
 		</span>
 		<MkA v-else-if="item.type === 'link'" :to="item.to" @click.passive="close()" :tabindex="i" class="_button item">
-			<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
+			<i v-if="item.icon" class="fa-fw" :class="item.icon"></i>
 			<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
 			<span>{{ item.text }}</span>
-			<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
+			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
 		</MkA>
 		<a v-else-if="item.type === 'a'" :href="item.href" :target="item.target" :download="item.download" @click="close()" :tabindex="i" class="_button item">
-			<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
+			<i v-if="item.icon" class="fa-fw" :class="item.icon"></i>
 			<span>{{ item.text }}</span>
-			<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
+			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
 		</a>
 		<button v-else-if="item.type === 'user'" @click="clicked(item.action, $event)" :tabindex="i" class="_button item">
 			<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
-			<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
+			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
 		</button>
 		<button v-else @click="clicked(item.action, $event)" :tabindex="i" class="_button item" :class="{ danger: item.danger }">
-			<Fa v-if="item.icon" :icon="item.icon" fixed-width/>
+			<i v-if="item.icon" class="fa-fw" :class="item.icon"></i>
 			<MkAvatar v-if="item.avatar" :user="item.avatar" class="avatar"/>
 			<span>{{ item.text }}</span>
-			<i v-if="item.indicate"><Fa :icon="faCircle"/></i>
+			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
 		</button>
 	</template>
 	<span v-if="_items.length === 0" class="none item">
@@ -42,7 +42,6 @@
 
 <script lang="ts">
 import { defineComponent, ref } from 'vue';
-import { faCircle } from '@fortawesome/free-solid-svg-icons';
 import { focusPrev, focusNext } from '@client/scripts/focus';
 import contains from '@client/scripts/contains';
 
@@ -65,7 +64,6 @@ export default defineComponent({
 	data() {
 		return {
 			_items: [],
-			faCircle,
 		};
 	},
 	computed: {
@@ -207,7 +205,7 @@ export default defineComponent({
 			opacity: 0.7;
 		}
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 			width: 20px;
 		}
@@ -218,7 +216,7 @@ export default defineComponent({
 			height: 20px;
 		}
 
-		> i {
+		> .indicator {
 			position: absolute;
 			top: 5px;
 			left: 13px;
diff --git a/src/client/components/ui/modal-window.vue b/src/client/components/ui/modal-window.vue
index 90b803801da4d61dca2390331f28bc7101e5a423..2d2b587662b057b1547533fdab3aa9311cf8a8fc 100644
--- a/src/client/components/ui/modal-window.vue
+++ b/src/client/components/ui/modal-window.vue
@@ -2,12 +2,12 @@
 <MkModal ref="modal" @click="$emit('click')" @closed="$emit('closed')">
 	<div class="ebkgoccj _popup _narrow_" @keydown="onKeydown" :style="{ width: `${width}px`, height: scroll ? (height ? `${height}px` : null) :  (height ? `min(${height}px, 100%)` : '100%') }">
 		<div class="header">
-			<button class="_button" v-if="withOkButton" @click="$emit('close')"><Fa :icon="faTimes"/></button>
+			<button class="_button" v-if="withOkButton" @click="$emit('close')"><i class="fas fa-times"></i></button>
 			<span class="title">
 				<slot name="header"></slot>
 			</span>
-			<button class="_button" v-if="!withOkButton" @click="$emit('close')"><Fa :icon="faTimes"/></button>
-			<button class="_button" v-if="withOkButton" @click="$emit('ok')" :disabled="okButtonDisabled"><Fa :icon="faCheck"/></button>
+			<button class="_button" v-if="!withOkButton" @click="$emit('close')"><i class="fas fa-times"></i></button>
+			<button class="_button" v-if="withOkButton" @click="$emit('ok')" :disabled="okButtonDisabled"><i class="fas fa-check"></i></button>
 		</div>
 		<div class="body" v-if="padding">
 			<div class="_section">
@@ -23,7 +23,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTimes, faCheck } from '@fortawesome/free-solid-svg-icons';
 import MkModal from './modal.vue';
 
 export default defineComponent({
@@ -72,7 +71,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faTimes, faCheck
 		};
 	},
 
diff --git a/src/client/components/ui/pagination.vue b/src/client/components/ui/pagination.vue
index 13181d39e23ec96ab15dff81cabab15922de73fe..ac8ed01e1272f51ec6ee5d27da0fb17c527b55ce 100644
--- a/src/client/components/ui/pagination.vue
+++ b/src/client/components/ui/pagination.vue
@@ -1,16 +1,23 @@
 <template>
-<div class="cxiknjgy">
-	<slot :items="items"></slot>
-	<div class="empty" v-if="empty" key="_empty_">
+<transition name="fade" mode="out-in">
+	<MkLoading v-if="fetching"/>
+
+	<MkError v-else-if="error" @retry="init()"/>
+
+	<div class="empty" v-else-if="empty" key="_empty_">
 		<slot name="empty"></slot>
 	</div>
-	<div class="more" v-show="more" key="_more_">
-		<MkButton class="button" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
-			<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
-			<template v-if="moreFetching"><MkLoading inline/></template>
-		</MkButton>
+
+	<div v-else class="cxiknjgy">
+		<slot :items="items"></slot>
+		<div class="more" v-show="more" key="_more_">
+			<MkButton class="button" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :disabled="moreFetching" :style="{ cursor: moreFetching ? 'wait' : 'pointer' }" primary>
+				<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
+				<template v-if="moreFetching"><MkLoading inline/></template>
+			</MkButton>
+		</div>
 	</div>
-</div>
+</transition>
 </template>
 
 <script lang="ts">
@@ -36,6 +43,15 @@ export default defineComponent({
 </script>
 
 <style lang="scss" scoped>
+.fade-enter-active,
+.fade-leave-active {
+	transition: opacity 0.125s ease;
+}
+.fade-enter-from,
+.fade-leave-to {
+	opacity: 0;
+}
+
 .cxiknjgy {
 	> .more > .button {
 		margin-left: auto;
diff --git a/src/client/components/ui/select.vue b/src/client/components/ui/select.vue
index d9250a62cd500aa7a479d815eb10d6f7eb6b1e7b..e78c44fe0d542fb3c59cf897068df8f7a25a06f2 100644
--- a/src/client/components/ui/select.vue
+++ b/src/client/components/ui/select.vue
@@ -15,7 +15,7 @@
 		</select>
 		<div class="suffix">
 			<slot name="suffix">
-				<Fa :icon="faChevronDown"/>
+				<i class="fas fa-chevron-down"></i>
 			</slot>
 		</div>
 	</div>
@@ -25,7 +25,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
 
 export default defineComponent({
 	props: {
@@ -49,7 +48,6 @@ export default defineComponent({
 	data() {
 		return {
 			focused: false,
-			faChevronDown,
 		};
 	},
 	computed: {
diff --git a/src/client/components/ui/window.vue b/src/client/components/ui/window.vue
index 70676cdaf5f6cb70ad3e17c0cebb15fda5495431..ce621ac6fd383aed887ed2223bc5cbdaba2f538c 100644
--- a/src/client/components/ui/window.vue
+++ b/src/client/components/ui/window.vue
@@ -4,13 +4,13 @@
 		<div class="body _popup _shadow _narrow_" @mousedown="onBodyMousedown" @keydown="onKeydown">
 			<div class="header" :class="{ mini }" @contextmenu.prevent.stop="onContextmenu">
 				<slot v-if="closeRight" name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
-				<button v-else class="_button" @click="close()"><Fa :icon="faTimes"/></button>
+				<button v-else class="_button" @click="close()"><i class="fas fa-times"></i></button>
 
 				<span class="title" @mousedown.prevent="onHeaderMousedown" @touchstart.prevent="onHeaderMousedown">
 					<slot name="header"></slot>
 				</span>
 
-				<button v-if="closeRight" class="_button" @click="close()"><Fa :icon="faTimes"/></button>
+				<button v-if="closeRight" class="_button" @click="close()"><i class="fas fa-times"></i></button>
 				<slot v-else name="buttons"><button class="_button" style="pointer-events: none;"></button></slot>
 			</div>
 			<div class="body" v-if="padding">
@@ -38,7 +38,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTimes, faCheck } from '@fortawesome/free-solid-svg-icons';
 import contains from '@client/scripts/contains';
 import * as os from '@client/os';
 
@@ -114,7 +113,6 @@ export default defineComponent({
 		return {
 			showing: true,
 			id: Math.random().toString(), // TODO: UUIDとかにする
-			faTimes
 		};
 	},
 
diff --git a/src/client/components/url-preview.vue b/src/client/components/url-preview.vue
index 7495da6f24745a6e74e76c9adee7b0d6249c879d..1d44b045784543eaab6f0f63949e824e1c3b473e 100644
--- a/src/client/components/url-preview.vue
+++ b/src/client/components/url-preview.vue
@@ -1,6 +1,6 @@
 <template>
 <div v-if="playerEnabled" class="player" :style="`padding: ${(player.height || 0) / (player.width || 1) * 100}% 0 0`">
-	<button class="disablePlayer" @click="playerEnabled = false" :title="$ts.disablePlayer"><Fa icon="times"/></button>
+	<button class="disablePlayer" @click="playerEnabled = false" :title="$ts.disablePlayer"><i class="fas fa-times"></i></button>
 	<iframe :src="player.url + (player.url.match(/\?/) ? '&autoplay=1&auto_play=1' : '?autoplay=1&auto_play=1')" :width="player.width || '100%'" :heigth="player.height || 250" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen />
 </div>
 <div v-else-if="tweetId && tweetExpanded" class="twitter" ref="twitter">
@@ -10,7 +10,7 @@
 	<transition name="zoom" mode="out-in">
 		<component :is="self ? 'MkA' : 'a'" :class="{ compact }" :[attr]="self ? url.substr(local.length) : url" rel="nofollow noopener" :target="target" :title="url" v-if="!fetching">
 			<div class="thumbnail" v-if="thumbnail" :style="`background-image: url('${thumbnail}')`">
-				<button class="_button" v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$ts.enablePlayer"><Fa :icon="faPlayCircle"/></button>
+				<button class="_button" v-if="!playerEnabled && player.url" @click.prevent="playerEnabled = true" :title="$ts.enablePlayer"><i class="fas fa-play-circle"></i></button>
 			</div>
 			<article>
 				<header>
@@ -26,7 +26,7 @@
 	</transition>
 	<div class="expandTweet" v-if="tweetId">
 		<a @click="tweetExpanded = true">
-			<Fa :icon="faTwitter"/> {{ $ts.expandTweet }}
+			<i class="fab fa-twitter"></i> {{ $ts.expandTweet }}
 		</a>
 	</div>
 </div>
@@ -34,8 +34,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlayCircle } from '@fortawesome/free-regular-svg-icons';
-import { faTwitter } from '@fortawesome/free-brands-svg-icons'; 
 import { url as local, lang } from '@client/config';
 import * as os from '@client/os';
 
@@ -83,7 +81,6 @@ export default defineComponent({
 			self: self,
 			attr: self ? 'to' : 'href',
 			target: self ? null : '_blank',
-			faPlayCircle, faTwitter
 		};
 	},
 
diff --git a/src/client/components/user-list.vue b/src/client/components/user-list.vue
index 38d9df63bb00940ef5efb616976490369b8eaee6..a7162ddcc259b79d7cd16215be6e377ba6cbcc58 100644
--- a/src/client/components/user-list.vue
+++ b/src/client/components/user-list.vue
@@ -9,7 +9,7 @@
 		<MkUserInfo class="user" v-for="user in users" :user="user" :key="user.id"/>
 	</div>
 	<button class="more" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" :class="{ fetching: moreFetching }" v-show="more" :disabled="moreFetching">
-		<template v-if="moreFetching"><Fa icon="spinner" pulse fixed-width/></template>{{ moreFetching ? $ts.loading : $ts.loadMore }}
+		<template v-if="moreFetching"><i class="fas fa-spinner fa-pulse fa-fw"></i></template>{{ moreFetching ? $ts.loading : $ts.loadMore }}
 	</button>
 </div>
 </template>
@@ -83,7 +83,7 @@ export default defineComponent({
 			cursor: wait;
 		}
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 		}
 	}
diff --git a/src/client/components/user-online-indicator.vue b/src/client/components/user-online-indicator.vue
index bb98978bba89eb5161807f720b1b080b3f6877c7..afaf0e8736d4e70b0aae0a87efecb512181f9e40 100644
--- a/src/client/components/user-online-indicator.vue
+++ b/src/client/components/user-online-indicator.vue
@@ -29,7 +29,7 @@ export default defineComponent({
 <style lang="scss" scoped>
 .fzgwjkgc {
 	box-shadow: 0 0 0 3px var(--panel);
-	border-radius: 100%;
+	border-radius: 120%; // Blinkのバグか知らんけど、100%ぴったりにすると何故か若干楕円でレンダリングされる
 
 	&.online {
 		background: #58d4c9;
diff --git a/src/client/components/user-select-dialog.vue b/src/client/components/user-select-dialog.vue
index a243e182e8a7002847aa6a3c90c0e868509fea80..620c8eee280a7e952a3cee4bdb40f28880799a7e 100644
--- a/src/client/components/user-select-dialog.vue
+++ b/src/client/components/user-select-dialog.vue
@@ -44,7 +44,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTimes, faCheck } from '@fortawesome/free-solid-svg-icons';
 import MkInput from './ui/input.vue';
 import XModalWindow from '@client/components/ui/modal-window.vue';
 import * as os from '@client/os';
@@ -67,7 +66,6 @@ export default defineComponent({
 			recentUsers: [],
 			users: [],
 			selected: null,
-			faTimes, faCheck
 		};
 	},
 
diff --git a/src/client/components/users-dialog.vue b/src/client/components/users-dialog.vue
index ebf867f702ffd5cbac249c63fc632886448f6ea8..90cd926f0c88d2528a8f655f19dc4eadbc3e7f68 100644
--- a/src/client/components/users-dialog.vue
+++ b/src/client/components/users-dialog.vue
@@ -2,7 +2,7 @@
 <div class="mk-users-dialog">
 	<div class="header">
 		<span>{{ title }}</span>
-		<button class="_button" @click="close()"><Fa :icon="faTimes"/></button>
+		<button class="_button" @click="close()"><i class="fas fa-times"></i></button>
 	</div>
 
 	<div class="users">
@@ -16,7 +16,7 @@
 	</div>
 	<button class="more _button" v-appear="$store.state.enableInfiniteScroll ? fetchMore : null" @click="fetchMore" v-show="more" :disabled="moreFetching">
 		<template v-if="!moreFetching">{{ $ts.loadMore }}</template>
-		<template v-if="moreFetching"><Fa :icon="faSpinner" pulse fixed-width/></template>
+		<template v-if="moreFetching"><i class="fas fa-spinner fa-pulse fa-fw"></i></template>
 	</button>
 
 	<p class="empty" v-if="empty">{{ $ts.noUsers }}</p>
@@ -27,7 +27,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTimes } from '@fortawesome/free-solid-svg-icons';
 import paging from '@client/scripts/paging';
 import { userPage } from '../filters/user';
 
@@ -50,7 +49,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faTimes
 		};
 	},
 
diff --git a/src/client/components/visibility-picker.vue b/src/client/components/visibility-picker.vue
index caa2b116a6fb0fb6ffdb842f13094a7a7709dbb8..492ec092e3d58d84b1d42be5c54bfb902e406712 100644
--- a/src/client/components/visibility-picker.vue
+++ b/src/client/components/visibility-picker.vue
@@ -2,28 +2,28 @@
 <MkModal ref="modal" :src="src" @click="$refs.modal.close()" @closed="$emit('closed')">
 	<div class="gqyayizv _popup">
 		<button class="_button" @click="choose('public')" :class="{ active: v == 'public' }" data-index="1" key="public">
-			<div><Fa :icon="faGlobe"/></div>
+			<div><i class="fas fa-globe"></i></div>
 			<div>
 				<span>{{ $ts._visibility.public }}</span>
 				<span>{{ $ts._visibility.publicDescription }}</span>
 			</div>
 		</button>
 		<button class="_button" @click="choose('home')" :class="{ active: v == 'home' }" data-index="2" key="home">
-			<div><Fa :icon="faHome"/></div>
+			<div><i class="fas fa-home"></i></div>
 			<div>
 				<span>{{ $ts._visibility.home }}</span>
 				<span>{{ $ts._visibility.homeDescription }}</span>
 			</div>
 		</button>
 		<button class="_button" @click="choose('followers')" :class="{ active: v == 'followers' }" data-index="3" key="followers">
-			<div><Fa :icon="faUnlock"/></div>
+			<div><i class="fas fa-unlock"></i></div>
 			<div>
 				<span>{{ $ts._visibility.followers }}</span>
 				<span>{{ $ts._visibility.followersDescription }}</span>
 			</div>
 		</button>
 		<button :disabled="localOnly" class="_button" @click="choose('specified')" :class="{ active: v == 'specified' }" data-index="4" key="specified">
-			<div><Fa :icon="faEnvelope"/></div>
+			<div><i class="fas fa-envelope"></i></div>
 			<div>
 				<span>{{ $ts._visibility.specified }}</span>
 				<span>{{ $ts._visibility.specifiedDescription }}</span>
@@ -31,12 +31,12 @@
 		</button>
 		<div class="divider"></div>
 		<button class="_button localOnly" @click="localOnly = !localOnly" :class="{ active: localOnly }" data-index="5" key="localOnly">
-			<div><Fa :icon="faBiohazard"/></div>
+			<div><i class="fas fa-biohazard"></i></div>
 			<div>
 				<span>{{ $ts._visibility.localOnly }}</span>
 				<span>{{ $ts._visibility.localOnlyDescription }}</span>
 			</div>
-			<div><Fa :icon="localOnly ? faToggleOn : faToggleOff" :key="localOnly"/></div>
+			<div><i :class="localOnly ? 'fas fa-toggle-on' : 'fas fa-toggle-off'"></i></div>
 		</button>
 	</div>
 </MkModal>
@@ -44,8 +44,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faGlobe, faUnlock, faHome, faBiohazard, faToggleOn, faToggleOff } from '@fortawesome/free-solid-svg-icons';
-import { faEnvelope } from '@fortawesome/free-regular-svg-icons';
 import MkModal from '@client/components/ui/modal.vue';
 
 export default defineComponent({
@@ -70,7 +68,6 @@ export default defineComponent({
 		return {
 			v: this.currentVisibility,
 			localOnly: this.currentLocalOnly,
-			faGlobe, faUnlock, faEnvelope, faHome, faBiohazard, faToggleOn, faToggleOff
 		}
 	},
 	watch: {
diff --git a/src/client/components/waiting-dialog.vue b/src/client/components/waiting-dialog.vue
index c3a265af9cf3e9aebe9fa03b6e0bad4c270b3e09..ea9f6756b29b595f843a81656071ebfdb45411e9 100644
--- a/src/client/components/waiting-dialog.vue
+++ b/src/client/components/waiting-dialog.vue
@@ -1,8 +1,8 @@
 <template>
 <MkModal ref="modal" @click="success ? done() : () => {}" @closed="$emit('closed')">
 	<div class="iuyakobc" :class="{ iconOnly: (text == null) || success }">
-		<Fa class="icon success" v-if="success" :icon="faCheck"/>
-		<Fa class="icon waiting" v-else :icon="faSpinner" pulse/>
+		<i v-if="success" class="fas fa-check icon success"></i>
+		<i v-else class="fas fa-spinner fa-pulse icon waiting"></i>
 		<div class="text" v-if="text && !success">{{ text }}<MkEllipsis/></div>
 	</div>
 </MkModal>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCheck, faSpinner } from '@fortawesome/free-solid-svg-icons';
 import MkModal from '@client/components/ui/modal.vue';
 
 export default defineComponent({
@@ -37,7 +36,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faCheck, faSpinner,
 		};
 	},
 
@@ -70,10 +68,9 @@ export default defineComponent({
 		padding: 0;
 		width: 96px;
 		height: 96px;
-
-		> .icon {
-			height: 100%;
-		}
+		display: flex;
+		align-items: center;
+		justify-content: center;
 	}
 
 	> .icon {
diff --git a/src/client/components/widgets.vue b/src/client/components/widgets.vue
index 993b843cb1a4c317def1f65bdfa96677b41a6ede..790ca5611230982e9e4b49310e6376641ae1245c 100644
--- a/src/client/components/widgets.vue
+++ b/src/client/components/widgets.vue
@@ -6,7 +6,7 @@
 				<template #label>{{ $ts.selectWidget }}</template>
 				<option v-for="widget in widgetDefs" :value="widget" :key="widget">{{ $t(`_widgets.${widget}`) }}</option>
 			</MkSelect>
-			<MkButton inline @click="addWidget" primary><Fa :icon="faPlus"/> {{ $ts.add }}</MkButton>
+			<MkButton inline @click="addWidget" primary><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
 			<MkButton inline @click="$emit('exit')">{{ $ts.close }}</MkButton>
 		</header>
 		<XDraggable
@@ -16,8 +16,8 @@
 		>
 			<template #item="{element}">
 				<div class="customize-container">
-					<button class="config _button" @click.prevent.stop="configWidget(element.id)"><Fa :icon="faCog"/></button>
-					<button class="remove _button" @click.prevent.stop="removeWidget(element)"><Fa :icon="faTimes"/></button>
+					<button class="config _button" @click.prevent.stop="configWidget(element.id)"><i class="fas fa-cog"></i></button>
+					<button class="remove _button" @click.prevent.stop="removeWidget(element)"><i class="fas fa-times"></i></button>
 					<component :is="`mkw-${element.name}`" :widget="element" :setting-callback="setting => settings[element.id] = setting" :column="column" @updateProps="updateWidget(element.id, $event)"/>
 				</div>
 			</template>
@@ -30,7 +30,6 @@
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
 import { v4 as uuid } from 'uuid';
-import { faTimes, faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
 import MkSelect from '@client/components/ui/select.vue';
 import MkButton from '@client/components/ui/button.vue';
 import { widgets as widgetDefs } from '@client/widgets';
@@ -59,7 +58,6 @@ export default defineComponent({
 			widgetAdderSelected: null,
 			widgetDefs,
 			settings: {},
-			faTimes, faPlus, faCog
 		};
 	},
 
diff --git a/src/client/directives/click-anime.ts b/src/client/directives/click-anime.ts
new file mode 100644
index 0000000000000000000000000000000000000000..864155f076681b14f1c70212400bdd9f35f8bf25
--- /dev/null
+++ b/src/client/directives/click-anime.ts
@@ -0,0 +1,22 @@
+import { Directive } from 'vue';
+
+export default {
+	mounted(el, binding, vn) {
+		el.addEventListener('mousedown', () => {
+			el.classList.add('_anime_bounce_ready');
+
+			el.addEventListener('mouseleave', () => {
+				el.classList.remove('_anime_bounce_ready');
+			});
+		});
+
+		el.addEventListener('click', () => {
+			el.classList.add('_anime_bounce');
+		});
+
+		el.addEventListener('animationend', () => {
+			el.classList.remove('_anime_bounce_ready');
+			el.classList.remove('_anime_bounce');
+		});
+	}
+} as Directive;
diff --git a/src/client/directives/index.ts b/src/client/directives/index.ts
index 6513350e0dd5186594734f91d6a7ffe77373a822..f0a0123771e3060e2509bec1965dc050872ffd24 100644
--- a/src/client/directives/index.ts
+++ b/src/client/directives/index.ts
@@ -8,6 +8,7 @@ import hotkey from './hotkey';
 import appear from './appear';
 import anim from './anim';
 import stickyContainer from './sticky-container';
+import clickAnime from './click-anime';
 
 export default function(app: App) {
 	app.directive('userPreview', userPreview);
@@ -18,5 +19,6 @@ export default function(app: App) {
 	app.directive('hotkey', hotkey);
 	app.directive('appear', appear);
 	app.directive('anim', anim);
+	app.directive('click-anime', clickAnime);
 	app.directive('sticky-container', stickyContainer);
 }
diff --git a/src/client/init.ts b/src/client/init.ts
index daedce4aee4b0fde5944783c909381cb4210fa60..a4465d75c3dc91c33c718bd444dabd6c5d24e92a 100644
--- a/src/client/init.ts
+++ b/src/client/init.ts
@@ -7,7 +7,6 @@ import '@client/style.scss';
 import * as Sentry from '@sentry/browser';
 import { Integrations } from '@sentry/tracing';
 import { computed, createApp, watch } from 'vue';
-import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
 
 import widgets from '@client/widgets';
 import directives from '@client/directives';
@@ -41,6 +40,11 @@ if ((typeof ColdDeviceStorage.get('lightTheme') === 'string') || (typeof ColdDev
 	ColdDeviceStorage.set('lightTheme', require('@client/themes/l-light.json5'));
 	ColdDeviceStorage.set('darkTheme', require('@client/themes/d-dark.json5'));
 }
+const link = document.createElement('link');
+link.rel = 'stylesheet';
+link.href = 'https://use.fontawesome.com/releases/v5.15.3/css/all.css';
+document.head.appendChild(link);
+// TODOここまで
 
 if (_DEV_) {
 	console.warn('Development mode!!!');
@@ -184,8 +188,6 @@ app.config.globalProperties = {
 };
 
 app.use(router);
-// eslint-disable-next-line vue/component-definition-name-casing
-app.component('Fa', FontAwesomeIcon);
 
 widgets(app);
 directives(app);
diff --git a/src/client/pages/_error_.vue b/src/client/pages/_error_.vue
index 67c1a1991c426df1fb5834ae8c42d23e3ed13f6d..6caecd6eaf61e4694656e778c842384ba99e1f2e 100644
--- a/src/client/pages/_error_.vue
+++ b/src/client/pages/_error_.vue
@@ -3,7 +3,7 @@
 	<div class="_section">
 		<div class="mjndxjch _content">
 			<img src="https://xn--931a.moe/assets/error.jpg" class="_ghost"/>
-			<p><Fa :icon="faExclamationTriangle"/> {{ $ts.pageLoadError }}</p>
+			<p><i class="fas fa-exclamation-triangle"></i> {{ $ts.pageLoadError }}</p>
 			<p>{{ $ts.pageLoadErrorDescription }}</p>
 		</div>
 	</div>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import * as symbols from '@client/symbols';
 
@@ -24,9 +23,8 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.error,
-				icon: faExclamationTriangle
+				icon: 'fas fa-exclamation-triangle'
 			},
-			faExclamationTriangle
 		};
 	},
 });
diff --git a/src/client/pages/about-misskey.vue b/src/client/pages/about-misskey.vue
index aae8a7052a0081d87dca24007205ea77fa65b5ae..1d57c80810eb79878b49dbc3a51320c7177df12c 100644
--- a/src/client/pages/about-misskey.vue
+++ b/src/client/pages/about-misskey.vue
@@ -15,17 +15,17 @@
 		</section>
 		<FormGroup>
 			<FormLink to="https://github.com/misskey-dev/misskey" external>
-				<template #icon><Fa :icon="faCode"/></template>
+				<template #icon><i class="fas fa-code"></i></template>
 				{{ $ts._aboutMisskey.source }}
 				<template #suffix>GitHub</template>
 			</FormLink>
 			<FormLink to="https://crowdin.com/project/misskey" external>
-				<template #icon><Fa :icon="faLanguage"/></template>
+				<template #icon><i class="fas fa-language"></i></template>
 				{{ $ts._aboutMisskey.translation }}
 				<template #suffix>Crowdin</template>
 			</FormLink>
 			<FormLink to="https://www.patreon.com/syuilo" external>
-				<template #icon><Fa :icon="faHandHoldingMedical"/></template>
+				<template #icon><i class="fas fa-hand-holding-medical"></i></template>
 				{{ $ts._aboutMisskey.donate }}
 				<template #suffix>Patreon</template>
 			</FormLink>
@@ -54,7 +54,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faInfoCircle, faCode, faLanguage, faHandHoldingMedical, } from '@fortawesome/free-solid-svg-icons';
 import VanillaTilt from 'vanilla-tilt';
 import { version } from '@client/config';
 import FormLink from '@client/components/form/link.vue';
@@ -125,7 +124,6 @@ export default defineComponent({
 			easterEggReady: false,
 			easterEggEmojis: [],
 			easterEggEngine: null,
-			faInfoCircle, faCode, faLanguage, faHandHoldingMedical,
 		}
 	},
 
diff --git a/src/client/pages/about.vue b/src/client/pages/about.vue
index 4084256cf4f6b4f7ff609bbfdb80685a1f5b277d..4f70998eeec145089ee0392becf0d76f165a3fbd 100644
--- a/src/client/pages/about.vue
+++ b/src/client/pages/about.vue
@@ -40,7 +40,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
 import { version, instanceName } from '@client/config';
 import FormLink from '@client/components/form/link.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -62,12 +61,11 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.instanceInfo,
-				icon: faInfoCircle
+				icon: 'fas fa-info-circle'
 			},
 			version,
 			instanceName,
 			stats: null,
-			faInfoCircle
 		}
 	},
 
diff --git a/src/client/pages/advanced-theme-editor.vue b/src/client/pages/advanced-theme-editor.vue
index fff525a32ded0614f17cb1faf9a1155303a74f03..b40d9808ca337b059e2a3cd6c7a5f47cab0f21a1 100644
--- a/src/client/pages/advanced-theme-editor.vue
+++ b/src/client/pages/advanced-theme-editor.vue
@@ -34,7 +34,7 @@
 						</div>
 						<div>
 							<div class="type" @click="chooseType($event, i)">
-								{{ getTypeOf(v) }} <Fa :icon="faChevronDown"/>
+								{{ getTypeOf(v) }} <i class="fas fa-chevron-down"></i>
 							</div>
 							<!-- default -->
 							<div v-if="v === null" v-text="baseProps[k]" class="default-value" />
@@ -92,7 +92,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPalette, faChevronDown, faKeyboard } from '@fortawesome/free-solid-svg-icons';
 import * as JSON5 from 'json5';
 import { toUnicode } from 'punycode/';
 
@@ -125,7 +124,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.themeEditor,
-				icon: faPalette,
+				icon: 'fas fa-palette',
 			},
 			theme: [] as ThemeViewModel,
 			name: '',
@@ -135,7 +134,6 @@ export default defineComponent({
 			themeToImport: '',
 			changed: false,
 			lightTheme, darkTheme, themeProps,
-			faPalette, faChevronDown, faKeyboard,
 		}
 	},
 
diff --git a/src/client/pages/announcements.vue b/src/client/pages/announcements.vue
index 4e5f0e7f9cb384c9b994945f2a2bd72c4265fa8e..a7ccb0358867ce06296bd47ae890dda4c1598a67 100644
--- a/src/client/pages/announcements.vue
+++ b/src/client/pages/announcements.vue
@@ -8,7 +8,7 @@
 				<img v-if="announcement.imageUrl" :src="announcement.imageUrl"/>
 			</div>
 			<div class="_footer" v-if="$i && !announcement.isRead">
-				<MkButton @click="read(items, announcement, i)" primary><Fa :icon="faCheck"/> {{ $ts.gotIt }}</MkButton>
+				<MkButton @click="read(items, announcement, i)" primary><i class="fas fa-check"></i> {{ $ts.gotIt }}</MkButton>
 			</div>
 		</section>
 	</MkPagination>
@@ -17,7 +17,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCheck, faBroadcastTower } from '@fortawesome/free-solid-svg-icons';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkButton from '@client/components/ui/button.vue';
 import * as os from '@client/os';
@@ -33,13 +32,12 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.announcements,
-				icon: faBroadcastTower
+				icon: 'fas fa-broadcast-tower'
 			},
 			pagination: {
 				endpoint: 'announcements',
 				limit: 10,
 			},
-			faCheck,
 		};
 	},
 
diff --git a/src/client/pages/api-console.vue b/src/client/pages/api-console.vue
index 669e8147786ce42d767a824122d80424040bfbe1..b153d10396f56731f6cf30c0ee1bb7fab04d3af4 100644
--- a/src/client/pages/api-console.vue
+++ b/src/client/pages/api-console.vue
@@ -12,7 +12,7 @@
 		</MkSwitch>
 		<MkButton primary full @click="send" :disabled="sending">
 			<template v-if="sending"><MkEllipsis/></template>
-			<template v-else><Fa :icon="faPaperPlane"/> Send</template>
+			<template v-else><i class="fas fa-paper-plane"></i> Send</template>
 		</MkButton>
 	</div>
 	<div v-if="res" class="_block" style="padding: 24px;">
@@ -25,7 +25,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTerminal, faPaperPlane } from '@fortawesome/free-solid-svg-icons';
 import * as JSON5 from 'json5';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -43,7 +42,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: 'API console',
-				icon: faTerminal
+				icon: 'fas fa-terminal'
 			},
 
 			endpoint: '',
@@ -53,7 +52,6 @@ export default defineComponent({
 			endpoints: [],
 			withCredential: true,
 
-			faPaperPlane
 		};
 	},
 
diff --git a/src/client/pages/channel-editor.vue b/src/client/pages/channel-editor.vue
index 7216aaec4a7b71ed5571180d4b19c95fbe83aa50..bc772d34faa6af474f47f057649308e146d12bb4 100644
--- a/src/client/pages/channel-editor.vue
+++ b/src/client/pages/channel-editor.vue
@@ -7,15 +7,15 @@
 			<MkTextarea v-model:value="description">{{ $ts.description }}</MkTextarea>
 
 			<div class="banner">
-				<MkButton v-if="bannerId == null" @click="setBannerImage"><Fa :icon="faPlus"/> {{ $ts._channel.setBanner }}</MkButton>
+				<MkButton v-if="bannerId == null" @click="setBannerImage"><i class="fas fa-plus"></i> {{ $ts._channel.setBanner }}</MkButton>
 				<div v-else-if="bannerUrl">
 					<img :src="bannerUrl" style="width: 100%;"/>
-					<MkButton @click="removeBannerImage()"><Fa :icon="faTrashAlt"/> {{ $ts._channel.removeBanner }}</MkButton>
+					<MkButton @click="removeBannerImage()"><i class="fas fa-trash-alt"></i> {{ $ts._channel.removeBanner }}</MkButton>
 				</div>
 			</div>
 		</div>
 		<div class="_footer">
-			<MkButton @click="save()" primary><Fa :icon="faSave"/> {{ channelId ? $ts.save : $ts.create }}</MkButton>
+			<MkButton @click="save()" primary><i class="fas fa-save"></i> {{ channelId ? $ts.save : $ts.create }}</MkButton>
 		</div>
 	</div>
 </div>
@@ -23,8 +23,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faPlus, faSatelliteDish } from '@fortawesome/free-solid-svg-icons';
-import { faSave, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import MkTextarea from '@client/components/ui/textarea.vue';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -48,17 +46,16 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: computed(() => this.channelId ? {
 				title: this.$ts._channel.edit,
-				icon: faSatelliteDish,
+				icon: 'fas fa-satellite-dish',
 			} : {
 				title: this.$ts._channel.create,
-				icon: faSatelliteDish,
+				icon: 'fas fa-satellite-dish',
 			}),
 			channel: null,
 			name: null,
 			description: null,
 			bannerUrl: null,
 			bannerId: null,
-			faSave, faTrashAlt, faPlus,faSatelliteDish,
 		};
 	},
 
diff --git a/src/client/pages/channel.vue b/src/client/pages/channel.vue
index f98bb41a38988e8f6c1a26d0bfaac1517351c06c..1504264af56a15469bf5053bfd530529a6c8b814 100644
--- a/src/client/pages/channel.vue
+++ b/src/client/pages/channel.vue
@@ -3,15 +3,15 @@
 	<div class="wpgynlbz _content _panel _gap" :class="{ hide: !showBanner }">
 		<XChannelFollowButton :channel="channel" :full="true" class="subscribe"/>
 		<button class="_button toggle" @click="() => showBanner = !showBanner">
-			<template v-if="showBanner"><Fa :icon="faAngleUp"/></template>
-			<template v-else><Fa :icon="faAngleDown"/></template>
+			<template v-if="showBanner"><i class="fas fa-angle-up"></i></template>
+			<template v-else><i class="fas fa-angle-down"></i></template>
 		</button>
 		<div class="hideOverlay" v-if="!showBanner">
 		</div>
 		<div :style="{ backgroundImage: channel.bannerUrl ? `url(${channel.bannerUrl})` : null }" class="banner">
 			<div class="status">
-				<div><Fa :icon="faUsers" fixed-width/><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div>
-				<div><Fa :icon="faPencilAlt" fixed-width/><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div>
+				<div><i class="fas fa-users fa-fw"></i><I18n :src="$ts._channel.usersCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.usersCount }}</b></template></I18n></div>
+				<div><i class="fas fa-pencil-alt fa-fw"></i><I18n :src="$ts._channel.notesCount" tag="span" style="margin-left: 4px;"><template #n><b>{{ channel.notesCount }}</b></template></I18n></div>
 			</div>
 			<div class="fade"></div>
 		</div>
@@ -28,8 +28,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faSatelliteDish, faUsers, faPencilAlt, faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
-import {  } from '@fortawesome/free-regular-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import XPostForm from '@client/components/post-form.vue';
 import XTimeline from '@client/components/timeline.vue';
@@ -56,7 +54,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: computed(() => this.channel ? {
 				title: this.channel.name,
-				icon: faSatelliteDish,
+				icon: 'fas fa-satellite-dish',
 			} : null),
 			channel: null,
 			showBanner: true,
@@ -67,7 +65,6 @@ export default defineComponent({
 					channelId: this.channelId,
 				})
 			},
-			faSatelliteDish, faUsers, faPencilAlt, faAngleUp, faAngleDown,
 		};
 	},
 
@@ -111,7 +108,7 @@ export default defineComponent({
 		background: rgba(0, 0, 0, 0.5);
 		border-radius: 100%;
 		
-		> [data-icon] {
+		> i {
 			vertical-align: middle;
 		}
 	}
diff --git a/src/client/pages/channels.vue b/src/client/pages/channels.vue
index ebf1e7b87118ce60d03ac0e3f9275e00edfdeb96..7e3302959b9898282427b425add303941bdf8fce 100644
--- a/src/client/pages/channels.vue
+++ b/src/client/pages/channels.vue
@@ -2,9 +2,9 @@
 <div>
 	<div class="_section" style="padding: 0;" v-if="$i">
 		<MkTab class="_content" v-model:value="tab">
-			<option value="featured"><Fa :icon="faFireAlt"/> {{ $ts._channel.featured }}</option>
-			<option value="following"><Fa :icon="faHeart"/> {{ $ts._channel.following }}</option>
-			<option value="owned"><Fa :icon="faEdit"/> {{ $ts._channel.owned }}</option>
+			<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._channel.featured }}</option>
+			<option value="following"><i class="fas fa-heart"></i> {{ $ts._channel.following }}</option>
+			<option value="owned"><i class="fas fa-edit"></i> {{ $ts._channel.owned }}</option>
 		</MkTab>
 	</div>
 
@@ -22,7 +22,7 @@
 		</div>
 
 		<div class="_content grwlizim owned" v-if="tab === 'owned'">
-			<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
+			<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
 			<MkPagination :pagination="ownedPagination" #default="{items}">
 				<MkChannelPreview v-for="channel in items" class="_gap" :channel="channel" :key="channel.id"/>
 			</MkPagination>
@@ -33,8 +33,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSatelliteDish, faPlus, faEdit, faFireAlt } from '@fortawesome/free-solid-svg-icons';
-import { faHeart } from '@fortawesome/free-regular-svg-icons';
 import MkChannelPreview from '@client/components/channel-preview.vue';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkButton from '@client/components/ui/button.vue';
@@ -49,9 +47,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.channel,
-				icon: faSatelliteDish,
+				icon: 'fas fa-satellite-dish',
 				action: {
-					icon: faPlus,
+					icon: 'fas fa-plus',
 					handler: this.create
 				}
 			},
@@ -68,7 +66,6 @@ export default defineComponent({
 				endpoint: 'channels/owned',
 				limit: 5,
 			},
-			faSatelliteDish, faPlus, faEdit, faHeart, faFireAlt
 		};
 	},
 	methods: {
diff --git a/src/client/pages/clip.vue b/src/client/pages/clip.vue
index ca3e051d517ef05d73da1a6e9ca9c97d94c77ca9..8777975557dba038f6461e95674dbe035f0aa79c 100644
--- a/src/client/pages/clip.vue
+++ b/src/client/pages/clip.vue
@@ -15,7 +15,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faEllipsisH, faPaperclip, faPencilAlt, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import XPostForm from '@client/components/post-form.vue';
 import XNotes from '@client/components/notes.vue';
@@ -40,9 +39,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: computed(() => this.clip ? {
 				title: this.clip.name,
-				icon: faPaperclip,
+				icon: 'fas fa-paperclip',
 				action: {
-					icon: faEllipsisH,
+					icon: 'fas fa-ellipsis-h',
 					handler: this.menu
 				}
 			} : null),
@@ -81,7 +80,7 @@ export default defineComponent({
 	methods: {
 		menu(ev) {
 			os.modalMenu([this.isOwned ? {
-				icon: faPencilAlt,
+				icon: 'fas fa-pencil-alt',
 				text: this.$ts.edit,
 				action: async () => {
 					const { canceled, result } = await os.form(this.clip.name, {
@@ -111,7 +110,7 @@ export default defineComponent({
 					});
 				}
 			} : undefined, this.isOwned ? {
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				text: this.$ts.delete,
 				danger: true,
 				action: async () => {
diff --git a/src/client/pages/doc.vue b/src/client/pages/doc.vue
index cf3628dafbfa1c6e3d745a0bc3fea3d984f7bff6..a4cf25033e0160df7210cb170424fe3c8ce6bf7e 100644
--- a/src/client/pages/doc.vue
+++ b/src/client/pages/doc.vue
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'
 import MarkdownIt from 'markdown-it';
 import MarkdownItAnchor from 'markdown-it-anchor';
 import { url, lang } from '@client/config';
@@ -41,7 +40,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: computed(() => this.title ? {
 				title: this.title,
-				icon: faQuestionCircle,
+				icon: 'fas fa-question-circle',
 			} : null),
 			title: null,
 			body: null,
diff --git a/src/client/pages/docs.vue b/src/client/pages/docs.vue
index 92eab86716e021a55b12a2fead2a42f85b41961e..e51528f83da6c150a79ca90b663ad7a27bd3596b 100644
--- a/src/client/pages/docs.vue
+++ b/src/client/pages/docs.vue
@@ -14,7 +14,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faQuestionCircle } from '@fortawesome/free-solid-svg-icons'
 import { url, lang } from '@client/config';
 import * as symbols from '@client/symbols';
 
@@ -23,10 +22,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.help,
-				icon: faQuestionCircle
+				icon: 'fas fa-question-circle'
 			},
 			docs: [],
-			faQuestionCircle
 		}
 	},
 
diff --git a/src/client/pages/drive.vue b/src/client/pages/drive.vue
index 33bbfbc50ff13aa5cee64dbcef378de47f06470b..753114f725c3f6bc721fd77c394c7ada35aeec10 100644
--- a/src/client/pages/drive.vue
+++ b/src/client/pages/drive.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faCloud } from '@fortawesome/free-solid-svg-icons';
 import XDrive from '@client/components/drive.vue';
 import * as os from '@client/os';
 import * as symbols from '@client/symbols';
@@ -20,7 +19,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: computed(() => this.folder ? this.folder.name : this.$ts.drive),
-				icon: faCloud,
+				icon: 'fas fa-cloud',
 				menu: () => this.$refs.drive.getMenu()
 			},
 			folder: null,
diff --git a/src/client/pages/explore.vue b/src/client/pages/explore.vue
index dc0803237b0716dd090fdc804ca5d21f385b737b..7bcb09d8c5e742a0d59f3ddeb618b8b4cf292de5 100644
--- a/src/client/pages/explore.vue
+++ b/src/client/pages/explore.vue
@@ -2,7 +2,7 @@
 <div class="lznhrdub _root">
 	<div>
 		<div class="_isolated">
-			<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $ts.searchUser }}</span></MkInput>
+			<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><i class="fas fa-search"></i></template><span>{{ $ts.searchUser }}</span></MkInput>
 		</div>
 
 		<XUserList v-if="query" class="_gap" :pagination="searchPagination" ref="search"/>
@@ -14,19 +14,19 @@
 
 		<template v-if="tag == null">
 			<MkFolder class="_gap" persist-key="explore-pinned-users">
-				<template #header><Fa :icon="faBookmark" fixed-width style="margin-right: 0.5em;"/>{{ $ts.pinnedUsers }}</template>
+				<template #header><i class="fas fa-bookmark fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.pinnedUsers }}</template>
 				<XUserList :pagination="pinnedUsers"/>
 			</MkFolder>
 			<MkFolder class="_gap" persist-key="explore-popular-users">
-				<template #header><Fa :icon="faChartLine" fixed-width style="margin-right: 0.5em;"/>{{ $ts.popularUsers }}</template>
+				<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template>
 				<XUserList :pagination="popularUsers"/>
 			</MkFolder>
 			<MkFolder class="_gap" persist-key="explore-recently-updated-users">
-				<template #header><Fa :icon="faCommentAlt" fixed-width style="margin-right: 0.5em;"/>{{ $ts.recentlyUpdatedUsers }}</template>
+				<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template>
 				<XUserList :pagination="recentlyUpdatedUsers"/>
 			</MkFolder>
 			<MkFolder class="_gap" persist-key="explore-recently-registered-users">
-				<template #header><Fa :icon="faPlus" fixed-width style="margin-right: 0.5em;"/>{{ $ts.recentlyRegisteredUsers }}</template>
+				<template #header><i class="fas fa-plus fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyRegisteredUsers }}</template>
 				<XUserList :pagination="recentlyRegisteredUsers"/>
 			</MkFolder>
 		</template>
@@ -37,7 +37,7 @@
 		</div>
 
 		<MkFolder :foldable="true" :expanded="false" ref="tags" class="_gap">
-			<template #header><Fa :icon="faHashtag" fixed-width style="margin-right: 0.5em;"/>{{ $ts.popularTags }}</template>
+			<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularTags }}</template>
 
 			<div class="vxjfqztj">
 				<MkA v-for="tag in tagsLocal" :to="`/explore/tags/${tag.tag}`" :key="'local:' + tag.tag" class="local">{{ tag.tag }}</MkA>
@@ -46,21 +46,21 @@
 		</MkFolder>
 
 		<MkFolder v-if="tag != null" :key="`${tag}`" class="_gap">
-			<template #header><Fa :icon="faHashtag" fixed-width style="margin-right: 0.5em;"/>{{ tag }}</template>
+			<template #header><i class="fas fa-hashtag fa-fw" style="margin-right: 0.5em;"></i>{{ tag }}</template>
 			<XUserList :pagination="tagUsers"/>
 		</MkFolder>
 
 		<template v-if="tag == null">
 			<MkFolder class="_gap">
-				<template #header><Fa :icon="faChartLine" fixed-width style="margin-right: 0.5em;"/>{{ $ts.popularUsers }}</template>
+				<template #header><i class="fas fa-chart-line fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.popularUsers }}</template>
 				<XUserList :pagination="popularUsersF"/>
 			</MkFolder>
 			<MkFolder class="_gap">
-				<template #header><Fa :icon="faCommentAlt" fixed-width style="margin-right: 0.5em;"/>{{ $ts.recentlyUpdatedUsers }}</template>
+				<template #header><i class="fas fa-comment-alt fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyUpdatedUsers }}</template>
 				<XUserList :pagination="recentlyUpdatedUsersF"/>
 			</MkFolder>
 			<MkFolder class="_gap">
-				<template #header><Fa :icon="faRocket" fixed-width style="margin-right: 0.5em;"/>{{ $ts.recentlyDiscoveredUsers }}</template>
+				<template #header><i class="fas fa-rocket fa-fw" style="margin-right: 0.5em;"></i>{{ $ts.recentlyDiscoveredUsers }}</template>
 				<XUserList :pagination="recentlyRegisteredUsersF"/>
 			</MkFolder>
 		</template>
@@ -70,8 +70,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faChartLine, faPlus, faHashtag, faRocket, faSearch } from '@fortawesome/free-solid-svg-icons';
-import { faBookmark, faCommentAlt } from '@fortawesome/free-regular-svg-icons';
 import XUserList from '@client/components/user-list.vue';
 import MkFolder from '@client/components/ui/folder.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -97,7 +95,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.explore,
-				icon: faHashtag
+				icon: 'fas fa-hashtag'
 			},
 			pinnedUsers: { endpoint: 'pinned-users' },
 			popularUsers: { endpoint: 'users', limit: 10, noPaging: true, params: {
@@ -139,7 +137,6 @@ export default defineComponent({
 			stats: null,
 			query: null,
 			num: number,
-			faBookmark, faChartLine, faCommentAlt, faPlus, faHashtag, faRocket, faSearch,
 		};
 	},
 
diff --git a/src/client/pages/favorites.vue b/src/client/pages/favorites.vue
index 7ecd3271378a82ffafae53833d25d2191828d394..408ab222b57971af8e61649ad0747e707d9b7cc4 100644
--- a/src/client/pages/favorites.vue
+++ b/src/client/pages/favorites.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faStar } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XNotes from '@client/components/notes.vue';
 import * as os from '@client/os';
@@ -21,7 +20,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.favorites,
-				icon: faStar
+				icon: 'fas fa-star'
 			},
 			pagination: {
 				endpoint: 'i/favorites',
diff --git a/src/client/pages/featured.vue b/src/client/pages/featured.vue
index cd7343f5831707824782b422d91f2540d5d38821..21818ba617d81d94a26fc6c71b753f3187ac4ac7 100644
--- a/src/client/pages/featured.vue
+++ b/src/client/pages/featured.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faFireAlt } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XNotes from '@client/components/notes.vue';
 import * as symbols from '@client/symbols';
@@ -20,14 +19,13 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.featured,
-				icon: faFireAlt
+				icon: 'fas fa-fire-alt'
 			},
 			pagination: {
 				endpoint: 'notes/featured',
 				limit: 10,
 				offsetMode: true
 			},
-			faFireAlt
 		};
 	},
 
diff --git a/src/client/pages/follow-requests.vue b/src/client/pages/follow-requests.vue
index 31c00d63cd4d5c1bc2cd93a3afab28e05ce2ff59..9f27a6baa864da238f0935576a3dd0428fd4438f 100644
--- a/src/client/pages/follow-requests.vue
+++ b/src/client/pages/follow-requests.vue
@@ -19,8 +19,8 @@
 						<Mfm :text="req.follower.description" :is-note="false" :author="req.follower" :i="$i" :custom-emojis="req.follower.emojis" :plain="true" :nowrap="true"/>
 					</div>
 					<div class="actions">
-						<button class="_button" @click="accept(req.follower)"><Fa :icon="faCheck"/></button>
-						<button class="_button" @click="reject(req.follower)"><Fa :icon="faTimes"/></button>
+						<button class="_button" @click="accept(req.follower)"><i class="fas fa-check"></i></button>
+						<button class="_button" @click="reject(req.follower)"><i class="fas fa-times"></i></button>
 					</div>
 				</div>
 			</div>
@@ -31,7 +31,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faUserClock, faCheck, faTimes } from '@fortawesome/free-solid-svg-icons';
 import MkPagination from '@client/components/ui/pagination.vue';
 import { userPage, acct } from '../filters/user';
 import * as os from '@client/os';
@@ -46,13 +45,12 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.followRequests,
-				icon: faUserClock,
+				icon: 'fas fa-user-clock',
 			},
 			pagination: {
 				endpoint: 'following/requests/list',
 				limit: 10,
 			},
-			faCheck, faTimes, faUserClock
 		};
 	},
 
diff --git a/src/client/pages/instance-info.vue b/src/client/pages/instance-info.vue
index a3cd4029938e12de96fb899ce5c77b81f0b48d72..662b82ddb1a47e3bbebad0c7508b5c2af5685cb0 100644
--- a/src/client/pages/instance-info.vue
+++ b/src/client/pages/instance-info.vue
@@ -99,9 +99,12 @@
 			<span>Raw</span>
 		</FormObjectView>
 		<FormGroup>
+			<template #label>Well-known resources</template>
 			<FormLink :to="`https://${host}/.well-known/host-meta`" external>host-meta</FormLink>
 			<FormLink :to="`https://${host}/.well-known/host-meta.json`" external>host-meta.json</FormLink>
 			<FormLink :to="`https://${host}/.well-known/nodeinfo`" external>nodeinfo</FormLink>
+			<FormLink :to="`https://${host}/robots.txt`" external>robots.txt</FormLink>
+			<FormLink :to="`https://${host}/manifest.json`" external>manifest.json</FormLink>
 		</FormGroup>
 		<FormSuspense :p="dnsPromiseFactory" v-slot="{ result: dns }">
 			<FormGroup>
@@ -130,7 +133,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faExternalLinkAlt, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
 import Chart from 'chart.js';
 import FormObjectView from '@client/components/form/object-view.vue';
 import FormTextarea from '@client/components/form/textarea.vue';
@@ -182,10 +184,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.instanceInfo,
-				icon: faInfoCircle,
+				icon: 'fas fa-info-circle',
 				actions: [{
 					text: `https://${this.host}`,
-					icon: faExternalLinkAlt,
+					icon: 'fas fa-external-link-alt',
 					handler: () => {
 						window.open(`https://${this.host}`, '_blank');
 					}
diff --git a/src/client/pages/instance/abuses.vue b/src/client/pages/instance/abuses.vue
index c8355b068365ae2a0a77dd8ab6eb624a96427d94..73196027dc1b041da829a5581ca1acf402ec0f23 100644
--- a/src/client/pages/instance/abuses.vue
+++ b/src/client/pages/instance/abuses.vue
@@ -1,5 +1,5 @@
 <template>
-<div class="">
+<div class="lcixvhis">
 	<div class="_section reports">
 		<div class="_content">
 			<div class="inputs" style="display: flex;">
@@ -63,8 +63,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlus, faUsers, faSearch, faBookmark, faMicrophoneSlash, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
-import { faSnowflake, faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons';
 import parseAcct from '@/misc/acct/parse';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -82,11 +80,13 @@ export default defineComponent({
 		MkPagination,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.abuseReports,
-				icon: faExclamationCircle
+				icon: 'fas fa-exclamation-circle'
 			},
 			searchUsername: '',
 			searchHost: '',
@@ -102,7 +102,6 @@ export default defineComponent({
 					targetUserOrigin: this.targetUserOrigin,
 				}),
 			},
-			faPlus, faUsers, faSearch, faBookmark, farBookmark, faMicrophoneSlash, faSnowflake
 		}
 	},
 
@@ -120,6 +119,10 @@ export default defineComponent({
 		},
 	},
 
+	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
 	methods: {
 		acct,
 
@@ -135,6 +138,10 @@ export default defineComponent({
 </script>
 
 <style lang="scss" scoped>
+.lcixvhis {
+	margin: var(--margin);
+}
+
 .bcekxzvu {
 	> .target {
 		display: flex;
diff --git a/src/client/pages/instance/announcements.vue b/src/client/pages/instance/announcements.vue
index f9d58a29c48cd3684d07396940f1134907e67809..ac0e9d51357c7a82e6f48c320dca7ef59f2c6b13 100644
--- a/src/client/pages/instance/announcements.vue
+++ b/src/client/pages/instance/announcements.vue
@@ -1,35 +1,29 @@
 <template>
 <div class="ztgjmzrw">
-	<div class="_section">
-		<div class="_content">
-			<MkButton @click="add()" primary style="margin: 0 auto 16px auto;"><Fa :icon="faPlus"/> {{ $ts.add }}</MkButton>
-			<section class="_card _gap announcements" v-for="announcement in announcements">
-				<div class="_content announcement">
-					<MkInput v-model:value="announcement.title">
-						<span>{{ $ts.title }}</span>
-					</MkInput>
-					<MkTextarea v-model:value="announcement.text">
-						<span>{{ $ts.text }}</span>
-					</MkTextarea>
-					<MkInput v-model:value="announcement.imageUrl">
-						<span>{{ $ts.imageUrl }}</span>
-					</MkInput>
-					<p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p>
-					<div class="buttons">
-						<MkButton class="button" inline @click="save(announcement)" primary><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-						<MkButton class="button" inline @click="remove(announcement)"><Fa :icon="faTrashAlt"/> {{ $ts.remove }}</MkButton>
-					</div>
-				</div>
-			</section>
+	<MkButton @click="add()" primary style="margin: 0 auto 16px auto;"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
+	<section class="_card _gap announcements" v-for="announcement in announcements">
+		<div class="_content announcement">
+			<MkInput v-model:value="announcement.title">
+				<span>{{ $ts.title }}</span>
+			</MkInput>
+			<MkTextarea v-model:value="announcement.text">
+				<span>{{ $ts.text }}</span>
+			</MkTextarea>
+			<MkInput v-model:value="announcement.imageUrl">
+				<span>{{ $ts.imageUrl }}</span>
+			</MkInput>
+			<p v-if="announcement.reads">{{ $t('nUsersRead', { n: announcement.reads }) }}</p>
+			<div class="buttons">
+				<MkButton class="button" inline @click="save(announcement)" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
+				<MkButton class="button" inline @click="remove(announcement)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
+			</div>
 		</div>
-	</div>
+	</section>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBroadcastTower, faPlus } from '@fortawesome/free-solid-svg-icons';
-import { faSave, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
@@ -43,14 +37,15 @@ export default defineComponent({
 		MkTextarea,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.announcements,
-				icon: faBroadcastTower
+				icon: 'fas fa-broadcast-tower'
 			},
 			announcements: [],
-			faBroadcastTower, faSave, faTrashAlt, faPlus
 		}
 	},
 
@@ -60,6 +55,10 @@ export default defineComponent({
 		});
 	},
 
+	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
 	methods: {
 		add() {
 			this.announcements.unshift({
@@ -112,3 +111,9 @@ export default defineComponent({
 	}
 });
 </script>
+
+<style lang="scss" scoped>
+.ztgjmzrw {
+	margin: var(--margin);
+}
+</style>
diff --git a/src/client/pages/instance/bot-protection.vue b/src/client/pages/instance/bot-protection.vue
new file mode 100644
index 0000000000000000000000000000000000000000..449b8a233d252020a0d7835434ec83f10bd96b9a
--- /dev/null
+++ b/src/client/pages/instance/bot-protection.vue
@@ -0,0 +1,138 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormRadios v-model="provider">
+			<template #desc><i class="fas fa-shield-alt"></i> {{ $ts.botProtection }}</template>
+			<option :value="null">{{ $ts.none }} ({{ $ts.notRecommended }})</option>
+			<option value="hcaptcha">hCaptcha</option>
+			<option value="recaptcha">reCAPTCHA</option>
+		</FormRadios>
+
+		<template v-if="provider === 'hcaptcha'">
+			<div class="_formItem _formNoConcat" v-sticky-container>
+				<div class="_formLabel">hCaptcha</div>
+				<div class="main">
+					<FormInput v-model:value="hcaptchaSiteKey">
+						<template #prefix><i class="fas fa-key"></i></template>
+						<span>{{ $ts.hcaptchaSiteKey }}</span>
+					</FormInput>
+					<FormInput v-model:value="hcaptchaSecretKey">
+						<template #prefix><i class="fas fa-key"></i></template>
+						<span>{{ $ts.hcaptchaSecretKey }}</span>
+					</FormInput>
+				</div>
+			</div>
+			<div class="_formItem _formNoConcat" v-sticky-container>
+				<div class="_formLabel">{{ $ts.preview }}</div>
+				<div class="_formPanel" style="padding: var(--formContentHMargin);">
+					<MkCaptcha provider="hcaptcha" :sitekey="hcaptchaSiteKey || '10000000-ffff-ffff-ffff-000000000001'"/>
+				</div>
+			</div>
+		</template>
+		<template v-else-if="provider === 'recaptcha'">
+			<div class="_formItem _formNoConcat" v-sticky-container>
+				<div class="_formLabel">reCAPTCHA</div>
+				<div class="main">
+					<FormInput v-model:value="recaptchaSiteKey">
+						<template #prefix><i class="fas fa-key"></i></template>
+						<span>{{ $ts.recaptchaSiteKey }}</span>
+					</FormInput>
+					<FormInput v-model:value="recaptchaSecretKey">
+						<template #prefix><i class="fas fa-key"></i></template>
+						<span>{{ $ts.recaptchaSecretKey }}</span>
+					</FormInput>
+				</div>
+			</div>
+			<div v-if="recaptchaSiteKey" class="_formItem _formNoConcat" v-sticky-container>
+				<div class="_formLabel">{{ $ts.preview }}</div>
+				<div class="_formPanel" style="padding: var(--formContentHMargin);">
+					<MkCaptcha provider="recaptcha" :sitekey="recaptchaSiteKey"/>
+				</div>
+			</div>
+		</template>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineAsyncComponent, defineComponent } from 'vue';
+import FormRadios from '@client/components/form/radios.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormRadios,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormInfo,
+		FormSuspense,
+		MkCaptcha: defineAsyncComponent(() => import('@client/components/captcha.vue')),
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.botProtection,
+				icon: 'fas fa-shield-alt'
+			},
+			provider: null,
+			enableHcaptcha: false,
+			hcaptchaSiteKey: null,
+			hcaptchaSecretKey: null,
+			enableRecaptcha: false,
+			recaptchaSiteKey: null,
+			recaptchaSecretKey: null,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableHcaptcha = meta.enableHcaptcha;
+			this.hcaptchaSiteKey = meta.hcaptchaSiteKey;
+			this.hcaptchaSecretKey = meta.hcaptchaSecretKey;
+			this.enableRecaptcha = meta.enableRecaptcha;
+			this.recaptchaSiteKey = meta.recaptchaSiteKey;
+			this.recaptchaSecretKey = meta.recaptchaSecretKey;
+
+			this.provider = this.enableHcaptcha ? 'hcaptcha' : this.enableRecaptcha ? 'recaptcha' : null;
+
+			this.$watch(() => this.provider, () => {
+				this.enableHcaptcha = this.provider === 'hcaptcha';
+				this.enableRecaptcha = this.provider === 'recaptcha';
+			});
+		},
+	
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				enableHcaptcha: this.enableHcaptcha,
+				hcaptchaSiteKey: this.hcaptchaSiteKey,
+				hcaptchaSecretKey: this.hcaptchaSecretKey,
+				enableRecaptcha: this.enableRecaptcha,
+				recaptchaSiteKey: this.recaptchaSiteKey,
+				recaptchaSecretKey: this.recaptchaSecretKey,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/database.vue b/src/client/pages/instance/database.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a41d61ce2b11dc9a308e9c870dfdc998b43fb6fb
--- /dev/null
+++ b/src/client/pages/instance/database.vue
@@ -0,0 +1,60 @@
+<template>
+<FormBase>
+	<FormSuspense :p="databasePromiseFactory" v-slot="{ result: database }">
+		<FormGroup v-for="table in database" :key="table[0]">
+			<template #label>{{ table[0] }}</template>
+			<FormKeyValueView>
+				<template #key>Size</template>
+				<template #value>{{ bytes(table[1].size) }}</template>
+			</FormKeyValueView>
+			<FormKeyValueView>
+				<template #key>Records</template>
+				<template #value>{{ number(table[1].count) }}</template>
+			</FormKeyValueView>
+		</FormGroup>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import FormKeyValueView from '@client/components/form/key-value-view.vue';
+import FormLink from '@client/components/form/link.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import bytes from '@client/filters/bytes';
+import number from '@client/filters/number';
+
+export default defineComponent({
+	components: {
+		FormSuspense,
+		FormKeyValueView,
+		FormBase,
+		FormGroup,
+		FormLink,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.database,
+				icon: 'fas fa-database'
+			},
+			databasePromiseFactory: () => os.api('admin/get-table-stats', {}).then(res => Object.entries(res).sort((a, b) => b[1].size - a[1].size)),
+		}
+	},
+
+	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		bytes, number,
+	}
+});
+</script>
diff --git a/src/client/pages/instance/email-settings.vue b/src/client/pages/instance/email-settings.vue
new file mode 100644
index 0000000000000000000000000000000000000000..9965a1420fb0567ac12525a95924f6df6fe5dcb2
--- /dev/null
+++ b/src/client/pages/instance/email-settings.vue
@@ -0,0 +1,127 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormSwitch v-model:value="enableEmail">{{ $ts.enableEmail }}<template #desc>{{ $ts.emailConfigInfo }}</template></FormSwitch>
+
+		<template v-if="enableEmail">
+			<FormInput v-model:value="email" type="email">
+				<span>{{ $ts.emailAddress }}</span>
+			</FormInput>
+
+			<div class="_formItem _formNoConcat" v-sticky-container>
+				<div class="_formLabel">{{ $ts.smtpConfig }}</div>
+				<div class="main">
+					<FormInput v-model:value="smtpHost">
+						<span>{{ $ts.smtpHost }}</span>
+					</FormInput>
+					<FormInput v-model:value="smtpPort" type="number">
+						<span>{{ $ts.smtpPort }}</span>
+					</FormInput>
+					<FormInput v-model:value="smtpUser">
+						<span>{{ $ts.smtpUser }}</span>
+					</FormInput>
+					<FormInput v-model:value="smtpPass" type="password">
+						<span>{{ $ts.smtpPass }}</span>
+					</FormInput>
+					<FormInfo>{{ $ts.emptyToDisableSmtpAuth }}</FormInfo>
+					<FormSwitch v-model:value="smtpSecure">{{ $ts.smtpSecure }}<template #desc>{{ $ts.smtpSecureInfo }}</template></FormSwitch>
+				</div>
+			</div>
+
+			<FormButton @click="testEmail">{{ $ts.testEmail }}</FormButton>
+		</template>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormInfo,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.emailServer,
+				icon: 'fas fa-envelope'
+			},
+			enableEmail: false,
+			email: null,
+			smtpSecure: false,
+			smtpHost: '',
+			smtpPort: 0,
+			smtpUser: '',
+			smtpPass: '',
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableEmail = meta.enableEmail;
+			this.email = meta.email;
+			this.smtpSecure = meta.smtpSecure;
+			this.smtpHost = meta.smtpHost;
+			this.smtpPort = meta.smtpPort;
+			this.smtpUser = meta.smtpUser;
+			this.smtpPass = meta.smtpPass;
+		},
+
+		async testEmail() {
+			const { canceled, result: destination } = await os.dialog({
+				title: this.$ts.destination,
+				input: {
+					placeholder: this.$instance.maintainerEmail
+				}
+			});
+			if (canceled) return;
+			os.apiWithDialog('admin/send-email', {
+				to: destination,
+				subject: 'Test email',
+				text: 'Yo'
+			});
+		},
+
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				enableEmail: this.enableEmail,
+				email: this.email,
+				smtpSecure: this.smtpSecure,
+				smtpHost: this.smtpHost,
+				smtpPort: this.smtpPort,
+				smtpUser: this.smtpUser,
+				smtpPass: this.smtpPass,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/emoji-edit-dialog.vue b/src/client/pages/instance/emoji-edit-dialog.vue
index 34eca47b4e18147595510db3d1e23bfe1db38189..f7a36715845305845bbd2609fe9ecd8cd6f39565 100644
--- a/src/client/pages/instance/emoji-edit-dialog.vue
+++ b/src/client/pages/instance/emoji-edit-dialog.vue
@@ -8,22 +8,23 @@
 >
 	<template #header>:{{ emoji.name }}:</template>
 
-	<div class="yigymqpb _section">
-		<img :src="emoji.url" class="img"/>
-		<MkInput v-model:value="name"><span>{{ $ts.name }}</span></MkInput>
-		<MkInput v-model:value="category" :datalist="categories"><span>{{ $ts.category }}</span></MkInput>
-		<MkInput v-model:value="aliases">
-			<span>{{ $ts.tags }}</span>
-			<template #desc>{{ $ts.setMultipleBySeparatingWithSpace }}</template>
-		</MkInput>
-		<MkButton danger @click="del()"><Fa :icon="faTrashAlt"/> {{ $ts.delete }}</MkButton>
+	<div class="_monolithic_">
+		<div class="yigymqpb _section">
+			<img :src="emoji.url" class="img"/>
+			<MkInput v-model:value="name"><span>{{ $ts.name }}</span></MkInput>
+			<MkInput v-model:value="category" :datalist="categories"><span>{{ $ts.category }}</span></MkInput>
+			<MkInput v-model:value="aliases">
+				<span>{{ $ts.tags }}</span>
+				<template #desc>{{ $ts.setMultipleBySeparatingWithSpace }}</template>
+			</MkInput>
+			<MkButton danger @click="del()"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
+		</div>
 	</div>
 </XModalWindow>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import XModalWindow from '@client/components/ui/modal-window.vue';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -51,7 +52,6 @@ export default defineComponent({
 			category: this.emoji.category,
 			aliases: this.emoji.aliases?.join(' '),
 			categories: [],
-			faTrashAlt,
 		}
 	},
 
diff --git a/src/client/pages/instance/emojis.vue b/src/client/pages/instance/emojis.vue
index 722ed0063f7a2eb5ed1da937cb69a501a4add1e5..fd641703cb90f9a5effb23ae17c9f14d844c6ca4 100644
--- a/src/client/pages/instance/emojis.vue
+++ b/src/client/pages/instance/emojis.vue
@@ -1,58 +1,52 @@
 <template>
-<div class="mk-instance-emojis">
-	<div class="_section" style="padding: 0;">
-		<MkTab v-model:value="tab">
-			<option value="local">{{ $ts.local }}</option>
-			<option value="remote">{{ $ts.remote }}</option>
-		</MkTab>
+<div class="ogwlenmc">
+	<MkTab v-model:value="tab">
+		<option value="local">{{ $ts.local }}</option>
+		<option value="remote">{{ $ts.remote }}</option>
+	</MkTab>
+
+	<div class="local" v-if="tab === 'local'">
+		<MkButton primary @click="add" style="margin: var(--margin) auto;"><i class="fas fa-plus"></i> {{ $ts.addEmoji }}</MkButton>
+		<MkInput v-model:value="query" :debounce="true" type="search" style="margin: var(--margin);"><template #icon><i class="fas fa-search"></i></template><span>{{ $ts.search }}</span></MkInput>
+		<MkPagination :pagination="pagination" ref="emojis">
+			<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
+			<template #default="{items}">
+				<div class="ldhfsamy">
+					<button class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="edit(emoji)">
+						<img :src="emoji.url" class="img" :alt="emoji.name"/>
+						<div class="body">
+							<div class="name _monospace">{{ emoji.name }}</div>
+							<div class="info">{{ emoji.category }}</div>
+						</div>
+					</button>
+				</div>
+			</template>
+		</MkPagination>
 	</div>
 
-	<div class="_section">
-		<div class="local" v-if="tab === 'local'">
-			<MkButton primary @click="add" style="margin: 0 auto var(--margin) auto;"><Fa :icon="faPlus"/> {{ $ts.addEmoji }}</MkButton>
-			<MkInput v-model:value="query" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $ts.search }}</span></MkInput>
-			<MkPagination :pagination="pagination" ref="emojis">
-				<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
-				<template #default="{items}">
-					<div class="emojis">
-						<button class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="edit(emoji)">
-							<img :src="emoji.url" class="img" :alt="emoji.name"/>
-							<div class="body">
-								<div class="name">{{ emoji.name }}</div>
-								<div class="info">{{ emoji.category }}</div>
-							</div>
-						</button>
-					</div>
-				</template>
-			</MkPagination>
-		</div>
-
-		<div class="remote" v-else-if="tab === 'remote'">
-			<MkInput v-model:value="queryRemote" :debounce="true" type="search"><template #icon><Fa :icon="faSearch"/></template><span>{{ $ts.search }}</span></MkInput>
-			<MkInput v-model:value="host" :debounce="true"><span>{{ $ts.host }}</span></MkInput>
-			<MkPagination :pagination="remotePagination" ref="remoteEmojis">
-				<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
-				<template #default="{items}">
-					<div class="emojis">
-						<div class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="remoteMenu(emoji, $event)">
-							<img :src="emoji.url" class="img" :alt="emoji.name"/>
-							<div class="body">
-								<div class="name">{{ emoji.name }}</div>
-								<div class="info">{{ emoji.host }}</div>
-							</div>
+	<div class="remote" v-else-if="tab === 'remote'">
+		<MkInput v-model:value="queryRemote" :debounce="true" type="search" style="margin: var(--margin);"><template #icon><i class="fas fa-search"></i></template><span>{{ $ts.search }}</span></MkInput>
+		<MkInput v-model:value="host" :debounce="true" style="margin: var(--margin);"><span>{{ $ts.host }}</span></MkInput>
+		<MkPagination :pagination="remotePagination" ref="remoteEmojis">
+			<template #empty><span>{{ $ts.noCustomEmojis }}</span></template>
+			<template #default="{items}">
+				<div class="ldhfsamy">
+					<div class="emoji _panel _button" v-for="emoji in items" :key="emoji.id" @click="remoteMenu(emoji, $event)">
+						<img :src="emoji.url" class="img" :alt="emoji.name"/>
+						<div class="body">
+							<div class="name _monospace">{{ emoji.name }}</div>
+							<div class="info">{{ emoji.host }}</div>
 						</div>
 					</div>
-				</template>
-			</MkPagination>
-		</div>
+				</div>
+			</template>
+		</MkPagination>
 	</div>
 </div>
 </template>
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faPlus, faSave, faSearch } from '@fortawesome/free-solid-svg-icons';
-import { faTrashAlt, faLaugh } from '@fortawesome/free-regular-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkPagination from '@client/components/ui/pagination.vue';
@@ -69,13 +63,15 @@ export default defineComponent({
 		MkPagination,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.customEmojis,
-				icon: faLaugh,
+				icon: 'fas fa-laugh',
 				action: {
-					icon: faPlus,
+					icon: 'fas fa-plus',
 					handler: this.add
 				}
 			},
@@ -98,10 +94,13 @@ export default defineComponent({
 					host: (this.host && this.host !== '') ? this.host : null
 				}))
 			},
-			faTrashAlt, faPlus, faLaugh, faSave, faSearch,
 		}
 	},
 
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
 	methods: {
 		async add(e) {
 			const files = await selectFile(e.currentTarget || e.target, null, true);
@@ -144,7 +143,7 @@ export default defineComponent({
 				text: ':' + emoji.name + ':',
 			}, {
 				text: this.$ts.import,
-				icon: faPlus,
+				icon: 'fas fa-plus',
 				action: () => { this.im(emoji) }
 			}], ev.currentTarget || ev.target);
 		}
@@ -153,85 +152,86 @@ export default defineComponent({
 </script>
 
 <style lang="scss" scoped>
-.mk-instance-emojis {
-	> ._section {
-		> .local {
-			.emojis {
-				display: grid;
-				grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
-				grid-gap: var(--margin);
-		
-				> .emoji {
-					display: flex;
-					align-items: center;
-					padding: 12px;
-					text-align: left;
-
-					&:hover {
-						color: var(--accent);
-					}
+.ogwlenmc {
+	> .local {
+		.ldhfsamy {
+			display: grid;
+			grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
+			grid-gap: 12px;
+			margin: var(--margin);
+	
+			> .emoji {
+				display: flex;
+				align-items: center;
+				padding: 12px;
+				text-align: left;
+
+				&:hover {
+					color: var(--accent);
+				}
 
-					> .img {
-						width: 42px;
-						height: 42px;
-					}
+				> .img {
+					width: 42px;
+					height: 42px;
+				}
 
-					> .body {
-						padding: 0 0 0 8px;
-						white-space: nowrap;
-						overflow: hidden;
+				> .body {
+					padding: 0 0 0 8px;
+					white-space: nowrap;
+					overflow: hidden;
 
-						> .name {
-							text-overflow: ellipsis;
-							overflow: hidden;
-						}
+					> .name {
+						text-overflow: ellipsis;
+						overflow: hidden;
+					}
 
-						> .info {
-							opacity: 0.5;
-							text-overflow: ellipsis;
-							overflow: hidden;
-						}
+					> .info {
+						opacity: 0.5;
+						text-overflow: ellipsis;
+						overflow: hidden;
 					}
 				}
 			}
 		}
+	}
 
-		> .remote {
-			.emojis {
-				display: grid;
-				grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
-				grid-gap: var(--margin);
+	> .remote {
+		.ldhfsamy {
+			display: grid;
+			grid-template-columns: repeat(auto-fill, minmax(190px, 1fr));
+			grid-gap: 12px;
+			margin: var(--margin);
+
+			> .emoji {
+				display: flex;
+				align-items: center;
+				padding: 12px;
+				text-align: left;
+
+				&:hover {
+					color: var(--accent);
+				}
 
-				> .emoji {
-					display: flex;
-					align-items: center;
-					padding: 12px;
-					text-align: left;
+				> .img {
+					width: 32px;
+					height: 32px;
+				}
 
-					&:hover {
-						color: var(--accent);
-					}
+				> .body {
+					padding: 0 0 0 8px;
+					white-space: nowrap;
+					overflow: hidden;
 
-					> .img {
-						width: 32px;
-						height: 32px;
+					> .name {
+						text-overflow: ellipsis;
+						overflow: hidden;
 					}
 
-					> .body {
-						padding: 0 0 0 8px;
-						white-space: nowrap;
+					> .info {
+						opacity: 0.5;
+						font-size: 90%;
+						text-overflow: ellipsis;
 						overflow: hidden;
-
-						> .name {
-							text-overflow: ellipsis;
-							overflow: hidden;
-						}
-
-						> .info {
-							opacity: 0.5;
-							text-overflow: ellipsis;
-							overflow: hidden;
-						}
 					}
 				}
 			}
diff --git a/src/client/pages/instance/federation.vue b/src/client/pages/instance/federation.vue
index 2a820e5baf4e4568013e5d9954491ed82ec950f0..96f72fed44ba748eb749232e509f904df17236cb 100644
--- a/src/client/pages/instance/federation.vue
+++ b/src/client/pages/instance/federation.vue
@@ -1,66 +1,60 @@
 <template>
-<div>
-	<div class="_section">
-		<div class="_content">
-			<MkInput v-model:value="host" :debounce="true"><span>{{ $ts.host }}</span></MkInput>
-			<div class="inputs" style="display: flex;">
-				<MkSelect v-model:value="state" style="margin: 0; flex: 1;">
-					<template #label>{{ $ts.state }}</template>
-					<option value="all">{{ $ts.all }}</option>
-					<option value="federating">{{ $ts.federating }}</option>
-					<option value="subscribing">{{ $ts.subscribing }}</option>
-					<option value="publishing">{{ $ts.publishing }}</option>
-					<option value="suspended">{{ $ts.suspended }}</option>
-					<option value="blocked">{{ $ts.blocked }}</option>
-					<option value="notResponding">{{ $ts.notResponding }}</option>
-				</MkSelect>
-				<MkSelect v-model:value="sort" style="margin: 0; flex: 1;">
-					<template #label>{{ $ts.sort }}</template>
-					<option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option>
-					<option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+notes">{{ $ts.notes }} ({{ $ts.descendingOrder }})</option>
-					<option value="-notes">{{ $ts.notes }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+users">{{ $ts.users }} ({{ $ts.descendingOrder }})</option>
-					<option value="-users">{{ $ts.users }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+following">{{ $ts.following }} ({{ $ts.descendingOrder }})</option>
-					<option value="-following">{{ $ts.following }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+followers">{{ $ts.followers }} ({{ $ts.descendingOrder }})</option>
-					<option value="-followers">{{ $ts.followers }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+caughtAt">{{ $ts.caughtAt }} ({{ $ts.descendingOrder }})</option>
-					<option value="-caughtAt">{{ $ts.caughtAt }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+lastCommunicatedAt">{{ $ts.lastCommunicatedAt }} ({{ $ts.descendingOrder }})</option>
-					<option value="-lastCommunicatedAt">{{ $ts.lastCommunicatedAt }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+driveUsage">{{ $ts.driveUsage }} ({{ $ts.descendingOrder }})</option>
-					<option value="-driveUsage">{{ $ts.driveUsage }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+driveFiles">{{ $ts.driveFiles }} ({{ $ts.descendingOrder }})</option>
-					<option value="-driveFiles">{{ $ts.driveFiles }} ({{ $ts.ascendingOrder }})</option>
-				</MkSelect>
-			</div>
+<div class="enuoauvw">
+	<div class="query">
+		<MkInput v-model:value="host" :debounce="true"><span>{{ $ts.host }}</span></MkInput>
+		<div class="inputs" style="display: flex;">
+			<MkSelect v-model:value="state" style="margin: 0; flex: 1;">
+				<template #label>{{ $ts.state }}</template>
+				<option value="all">{{ $ts.all }}</option>
+				<option value="federating">{{ $ts.federating }}</option>
+				<option value="subscribing">{{ $ts.subscribing }}</option>
+				<option value="publishing">{{ $ts.publishing }}</option>
+				<option value="suspended">{{ $ts.suspended }}</option>
+				<option value="blocked">{{ $ts.blocked }}</option>
+				<option value="notResponding">{{ $ts.notResponding }}</option>
+			</MkSelect>
+			<MkSelect v-model:value="sort" style="margin: 0; flex: 1;">
+				<template #label>{{ $ts.sort }}</template>
+				<option value="+pubSub">{{ $ts.pubSub }} ({{ $ts.descendingOrder }})</option>
+				<option value="-pubSub">{{ $ts.pubSub }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+notes">{{ $ts.notes }} ({{ $ts.descendingOrder }})</option>
+				<option value="-notes">{{ $ts.notes }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+users">{{ $ts.users }} ({{ $ts.descendingOrder }})</option>
+				<option value="-users">{{ $ts.users }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+following">{{ $ts.following }} ({{ $ts.descendingOrder }})</option>
+				<option value="-following">{{ $ts.following }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+followers">{{ $ts.followers }} ({{ $ts.descendingOrder }})</option>
+				<option value="-followers">{{ $ts.followers }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+caughtAt">{{ $ts.caughtAt }} ({{ $ts.descendingOrder }})</option>
+				<option value="-caughtAt">{{ $ts.caughtAt }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+lastCommunicatedAt">{{ $ts.lastCommunicatedAt }} ({{ $ts.descendingOrder }})</option>
+				<option value="-lastCommunicatedAt">{{ $ts.lastCommunicatedAt }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+driveUsage">{{ $ts.driveUsage }} ({{ $ts.descendingOrder }})</option>
+				<option value="-driveUsage">{{ $ts.driveUsage }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+driveFiles">{{ $ts.driveFiles }} ({{ $ts.descendingOrder }})</option>
+				<option value="-driveFiles">{{ $ts.driveFiles }} ({{ $ts.ascendingOrder }})</option>
+			</MkSelect>
 		</div>
 	</div>
-	<div class="_section">
-		<div class="_content">
-			<MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state">
-				<div class="ppgwaixt _panel" v-for="instance in items" :key="instance.id" @click="info(instance)">
-					<div class="host"><Fa :icon="faCircle" class="indicator" :class="getStatus(instance)"/><b>{{ instance.host }}</b></div>
-					<div class="status">
-						<span class="sub" v-if="instance.followersCount > 0"><Fa :icon="faCaretDown" class="icon"/>Sub</span>
-						<span class="sub" v-else><Fa :icon="faCaretDown" class="icon"/>-</span>
-						<span class="pub" v-if="instance.followingCount > 0"><Fa :icon="faCaretUp" class="icon"/>Pub</span>
-						<span class="pub" v-else><Fa :icon="faCaretUp" class="icon"/>-</span>
-						<span class="lastCommunicatedAt"><Fa :icon="faExchangeAlt" class="icon"/><MkTime :time="instance.lastCommunicatedAt"/></span>
-						<span class="latestStatus"><Fa :icon="faTrafficLight" class="icon"/>{{ instance.latestStatus || '-' }}</span>
-					</div>
-				</div>
-			</MkPagination>
+
+	<MkPagination :pagination="pagination" #default="{items}" ref="instances" :key="host + state">
+		<div class="ppgwaixt _block" v-for="instance in items" :key="instance.id" @click="info(instance)">
+			<div class="host"><i class="fas fa-circle indicator" :class="getStatus(instance)"></i><b>{{ instance.host }}</b></div>
+			<div class="status">
+				<span class="sub" v-if="instance.followersCount > 0"><i class="fas fa-caret-down icon"></i>Sub</span>
+				<span class="sub" v-else><i class="fas fa-caret-down icon"></i>-</span>
+				<span class="pub" v-if="instance.followingCount > 0"><i class="fas fa-caret-up icon"></i>Pub</span>
+				<span class="pub" v-else><i class="fas fa-caret-up icon"></i>-</span>
+				<span class="lastCommunicatedAt"><i class="fas fa-exchange-alt icon"></i><MkTime :time="instance.lastCommunicatedAt"/></span>
+				<span class="latestStatus"><i class="fas fa-traffic-light icon"></i>{{ instance.latestStatus || '-' }}</span>
+			</div>
 		</div>
-	</div>
+	</MkPagination>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faGlobe, faCircle, faExchangeAlt, faCaretDown, faCaretUp, faTrafficLight } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -77,11 +71,13 @@ export default defineComponent({
 		MkPagination,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.federation,
-				icon: faGlobe
+				icon: 'fas fa-globe'
 			},
 			host: '',
 			state: 'federating',
@@ -103,7 +99,6 @@ export default defineComponent({
 						{})
 				})
 			},
-			faGlobe, faCircle, faExchangeAlt, faCaretDown, faCaretUp, faTrafficLight
 		}
 	},
 
@@ -116,6 +111,10 @@ export default defineComponent({
 		}
 	},
 
+	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
 	methods: {
 		getStatus(instance) {
 			if (instance.isSuspended) return 'off';
@@ -133,6 +132,12 @@ export default defineComponent({
 </script>
 
 <style lang="scss" scoped>
+.enuoauvw {
+	> .query {
+		margin: var(--margin);
+	}
+}
+
 .ppgwaixt {
 	cursor: pointer;
 	padding: 16px;
diff --git a/src/client/pages/instance/file-dialog.vue b/src/client/pages/instance/file-dialog.vue
index 85c03e3dcea58f41710f471d7c34939e44ce6790..74a755fa15dac5c79ae49adc5793d43e56b1201f 100644
--- a/src/client/pages/instance/file-dialog.vue
+++ b/src/client/pages/instance/file-dialog.vue
@@ -21,8 +21,8 @@
 		</div>
 		<div class="_section">
 			<div class="_content">
-				<MkButton full @click="showUser"><Fa :icon="faExternalLinkSquareAlt"/> {{ $ts.user }}</MkButton>
-				<MkButton full danger @click="del"><Fa :icon="faTrashAlt"/> {{ $ts.delete }}</MkButton>
+				<MkButton full @click="showUser"><i class="fas fa-external-link-square-alt"></i> {{ $ts.user }}</MkButton>
+				<MkButton full danger @click="del"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
 			</div>
 		</div>
 		<div class="_section" v-if="info">
@@ -36,8 +36,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faTimes, faBookmark, faKey, faSync, faMicrophoneSlash, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
-import { faSnowflake, faTrashAlt, faBookmark as farBookmark  } from '@fortawesome/free-regular-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkSwitch from '@client/components/ui/switch.vue';
 import XModalWindow from '@client/components/ui/modal-window.vue';
@@ -67,7 +65,6 @@ export default defineComponent({
 			file: null,
 			info: null,
 			isSensitive: false,
-			faTimes, faBookmark, farBookmark, faKey, faSync, faMicrophoneSlash, faSnowflake, faTrashAlt, faExternalLinkSquareAlt
 		};
 	},
 
@@ -85,9 +82,7 @@ export default defineComponent({
 		},
 
 		showUser() {
-			os.popup(import('./user-dialog.vue'), {
-				userId: this.file.userId
-			}, {}, 'closed');
+			os.pageWindow(`/user-info/${this.file.userId}`);
 		},
 
 		async del() {
diff --git a/src/client/pages/instance/files-settings.vue b/src/client/pages/instance/files-settings.vue
new file mode 100644
index 0000000000000000000000000000000000000000..614c7d4dbbbe859ec0ede98d207084ebf117f18d
--- /dev/null
+++ b/src/client/pages/instance/files-settings.vue
@@ -0,0 +1,92 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormSwitch v-model:value="cacheRemoteFiles">
+			{{ $ts.cacheRemoteFiles }}
+			<template #desc>{{ $ts.cacheRemoteFilesDescription }}</template>
+		</FormSwitch>
+
+		<FormSwitch v-model:value="proxyRemoteFiles">
+			{{ $ts.proxyRemoteFiles }}
+			<template #desc>{{ $ts.proxyRemoteFilesDescription }}</template>
+		</FormSwitch>
+
+		<FormInput v-model:value="localDriveCapacityMb" type="number">
+			<span>{{ $ts.driveCapacityPerLocalAccount }}</span>
+			<template #suffix>MB</template>
+			<template #desc>{{ $ts.inMb }}</template>
+		</FormInput>
+
+		<FormInput v-model:value="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles">
+			<span>{{ $ts.driveCapacityPerRemoteAccount }}</span>
+			<template #suffix>MB</template>
+			<template #desc>{{ $ts.inMb }}</template>
+		</FormInput>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.files,
+				icon: 'fas fa-cloud'
+			},
+			cacheRemoteFiles: false,
+			proxyRemoteFiles: false,
+			localDriveCapacityMb: 0,
+			remoteDriveCapacityMb: 0,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.cacheRemoteFiles = meta.cacheRemoteFiles;
+			this.proxyRemoteFiles = meta.proxyRemoteFiles;
+			this.localDriveCapacityMb = meta.driveCapacityPerLocalUserMb;
+			this.remoteDriveCapacityMb = meta.driveCapacityPerRemoteUserMb;
+		},
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				cacheRemoteFiles: this.cacheRemoteFiles,
+				proxyRemoteFiles: this.proxyRemoteFiles,
+				localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
+				remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/files.vue b/src/client/pages/instance/files.vue
index e7de050df8a481d8d575b87002d1272924e59b04..427c5b411ae968598f252e597983ff99307116b1 100644
--- a/src/client/pages/instance/files.vue
+++ b/src/client/pages/instance/files.vue
@@ -2,17 +2,17 @@
 <div class="xrmjdkdw">
 	<div class="_section">
 		<div class="_content">
-			<MkButton primary @click="clear()"><Fa :icon="faTrashAlt"/> {{ $ts.clearCachedFiles }}</MkButton>
+			<MkButton primary @click="clear()"><i class="fas fa-trash-alt"></i> {{ $ts.clearCachedFiles }}</MkButton>
 		</div>
 	</div>
 
 	<div class="_section lookup">
-		<div class="_title"><Fa :icon="faSearch"/> {{ $ts.lookup }}</div>
+		<div class="_title"><i class="fas fa-search"></i> {{ $ts.lookup }}</div>
 		<div class="_content">
 			<MkInput class="target" v-model:value="q" type="text" @enter="find()">
 				<span>{{ $ts.fileIdOrUrl }}</span>
 			</MkInput>
-			<MkButton @click="find()" primary><Fa :icon="faSearch"/> {{ $ts.lookup }}</MkButton>
+			<MkButton @click="find()" primary><i class="fas fa-search"></i> {{ $ts.lookup }}</MkButton>
 		</div>
 	</div>
 
@@ -62,8 +62,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCloud, faSearch } from '@fortawesome/free-solid-svg-icons';
-import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -82,11 +80,13 @@ export default defineComponent({
 		MkDriveFileThumbnail,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.files,
-				icon: faCloud
+				icon: 'fas fa-cloud'
 			},
 			q: null,
 			origin: 'local',
@@ -101,7 +101,6 @@ export default defineComponent({
 					hostname: (this.hostname && this.hostname !== '') ? this.hostname : null,
 				}),
 			},
-			faTrashAlt, faCloud, faSearch,
 		}
 	},
 
@@ -117,6 +116,10 @@ export default defineComponent({
 		},
 	},
 
+	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
 	methods: {
 		clear() {
 			os.dialog({
@@ -156,6 +159,8 @@ export default defineComponent({
 
 <style lang="scss" scoped>
 .xrmjdkdw {
+	margin: var(--margin);
+
 	.urempief {
 		margin-top: var(--margin);
 
diff --git a/src/client/pages/instance/index.vue b/src/client/pages/instance/index.vue
index 731acd8f00d9fe800d65a3a5de0c84d660611a68..5972a02de0c3c7016dd2532a9ef04a7e495d76b8 100644
--- a/src/client/pages/instance/index.vue
+++ b/src/client/pages/instance/index.vue
@@ -1,173 +1,243 @@
 <template>
-<div v-if="meta" v-show="page === 'index'" class="xhexznfu _section">
-	<MkFolder>
-		<template #header><Fa :icon="faTachometerAlt"/> {{ $ts.overview }}</template>
-
-		<div class="sboqnrfi" :style="{ gridTemplateRows: overviewHeight }">
-			<MkInstanceStats :chart-limit="300" :detailed="true" class="_gap" ref="stats"/>
-
-			<MkContainer :foldable="true" class="_gap">
-				<template #header><Fa :icon="faInfoCircle"/>{{ $ts.instanceInfo }}</template>
-
-				<div class="_content">
-					<div class="_keyValue"><b>Misskey</b><span>v{{ version }}</span></div>
-				</div>
-				<div class="_content" v-if="serverInfo">
-					<div class="_keyValue"><b>Node.js</b><span>{{ serverInfo.node }}</span></div>
-					<div class="_keyValue"><b>PostgreSQL</b><span>v{{ serverInfo.psql }}</span></div>
-					<div class="_keyValue"><b>Redis</b><span>v{{ serverInfo.redis }}</span></div>
+<div class="hiyeyicy" :class="{ wide: !narrow }" ref="el">
+	<div class="nav" v-if="!narrow || page == null">
+		<FormBase>
+			<FormGroup>
+				<div class="_formItem">
+					<div class="_formPanel lxpfedzu">
+						<img :src="$instance.iconUrl || '/favicon.ico'" alt="" class="icon"/>
+					</div>
 				</div>
-			</MkContainer>
-			
-			<MkContainer :foldable="true" :scrollable="true" class="_gap" style="height: 300px;">
-				<template #header><Fa :icon="faDatabase"/>{{ $ts.database }}</template>
-
-				<div class="_content" v-if="dbInfo">
-					<table style="border-collapse: collapse; width: 100%;">
-						<tr style="opacity: 0.7;">
-							<th style="text-align: left; padding: 0 8px 8px 0;">Table</th>
-							<th style="text-align: left; padding: 0 8px 8px 0;">Records</th>
-							<th style="text-align: left; padding: 0 0 8px 0;">Size</th>
-						</tr>
-						<tr v-for="table in dbInfo" :key="table[0]">
-							<th style="text-align: left; padding: 0 8px 0 0; word-break: break-all;">{{ table[0] }}</th>
-							<td style="padding: 0 8px 0 0;">{{ number(table[1].count) }}</td>
-							<td style="padding: 0; opacity: 0.7;">{{ bytes(table[1].size) }}</td>
-						</tr>
-					</table>
-				</div>
-			</MkContainer>
-		</div>
-	</MkFolder>
-</div>
-<div v-if="page === 'logs'" class="_section">
-	<MkFolder>
-		<template #header><Fa :icon="faStream"/> {{ $ts.logs }}</template>
-
-		<div class="_keyValue" v-for="log in modLogs">
-			<b>{{ log.type }}</b><span>by {{ log.user.username }}</span><MkTime :time="log.createdAt" style="opacity: 0.7;"/>
-		</div>
-	</MkFolder>
-</div>
-<div v-if="page === 'metrics'">
-	<XMetrics/>
+				<FormLink :active="page === 'overview'" replace to="/instance/overview"><template #icon><i class="fas fa-tachometer-alt"></i></template>{{ $ts.overview }}</FormLink>
+			</FormGroup>
+			<FormGroup>
+				<template #label>{{ $ts.quickAction }}</template>
+				<FormButton @click="lookup"><i class="fas fa-search"></i> {{ $ts.lookup }}</FormButton>
+				<FormButton v-if="$instance.disableRegistration" @click="invite"><i class="fas fa-user"></i> {{ $ts.invite }}</FormButton>
+			</FormGroup>
+			<FormGroup>
+				<template #label>{{ $ts.administration }}</template>
+				<FormLink :active="page === 'users'" replace to="/instance/users"><template #icon><i class="fas fa-users"></i></template>{{ $ts.users }}</FormLink>
+				<FormLink :active="page === 'emojis'" replace to="/instance/emojis"><template #icon><i class="fas fa-laugh"></i></template>{{ $ts.customEmojis }}</FormLink>
+				<FormLink :active="page === 'federation'" replace to="/instance/federation"><template #icon><i class="fas fa-globe"></i></template>{{ $ts.federation }}</FormLink>
+				<FormLink :active="page === 'queue'" replace to="/instance/queue"><template #icon><i class="fas fa-clipboard-list"></i></template>{{ $ts.jobQueue }}</FormLink>
+				<FormLink :active="page === 'files'" replace to="/instance/files"><template #icon><i class="fas fa-cloud"></i></template>{{ $ts.files }}</FormLink>
+				<FormLink :active="page === 'announcements'" replace to="/instance/announcements"><template #icon><i class="fas fa-broadcast-tower"></i></template>{{ $ts.announcements }}</FormLink>
+				<FormLink :active="page === 'abuses'" replace to="/instance/abuses"><template #icon><i class="fas fa-exclamation-circle"></i></template>{{ $ts.abuseReports }}</FormLink>
+			</FormGroup>
+			<FormGroup>
+				<template #label>{{ $ts.settings }}</template>
+				<FormLink :active="page === 'settings'" replace to="/instance/settings"><template #icon><i class="fas fa-cog"></i></template>{{ $ts.general }}</FormLink>
+				<FormLink :active="page === 'files-settings'" replace to="/instance/files-settings"><template #icon><i class="fas fa-cloud"></i></template>{{ $ts.files }}</FormLink>
+				<FormLink :active="page === 'email-settings'" replace to="/instance/email-settings"><template #icon><i class="fas fa-envelope"></i></template>{{ $ts.emailServer }}</FormLink>
+				<FormLink :active="page === 'object-storage'" replace to="/instance/object-storage"><template #icon><i class="fas fa-cloud"></i></template>{{ $ts.objectStorage }}</FormLink>
+				<FormLink :active="page === 'security'" replace to="/instance/security"><template #icon><i class="fas fa-lock"></i></template>{{ $ts.security }}</FormLink>
+				<FormLink :active="page === 'service-worker'" replace to="/instance/service-worker"><template #icon><i class="fas fa-bolt"></i></template>ServiceWorker</FormLink>
+				<FormLink :active="page === 'relays'" replace to="/instance/relays"><template #icon><i class="fas fa-globe"></i></template>{{ $ts.relays }}</FormLink>
+				<FormLink :active="page === 'integrations'" replace to="/instance/integrations"><template #icon><i class="fas fa-share-alt"></i></template>{{ $ts.integration }}</FormLink>
+				<FormLink :active="page === 'instance-block'" replace to="/instance/instance-block"><template #icon><i class="fas fa-ban"></i></template>{{ $ts.instanceBlocking }}</FormLink>
+				<FormLink :active="page === 'proxy-account'" replace to="/instance/proxy-account"><template #icon><i class="fas fa-ghost"></i></template>{{ $ts.proxyAccount }}</FormLink>
+				<FormLink :active="page === 'other-settings'" replace to="/instance/other-settings"><template #icon><i class="fas fa-cogs"></i></template>{{ $ts.other }}</FormLink>
+			</FormGroup>
+			<FormGroup>
+				<template #label>{{ $ts.info }}</template>
+				<FormLink :active="page === 'database'" replace to="/instance/database"><template #icon><i class="fas fa-database"></i></template>{{ $ts.database }}</FormLink>
+			</FormGroup>
+		</FormBase>
+	</div>
+	<div class="main">
+		<component :is="component" :key="page" @info="onInfo" v-bind="pageProps"/>
+	</div>
 </div>
 </template>
 
 <script lang="ts">
-import { computed, defineComponent, markRaw } from 'vue';
-import { faPlay, faPause, faDatabase, faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList } from '@fortawesome/free-solid-svg-icons';
-import VueJsonPretty from 'vue-json-pretty';
-import MkInstanceStats from '@client/components/instance-stats.vue';
-import MkButton from '@client/components/ui/button.vue';
-import MkSelect from '@client/components/ui/select.vue';
-import MkInput from '@client/components/ui/input.vue';
-import MkContainer from '@client/components/ui/container.vue';
-import MkFolder from '@client/components/ui/folder.vue';
-import { version, url } from '@client/config';
-import bytes from '../../filters/bytes';
-import number from '../../filters/number';
-import MkInstanceInfo from './instance.vue';
-import XMetrics from './index.metrics.vue';
-import * as os from '@client/os';
+import { computed, defineAsyncComponent, defineComponent, nextTick, onMounted, reactive, ref, watch } from 'vue';
+import { i18n } from '@client/i18n';
+import FormLink from '@client/components/form/link.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormButton from '@client/components/form/button.vue';
+import { scroll } from '@client/scripts/scroll';
 import * as symbols from '@client/symbols';
+import * as os from '@client/os';
+import { lookupUser } from '@client/scripts/lookup-user';
 
 export default defineComponent({
 	components: {
-		MkInstanceStats,
-		MkButton,
-		MkSelect,
-		MkInput,
-		MkContainer,
-		MkFolder,
-		XMetrics,
-		VueJsonPretty,
+		FormBase,
+		FormLink,
+		FormGroup,
+		FormButton,
 	},
 
-	data() {
-		return {
-			[symbols.PAGE_INFO]: {
-				tabs: [{
-					id: 'index',
-					title: null,
-					tooltip: this.$ts.instance,
-					icon: faServer,
-					onClick: () => { this.page = 'index'; },
-					selected: computed(() => this.page === 'index')
-				}, {
-					id: 'metrics',
-					title: null,
-					tooltip: this.$ts.metrics,
-					icon: faHeartbeat,
-					onClick: () => { this.page = 'metrics'; },
-					selected: computed(() => this.page === 'metrics')
-				}, {
-					id: 'logs',
-					title: null,
-					tooltip: this.$ts.logs,
-					icon: faStream,
-					onClick: () => { this.page = 'logs'; },
-					selected: computed(() => this.page === 'logs')
-				}]
-			},
-			page: 'index',
-			version,
-			url,
-			stats: null,
-			serverInfo: null,
-			modLogs: [],
-			dbInfo: null,
-			faPlay, faPause, faDatabase, faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList,
+	props: {
+		initialPage: {
+			type: String,
+			required: false
 		}
 	},
 
-	computed: {
-		meta() {
-			return this.$instance;
-		},
-	},
+	setup(props, context) {
+		const indexInfo = {
+			title: i18n.locale.instance,
+			icon: 'fas fa-cog'
+		};
+		const INFO = ref(indexInfo);
+		const page = ref(props.initialPage);
+		const narrow = ref(false);
+		const view = ref(null);
+		const el = ref(null);
+		const onInfo = (viewInfo) => {
+			INFO.value = viewInfo;
+		};
+		const pageProps = ref({});
+		const component = computed(() => {
+			if (page.value == null) return null;
+			switch (page.value) {
+				case 'overview': return defineAsyncComponent(() => import('./overview.vue'));
+				case 'users': return defineAsyncComponent(() => import('./users.vue'));
+				case 'emojis': return defineAsyncComponent(() => import('./emojis.vue'));
+				case 'federation': return defineAsyncComponent(() => import('./federation.vue'));
+				case 'queue': return defineAsyncComponent(() => import('./queue.vue'));
+				case 'files': return defineAsyncComponent(() => import('./files.vue'));
+				case 'announcements': return defineAsyncComponent(() => import('./announcements.vue'));
+				case 'database': return defineAsyncComponent(() => import('./database.vue'));
+				case 'abuses': return defineAsyncComponent(() => import('./abuses.vue'));
+				case 'settings': return defineAsyncComponent(() => import('./settings.vue'));
+				case 'files-settings': return defineAsyncComponent(() => import('./files-settings.vue'));
+				case 'email-settings': return defineAsyncComponent(() => import('./email-settings.vue'));
+				case 'object-storage': return defineAsyncComponent(() => import('./object-storage.vue'));
+				case 'security': return defineAsyncComponent(() => import('./security.vue'));
+				case 'bot-protection': return defineAsyncComponent(() => import('./bot-protection.vue'));
+				case 'service-worker': return defineAsyncComponent(() => import('./service-worker.vue'));
+				case 'relays': return defineAsyncComponent(() => import('./relays.vue'));
+				case 'integrations': return defineAsyncComponent(() => import('./integrations.vue'));
+				case 'integrations/twitter': return defineAsyncComponent(() => import('./integrations-twitter.vue'));
+				case 'integrations/github': return defineAsyncComponent(() => import('./integrations-github.vue'));
+				case 'integrations/discord': return defineAsyncComponent(() => import('./integrations-discord.vue'));
+				case 'instance-block': return defineAsyncComponent(() => import('./instance-block.vue'));
+				case 'proxy-account': return defineAsyncComponent(() => import('./proxy-account.vue'));
+				case 'other-settings': return defineAsyncComponent(() => import('./other-settings.vue'));
+			}
+		});
 
-	mounted() {
-		this.fetchJobs();
-		this.fetchModLogs();
+		watch(component, () => {
+			pageProps.value = {};
 
-		os.api('admin/server-info', {}).then(res => {
-			this.serverInfo = res;
+			nextTick(() => {
+				scroll(el.value, 0);
+			});
+		}, { immediate: true });
+
+		watch(() => props.initialPage, () => {
+			if (props.initialPage == null && !narrow.value) {
+				page.value = 'overview';
+			} else {
+				page.value = props.initialPage;
+				if (props.initialPage == null) {
+					INFO.value = indexInfo;
+				}
+			}
 		});
 
-		os.api('admin/get-table-stats', {}).then(res => {
-			this.dbInfo = Object.entries(res).sort((a, b) => b[1].size - a[1].size);
+		onMounted(() => {
+			narrow.value = el.value.offsetWidth < 800;
+			if (!narrow.value) {
+				page.value = 'overview';
+			}
 		});
-	},
 
-	methods: {
-		async showInstanceInfo(q) {
-			let instance = q;
-			if (typeof q === 'string') {
-				instance = await os.api('federation/show-instance', {
-					host: q
+		const invite = () => {
+			os.api('admin/invite').then(x => {
+				os.dialog({
+					type: 'info',
+					text: x.code
+				});
+			}).catch(e => {
+				os.dialog({
+					type: 'error',
+					text: e
 				});
-			}
-			os.popup(MkInstanceInfo, {
-				instance: instance
-			}, {}, 'closed');
-		},
-
-		fetchJobs() {
-			os.api('admin/queue/deliver-delayed', {}).then(jobs => {
-				this.jobs = jobs;
 			});
-		},
+		};
+
+		const lookup = (ev) => {
+			os.modalMenu([{
+				text: i18n.locale.user,
+				icon: 'fas fa-user',
+				action: () => {
+					lookupUser();
+				}
+			}, {
+				text: i18n.locale.note,
+				icon: 'fas fa-pencil-alt',
+				action: () => {
+					alert('TODO');
+				}
+			}, {
+				text: i18n.locale.file,
+				icon: 'fas fa-cloud',
+				action: () => {
+					alert('TODO');
+				}
+			}, {
+				text: i18n.locale.instance,
+				icon: 'fas fa-globe',
+				action: () => {
+					alert('TODO');
+				}
+			}], ev.currentTarget || ev.target);
+		};
 
-		fetchModLogs() {
-			os.api('admin/show-moderation-logs', {}).then(logs => {
-				this.modLogs = logs;
-			});
-		},
+		return {
+			[symbols.PAGE_INFO]: INFO,
+			page,
+			narrow,
+			view,
+			el,
+			onInfo,
+			pageProps,
+			component,
+			invite,
+			lookup,
+		};
+	},
+});
+</script>
 
-		bytes,
+<style lang="scss" scoped>
+.hiyeyicy {
+	&.wide {
+		display: flex;
+		max-width: 1100px;
+		margin: 0 auto;
+		height: 100%;
+
+		> .nav {
+			width: 32%;
+			box-sizing: border-box;
+			border-right: solid 0.5px var(--divider);
+			overflow: auto;
+		}
 
-		number,
+		> .main {
+			flex: 1;
+			min-width: 0;
+			overflow: auto;
+			--baseContentWidth: 100%;
+		}
 	}
-});
-</script>
+}
+
+.lxpfedzu {
+	padding: 16px;
+
+	> .icon {
+		display: block;
+		margin: auto;
+		height: 42px;
+		border-radius: 8px;
+	}
+}
+</style>
diff --git a/src/client/pages/instance/instance-block.vue b/src/client/pages/instance/instance-block.vue
new file mode 100644
index 0000000000000000000000000000000000000000..ed5740f33982121b4d66bf50f3938aa7dc57caf0
--- /dev/null
+++ b/src/client/pages/instance/instance-block.vue
@@ -0,0 +1,71 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormTextarea v-model:value="blockedHosts">
+			<span>{{ $ts.blockedInstances }}</span>
+			<template #desc>{{ $ts.blockedInstancesDescription }}</template>
+		</FormTextarea>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormTextarea from '@client/components/form/textarea.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormTextarea,
+		FormInfo,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.instanceBlocking,
+				icon: 'fas fa-ban'
+			},
+			blockedHosts: '',
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.blockedHosts = meta.blockedHosts.join('\n');
+		},
+
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				blockedHosts: this.blockedHosts.split('\n') || [],
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/instance.vue b/src/client/pages/instance/instance.vue
index 1adb3ab9d2e046b75dbb5f2aaba3fce394741d63..f52e5d866b15914dc71cfbe522f33d36b63aebb5 100644
--- a/src/client/pages/instance/instance.vue
+++ b/src/client/pages/instance/instance.vue
@@ -106,11 +106,11 @@
 			<MkSwitch :value="isBlocked" class="switch" @update:value="changeBlock">{{ $ts.blockThisInstance }}</MkSwitch>
 			<details>
 				<summary>{{ $ts.deleteAllFiles }}</summary>
-				<MkButton @click="deleteAllFiles()" style="margin: 0.5em 0 0.5em 0;"><Fa :icon="faTrashAlt"/> {{ $ts.deleteAllFiles }}</MkButton>
+				<MkButton @click="deleteAllFiles()" style="margin: 0.5em 0 0.5em 0;"><i class="fas fa-trash-alt"></i> {{ $ts.deleteAllFiles }}</MkButton>
 			</details>
 			<details>
 				<summary>{{ $ts.removeAllFollowing }}</summary>
-				<MkButton @click="removeAllFollowing()" style="margin: 0.5em 0 0.5em 0;"><Fa :icon="faMinusCircle"/> {{ $ts.removeAllFollowing }}</MkButton>
+				<MkButton @click="removeAllFollowing()" style="margin: 0.5em 0 0.5em 0;"><i class="fas fa-minus-circle"></i> {{ $ts.removeAllFollowing }}</MkButton>
 				<MkInfo warn>{{ $t('removeAllFollowingDescription', { host: instance.host }) }}</MkInfo>
 			</details>
 		</div>
@@ -125,7 +125,6 @@
 <script lang="ts">
 import { defineComponent } from 'vue';
 import Chart from 'chart.js';
-import { faTimes, faCrosshairs, faCloudDownloadAlt, faCloudUploadAlt, faUsers, faPencilAlt, faFileImage, faDatabase, faTrafficLight, faLongArrowAltUp, faLongArrowAltDown, faMinusCircle, faTrashAlt } from '@fortawesome/free-solid-svg-icons';
 import XModalWindow from '@client/components/ui/modal-window.vue';
 import MkUsersDialog from '@client/components/users-dialog.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -174,7 +173,6 @@ export default defineComponent({
 			chartInstance: null,
 			chartSrc: 'requests',
 			chartSpan: 'hour',
-			faTimes, faCrosshairs, faCloudDownloadAlt, faCloudUploadAlt, faUsers, faPencilAlt, faFileImage, faDatabase, faTrafficLight, faLongArrowAltUp, faLongArrowAltDown, faMinusCircle, faTrashAlt
 		};
 	},
 
diff --git a/src/client/pages/instance/integrations-discord.vue b/src/client/pages/instance/integrations-discord.vue
new file mode 100644
index 0000000000000000000000000000000000000000..c7508918f8d3d2b22f565dc08554069b5dd27e65
--- /dev/null
+++ b/src/client/pages/instance/integrations-discord.vue
@@ -0,0 +1,85 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormSwitch v-model:value="enableDiscordIntegration">
+			{{ $ts.enable }}
+		</FormSwitch>
+
+		<template v-if="enableDiscordIntegration">
+			<FormInfo>Callback URL: {{ `${url}/api/dc/cb` }}</FormInfo>
+		
+			<FormInput v-model:value="discordClientId">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Client ID
+			</FormInput>
+
+			<FormInput v-model:value="discordClientSecret">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Client Secret
+			</FormInput>
+		</template>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormInfo,
+		FormButton,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: 'Discord',
+				icon: 'fab fa-discord'
+			},
+			enableDiscordIntegration: false,
+			discordClientId: null,
+			discordClientSecret: null,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableDiscordIntegration = meta.enableDiscordIntegration;
+			this.discordClientId = meta.discordClientId;
+			this.discordClientSecret = meta.discordClientSecret;
+		},
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				enableDiscordIntegration: this.enableDiscordIntegration,
+				discordClientId: this.discordClientId,
+				discordClientSecret: this.discordClientSecret,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/integrations-github.vue b/src/client/pages/instance/integrations-github.vue
new file mode 100644
index 0000000000000000000000000000000000000000..16586b15b4e79c49631adaf4e8f38c78e21d8c67
--- /dev/null
+++ b/src/client/pages/instance/integrations-github.vue
@@ -0,0 +1,85 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormSwitch v-model:value="enableGithubIntegration">
+			{{ $ts.enable }}
+		</FormSwitch>
+
+		<template v-if="enableGithubIntegration">
+			<FormInfo>Callback URL: {{ `${url}/api/gh/cb` }}</FormInfo>
+		
+			<FormInput v-model:value="githubClientId">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Client ID
+			</FormInput>
+
+			<FormInput v-model:value="githubClientSecret">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Client Secret
+			</FormInput>
+		</template>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormInfo,
+		FormButton,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: 'GitHub',
+				icon: 'fab fa-github'
+			},
+			enableGithubIntegration: false,
+			githubClientId: null,
+			githubClientSecret: null,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableGithubIntegration = meta.enableGithubIntegration;
+			this.githubClientId = meta.githubClientId;
+			this.githubClientSecret = meta.githubClientSecret;
+		},
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				enableGithubIntegration: this.enableGithubIntegration,
+				githubClientId: this.githubClientId,
+				githubClientSecret: this.githubClientSecret,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/integrations-twitter.vue b/src/client/pages/instance/integrations-twitter.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b08b7f40a55fccf605aac2f723eb3c99c687ebb2
--- /dev/null
+++ b/src/client/pages/instance/integrations-twitter.vue
@@ -0,0 +1,85 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormSwitch v-model:value="enableTwitterIntegration">
+			{{ $ts.enable }}
+		</FormSwitch>
+
+		<template v-if="enableTwitterIntegration">
+			<FormInfo>Callback URL: {{ `${url}/api/tw/cb` }}</FormInfo>
+		
+			<FormInput v-model:value="twitterConsumerKey">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Consumer Key
+			</FormInput>
+
+			<FormInput v-model:value="twitterConsumerSecret">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Consumer Secret
+			</FormInput>
+		</template>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormInfo,
+		FormButton,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: 'Twitter',
+				icon: 'fab fa-twitter'
+			},
+			enableTwitterIntegration: false,
+			twitterConsumerKey: null,
+			twitterConsumerSecret: null,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableTwitterIntegration = meta.enableTwitterIntegration;
+			this.twitterConsumerKey = meta.twitterConsumerKey;
+			this.twitterConsumerSecret = meta.twitterConsumerSecret;
+		},
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				enableTwitterIntegration: this.enableTwitterIntegration,
+				twitterConsumerKey: this.twitterConsumerKey,
+				twitterConsumerSecret: this.twitterConsumerSecret,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/integrations.vue b/src/client/pages/instance/integrations.vue
new file mode 100644
index 0000000000000000000000000000000000000000..7debedc367ab6d822972d6bfa1f0575b103363ac
--- /dev/null
+++ b/src/client/pages/instance/integrations.vue
@@ -0,0 +1,73 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormLink to="/instance/integrations/twitter">
+			<i class="fab fa-twitter"></i> Twitter
+			<template #suffix>{{ enableTwitterIntegration ? $ts.enabled : $ts.disabled }}</template>
+		</FormLink>
+		<FormLink to="/instance/integrations/github">
+			<i class="fab fa-github"></i> GitHub
+			<template #suffix>{{ enableGithubIntegration ? $ts.enabled : $ts.disabled }}</template>
+		</FormLink>
+		<FormLink to="/instance/integrations/discord">
+			<i class="fab fa-discord"></i> Discord
+			<template #suffix>{{ enableDiscordIntegration ? $ts.enabled : $ts.disabled }}</template>
+		</FormLink>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormLink from '@client/components/form/link.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormTextarea from '@client/components/form/textarea.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormLink,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormTextarea,
+		FormInfo,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.integration,
+				icon: 'fas fa-share-alt'
+			},
+			enableTwitterIntegration: false,
+			enableGithubIntegration: false,
+			enableDiscordIntegration: false,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableTwitterIntegration = meta.enableTwitterIntegration;
+			this.enableGithubIntegration = meta.enableGithubIntegration;
+			this.enableDiscordIntegration = meta.enableDiscordIntegration;
+		},
+	}
+});
+</script>
diff --git a/src/client/pages/instance/logs.vue b/src/client/pages/instance/logs.vue
index f27546a40116e79d2f7f4cddd92ff582dac959ff..7b634259d357e97719934827b8fdc2a87af86b6f 100644
--- a/src/client/pages/instance/logs.vue
+++ b/src/client/pages/instance/logs.vue
@@ -24,14 +24,12 @@
 		</code>
 	</div>
 
-	<MkButton @click="deleteAllLogs()" primary><Fa :icon="faTrashAlt"/> {{ $ts.deleteAll }}</MkButton>
+	<MkButton @click="deleteAllLogs()" primary><i class="fas fa-trash-alt"></i> {{ $ts.deleteAll }}</MkButton>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faStream } from '@fortawesome/free-solid-svg-icons';
-import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -51,12 +49,11 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.serverLogs,
-				icon: faStream
+				icon: 'fas fa-stream'
 			},
 			logs: [],
 			logLevel: 'all',
 			logDomain: '',
-			faTrashAlt,
 		}
 	},
 
diff --git a/src/client/pages/instance/index.metrics.vue b/src/client/pages/instance/metrics.vue
similarity index 59%
rename from src/client/pages/instance/index.metrics.vue
rename to src/client/pages/instance/metrics.vue
index 17ebf5d0d668e557202aceddac24cebbbd25abe6..18cfe5eee2f2aee13ab5916914f8b72ed925707a 100644
--- a/src/client/pages/instance/index.metrics.vue
+++ b/src/client/pages/instance/metrics.vue
@@ -1,107 +1,57 @@
 <template>
-<div>
-	<MkFolder>
-		<template #header><Fa :icon="faHeartbeat"/> {{ $ts.metrics }}</template>
-		<div class="_section" style="padding: 0 var(--margin);">
-			<div class="_content">
-				<MkContainer :foldable="false" class="_gap">
-					<template #header><Fa :icon="faMicrochip"/>{{ $ts.cpuAndMemory }}</template>
-					<!--
-					<template #func>
-						<button class="_button" @click="resume" :disabled="!paused"><Fa :icon="faPlay"/></button>
-						<button class="_button" @click="pause" :disabled="paused"><Fa :icon="faPause"/></button>
-					</template>
-					-->
-
-					<div class="_content" style="margin-top: -8px; margin-bottom: -12px;">
-						<canvas :ref="cpumem"></canvas>
-					</div>
-					<div class="_content" v-if="serverInfo">
-						<div class="_table">
-							<div class="_row">
-								<div class="_cell"><div class="_label">MEM total</div>{{ bytes(serverInfo.mem.total) }}</div>
-								<div class="_cell"><div class="_label">MEM used</div>{{ bytes(memUsage) }} ({{ (memUsage / serverInfo.mem.total * 100).toFixed(0) }}%)</div>
-								<div class="_cell"><div class="_label">MEM free</div>{{ bytes(serverInfo.mem.total - memUsage) }} ({{ ((serverInfo.mem.total - memUsage) / serverInfo.mem.total * 100).toFixed(0) }}%)</div>
-							</div>
-						</div>
-					</div>
-				</MkContainer>
-
-				<MkContainer :foldable="false" class="_gap">
-					<template #header><Fa :icon="faHdd"/> {{ $ts.disk }}</template>
-					<!--
-					<template #func>
-						<button class="_button" @click="resume" :disabled="!paused"><Fa :icon="faPlay"/></button>
-						<button class="_button" @click="pause" :disabled="paused"><Fa :icon="faPause"/></button>
-					</template>
-					-->
-
-					<div class="_content" style="margin-top: -8px; margin-bottom: -12px;">
-						<canvas :ref="disk"></canvas>
-					</div>
-					<div class="_content" v-if="serverInfo">
-						<div class="_table">
-							<div class="_row">
-								<div class="_cell"><div class="_label">Disk total</div>{{ bytes(serverInfo.fs.total) }}</div>
-								<div class="_cell"><div class="_label">Disk used</div>{{ bytes(serverInfo.fs.used) }} ({{ (serverInfo.fs.used / serverInfo.fs.total * 100).toFixed(0) }}%)</div>
-								<div class="_cell"><div class="_label">Disk free</div>{{ bytes(serverInfo.fs.total - serverInfo.fs.used) }} ({{ ((serverInfo.fs.total - serverInfo.fs.used) / serverInfo.fs.total * 100).toFixed(0) }}%)</div>
-							</div>
-						</div>
-					</div>
-				</MkContainer>
-
-				<MkContainer :foldable="false" class="_gap">
-					<template #header><Fa :icon="faExchangeAlt"/> {{ $ts.network }}</template>
-					<!--
-					<template #func>
-						<button class="_button" @click="resume" :disabled="!paused"><Fa :icon="faPlay"/></button>
-						<button class="_button" @click="pause" :disabled="paused"><Fa :icon="faPause"/></button>
-					</template>
-					-->
-
-					<div class="_content" style="margin-top: -8px; margin-bottom: -12px;">
-						<canvas :ref="net"></canvas>
-					</div>
-					<div class="_content" v-if="serverInfo">
-						<div class="_table">
-							<div class="_row">
-								<div class="_cell"><div class="_label">Interface</div>{{ serverInfo.net.interface }}</div>
-							</div>
-						</div>
-					</div>
-				</MkContainer>
+<div class="_formItem">
+	<div class="_formLabel"><i class="fas fa-microchip"></i> {{ $ts.cpuAndMemory }}</div>
+	<div class="_formPanel xhexznfu">
+		<div>
+			<canvas :ref="cpumem"></canvas>
+		</div>
+		<div v-if="serverInfo">
+			<div class="_table">
+				<div class="_row">
+					<div class="_cell"><div class="_label">MEM total</div>{{ bytes(serverInfo.mem.total) }}</div>
+					<div class="_cell"><div class="_label">MEM used</div>{{ bytes(memUsage) }} ({{ (memUsage / serverInfo.mem.total * 100).toFixed(0) }}%)</div>
+					<div class="_cell"><div class="_label">MEM free</div>{{ bytes(serverInfo.mem.total - memUsage) }} ({{ ((serverInfo.mem.total - memUsage) / serverInfo.mem.total * 100).toFixed(0) }}%)</div>
+				</div>
 			</div>
 		</div>
-	</MkFolder>
-
-	<MkFolder>
-		<template #header><Fa :icon="faClipboardList"/> {{ $ts.jobQueue }}</template>
-
-		<div class="vkyrmkwb" :style="{ gridTemplateRows: queueHeight }">
-			<MkContainer :foldable="false" :scrollable="true" :resize-base-el="() => $el">
-				<template #header><Fa :icon="faExclamationTriangle"/> {{ $ts.delayed }}</template>
-
-				<div class="_content">
-					<div class="_keyValue" v-for="job in jobs" :key="job[0]">
-						<button class="_button" @click="showInstanceInfo(job[0])">{{ job[0] }}</button>
-						<div style="text-align: right;">{{ number(job[1]) }} jobs</div>
-					</div>
+	</div>
+</div>
+<div class="_formItem">
+	<div class="_formLabel"><i class="fas fa-hdd"></i> {{ $ts.disk }}</div>
+	<div class="_formPanel xhexznfu">
+		<div>
+			<canvas :ref="disk"></canvas>
+		</div>
+		<div v-if="serverInfo">
+			<div class="_table">
+				<div class="_row">
+					<div class="_cell"><div class="_label">Disk total</div>{{ bytes(serverInfo.fs.total) }}</div>
+					<div class="_cell"><div class="_label">Disk used</div>{{ bytes(serverInfo.fs.used) }} ({{ (serverInfo.fs.used / serverInfo.fs.total * 100).toFixed(0) }}%)</div>
+					<div class="_cell"><div class="_label">Disk free</div>{{ bytes(serverInfo.fs.total - serverInfo.fs.used) }} ({{ ((serverInfo.fs.total - serverInfo.fs.used) / serverInfo.fs.total * 100).toFixed(0) }}%)</div>
 				</div>
-			</MkContainer>
-			<XQueue :connection="queueConnection" domain="inbox" ref="queue" class="queue">
-				<template #title><Fa :icon="faExchangeAlt"/> In</template>
-			</XQueue>
-			<XQueue :connection="queueConnection" domain="deliver" class="queue">
-				<template #title><Fa :icon="faExchangeAlt"/> Out</template>
-			</XQueue>
+			</div>
+		</div>
+	</div>
+</div>
+<div class="_formItem">
+	<div class="_formLabel"><i class="fas fa-exchange-alt"></i> {{ $ts.network }}</div>
+	<div class="_formPanel xhexznfu">
+		<div>
+			<canvas :ref="net"></canvas>
+		</div>
+		<div v-if="serverInfo">
+			<div class="_table">
+				<div class="_row">
+					<div class="_cell"><div class="_label">Interface</div>{{ serverInfo.net.interface }}</div>
+				</div>
+			</div>
 		</div>
-	</MkFolder>
+	</div>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, markRaw } from 'vue';
-import { faPlay, faPause, faDatabase, faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList } from '@fortawesome/free-solid-svg-icons';
 import Chart from 'chart.js';
 import MkButton from '@client/components/ui/button.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -153,7 +103,6 @@ export default defineComponent({
 			overviewHeight: '1fr',
 			queueHeight: '1fr',
 			paused: false,
-			faPlay, faPause, faDatabase, faServer, faExchangeAlt, faMicrochip, faHdd, faStream, faTrashAlt, faInfoCircle, faExclamationTriangle, faTachometerAlt, faHeartbeat, faClipboardList,
 		}
 	},
 
@@ -190,9 +139,11 @@ export default defineComponent({
 	},
 
 	beforeUnmount() {
-		this.connection.off('stats', this.onStats);
-		this.connection.off('statsLog', this.onStatsLog);
-		this.connection.dispose();
+		if (this.connection) {
+			this.connection.off('stats', this.onStats);
+			this.connection.off('statsLog', this.onStatsLog);
+			this.connection.dispose();
+		}
 		this.queueConnection.dispose();
 	},
 
@@ -234,9 +185,9 @@ export default defineComponent({
 					aspectRatio: 3,
 					layout: {
 						padding: {
-							left: 0,
-							right: 0,
-							top: 8,
+							left: 16,
+							right: 16,
+							top: 16,
 							bottom: 0
 						}
 					},
@@ -306,9 +257,9 @@ export default defineComponent({
 					aspectRatio: 3,
 					layout: {
 						padding: {
-							left: 0,
-							right: 0,
-							top: 8,
+							left: 16,
+							right: 16,
+							top: 16,
 							bottom: 0
 						}
 					},
@@ -377,9 +328,9 @@ export default defineComponent({
 					aspectRatio: 3,
 					layout: {
 						padding: {
-							left: 0,
-							right: 0,
-							top: 8,
+							left: 16,
+							right: 16,
+							top: 16,
 							bottom: 0
 						}
 					},
@@ -496,81 +447,9 @@ export default defineComponent({
 
 <style lang="scss" scoped>
 .xhexznfu {
-	&.min-width_1000px {
-		.sboqnrfi {
-			display: grid;
-			grid-template-columns: 3.2fr 1fr;
-			grid-template-rows: 1fr;
-			gap: 16px 16px;
-
-			> .stats {
-				height: min-content;
-			}
-
-			> .column {
-				display: flex;
-				flex-direction: column;
-
-				> .info {
-					flex-shrink: 0;
-					flex-grow: 0;
-				}
-
-				> .db {
-					flex: 1;
-					flex-grow: 0;
-					height: 100%;
-				}
-
-				> .fed {
-					flex: 1;
-					flex-grow: 0;
-					height: 100%;
-				}
-
-				> *:not(:last-child) {
-					margin-bottom: var(--margin);
-				}
-			}
-		}
-
-		.segusily {
-			display: grid;
-			grid-template-columns: 1fr 1fr 1fr;
-			grid-template-rows: 1fr;
-			gap: 16px 16px;
-			padding: 0 16px;
-		}
-
-		.vkyrmkwb {
-			display: grid;
-			grid-template-columns: 0.5fr 1fr 1fr;
-			grid-template-rows: 1fr;
-			gap: 16px 16px;
-			margin-bottom: var(--margin);
-
-			> .queue {
-				height: min-content;
-			}
-
-			> * {
-				margin-bottom: 0;
-			}
-		}
-
-		.uwuemslx {
-			display: grid;
-			grid-template-columns: 2fr 3fr;
-			grid-template-rows: 1fr;
-			gap: 16px 16px;
-			height: 400px;
-		}
-	}
-
-	.vkyrmkwb {
-		> * {
-			margin-bottom: var(--margin);
-		}
+	> div:nth-child(2) {
+		padding: 16px;
+		border-top: solid 0.5px var(--divider);
 	}
 }
 </style>
diff --git a/src/client/pages/instance/object-storage.vue b/src/client/pages/instance/object-storage.vue
new file mode 100644
index 0000000000000000000000000000000000000000..814aeb6e48667b41b779c8987fb4ee8ef5142603
--- /dev/null
+++ b/src/client/pages/instance/object-storage.vue
@@ -0,0 +1,154 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormSwitch v-model:value="useObjectStorage">{{ $ts.useObjectStorage }}</FormSwitch>
+
+		<template v-if="useObjectStorage">
+			<FormInput v-model:value="objectStorageBaseUrl">
+				<span>{{ $ts.objectStorageBaseUrl }}</span>
+				<template #desc>{{ $ts.objectStorageBaseUrlDesc }}</template>
+			</FormInput>
+
+			<FormInput v-model:value="objectStorageBucket">
+				<span>{{ $ts.objectStorageBucket }}</span>
+				<template #desc>{{ $ts.objectStorageBucketDesc }}</template>
+			</FormInput>
+
+			<FormInput v-model:value="objectStoragePrefix">
+				<span>{{ $ts.objectStoragePrefix }}</span>
+				<template #desc>{{ $ts.objectStoragePrefixDesc }}</template>
+			</FormInput>
+
+			<FormInput v-model:value="objectStorageEndpoint">
+				<span>{{ $ts.objectStorageEndpoint }}</span>
+				<template #desc>{{ $ts.objectStorageEndpointDesc }}</template>
+			</FormInput>
+
+			<FormInput v-model:value="objectStorageRegion">
+				<span>{{ $ts.objectStorageRegion }}</span>
+				<template #desc>{{ $ts.objectStorageRegionDesc }}</template>
+			</FormInput>
+
+			<FormInput v-model:value="objectStorageAccessKey">
+				<template #prefix><i class="fas fa-key"></i></template>
+				<span>Access key</span>
+			</FormInput>
+
+			<FormInput v-model:value="objectStorageSecretKey">
+				<template #prefix><i class="fas fa-key"></i></template>
+				<span>Secret key</span>
+			</FormInput>
+
+			<FormSwitch v-model:value="objectStorageUseSSL">
+				{{ $ts.objectStorageUseSSL }}
+				<template #desc>{{ $ts.objectStorageUseSSLDesc }}</template>
+			</FormSwitch>
+
+			<FormSwitch v-model:value="objectStorageUseProxy">
+				{{ $ts.objectStorageUseProxy }}
+				<template #desc>{{ $ts.objectStorageUseProxyDesc }}</template>
+			</FormSwitch>
+
+			<FormSwitch v-model:value="objectStorageSetPublicRead">
+				{{ $ts.objectStorageSetPublicRead }}
+			</FormSwitch>
+
+			<FormSwitch v-model:value="objectStorageS3ForcePathStyle">
+				s3ForcePathStyle
+			</FormSwitch>
+		</template>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.objectStorage,
+				icon: 'fas fa-cloud'
+			},
+			useObjectStorage: false,
+			objectStorageBaseUrl: null,
+			objectStorageBucket: null,
+			objectStoragePrefix: null,
+			objectStorageEndpoint: null,
+			objectStorageRegion: null,
+			objectStoragePort: null,
+			objectStorageAccessKey: null,
+			objectStorageSecretKey: null,
+			objectStorageUseSSL: false,
+			objectStorageUseProxy: false,
+			objectStorageSetPublicRead: false,
+			objectStorageS3ForcePathStyle: true,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.useObjectStorage = meta.useObjectStorage;
+			this.objectStorageBaseUrl = meta.objectStorageBaseUrl;
+			this.objectStorageBucket = meta.objectStorageBucket;
+			this.objectStoragePrefix = meta.objectStoragePrefix;
+			this.objectStorageEndpoint = meta.objectStorageEndpoint;
+			this.objectStorageRegion = meta.objectStorageRegion;
+			this.objectStoragePort = meta.objectStoragePort;
+			this.objectStorageAccessKey = meta.objectStorageAccessKey;
+			this.objectStorageSecretKey = meta.objectStorageSecretKey;
+			this.objectStorageUseSSL = meta.objectStorageUseSSL;
+			this.objectStorageUseProxy = meta.objectStorageUseProxy;
+			this.objectStorageSetPublicRead = meta.objectStorageSetPublicRead;
+			this.objectStorageS3ForcePathStyle = meta.objectStorageS3ForcePathStyle;
+		},
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				useObjectStorage: this.useObjectStorage,
+				objectStorageBaseUrl: this.objectStorageBaseUrl ? this.objectStorageBaseUrl : null,
+				objectStorageBucket: this.objectStorageBucket ? this.objectStorageBucket : null,
+				objectStoragePrefix: this.objectStoragePrefix ? this.objectStoragePrefix : null,
+				objectStorageEndpoint: this.objectStorageEndpoint ? this.objectStorageEndpoint : null,
+				objectStorageRegion: this.objectStorageRegion ? this.objectStorageRegion : null,
+				objectStoragePort: this.objectStoragePort ? this.objectStoragePort : null,
+				objectStorageAccessKey: this.objectStorageAccessKey ? this.objectStorageAccessKey : null,
+				objectStorageSecretKey: this.objectStorageSecretKey ? this.objectStorageSecretKey : null,
+				objectStorageUseSSL: this.objectStorageUseSSL,
+				objectStorageUseProxy: this.objectStorageUseProxy,
+				objectStorageSetPublicRead: this.objectStorageSetPublicRead,
+				objectStorageS3ForcePathStyle: this.objectStorageS3ForcePathStyle,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/other-settings.vue b/src/client/pages/instance/other-settings.vue
new file mode 100644
index 0000000000000000000000000000000000000000..b3954149a823e9d856c711cdd2ece8ecf0f56644
--- /dev/null
+++ b/src/client/pages/instance/other-settings.vue
@@ -0,0 +1,68 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormGroup>
+			<FormInput v-model:value="summalyProxy">
+				<template #prefix><i class="fas fa-link"></i></template>
+				Summaly Proxy URL
+			</FormInput>
+		</FormGroup>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.other,
+				icon: 'fas fa-cogs'
+			},
+			summalyProxy: '',
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.summalyProxy = meta.summalyProxy;
+		},
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				summalyProxy: this.summalyProxy,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/overview.vue b/src/client/pages/instance/overview.vue
new file mode 100644
index 0000000000000000000000000000000000000000..dca2529e1bbe8875539004314dad65d091b9f428
--- /dev/null
+++ b/src/client/pages/instance/overview.vue
@@ -0,0 +1,135 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormInfo v-if="noMaintainerInformation" warn>{{ $ts.noMaintainerInformationWarning }} <MkA to="/instance/settings" class="_link">{{ $ts.configure }}</MkA></FormInfo>
+		<FormInfo v-if="noBotProtection" warn>{{ $ts.noBotProtectionWarning }} <MkA to="/instance/bot-protection" class="_link">{{ $ts.configure }}</MkA></FormInfo>
+
+		<FormSuspense :p="fetchStats" v-slot="{ result: stats }">
+			<FormGroup>
+				<FormKeyValueView>
+					<template #key>Users</template>
+					<template #value>{{ number(stats.originalUsersCount) }}</template>
+				</FormKeyValueView>
+				<FormKeyValueView>
+					<template #key>Notes</template>
+					<template #value>{{ number(stats.originalNotesCount) }}</template>
+				</FormKeyValueView>
+			</FormGroup>
+		</FormSuspense>
+	
+		<div class="_formItem">
+			<div class="_formPanel">
+				<MkInstanceStats :chart-limit="300" :detailed="true"/>
+			</div>
+		</div>
+
+		<XMetrics/>
+
+		<FormSuspense :p="fetchServerInfo" v-slot="{ result: serverInfo }">
+			<FormGroup>
+				<FormKeyValueView>
+					<template #key>Node.js</template>
+					<template #value>{{ serverInfo.node }}</template>
+				</FormKeyValueView>
+				<FormKeyValueView>
+					<template #key>PostgreSQL</template>
+					<template #value>{{ serverInfo.psql }}</template>
+				</FormKeyValueView>
+				<FormKeyValueView>
+					<template #key>Redis</template>
+					<template #value>{{ serverInfo.redis }}</template>
+				</FormKeyValueView>
+			</FormGroup>
+		</FormSuspense>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { computed, defineComponent, markRaw } from 'vue';
+import FormKeyValueView from '@client/components/form/key-value-view.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormTextarea from '@client/components/form/textarea.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import MkInstanceStats from '@client/components/instance-stats.vue';
+import MkButton from '@client/components/ui/button.vue';
+import MkSelect from '@client/components/ui/select.vue';
+import MkInput from '@client/components/ui/input.vue';
+import MkContainer from '@client/components/ui/container.vue';
+import MkFolder from '@client/components/ui/folder.vue';
+import { version, url } from '@client/config';
+import bytes from '../../filters/bytes';
+import number from '../../filters/number';
+import MkInstanceInfo from './instance.vue';
+import XMetrics from './metrics.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+
+export default defineComponent({
+	components: {
+		FormBase,
+		FormSuspense,
+		FormGroup,
+		FormInfo,
+		FormKeyValueView,
+		MkInstanceStats,
+		XMetrics,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.overview,
+				icon: 'fas fa-tachometer-alt'
+			},
+			page: 'index',
+			version,
+			url,
+			stats: null,
+			fetchStats: () => os.api('stats', {}),
+			fetchServerInfo: () => os.api('admin/server-info', {}),
+			fetchJobs: () => os.api('admin/queue/deliver-delayed', {}),
+			fetchModLogs: () => os.api('admin/show-moderation-logs', {}),
+			noMaintainerInformation: false,
+			noBotProtection: false,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			this.meta = await os.api('meta', { detail: true });
+
+			const isEmpty = (x: any) => x == null || x == '';
+
+			this.noMaintainerInformation = isEmpty(this.meta.maintainerName) || isEmpty(this.meta.maintainerEmail);
+			this.noBotProtection = !this.meta.enableHcaptcha && !this.meta.enableRecaptcha;
+		},
+	
+		async showInstanceInfo(q) {
+			let instance = q;
+			if (typeof q === 'string') {
+				instance = await os.api('federation/show-instance', {
+					host: q
+				});
+			}
+			os.popup(MkInstanceInfo, {
+				instance: instance
+			}, {}, 'closed');
+		},
+
+		bytes,
+
+		number,
+	}
+});
+</script>
diff --git a/src/client/pages/instance/proxy-account.vue b/src/client/pages/instance/proxy-account.vue
new file mode 100644
index 0000000000000000000000000000000000000000..3e2df8dcb4ee8435c7b39fc2fcdd667610c7a89b
--- /dev/null
+++ b/src/client/pages/instance/proxy-account.vue
@@ -0,0 +1,86 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormGroup>
+			<FormKeyValueView>
+				<template #key>{{ $ts.proxyAccount }}</template>
+				<template #value>{{ proxyAccount ? `@${proxyAccount.username}` : $ts.none }}</template>
+			</FormKeyValueView>
+			<template #caption>{{ $ts.proxyAccountDescription }}</template>
+		</FormGroup>
+
+		<FormButton @click="chooseProxyAccount" primary>{{ $ts.selectAccount }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormKeyValueView from '@client/components/form/key-value-view.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormTextarea from '@client/components/form/textarea.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormKeyValueView,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormTextarea,
+		FormInfo,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.proxyAccount,
+				icon: 'fas fa-ghost'
+			},
+			proxyAccount: null,
+			proxyAccountId: null,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.proxyAccountId = meta.proxyAccountId;
+			if (this.proxyAccountId) {
+				this.proxyAccount = await os.api('users/show', { userId: this.proxyAccountId });
+			}
+		},
+
+		chooseProxyAccount() {
+			os.selectUser().then(user => {
+				this.proxyAccount = user;
+				this.proxyAccountId = user.id;
+				this.save();
+			});
+		},
+
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				proxyAccountId: this.proxyAccountId,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/queue.chart.vue b/src/client/pages/instance/queue.chart.vue
index 0eb70debfba8ce117df9875616f3427375f40e66..446c979209f39e08606afbecd70c05f551de1196 100644
--- a/src/client/pages/instance/queue.chart.vue
+++ b/src/client/pages/instance/queue.chart.vue
@@ -1,27 +1,29 @@
 <template>
-<section class="_section">
-	<div class="_title"><slot name="title"></slot></div>
-	<div class="_content _table">
-		<div class="_row">
-			<div class="_cell"><div class="_label">Process</div>{{ number(activeSincePrevTick) }}</div>
-			<div class="_cell"><div class="_label">Active</div>{{ number(active) }}</div>
-			<div class="_cell"><div class="_label">Waiting</div>{{ number(waiting) }}</div>
-			<div class="_cell"><div class="_label">Delayed</div>{{ number(delayed) }}</div>
+<div class="_formItem">
+	<div class="_formLabel"><slot name="title"></slot></div>
+	<div class="_formPanel pumxzjhg">
+		<div class="_table status">
+			<div class="_row">
+				<div class="_cell"><div class="_label">Process</div>{{ number(activeSincePrevTick) }}</div>
+				<div class="_cell"><div class="_label">Active</div>{{ number(active) }}</div>
+				<div class="_cell"><div class="_label">Waiting</div>{{ number(waiting) }}</div>
+				<div class="_cell"><div class="_label">Delayed</div>{{ number(delayed) }}</div>
+			</div>
 		</div>
-	</div>
-	<div class="_content" style="margin-bottom: -8px;">
-		<canvas ref="chart"></canvas>
-	</div>
-	<div class="_content" style="max-height: 180px; overflow: auto;">
-		<div v-if="jobs.length > 0">
-			<div v-for="job in jobs" :key="job[0]">
-				<span>{{ job[0] }}</span>
-				<span style="margin-left: 8px; opacity: 0.7;">({{ number(job[1]) }} jobs)</span>
+		<div class="">
+			<canvas ref="chart"></canvas>
+		</div>
+		<div class="jobs">
+			<div v-if="jobs.length > 0">
+				<div v-for="job in jobs" :key="job[0]">
+					<span>{{ job[0] }}</span>
+					<span style="margin-left: 8px; opacity: 0.7;">({{ number(job[1]) }} jobs)</span>
+				</div>
 			</div>
+			<span v-else style="opacity: 0.5;">{{ $ts.noJobs }}</span>
 		</div>
-		<span v-else style="opacity: 0.5;">{{ $ts.noJobs }}</span>
 	</div>
-</section>
+</div>
 </template>
 
 <script lang="ts">
@@ -110,10 +112,10 @@ export default defineComponent({
 				aspectRatio: 3,
 				layout: {
 					padding: {
-						left: 0,
-						right: 0,
-						top: 8,
-						bottom: 0
+						left: 16,
+						right: 16,
+						top: 16,
+						bottom: 12
 					}
 				},
 				legend: {
@@ -198,3 +200,19 @@ export default defineComponent({
 	}
 });
 </script>
+
+<style lang="scss" scoped>
+.pumxzjhg {
+	> .status {
+		padding: 16px;
+		border-bottom: solid 0.5px var(--divider);
+	}
+
+	> .jobs {
+		padding: 16px;
+		border-top: solid 0.5px var(--divider);
+		max-height: 180px;
+		overflow: auto;
+	}
+}
+</style>
diff --git a/src/client/pages/instance/queue.vue b/src/client/pages/instance/queue.vue
index 249babcf4108072c79505e3ed9a289b6e90d8e62..2dccf48d315012062b85d71691aac60449c200bf 100644
--- a/src/client/pages/instance/queue.vue
+++ b/src/client/pages/instance/queue.vue
@@ -1,46 +1,47 @@
 <template>
-<div>
+<FormBase>
 	<XQueue :connection="connection" domain="inbox">
-		<template #title><Fa :icon="faExchangeAlt"/> In</template>
+		<template #title>In</template>
 	</XQueue>
 	<XQueue :connection="connection" domain="deliver">
-		<template #title><Fa :icon="faExchangeAlt"/> Out</template>
+		<template #title>Out</template>
 	</XQueue>
-	<section class="_section">
-		<div class="_content">
-			<MkButton @click="clear()"><Fa :icon="faTrashAlt"/> {{ $ts.clearQueue }}</MkButton>
-		</div>
-	</section>
-</div>
+	<FormButton @click="clear()" danger><i class="fas fa-trash-alt"></i> {{ $ts.clearQueue }}</FormButton>
+</FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExchangeAlt } from '@fortawesome/free-solid-svg-icons';
-import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import XQueue from './queue.chart.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormButton from '@client/components/form/button.vue';
 import * as os from '@client/os';
 import * as symbols from '@client/symbols';
 
 export default defineComponent({
 	components: {
+		FormBase,
+		FormButton,
 		MkButton,
 		XQueue,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.jobQueue,
-				icon: faExchangeAlt,
+				icon: 'fas fa-clipboard-list',
 			},
 			connection: os.stream.useSharedConnection('queueStats'),
-			faExchangeAlt, faTrashAlt
 		}
 	},
 
 	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+
 		this.$nextTick(() => {
 			this.connection.send('requestLog', {
 				id: Math.random().toString().substr(2, 8),
diff --git a/src/client/pages/instance/relays.vue b/src/client/pages/instance/relays.vue
index d97a07cbb22255785362b31d3a196e5294513e94..a3e4e7d1da16b53cb5ee82ab444b40f35667a5c4 100644
--- a/src/client/pages/instance/relays.vue
+++ b/src/client/pages/instance/relays.vue
@@ -1,50 +1,44 @@
 <template>
-<div class="relaycxt">
-	<section class="_section add">
-		<div class="_title"><Fa :icon="faPlus"/> {{ $ts.addRelay }}</div>
-		<div class="_content">
-			<MkInput v-model:value="inbox">
-				<span>{{ $ts.inboxUrl }}</span>
-			</MkInput>
-			<MkButton @click="add(inbox)" primary><Fa :icon="faPlus"/> {{ $ts.add }}</MkButton>
-		</div>
-	</section>
+<FormBase class="relaycxt">
+	<FormButton @click="addRelay" primary><i class="fas fa-plus"></i> {{ $ts.addRelay }}</FormButton>
 
-	<section class="_section relays">
-		<div class="_title"><Fa :icon="faProjectDiagram"/> {{ $ts.addedRelays }}</div>
-		<div class="_content relay" v-for="relay in relays" :key="relay.inbox">
+	<div class="_formItem" v-for="relay in relays" :key="relay.inbox">
+		<div class="_formPanel" style="padding: 16px;">
 			<div>{{ relay.inbox }}</div>
 			<div>{{ $t(`_relayStatus.${relay.status}`) }}</div>
-			<MkButton class="button" inline @click="remove(relay.inbox)"><Fa :icon="faTrashAlt"/> {{ $ts.remove }}</MkButton>
+			<MkButton class="button" inline danger @click="remove(relay.inbox)"><i class="fas fa-trash-alt"></i> {{ $ts.remove }}</MkButton>
 		</div>
-	</section>
-</div>
+	</div>
+</FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlus, faProjectDiagram } from '@fortawesome/free-solid-svg-icons';
-import { faSave, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormButton from '@client/components/form/button.vue';
 import * as os from '@client/os';
 import * as symbols from '@client/symbols';
 
 export default defineComponent({
 	components: {
+		FormBase,
+		FormButton,
 		MkButton,
 		MkInput,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.relays,
-				icon: faProjectDiagram,
+				icon: 'fas fa-globe',
 			},
 			relays: [],
 			inbox: '',
-			faPlus, faProjectDiagram, faSave, faTrashAlt
 		}
 	},
 
@@ -52,8 +46,19 @@ export default defineComponent({
 		this.refresh();
 	},
 
+	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
 	methods: {
-		add(inbox: string) {
+		async addRelay() {
+			const { canceled, result: inbox } = await os.dialog({
+				title: this.$ts.addRelay,
+				input: {
+					placeholder: this.$ts.inboxUrl
+				}
+			});
+			if (canceled) return;
 			os.api('admin/relays/add', {
 				inbox
 			}).then((relay: any) => {
@@ -89,9 +94,5 @@ export default defineComponent({
 </script>
 
 <style lang="scss" scoped>
-._content.relay {
-	div {
-		margin: 0.5em 0;
-	}
-}
+
 </style>
diff --git a/src/client/pages/instance/security.vue b/src/client/pages/instance/security.vue
new file mode 100644
index 0000000000000000000000000000000000000000..e3397a113bafac857cf921b1d11b7d9088d4c404
--- /dev/null
+++ b/src/client/pages/instance/security.vue
@@ -0,0 +1,77 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormLink to="/instance/bot-protection">
+			<i class="fas fa-shield-alt"></i> {{ $ts.botProtection }}
+			<template #suffix v-if="enableHcaptcha">hCaptcha</template>
+			<template #suffix v-else-if="enableRecaptcha">reCAPTCHA</template>
+			<template #suffix v-else>{{ $ts.none }} ({{ $ts.notRecommended }})</template>
+		</FormLink>
+
+		<FormSwitch v-model:value="enableRegistration">{{ $ts.enableRegistration }}</FormSwitch>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineAsyncComponent, defineComponent } from 'vue';
+import FormLink from '@client/components/form/link.vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormLink,
+		FormSwitch,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormInfo,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.security,
+				icon: 'fas fa-lock'
+			},
+			enableHcaptcha: false,
+			enableRecaptcha: false,
+			enableRegistration: false,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableHcaptcha = meta.enableHcaptcha;
+			this.enableRecaptcha = meta.enableRecaptcha;
+			this.enableRegistration = !meta.disableRegistration;
+		},
+	
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				disableRegistration: !this.enableRegistration,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/service-worker.vue b/src/client/pages/instance/service-worker.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a52932bb75c9099baa464b98281b0445dcd2da95
--- /dev/null
+++ b/src/client/pages/instance/service-worker.vue
@@ -0,0 +1,84 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormSwitch v-model:value="enableServiceWorker">
+			{{ $ts.enableServiceworker }}
+			<template #desc>{{ $ts.serviceworkerInfo }}</template>
+		</FormSwitch>
+
+		<template v-if="enableServiceWorker">
+			<FormInput v-model:value="swPublicKey">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Public key
+			</FormInput>
+
+			<FormInput v-model:value="swPrivateKey">
+				<template #prefix><i class="fas fa-key"></i></template>
+				Private key
+			</FormInput>
+		</template>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
+
+export default defineComponent({
+	components: {
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormSuspense,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: 'ServiceWorker',
+				icon: 'fas fa-bolt'
+			},
+			enableServiceWorker: false,
+			swPublicKey: null,
+			swPrivateKey: null,
+		}
+	},
+
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.enableServiceWorker = meta.enableServiceWorker;
+			this.swPublicKey = meta.swPublickey;
+			this.swPrivateKey = meta.swPrivateKey;
+		},
+		save() {
+			os.apiWithDialog('admin/update-meta', {
+				enableServiceWorker: this.enableServiceWorker,
+				swPublicKey: this.swPublicKey,
+				swPrivateKey: this.swPrivateKey,
+			}).then(() => {
+				fetchInstance();
+			});
+		}
+	}
+});
+</script>
diff --git a/src/client/pages/instance/settings.vue b/src/client/pages/instance/settings.vue
index 038ecfd5ac1bf5bccc0af0dc47fd82e8719dc5fb..66f01c42c77e79ef91fc83460066da8a61e55a9d 100644
--- a/src/client/pages/instance/settings.vue
+++ b/src/client/pages/instance/settings.vue
@@ -1,585 +1,132 @@
 <template>
-<div v-if="meta" class="_section">
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faInfoCircle"/> {{ $ts.basicInfo }}</div>
-		<div class="_content">
-			<MkInput v-model:value="name">{{ $ts.instanceName }}</MkInput>
-			<MkTextarea v-model:value="description">{{ $ts.instanceDescription }}</MkTextarea>
-			<MkInput v-model:value="iconUrl"><template #icon><Fa :icon="faLink"/></template>{{ $ts.iconUrl }}</MkInput>
-			<MkInput v-model:value="bannerUrl"><template #icon><Fa :icon="faLink"/></template>{{ $ts.bannerUrl }}</MkInput>
-			<MkInput v-model:value="backgroundImageUrl"><template #icon><Fa :icon="faLink"/></template>{{ $ts.backgroundImageUrl }}</MkInput>
-			<MkInput v-model:value="logoImageUrl"><template #icon><Fa :icon="faLink"/></template>{{ $ts.logoImageUrl }}</MkInput>
-			<MkInput v-model:value="tosUrl"><template #icon><Fa :icon="faLink"/></template>{{ $ts.tosUrl }}</MkInput>
-			<MkInput v-model:value="maintainerName">{{ $ts.maintainerName }}</MkInput>
-			<MkInput v-model:value="maintainerEmail" type="email"><template #icon><Fa :icon="faEnvelope"/></template>{{ $ts.maintainerEmail }}</MkInput>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<MkInput v-model:value="pinnedClipId">{{ $ts.pinnedClipId }}</MkInput>
-
-	<section class="_card _gap">
-		<div class="_content">
-			<MkInput v-model:value="maxNoteTextLength" type="number" :save="() => save()"><template #icon><Fa :icon="faPencilAlt"/></template>{{ $ts.maxNoteTextLength }}</MkInput>
-		</div>
-		<div class="_content">
-			<MkSwitch v-model:value="enableLocalTimeline" @update:value="save()">{{ $ts.enableLocalTimeline }}</MkSwitch>
-			<MkSwitch v-model:value="enableGlobalTimeline" @update:value="save()">{{ $ts.enableGlobalTimeline }}</MkSwitch>
-			<MkInfo>{{ $ts.disablingTimelinesInfo }}</MkInfo>
-		</div>
-		<div class="_content">
-			<MkSwitch v-model:value="useStarForReactionFallback" @update:value="save()">{{ $ts.useStarForReactionFallback }}</MkSwitch>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faUser"/> {{ $ts.registration }}</div>
-		<div class="_content">
-			<MkSwitch v-model:value="enableRegistration" @update:value="save()">{{ $ts.enableRegistration }}</MkSwitch>
-			<MkButton v-if="!enableRegistration" @click="invite">{{ $ts.invite }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faShieldAlt"/> {{ $ts.hcaptcha }}</div>
-		<div class="_content">
-			<MkSwitch v-model:value="enableHcaptcha">{{ $ts.enableHcaptcha }}</MkSwitch>
-			<template v-if="enableHcaptcha">
-				<MkInput v-model:value="hcaptchaSiteKey" :disabled="!enableHcaptcha"><template #icon><Fa :icon="faKey"/></template>{{ $ts.hcaptchaSiteKey }}</MkInput>
-				<MkInput v-model:value="hcaptchaSecretKey" :disabled="!enableHcaptcha"><template #icon><Fa :icon="faKey"/></template>{{ $ts.hcaptchaSecretKey }}</MkInput>
-			</template>
-		</div>
-		<div class="_content" v-if="enableHcaptcha">
-			<header>{{ $ts.preview }}</header>
-			<captcha v-if="enableHcaptcha" provider="hcaptcha" :sitekey="hcaptchaSiteKey || '10000000-ffff-ffff-ffff-000000000001'"/>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faShieldAlt"/> {{ $ts.recaptcha }}</div>
-		<div class="_content">
-			<MkSwitch v-model:value="enableRecaptcha" ref="enableRecaptcha">{{ $ts.enableRecaptcha }}</MkSwitch>
-			<template v-if="enableRecaptcha">
-				<MkInput v-model:value="recaptchaSiteKey" :disabled="!enableRecaptcha"><template #icon><Fa :icon="faKey"/></template>{{ $ts.recaptchaSiteKey }}</MkInput>
-				<MkInput v-model:value="recaptchaSecretKey" :disabled="!enableRecaptcha"><template #icon><Fa :icon="faKey"/></template>{{ $ts.recaptchaSecretKey }}</MkInput>
-			</template>
-		</div>
-		<div class="_content" v-if="enableRecaptcha && recaptchaSiteKey">
-			<header>{{ $ts.preview }}</header>
-			<captcha v-if="enableRecaptcha" provider="grecaptcha" :sitekey="recaptchaSiteKey"/>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faEnvelope" /> {{ $ts.emailConfig }}</div>
-		<div class="_content">
-			<MkSwitch v-model:value="enableEmail" @update:value="save()">{{ $ts.enableEmail }}<template #desc>{{ $ts.emailConfigInfo }}</template></MkSwitch>
-			<MkInput v-model:value="email" type="email" :disabled="!enableEmail">{{ $ts.email }}</MkInput>
-			<div><b>{{ $ts.smtpConfig }}</b></div>
-			<div class="_inputs">
-				<MkInput v-model:value="smtpHost" :disabled="!enableEmail">{{ $ts.smtpHost }}</MkInput>
-				<MkInput v-model:value="smtpPort" type="number" :disabled="!enableEmail">{{ $ts.smtpPort }}</MkInput>
-			</div>
-			<div class="_inputs">
-				<MkInput v-model:value="smtpUser" :disabled="!enableEmail">{{ $ts.smtpUser }}</MkInput>
-				<MkInput v-model:value="smtpPass" type="password" :disabled="!enableEmail">{{ $ts.smtpPass }}</MkInput>
-			</div>
-			<MkInfo>{{ $ts.emptyToDisableSmtpAuth }}</MkInfo>
-			<MkSwitch v-model:value="smtpSecure" :disabled="!enableEmail">{{ $ts.smtpSecure }}<template #desc>{{ $ts.smtpSecureInfo }}</template></MkSwitch>
-			<div>
-			  <MkButton :disabled="!enableEmail" primary inline @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-				<MkButton :disabled="!enableEmail" inline @click="testEmail()">{{ $ts.testEmail }}</MkButton>
-			</div>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faBolt"/> {{ $ts.serviceworker }}</div>
-		<div class="_content">
-			<MkSwitch v-model:value="enableServiceWorker">{{ $ts.enableServiceworker }}<template #desc>{{ $ts.serviceworkerInfo }}</template></MkSwitch>
-			<template v-if="enableServiceWorker">
-				<div class="_inputs">
-					<MkInput v-model:value="swPublicKey" :disabled="!enableServiceWorker"><template #icon><Fa :icon="faKey"/></template>Public key</MkInput>
-					<MkInput v-model:value="swPrivateKey" :disabled="!enableServiceWorker"><template #icon><Fa :icon="faKey"/></template>Private key</MkInput>
-				</div>
-			</template>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faThumbtack"/> {{ $ts.pinnedUsers }}</div>
-		<div class="_content">
-			<MkTextarea v-model:value="pinnedUsers">
-				<template #desc>{{ $ts.pinnedUsersDescription }} <button class="_textButton" @click="addPinUser">{{ $ts.addUser }}</button></template>
-			</MkTextarea>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faThumbtack"/> {{ $ts.pinnedPages }}</div>
-		<div class="_content">
-			<MkTextarea v-model:value="pinnedPages">
-				<template #desc>{{ $ts.pinnedPagesDescription }}</template>
-			</MkTextarea>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faCloud"/> {{ $ts.files }}</div>
-		<div class="_content">
-			<MkSwitch v-model:value="cacheRemoteFiles">{{ $ts.cacheRemoteFiles }}<template #desc>{{ $ts.cacheRemoteFilesDescription }}</template></MkSwitch>
-			<MkSwitch v-model:value="proxyRemoteFiles">{{ $ts.proxyRemoteFiles }}<template #desc>{{ $ts.proxyRemoteFilesDescription }}</template></MkSwitch>
-			<MkInput v-model:value="localDriveCapacityMb" type="number">{{ $ts.driveCapacityPerLocalAccount }}<template #suffix>MB</template><template #desc>{{ $ts.inMb }}</template></MkInput>
-			<MkInput v-model:value="remoteDriveCapacityMb" type="number" :disabled="!cacheRemoteFiles">{{ $ts.driveCapacityPerRemoteAccount }}<template #suffix>MB</template><template #desc>{{ $ts.inMb }}</template></MkInput>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faCloud"/> {{ $ts.objectStorage }}</div>
-		<div class="_content">
-			<MkSwitch v-model:value="useObjectStorage">{{ $ts.useObjectStorage }}</MkSwitch>
-			<template v-if="useObjectStorage">
-				<MkInput v-model:value="objectStorageBaseUrl" :disabled="!useObjectStorage">{{ $ts.objectStorageBaseUrl }}<template #desc>{{ $ts.objectStorageBaseUrlDesc }}</template></MkInput>
-				<div class="_inputs">
-					<MkInput v-model:value="objectStorageBucket" :disabled="!useObjectStorage">{{ $ts.objectStorageBucket }}<template #desc>{{ $ts.objectStorageBucketDesc }}</template></MkInput>
-					<MkInput v-model:value="objectStoragePrefix" :disabled="!useObjectStorage">{{ $ts.objectStoragePrefix }}<template #desc>{{ $ts.objectStoragePrefixDesc }}</template></MkInput>
-				</div>
-				<MkInput v-model:value="objectStorageEndpoint" :disabled="!useObjectStorage">{{ $ts.objectStorageEndpoint }}<template #desc>{{ $ts.objectStorageEndpointDesc }}</template></MkInput>
-				<div class="_inputs">
-					<MkInput v-model:value="objectStorageRegion" :disabled="!useObjectStorage">{{ $ts.objectStorageRegion }}<template #desc>{{ $ts.objectStorageRegionDesc }}</template></MkInput>
-				</div>
-				<div class="_inputs">
-					<MkInput v-model:value="objectStorageAccessKey" :disabled="!useObjectStorage"><template #icon><Fa :icon="faKey"/></template>Access key</MkInput>
-					<MkInput v-model:value="objectStorageSecretKey" :disabled="!useObjectStorage"><template #icon><Fa :icon="faKey"/></template>Secret key</MkInput>
-				</div>
-				<MkSwitch v-model:value="objectStorageUseSSL" :disabled="!useObjectStorage">{{ $ts.objectStorageUseSSL }}<template #desc>{{ $ts.objectStorageUseSSLDesc }}</template></MkSwitch>
-				<MkSwitch v-model:value="objectStorageUseProxy" :disabled="!useObjectStorage">{{ $ts.objectStorageUseProxy }}<template #desc>{{ $ts.objectStorageUseProxyDesc }}</template></MkSwitch>
-				<MkSwitch v-model:value="objectStorageSetPublicRead" :disabled="!useObjectStorage">{{ $ts.objectStorageSetPublicRead }}</MkSwitch>
-				<MkSwitch v-model:value="objectStorageS3ForcePathStyle" :disabled="!useObjectStorage">s3ForcePathStyle</MkSwitch>
-			</template>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faGhost"/> {{ $ts.proxyAccount }}</div>
-		<div class="_content">
-			<MkInput :value="proxyAccount ? proxyAccount.username : null" disabled><template #prefix>@</template>{{ $ts.proxyAccount }}<template #desc>{{ $ts.proxyAccountDescription }}</template></MkInput>
-			<MkButton primary @click="chooseProxyAccount">{{ $ts.chooseProxyAccount }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faBan"/> {{ $ts.blockedInstances }}</div>
-		<div class="_content">
-			<MkTextarea v-model:value="blockedHosts">
-				<template #desc>{{ $ts.blockedInstancesDescription }}</template>
-			</MkTextarea>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faShareAlt"/> {{ $ts.integration }}</div>
-		<div class="_content">
-			<header><Fa :icon="faTwitter"/> Twitter</header>
-			<MkSwitch v-model:value="enableTwitterIntegration">{{ $ts.enable }}</MkSwitch>
-			<template v-if="enableTwitterIntegration">
-				<MkInfo>Callback URL: {{ `${url}/api/tw/cb` }}</MkInfo>
-				<MkInput v-model:value="twitterConsumerKey" :disabled="!enableTwitterIntegration"><template #icon><Fa :icon="faKey"/></template>Consumer Key</MkInput>
-				<MkInput v-model:value="twitterConsumerSecret" :disabled="!enableTwitterIntegration"><template #icon><Fa :icon="faKey"/></template>Consumer Secret</MkInput>
-			</template>
-		</div>
-		<div class="_content">
-			<header><Fa :icon="faGithub"/> GitHub</header>
-			<MkSwitch v-model:value="enableGithubIntegration">{{ $ts.enable }}</MkSwitch>
-			<template v-if="enableGithubIntegration">
-				<MkInfo>Callback URL: {{ `${url}/api/gh/cb` }}</MkInfo>
-				<MkInput v-model:value="githubClientId" :disabled="!enableGithubIntegration"><template #icon><Fa :icon="faKey"/></template>Client ID</MkInput>
-				<MkInput v-model:value="githubClientSecret" :disabled="!enableGithubIntegration"><template #icon><Fa :icon="faKey"/></template>Client Secret</MkInput>
-			</template>
-		</div>
-		<div class="_content">
-			<header><Fa :icon="faDiscord"/> Discord</header>
-			<MkSwitch v-model:value="enableDiscordIntegration">{{ $ts.enable }}</MkSwitch>
-			<template v-if="enableDiscordIntegration">
-				<MkInfo>Callback URL: {{ `${url}/api/dc/cb` }}</MkInfo>
-				<MkInput v-model:value="discordClientId" :disabled="!enableDiscordIntegration"><template #icon><Fa :icon="faKey"/></template>Client ID</MkInput>
-				<MkInput v-model:value="discordClientSecret" :disabled="!enableDiscordIntegration"><template #icon><Fa :icon="faKey"/></template>Client Secret</MkInput>
-			</template>
-		</div>
-		<div class="_footer">
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-
-	<section class="_card _gap">
-		<div class="_title"><Fa :icon="faArchway" /> Summaly Proxy</div>
-		<div class="_content">
-			<MkInput v-model:value="summalyProxy">URL</MkInput>
-			<MkButton primary @click="save(true)"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		</div>
-	</section>
-</div>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormInput v-model:value="name">
+			<span>{{ $ts.instanceName }}</span>
+		</FormInput>
+
+		<FormTextarea v-model:value="description">
+			<span>{{ $ts.instanceDescription }}</span>
+		</FormTextarea>
+
+		<FormInput v-model:value="iconUrl">
+			<template #prefix><i class="fas fa-link"></i></template>
+			<span>{{ $ts.iconUrl }}</span>
+		</FormInput>
+
+		<FormInput v-model:value="bannerUrl">
+			<template #prefix><i class="fas fa-link"></i></template>
+			<span>{{ $ts.bannerUrl }}</span>
+		</FormInput>
+
+		<FormInput v-model:value="tosUrl">
+			<template #prefix><i class="fas fa-link"></i></template>
+			<span>{{ $ts.tosUrl }}</span>
+		</FormInput>
+
+		<FormInput v-model:value="maintainerName">
+			<span>{{ $ts.maintainerName }}</span>
+		</FormInput>
+
+		<FormInput v-model:value="maintainerEmail" type="email">
+			<template #prefix><i class="fas fa-envelope"></i></template>
+			<span>{{ $ts.maintainerEmail }}</span>
+		</FormInput>
+
+		<FormInput v-model:value="maxNoteTextLength" type="number">
+			<template #prefix><i class="fas fa-pencil-alt"></i></template>
+			<span>{{ $ts.maxNoteTextLength }}</span>
+		</FormInput>
+
+		<FormSwitch v-model:value="enableLocalTimeline">{{ $ts.enableLocalTimeline }}</FormSwitch>
+		<FormSwitch v-model:value="enableGlobalTimeline">{{ $ts.enableGlobalTimeline }}</FormSwitch>
+		<FormInfo>{{ $ts.disablingTimelinesInfo }}</FormInfo>
+
+		<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	</FormSuspense>
+</FormBase>
 </template>
 
 <script lang="ts">
-import { defineComponent, defineAsyncComponent } from 'vue';
-import { faPencilAlt, faShareAlt, faGhost, faCog, faPlus, faCloud, faInfoCircle, faBan, faSave, faServer, faLink, faThumbtack, faUser, faShieldAlt, faKey, faBolt, faArchway } from '@fortawesome/free-solid-svg-icons';
-import { faTrashAlt, faEnvelope } from '@fortawesome/free-regular-svg-icons';
-import { faTwitter, faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons';
-import MkButton from '@client/components/ui/button.vue';
-import MkInput from '@client/components/ui/input.vue';
-import MkTextarea from '@client/components/ui/textarea.vue';
-import MkSwitch from '@client/components/ui/switch.vue';
-import MkInfo from '@client/components/ui/info.vue';
-import { url } from '@client/config';
-import getAcct from '@/misc/acct/render';
+import { defineComponent } from 'vue';
+import FormSwitch from '@client/components/form/switch.vue';
+import FormInput from '@client/components/form/input.vue';
+import FormButton from '@client/components/form/button.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormTextarea from '@client/components/form/textarea.vue';
+import FormInfo from '@client/components/form/info.vue';
+import FormSuspense from '@client/components/form/suspense.vue';
 import * as os from '@client/os';
-import { fetchInstance } from '@client/instance';
 import * as symbols from '@client/symbols';
+import { fetchInstance } from '@client/instance';
 
 export default defineComponent({
 	components: {
-		MkButton,
-		MkInput,
-		MkTextarea,
-		MkSwitch,
-		MkInfo,
-		Captcha: defineAsyncComponent(() => import('@client/components/captcha.vue')),
+		FormSwitch,
+		FormInput,
+		FormBase,
+		FormGroup,
+		FormButton,
+		FormTextarea,
+		FormInfo,
+		FormSuspense,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
-				title: this.$ts.instance,
-				icon: faCog,
+				title: this.$ts.general,
+				icon: 'fas fa-cog'
 			},
-			meta: null,
-			url,
-			proxyAccount: null,
-			proxyAccountId: null,
-			cacheRemoteFiles: false,
-			proxyRemoteFiles: false,
-			localDriveCapacityMb: 0,
-			remoteDriveCapacityMb: 0,
-			blockedHosts: '',
-			pinnedUsers: '',
-			pinnedPages: '',
-			pinnedClipId: null,
-			maintainerName: null,
-			maintainerEmail: null,
 			name: null,
 			description: null,
 			tosUrl: null as string | null,
-			enableEmail: false,
-			email: null,
-			bannerUrl: null,
+			maintainerName: null,
+			maintainerEmail: null,
 			iconUrl: null,
-			logoImageUrl: null,
-			backgroundImageUrl: null,
+			bannerUrl: null,
 			maxNoteTextLength: 0,
-			enableRegistration: false,
 			enableLocalTimeline: false,
 			enableGlobalTimeline: false,
-			enableHcaptcha: false,
-			hcaptchaSiteKey: null,
-			hcaptchaSecretKey: null,
-			enableRecaptcha: false,
-			recaptchaSiteKey: null,
-			recaptchaSecretKey: null,
-			enableServiceWorker: false,
-			swPublicKey: null,
-			swPrivateKey: null,
-			useObjectStorage: false,
-			objectStorageBaseUrl: null,
-			objectStorageBucket: null,
-			objectStoragePrefix: null,
-			objectStorageEndpoint: null,
-			objectStorageRegion: null,
-			objectStoragePort: null,
-			objectStorageAccessKey: null,
-			objectStorageSecretKey: null,
-			objectStorageUseSSL: false,
-			objectStorageUseProxy: false,
-			objectStorageSetPublicRead: false,
-			objectStorageS3ForcePathStyle: true,
-			enableTwitterIntegration: false,
-			twitterConsumerKey: null,
-			twitterConsumerSecret: null,
-			enableGithubIntegration: false,
-			githubClientId: null,
-			githubClientSecret: null,
-			enableDiscordIntegration: false,
-			discordClientId: null,
-			discordClientSecret: null,
-			useStarForReactionFallback: false,
-			smtpSecure: false,
-			smtpHost: '',
-			smtpPort: 0,
-			smtpUser: '',
-			smtpPass: '',
-			summalyProxy: '',
-			faPencilAlt, faTwitter, faDiscord, faGithub, faShareAlt, faTrashAlt, faGhost, faCog, faPlus, faCloud, faInfoCircle, faBan, faSave, faServer, faLink, faEnvelope, faThumbtack, faUser, faShieldAlt, faKey, faBolt, faArchway
 		}
 	},
 
-	async created() {
-		this.meta = await os.api('meta', { detail: true });
-
-		this.name = this.meta.name;
-		this.description = this.meta.description;
-		this.tosUrl = this.meta.tosUrl;
-		this.bannerUrl = this.meta.bannerUrl;
-		this.iconUrl = this.meta.iconUrl;
-		this.logoImageUrl = this.meta.logoImageUrl;
-		this.backgroundImageUrl = this.meta.backgroundImageUrl;
-		this.enableEmail = this.meta.enableEmail;
-		this.email = this.meta.email;
-		this.maintainerName = this.meta.maintainerName;
-		this.maintainerEmail = this.meta.maintainerEmail;
-		this.maxNoteTextLength = this.meta.maxNoteTextLength;
-		this.enableRegistration = !this.meta.disableRegistration;
-		this.enableLocalTimeline = !this.meta.disableLocalTimeline;
-		this.enableGlobalTimeline = !this.meta.disableGlobalTimeline;
-		this.enableHcaptcha = this.meta.enableHcaptcha;
-		this.hcaptchaSiteKey = this.meta.hcaptchaSiteKey;
-		this.hcaptchaSecretKey = this.meta.hcaptchaSecretKey;
-		this.enableRecaptcha = this.meta.enableRecaptcha;
-		this.recaptchaSiteKey = this.meta.recaptchaSiteKey;
-		this.recaptchaSecretKey = this.meta.recaptchaSecretKey;
-		this.proxyAccountId = this.meta.proxyAccountId;
-		this.cacheRemoteFiles = this.meta.cacheRemoteFiles;
-		this.proxyRemoteFiles = this.meta.proxyRemoteFiles;
-		this.localDriveCapacityMb = this.meta.driveCapacityPerLocalUserMb;
-		this.remoteDriveCapacityMb = this.meta.driveCapacityPerRemoteUserMb;
-		this.blockedHosts = this.meta.blockedHosts.join('\n');
-		this.pinnedUsers = this.meta.pinnedUsers.join('\n');
-		this.pinnedPages = this.meta.pinnedPages.join('\n');
-		this.pinnedClipId = this.meta.pinnedClipId;
-		this.enableServiceWorker = this.meta.enableServiceWorker;
-		this.swPublicKey = this.meta.swPublickey;
-		this.swPrivateKey = this.meta.swPrivateKey;
-		this.useObjectStorage = this.meta.useObjectStorage;
-		this.objectStorageBaseUrl = this.meta.objectStorageBaseUrl;
-		this.objectStorageBucket = this.meta.objectStorageBucket;
-		this.objectStoragePrefix = this.meta.objectStoragePrefix;
-		this.objectStorageEndpoint = this.meta.objectStorageEndpoint;
-		this.objectStorageRegion = this.meta.objectStorageRegion;
-		this.objectStoragePort = this.meta.objectStoragePort;
-		this.objectStorageAccessKey = this.meta.objectStorageAccessKey;
-		this.objectStorageSecretKey = this.meta.objectStorageSecretKey;
-		this.objectStorageUseSSL = this.meta.objectStorageUseSSL;
-		this.objectStorageUseProxy = this.meta.objectStorageUseProxy;
-		this.objectStorageSetPublicRead = this.meta.objectStorageSetPublicRead;
-		this.objectStorageS3ForcePathStyle = this.meta.objectStorageS3ForcePathStyle;
-		this.enableTwitterIntegration = this.meta.enableTwitterIntegration;
-		this.twitterConsumerKey = this.meta.twitterConsumerKey;
-		this.twitterConsumerSecret = this.meta.twitterConsumerSecret;
-		this.enableGithubIntegration = this.meta.enableGithubIntegration;
-		this.githubClientId = this.meta.githubClientId;
-		this.githubClientSecret = this.meta.githubClientSecret;
-		this.enableDiscordIntegration = this.meta.enableDiscordIntegration;
-		this.discordClientId = this.meta.discordClientId;
-		this.discordClientSecret = this.meta.discordClientSecret;
-		this.useStarForReactionFallback = this.meta.useStarForReactionFallback;
-		this.smtpSecure = this.meta.smtpSecure;
-		this.smtpHost = this.meta.smtpHost;
-		this.smtpPort = this.meta.smtpPort;
-		this.smtpUser = this.meta.smtpUser;
-		this.smtpPass = this.meta.smtpPass;
-		this.summalyProxy = this.meta.summalyProxy;
-
-		if (this.proxyAccountId) {
-			os.api('users/show', { userId: this.proxyAccountId }).then(proxyAccount => {
-				this.proxyAccount = proxyAccount;
-			});
-		}
-	},
-
-	mounted() {
-		this.$watch('enableHcaptcha', () => {
-			if (this.enableHcaptcha && this.enableRecaptcha) {
-				os.dialog({
-					type: 'question', // warning だと間違って cancel するかもしれない
-					showCancelButton: true,
-					title: this.$ts.settingGuide,
-					text: this.$ts.avoidMultiCaptchaConfirm,
-				}).then(({ canceled }) => {
-					if (canceled) {
-						return;
-					}
-
-					this.enableRecaptcha = false;
-				});
-			}
-		});
-
-		this.$watch('enableRecaptcha', () => {
-			if (this.enableRecaptcha && this.enableHcaptcha) {
-				os.dialog({
-					type: 'question', // warning だと間違って cancel するかもしれない
-					showCancelButton: true,
-					title: this.$ts.settingGuide,
-					text: this.$ts.avoidMultiCaptchaConfirm,
-				}).then(({ canceled }) => {
-					if (canceled) {
-						return;
-					}
-
-					this.enableHcaptcha = false;
-				});
-			}
-		});
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
 	},
 
 	methods: {
-		invite() {
-			os.api('admin/invite').then(x => {
-				os.dialog({
-					type: 'info',
-					text: x.code
-				});
-			}).catch(e => {
-				os.dialog({
-					type: 'error',
-					text: e
-				});
-			});
+		async init() {
+			const meta = await os.api('meta', { detail: true });
+			this.name = meta.name;
+			this.description = meta.description;
+			this.tosUrl = meta.tosUrl;
+			this.iconUrl = meta.iconUrl;
+			this.bannerUrl = meta.bannerUrl;
+			this.maintainerName = meta.maintainerName;
+			this.maintainerEmail = meta.maintainerEmail;
+			this.maxNoteTextLength = meta.maxNoteTextLength;
+			this.enableLocalTimeline = !meta.disableLocalTimeline;
+			this.enableGlobalTimeline = !meta.disableGlobalTimeline;
 		},
 
-		addPinUser() {
-			os.selectUser().then(user => {
-				this.pinnedUsers = this.pinnedUsers.trim();
-				this.pinnedUsers += '\n@' + getAcct(user);
-				this.pinnedUsers = this.pinnedUsers.trim();
-			});
-		},
-
-		chooseProxyAccount() {
-			os.selectUser().then(user => {
-				this.proxyAccount = user;
-				this.proxyAccountId = user.id;
-				this.save(true);
-			});
-		},
-
-		async testEmail() {
-			os.api('admin/send-email', {
-				to: this.maintainerEmail,
-				subject: 'Test email',
-				text: 'Yo'
-			}).then(x => {
-				os.dialog({
-					type: 'success',
-					splash: true
-				});
-			}).catch(e => {
-				os.dialog({
-					type: 'error',
-					text: e
-				});
-			});
-		},
-
-		save(withDialog = false) {
-			os.api('admin/update-meta', {
+		save() {
+			os.apiWithDialog('admin/update-meta', {
 				name: this.name,
 				description: this.description,
 				tosUrl: this.tosUrl,
-				bannerUrl: this.bannerUrl,
 				iconUrl: this.iconUrl,
-				logoImageUrl: this.logoImageUrl,
-				backgroundImageUrl: this.backgroundImageUrl,
+				bannerUrl: this.bannerUrl,
 				maintainerName: this.maintainerName,
 				maintainerEmail: this.maintainerEmail,
 				maxNoteTextLength: this.maxNoteTextLength,
-				disableRegistration: !this.enableRegistration,
 				disableLocalTimeline: !this.enableLocalTimeline,
 				disableGlobalTimeline: !this.enableGlobalTimeline,
-				enableHcaptcha: this.enableHcaptcha,
-				hcaptchaSiteKey: this.hcaptchaSiteKey,
-				hcaptchaSecretKey: this.hcaptchaSecretKey,
-				enableRecaptcha: this.enableRecaptcha,
-				recaptchaSiteKey: this.recaptchaSiteKey,
-				recaptchaSecretKey: this.recaptchaSecretKey,
-				proxyAccountId: this.proxyAccountId,
-				cacheRemoteFiles: this.cacheRemoteFiles,
-				proxyRemoteFiles: this.proxyRemoteFiles,
-				localDriveCapacityMb: parseInt(this.localDriveCapacityMb, 10),
-				remoteDriveCapacityMb: parseInt(this.remoteDriveCapacityMb, 10),
-				blockedHosts: this.blockedHosts.split('\n') || [],
-				pinnedUsers: this.pinnedUsers ? this.pinnedUsers.split('\n') : [],
-				pinnedPages: this.pinnedPages ? this.pinnedPages.split('\n') : [],
-				pinnedClipId: (this.pinnedClipId && this.pinnedClipId) != '' ? this.pinnedClipId : null,
-				enableServiceWorker: this.enableServiceWorker,
-				swPublicKey: this.swPublicKey,
-				swPrivateKey: this.swPrivateKey,
-				useObjectStorage: this.useObjectStorage,
-				objectStorageBaseUrl: this.objectStorageBaseUrl ? this.objectStorageBaseUrl : null,
-				objectStorageBucket: this.objectStorageBucket ? this.objectStorageBucket : null,
-				objectStoragePrefix: this.objectStoragePrefix ? this.objectStoragePrefix : null,
-				objectStorageEndpoint: this.objectStorageEndpoint ? this.objectStorageEndpoint : null,
-				objectStorageRegion: this.objectStorageRegion ? this.objectStorageRegion : null,
-				objectStoragePort: this.objectStoragePort ? this.objectStoragePort : null,
-				objectStorageAccessKey: this.objectStorageAccessKey ? this.objectStorageAccessKey : null,
-				objectStorageSecretKey: this.objectStorageSecretKey ? this.objectStorageSecretKey : null,
-				objectStorageUseSSL: this.objectStorageUseSSL,
-				objectStorageUseProxy: this.objectStorageUseProxy,
-				objectStorageSetPublicRead: this.objectStorageSetPublicRead,
-				objectStorageS3ForcePathStyle: this.objectStorageS3ForcePathStyle,
-				enableTwitterIntegration: this.enableTwitterIntegration,
-				twitterConsumerKey: this.twitterConsumerKey,
-				twitterConsumerSecret: this.twitterConsumerSecret,
-				enableGithubIntegration: this.enableGithubIntegration,
-				githubClientId: this.githubClientId,
-				githubClientSecret: this.githubClientSecret,
-				enableDiscordIntegration: this.enableDiscordIntegration,
-				discordClientId: this.discordClientId,
-				discordClientSecret: this.discordClientSecret,
-				enableEmail: this.enableEmail,
-				email: this.email,
-				smtpSecure: this.smtpSecure,
-				smtpHost: this.smtpHost,
-				smtpPort: this.smtpPort,
-				smtpUser: this.smtpUser,
-				smtpPass: this.smtpPass,
-				summalyProxy: this.summalyProxy,
-				useStarForReactionFallback: this.useStarForReactionFallback,
 			}).then(() => {
 				fetchInstance();
-				if (withDialog) {
-					os.success();
-				}
-			}).catch(e => {
-				os.dialog({
-					type: 'error',
-					text: e
-				});
 			});
 		}
 	}
diff --git a/src/client/pages/instance/user-dialog.vue b/src/client/pages/instance/user-dialog.vue
deleted file mode 100644
index a6bab5ecb812280354342067825e8b6186e59f46..0000000000000000000000000000000000000000
--- a/src/client/pages/instance/user-dialog.vue
+++ /dev/null
@@ -1,233 +0,0 @@
-<template>
-<XModalWindow ref="dialog"
-	:width="370"
-	@close="$refs.dialog.close()"
-	@closed="$emit('closed')"
->
-	<template #header v-if="user"><MkUserName class="name" :user="user"/></template>
-	<div class="vrcsvlkm" v-if="user && info">
-		<div class="_section">
-			<div class="banner" :style="bannerStyle">
-				<MkAvatar class="avatar" :user="user" :show-indicator="true"/>
-			</div>
-		</div>
-		<div class="_section">
-			<div class="title">
-				<span class="acct">@{{ acct(user) }}</span>
-			</div>
-			<div class="status">
-				<span class="staff" v-if="user.isAdmin"><Fa :icon="faBookmark"/></span>
-				<span class="staff" v-if="user.isModerator"><Fa :icon="farBookmark"/></span>
-				<span class="punished" v-if="user.isSilenced"><Fa :icon="faMicrophoneSlash"/></span>
-				<span class="punished" v-if="user.isSuspended"><Fa :icon="faSnowflake"/></span>
-			</div>
-		</div>
-		<div class="_section">
-			<div class="_content">
-				<MkSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" @update:value="toggleModerator" v-model:value="moderator">{{ $ts.moderator }}</MkSwitch>
-				<MkSwitch @update:value="toggleSilence" v-model:value="silenced">{{ $ts.silence }}</MkSwitch>
-				<MkSwitch @update:value="toggleSuspend" v-model:value="suspended">{{ $ts.suspend }}</MkSwitch>
-			</div>
-		</div>
-		<div class="_section">
-			<div class="_content">
-				<MkButton full @click="openProfile"><Fa :icon="faExternalLinkSquareAlt"/> {{ $ts.profile }}</MkButton>
-				<MkButton full v-if="user.host != null" @click="updateRemoteUser"><Fa :icon="faSync"/> {{ $ts.updateRemoteUser }}</MkButton>
-				<MkButton full @click="resetPassword"><Fa :icon="faKey"/> {{ $ts.resetPassword }}</MkButton>
-				<MkButton full @click="deleteAllFiles" danger><Fa :icon="faTrashAlt"/> {{ $ts.deleteAllFiles }}</MkButton>
-			</div>
-		</div>
-		<div class="_section">
-			<details class="_content rawdata">
-				<pre><code>{{ JSON.stringify(info, null, 2) }}</code></pre>
-			</details>
-		</div>
-	</div>
-</XModalWindow>
-</template>
-
-<script lang="ts">
-import { computed, defineComponent } from 'vue';
-import { faTimes, faBookmark, faKey, faSync, faMicrophoneSlash, faExternalLinkSquareAlt } from '@fortawesome/free-solid-svg-icons';
-import { faSnowflake, faTrashAlt, faBookmark as farBookmark  } from '@fortawesome/free-regular-svg-icons';
-import MkButton from '@client/components/ui/button.vue';
-import MkSwitch from '@client/components/ui/switch.vue';
-import XModalWindow from '@client/components/ui/modal-window.vue';
-import Progress from '@client/scripts/loading';
-import { acct, userPage } from '../../filters/user';
-import * as os from '@client/os';
-
-export default defineComponent({
-	components: {
-		MkButton,
-		MkSwitch,
-		XModalWindow,
-	},
-
-	props: {
-		userId: {
-			required: true,
-		}
-	},
-
-	emits: ['closed'],
-
-	data() {
-		return {
-			user: null,
-			info: null,
-			moderator: false,
-			silenced: false,
-			suspended: false,
-			faTimes, faBookmark, farBookmark, faKey, faSync, faMicrophoneSlash, faSnowflake, faTrashAlt, faExternalLinkSquareAlt
-		};
-	},
-
-	computed: {
-		bannerStyle(): any {
-			if (this.user.bannerUrl == null) return {};
-			return {
-				backgroundImage: `url(${ this.user.bannerUrl })`
-			};
-		},
-	},
-
-	created() {
-		this.fetch();
-	},
-
-	methods: {
-		async fetch() {
-			Progress.start();
-			this.user = await os.api('users/show', { userId: this.userId });
-			this.info = await os.api('admin/show-user', { userId: this.userId });
-			this.moderator = this.info.isModerator;
-			this.silenced = this.info.isSilenced;
-			this.suspended = this.info.isSuspended;
-			Progress.done();
-		},
-
-		/** 処理対象ユーザーの情報を更新する */
-		async refreshUser() {
-			this.user = await os.api('users/show', { userId: this.user.id });
-			this.info = await os.api('admin/show-user', { userId: this.user.id });
-		},
-
-		openProfile() {
-			window.open(userPage(this.user, null, true), '_blank');
-		},
-
-		async updateRemoteUser() {
-			await os.api('admin/update-remote-user', { userId: this.user.id }).then(res => {
-				os.success();
-			});
-			await this.refreshUser();
-		},
-
-		async resetPassword() {
-			os.apiWithDialog('admin/reset-password', {
-				userId: this.user.id,
-			}, undefined, ({ password }) => {
-				os.dialog({
-					type: 'success',
-					text: this.$t('newPasswordIs', { password })
-				});
-			});
-		},
-
-		async toggleSilence(v) {
-			const confirm = await os.dialog({
-				type: 'warning',
-				showCancelButton: true,
-				text: v ? this.$ts.silenceConfirm : this.$ts.unsilenceConfirm,
-			});
-			if (confirm.canceled) {
-				this.silenced = !v;
-			} else {
-				await os.api(v ? 'admin/silence-user' : 'admin/unsilence-user', { userId: this.user.id });
-				await this.refreshUser();
-			}
-		},
-
-		async toggleSuspend(v) {
-			const confirm = await os.dialog({
-				type: 'warning',
-				showCancelButton: true,
-				text: v ? this.$ts.suspendConfirm : this.$ts.unsuspendConfirm,
-			});
-			if (confirm.canceled) {
-				this.suspended = !v;
-			} else {
-				await os.api(v ? 'admin/suspend-user' : 'admin/unsuspend-user', { userId: this.user.id });
-				await this.refreshUser();
-			}
-		},
-
-		async toggleModerator(v) {
-			await os.api(v ? 'admin/moderators/add' : 'admin/moderators/remove', { userId: this.user.id });
-			await this.refreshUser();
-		},
-
-		async deleteAllFiles() {
-			const confirm = await os.dialog({
-				type: 'warning',
-				showCancelButton: true,
-				text: this.$ts.deleteAllFilesConfirm,
-			});
-			if (confirm.canceled) return;
-			const process = async () => {
-				await os.api('admin/delete-all-files-of-a-user', { userId: this.user.id });
-				os.success();
-			};
-			await process().catch(e => {
-				os.dialog({
-					type: 'error',
-					text: e.toString()
-				});
-			});
-			await this.refreshUser();
-		},
-
-		acct
-	}
-});
-</script>
-
-<style lang="scss" scoped>
-.vrcsvlkm {
-	> ._section {
-		> .banner {
-			position: relative;
-			height: 100px;
-			background-color: #4c5e6d;
-			background-size: cover;
-			background-position: center;
-			border-radius: 8px;
-
-			> .avatar {
-				position: absolute;
-				top: 60px;
-				width: 64px;
-				height: 64px;
-				left: 0;
-				right: 0;
-				margin: 0 auto;
-				border: solid 4px var(--panel);
-			}
-		}
-
-		> .title {
-			text-align: center;
-		}
-
-		> .status {
-			text-align: center;
-			margin-top: 8px;
-		}
-
-		> .rawdata {
-			overflow: auto;
-		}
-	}
-}
-</style>
diff --git a/src/client/pages/instance/users.vue b/src/client/pages/instance/users.vue
index ea09b1bda09ccb1f7fd734662bf486b92dee0ed3..2808b70fba6ca8b2936297f4155ebfdd098b69c3 100644
--- a/src/client/pages/instance/users.vue
+++ b/src/client/pages/instance/users.vue
@@ -1,88 +1,71 @@
 <template>
-<div class="mk-instance-users">
-	<div class="_section">
-		<div class="_content">
-			<MkButton inline primary @click="addUser()"><Fa :icon="faPlus"/> {{ $ts.addUser }}</MkButton>
-		</div>
+<div class="lknzcolw">
+	<div class="actions">
+		<MkButton inline primary @click="addUser()"><i class="fas fa-plus"></i> {{ $ts.addUser }}</MkButton>
+		<MkButton inline primary @click="lookupUser()"><i class="fas fa-search"></i> {{ $ts.lookup }}</MkButton>
 	</div>
 
-	<div class="_section lookup">
-		<div class="_title"><Fa :icon="faSearch"/> {{ $ts.lookup }}</div>
-		<div class="_content">
-			<MkInput class="target" v-model:value="target" type="text" @enter="showUser()">
-				<span>{{ $ts.usernameOrUserId }}</span>
+	<div class="users">
+		<div class="inputs" style="display: flex;">
+			<MkSelect v-model:value="sort" style="margin: 0; flex: 1;">
+				<template #label>{{ $ts.sort }}</template>
+				<option value="-createdAt">{{ $ts.registeredDate }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+createdAt">{{ $ts.registeredDate }} ({{ $ts.descendingOrder }})</option>
+				<option value="-updatedAt">{{ $ts.lastUsed }} ({{ $ts.ascendingOrder }})</option>
+				<option value="+updatedAt">{{ $ts.lastUsed }} ({{ $ts.descendingOrder }})</option>
+			</MkSelect>
+			<MkSelect v-model:value="state" style="margin: 0; flex: 1;">
+				<template #label>{{ $ts.state }}</template>
+				<option value="all">{{ $ts.all }}</option>
+				<option value="available">{{ $ts.normal }}</option>
+				<option value="admin">{{ $ts.administrator }}</option>
+				<option value="moderator">{{ $ts.moderator }}</option>
+				<option value="silenced">{{ $ts.silence }}</option>
+				<option value="suspended">{{ $ts.suspend }}</option>
+			</MkSelect>
+			<MkSelect v-model:value="origin" style="margin: 0; flex: 1;">
+				<template #label>{{ $ts.instance }}</template>
+				<option value="combined">{{ $ts.all }}</option>
+				<option value="local">{{ $ts.local }}</option>
+				<option value="remote">{{ $ts.remote }}</option>
+			</MkSelect>
+		</div>
+		<div class="inputs" style="display: flex; padding-top: 1.2em;">
+			<MkInput v-model:value="searchUsername" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:value="$refs.users.reload()">
+				<span>{{ $ts.username }}</span>
+			</MkInput>
+			<MkInput v-model:value="searchHost" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:value="$refs.users.reload()" :disabled="pagination.params().origin === 'local'">
+				<span>{{ $ts.host }}</span>
 			</MkInput>
-			<MkButton @click="showUser()" primary><Fa :icon="faSearch"/> {{ $ts.lookup }}</MkButton>
 		</div>
-	</div>
 
-	<div class="_section users">
-		<div class="_title"><Fa :icon="faUsers"/> {{ $ts.users }}</div>
-		<div class="_content">
-			<div class="inputs" style="display: flex;">
-				<MkSelect v-model:value="sort" style="margin: 0; flex: 1;">
-					<template #label>{{ $ts.sort }}</template>
-					<option value="-createdAt">{{ $ts.registeredDate }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+createdAt">{{ $ts.registeredDate }} ({{ $ts.descendingOrder }})</option>
-					<option value="-updatedAt">{{ $ts.lastUsed }} ({{ $ts.ascendingOrder }})</option>
-					<option value="+updatedAt">{{ $ts.lastUsed }} ({{ $ts.descendingOrder }})</option>
-				</MkSelect>
-				<MkSelect v-model:value="state" style="margin: 0; flex: 1;">
-					<template #label>{{ $ts.state }}</template>
-					<option value="all">{{ $ts.all }}</option>
-					<option value="available">{{ $ts.normal }}</option>
-					<option value="admin">{{ $ts.administrator }}</option>
-					<option value="moderator">{{ $ts.moderator }}</option>
-					<option value="silenced">{{ $ts.silence }}</option>
-					<option value="suspended">{{ $ts.suspend }}</option>
-				</MkSelect>
-				<MkSelect v-model:value="origin" style="margin: 0; flex: 1;">
-					<template #label>{{ $ts.instance }}</template>
-					<option value="combined">{{ $ts.all }}</option>
-					<option value="local">{{ $ts.local }}</option>
-					<option value="remote">{{ $ts.remote }}</option>
-				</MkSelect>
-			</div>
-			<div class="inputs" style="display: flex; padding-top: 1.2em;">
-				<MkInput v-model:value="searchUsername" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:value="$refs.users.reload()">
-					<span>{{ $ts.username }}</span>
-				</MkInput>
-				<MkInput v-model:value="searchHost" style="margin: 0; flex: 1;" type="text" spellcheck="false" @update:value="$refs.users.reload()" :disabled="pagination.params().origin === 'local'">
-					<span>{{ $ts.host }}</span>
-				</MkInput>
-			</div>
-
-			<MkPagination :pagination="pagination" #default="{items}" class="users" ref="users">
-				<button class="user _panel _button _gap" v-for="user in items" :key="user.id" @click="show(user)">
-					<MkAvatar class="avatar" :user="user" :disable-link="true" :show-indicator="true"/>
-					<div class="body">
-						<header>
-							<MkUserName class="name" :user="user"/>
-							<span class="acct">@{{ acct(user) }}</span>
-							<span class="staff" v-if="user.isAdmin"><Fa :icon="faBookmark"/></span>
-							<span class="staff" v-if="user.isModerator"><Fa :icon="farBookmark"/></span>
-							<span class="punished" v-if="user.isSilenced"><Fa :icon="faMicrophoneSlash"/></span>
-							<span class="punished" v-if="user.isSuspended"><Fa :icon="faSnowflake"/></span>
-						</header>
-						<div>
-							<span>{{ $ts.lastUsed }}: <MkTime v-if="user.updatedAt" :time="user.updatedAt" mode="detail"/></span>
-						</div>
-						<div>
-							<span>{{ $ts.registeredDate }}: <MkTime :time="user.createdAt" mode="detail"/></span>
-						</div>
+		<MkPagination :pagination="pagination" #default="{items}" class="users" ref="users">
+			<button class="user _panel _button _gap" v-for="user in items" :key="user.id" @click="show(user)">
+				<MkAvatar class="avatar" :user="user" :disable-link="true" :show-indicator="true"/>
+				<div class="body">
+					<header>
+						<MkUserName class="name" :user="user"/>
+						<span class="acct">@{{ acct(user) }}</span>
+						<span class="staff" v-if="user.isAdmin"><i class="fas fa-bookmark"></i></span>
+						<span class="staff" v-if="user.isModerator"><i class="far fa-bookmark"></i></span>
+						<span class="punished" v-if="user.isSilenced"><i class="fas fa-microphone-slash"></i></span>
+						<span class="punished" v-if="user.isSuspended"><i class="fas fa-snowflake"></i></span>
+					</header>
+					<div>
+						<span>{{ $ts.lastUsed }}: <MkTime v-if="user.updatedAt" :time="user.updatedAt" mode="detail"/></span>
 					</div>
-				</button>
-			</MkPagination>
-		</div>
+					<div>
+						<span>{{ $ts.registeredDate }}: <MkTime :time="user.createdAt" mode="detail"/></span>
+					</div>
+				</div>
+			</button>
+		</MkPagination>
 	</div>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlus, faUsers, faSearch, faBookmark, faMicrophoneSlash } from '@fortawesome/free-solid-svg-icons';
-import { faSnowflake, faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons';
-import parseAcct from '@/misc/acct/parse';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -90,6 +73,7 @@ import MkPagination from '@client/components/ui/pagination.vue';
 import { acct } from '../../filters/user';
 import * as os from '@client/os';
 import * as symbols from '@client/symbols';
+import { lookupUser } from '@client/scripts/lookup-user';
 
 export default defineComponent({
 	components: {
@@ -99,17 +83,18 @@ export default defineComponent({
 		MkPagination,
 	},
 
+	emits: ['info'],
+
 	data() {
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.users,
-				icon: faUsers,
+				icon: 'fas fa-users',
 				action: {
-					icon: faSearch,
+					icon: 'fas fa-search',
 					handler: this.searchUser
 				}
 			},
-			target: '',
 			sort: '+createdAt',
 			state: 'all',
 			origin: 'local',
@@ -127,7 +112,6 @@ export default defineComponent({
 				}),
 				offsetMode: true
 			},
-			faPlus, faUsers, faSearch, faBookmark, farBookmark, faMicrophoneSlash, faSnowflake
 		}
 	},
 
@@ -143,40 +127,12 @@ export default defineComponent({
 		},
 	},
 
-	methods: {
-		/** テキストエリアのユーザーを解決する */
-		fetchUser() {
-			return new Promise((res) => {
-				const usernamePromise = os.api('users/show', parseAcct(this.target));
-				const idPromise = os.api('users/show', { userId: this.target });
-				let _notFound = false;
-				const notFound = () => {
-					if (_notFound) {
-						os.dialog({
-							type: 'error',
-							text: this.$ts.noSuchUser
-						});
-					} else {
-						_notFound = true;
-					}
-				};
-				usernamePromise.then(res).catch(e => {
-					if (e.code === 'NO_SUCH_USER') {
-						notFound();
-					}
-				});
-				idPromise.then(res).catch(e => {
-					notFound();
-				});
-			});
-		},
+	async mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
 
-		/** テキストエリアから処理対象ユーザーを設定する */
-		async showUser() {
-			const user = await this.fetchUser();
-			this.show(user);
-			this.target = '';
-		},
+	methods: {
+		lookupUser,
 
 		searchUser() {
 			os.selectUser().then(user => {
@@ -206,9 +162,7 @@ export default defineComponent({
 		},
 
 		show(user) {
-			os.popup(import('./user-dialog.vue'), {
-				userId: user.id
-			}, {}, 'closed');
+			os.pageWindow(`/user-info/${user.id}`);
 		},
 
 		acct
@@ -217,57 +171,61 @@ export default defineComponent({
 </script>
 
 <style lang="scss" scoped>
-.mk-instance-users {
+.lknzcolw {
+	> .actions {
+		margin: var(--margin);
+	}
+
 	> .users {
-		> ._content {
-			> .users {
-				margin-top: var(--margin);
+		margin: var(--margin);
+	
+		> .users {
+			margin-top: var(--margin);
+
+			> .user {
+				display: flex;
+				width: 100%;
+				box-sizing: border-box;
+				text-align: left;
+				align-items: center;
+				padding: 16px;
+
+				&:hover {
+					color: var(--accent);
+				}
 
-				> .user {
-					display: flex;
-					width: 100%;
-					box-sizing: border-box;
-					text-align: left;
-					align-items: center;
-					padding: 16px;
+				> .avatar {
+					width: 60px;
+					height: 60px;
+				}
 
-					&:hover {
-						color: var(--accent);
-					}
+				> .body {
+					margin-left: 0.3em;
+					padding: 0 8px;
+					flex: 1;
 
-					> .avatar {
-						width: 60px;
-						height: 60px;
+					@media (max-width: 500px) {
+						font-size: 14px;
 					}
 
-					> .body {
-						margin-left: 0.3em;
-						padding: 0 8px;
-						flex: 1;
-
-						@media (max-width: 500px) {
-							font-size: 14px;
+					> header {
+						> .name {
+							font-weight: bold;
 						}
 
-						> header {
-							> .name {
-								font-weight: bold;
-							}
-
-							> .acct {
-								margin-left: 8px;
-								opacity: 0.7;
-							}
+						> .acct {
+							margin-left: 8px;
+							opacity: 0.7;
+						}
 
-							> .staff {
-								margin-left: 0.5em;
-								color: var(--badge);
-							}
+						> .staff {
+							margin-left: 0.5em;
+							color: var(--badge);
+						}
 
-							> .punished {
-								margin-left: 0.5em;
-								color: #4dabf7;
-							}
+						> .punished {
+							margin-left: 0.5em;
+							color: #4dabf7;
 						}
 					}
 				}
diff --git a/src/client/pages/mentions.vue b/src/client/pages/mentions.vue
index 042c3a498be8a28cef42cee268a4bdac54be3fbc..a12993ebb814f54eec2f0e4b594d1b90adc19166 100644
--- a/src/client/pages/mentions.vue
+++ b/src/client/pages/mentions.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAt } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XNotes from '@client/components/notes.vue';
 import * as symbols from '@client/symbols';
@@ -20,7 +19,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.mentions,
-				icon: faAt
+				icon: 'fas fa-at'
 			},
 			pagination: {
 				endpoint: 'notes/mentions',
diff --git a/src/client/pages/messages.vue b/src/client/pages/messages.vue
index 09d92e51ba25bc0c758f817893db8317b602d3ef..6ac9746d4e86e3d3dac516508716ecff7ccdca0e 100644
--- a/src/client/pages/messages.vue
+++ b/src/client/pages/messages.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faEnvelope } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XNotes from '@client/components/notes.vue';
 import * as symbols from '@client/symbols';
@@ -20,7 +19,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.directNotes,
-				icon: faEnvelope
+				icon: 'fas fa-envelope'
 			},
 			pagination: {
 				endpoint: 'notes/mentions',
@@ -29,7 +28,6 @@ export default defineComponent({
 					visibility: 'specified'
 				})
 			},
-			faEnvelope
 		};
 	},
 
diff --git a/src/client/pages/messaging/index.vue b/src/client/pages/messaging/index.vue
index 1e316e9090021bdb8f156971e25573aece44cf66..9f3323f629d6c8ae048c48eb8aa83e9cff7dd244 100644
--- a/src/client/pages/messaging/index.vue
+++ b/src/client/pages/messaging/index.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="yweeujhr _root" v-size="{ max: [400] }">
-	<MkButton @click="start" primary class="start"><Fa :icon="faPlus"/> {{ $ts.startMessaging }}</MkButton>
+	<MkButton @click="start" primary class="start"><i class="fas fa-plus"></i> {{ $ts.startMessaging }}</MkButton>
 
 	<div class="history" v-if="messages.length > 0">
 		<MkA v-for="(message, i) in messages"
@@ -38,7 +38,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faUser, faUsers, faComments, faPlus } from '@fortawesome/free-solid-svg-icons';
 import getAcct from '@/misc/acct/render';
 import MkButton from '@client/components/ui/button.vue';
 import { acct } from '../../filters/user';
@@ -54,13 +53,12 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.messaging,
-				icon: faComments
+				icon: 'fas fa-comments'
 			},
 			fetching: true,
 			moreFetching: false,
 			messages: [],
 			connection: null,
-			faUser, faUsers, faComments, faPlus
 		};
 	},
 
@@ -120,11 +118,11 @@ export default defineComponent({
 		start(ev) {
 			os.modalMenu([{
 				text: this.$ts.messagingWithUser,
-				icon: faUser,
+				icon: 'fas fa-user',
 				action: () => { this.startUser() }
 			}, {
 				text: this.$ts.messagingWithGroup,
-				icon: faUsers,
+				icon: 'fas fa-users',
 				action: () => { this.startGroup() }
 			}], ev.currentTarget || ev.target);
 		},
diff --git a/src/client/pages/messaging/messaging-room.form.vue b/src/client/pages/messaging/messaging-room.form.vue
index c547e18850425e441b59ef39244c6ddfdc72c024..31c42e4ab39be6f4b76dfab746467d41a4077b1c 100644
--- a/src/client/pages/messaging/messaging-room.form.vue
+++ b/src/client/pages/messaging/messaging-room.form.vue
@@ -13,17 +13,16 @@
 	></textarea>
 	<div class="file" @click="file = null" v-if="file">{{ file.name }}</div>
 	<button class="send _button" @click="send" :disabled="!canSend || sending" :title="$ts.send">
-		<template v-if="!sending"><Fa :icon="faPaperPlane"/></template><template v-if="sending"><Fa icon="spinner .spin"/></template>
+		<template v-if="!sending"><i class="fas fa-paper-plane"></i></template><template v-if="sending"><i class="fas fa-spinner fa-pulse fa-fw"></i></template>
 	</button>
-	<button class="_button" @click="chooseFile"><Fa :icon="faPhotoVideo"/></button>
-	<button class="_button" @click="insertEmoji"><Fa :icon="faLaughSquint"/></button>
+	<button class="_button" @click="chooseFile"><i class="fas fa-photo-video"></i></button>
+	<button class="_button" @click="insertEmoji"><i class="fas fa-laugh-squint"></i></button>
 	<input ref="file" type="file" @change="onChangeFile"/>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faPaperPlane, faPhotoVideo, faLaughSquint } from '@fortawesome/free-solid-svg-icons';
 import insertTextAtCursor from 'insert-text-at-cursor';
 import * as autosize from 'autosize';
 import { formatTimeString } from '@/misc/format-time-string';
@@ -51,7 +50,6 @@ export default defineComponent({
 			typing: throttle(3000, () => {
 				os.stream.send('typingOnMessaging', this.user ? { partner: this.user.id } : { group: this.group.id });
 			}),
-			faPaperPlane, faPhotoVideo, faLaughSquint
 		};
 	},
 	computed: {
diff --git a/src/client/pages/messaging/messaging-room.message.vue b/src/client/pages/messaging/messaging-room.message.vue
index 1228baff68e35783ca608f9102aeeda11f36db7b..dfac83ad6a3776b52cf43e7d4120f529c34972e0 100644
--- a/src/client/pages/messaging/messaging-room.message.vue
+++ b/src/client/pages/messaging/messaging-room.message.vue
@@ -29,7 +29,7 @@
 				<span class="read" v-if="isMe && message.isRead">{{ $ts.messageRead }}</span>
 			</template>
 			<MkTime :time="message.createdAt"/>
-			<template v-if="message.is_edited"><Fa icon="pencil-alt"/></template>
+			<template v-if="message.is_edited"><i class="fas fa-pencil-alt"></i></template>
 		</footer>
 	</div>
 </div>
@@ -221,7 +221,7 @@ export default defineComponent({
 				margin: 0 8px;
 			}
 
-			> [data-icon] {
+			> i {
 				margin-left: 4px;
 			}
 		}
diff --git a/src/client/pages/messaging/messaging-room.vue b/src/client/pages/messaging/messaging-room.vue
index dae4590213b8c9633fb1812a893a359bae8b8ccc..44bfd6c51dc7229867b180bd3c9e6e21238bc37b 100644
--- a/src/client/pages/messaging/messaging-room.vue
+++ b/src/client/pages/messaging/messaging-room.vue
@@ -6,10 +6,10 @@
 	<div class="_content mk-messaging-room">
 		<div class="body">
 			<MkLoading v-if="fetching"/>
-			<p class="empty" v-if="!fetching && messages.length == 0"><Fa :icon="faInfoCircle"/>{{ $ts.noMessagesYet }}</p>
-			<p class="no-history" v-if="!fetching && messages.length > 0 && !existMoreMessages"><Fa :icon="faFlag"/>{{ $ts.noMoreHistory }}</p>
+			<p class="empty" v-if="!fetching && messages.length == 0"><i class="fas fa-info-circle"></i>{{ $ts.noMessagesYet }}</p>
+			<p class="no-history" v-if="!fetching && messages.length > 0 && !existMoreMessages"><i class="fas fa-flag"></i>{{ $ts.noMoreHistory }}</p>
 			<button class="more _button" ref="loadMore" :class="{ fetching: fetchingMoreMessages }" v-show="existMoreMessages" @click="fetchMoreMessages" :disabled="fetchingMoreMessages">
-				<template v-if="fetchingMoreMessages"><Fa icon="spinner" pulse fixed-width/></template>{{ fetchingMoreMessages ? $ts.loading : $ts.loadMore }}
+				<template v-if="fetchingMoreMessages"><i class="fas fa-spinner fa-pulse fa-fw"></i></template>{{ fetchingMoreMessages ? $ts.loading : $ts.loadMore }}
 			</button>
 			<XList class="messages" :items="messages" v-slot="{ item: message }" direction="up" reversed>
 				<XMessage :message="message" :is-group="group != null" :key="message.id"/>
@@ -26,7 +26,7 @@
 			</div>
 			<transition name="fade">
 				<div class="new-message" v-show="showIndicator">
-					<button class="_buttonPrimary" @click="onIndicatorClick"><i><Fa :icon="faArrowCircleDown"/></i>{{ $ts.newMessageExists }}</button>
+					<button class="_buttonPrimary" @click="onIndicatorClick"><i class="fas fa-arrow-circle-down"></i>{{ $ts.newMessageExists }}</button>
 				</div>
 			</transition>
 			<XForm v-if="!fetching" :user="user" :group="group" ref="form"/>
@@ -37,8 +37,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faArrowCircleDown, faFlag, faUsers, faInfoCircle, faEllipsisH, faExternalLinkAlt } from '@fortawesome/free-solid-svg-icons';
-import { faWindowMaximize } from '@fortawesome/free-regular-svg-icons';
 import XList from '@client/components/date-separated-list.vue';
 import XMessage from './messaging-room.message.vue';
 import XForm from './messaging-room.form.vue';
@@ -75,14 +73,14 @@ const Component = defineComponent({
 				userName: this.user,
 				avatar: this.user,
 				action: {
-					icon: faEllipsisH,
+					icon: 'fas fa-ellipsis-h',
 					handler: this.menu,
 				},
 			} : {
 				title: this.group.name,
-				icon: faUsers,
+				icon: 'fas fa-users',
 				action: {
-					icon: faEllipsisH,
+					icon: 'fas fa-ellipsis-h',
 					handler: this.menu,
 				},
 			} : null),
@@ -103,7 +101,6 @@ const Component = defineComponent({
 					&& this.existMoreMessages
 					&& this.fetchMoreMessages()
 			),
-			faArrowCircleDown, faFlag, faInfoCircle
 		};
 	},
 
@@ -325,14 +322,14 @@ const Component = defineComponent({
 
 			os.modalMenu([this.inWindow ? undefined : {
 				text: this.$ts.openInWindow,
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				action: () => {
 					os.pageWindow(path);
 					this.$router.back();
 				},
 			}, this.inWindow ? undefined : {
 				text: this.$ts.popout,
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				action: () => {
 					popout(path);
 					this.$router.back();
@@ -356,7 +353,7 @@ export default Component;
 			font-size: 0.8em;
 			opacity: 0.5;
 
-			[data-icon] {
+			i {
 				margin-right: 4px;
 			}
 		}
@@ -370,7 +367,7 @@ export default Component;
 			color: var(--messagingRoomInfo);
 			opacity: 0.5;
 
-			[data-icon] {
+			i {
 				margin-right: 4px;
 			}
 		}
@@ -396,7 +393,7 @@ export default Component;
 				cursor: wait;
 			}
 
-			> [data-icon] {
+			> i {
 				margin-right: 4px;
 			}
 		}
diff --git a/src/client/pages/mfm-cheat-sheet.vue b/src/client/pages/mfm-cheat-sheet.vue
index 36f40dbcab10972de3a35a648ce62927fc13041e..52278552362fc629928277c46d4cb7d860714e49 100644
--- a/src/client/pages/mfm-cheat-sheet.vue
+++ b/src/client/pages/mfm-cheat-sheet.vue
@@ -266,7 +266,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faQuestionCircle } from '@fortawesome/free-regular-svg-icons';
 import MkTextarea from '@client/components/ui/textarea.vue';
 import * as symbols from '@client/symbols';
 
@@ -279,7 +278,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts._mfm.cheatSheet,
-				icon: faQuestionCircle,
+				icon: 'fas fa-question-circle',
 			},
 			preview_mention: '@example',
 			preview_hashtag: '#test',
diff --git a/src/client/pages/my-antennas/index.antenna.vue b/src/client/pages/my-antennas/index.antenna.vue
index d7050d08c46217be5e87180790d9ae304b08021c..8cad6fa5538f1d7315d0e189badb106df7bb8b7d 100644
--- a/src/client/pages/my-antennas/index.antenna.vue
+++ b/src/client/pages/my-antennas/index.antenna.vue
@@ -39,15 +39,14 @@
 		<MkSwitch v-model:value="notify">{{ $ts.notifyAntenna }}</MkSwitch>
 	</div>
 	<div class="_footer">
-		<MkButton inline @click="saveAntenna()" primary><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		<MkButton inline @click="deleteAntenna()" v-if="antenna.id != null"><Fa :icon="faTrash"/> {{ $ts.delete }}</MkButton>
+		<MkButton inline @click="saveAntenna()" primary><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
+		<MkButton inline @click="deleteAntenna()" v-if="antenna.id != null"><i class="fas fa-trash"></i> {{ $ts.delete }}</MkButton>
 	</div>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSave, faTrash } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
@@ -83,7 +82,6 @@ export default defineComponent({
 			notify: false,
 			userLists: null,
 			userGroups: null,
-			faSave, faTrash
 		};
 	},
 
diff --git a/src/client/pages/my-antennas/index.vue b/src/client/pages/my-antennas/index.vue
index dfb752b831ab1d4b73e00dfb93e9ada1a892cc91..57c55cefddae0b9eda635bd35b1b0dbf86184e46 100644
--- a/src/client/pages/my-antennas/index.vue
+++ b/src/client/pages/my-antennas/index.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="ieepwinx _section">
-	<MkButton @click="create" primary class="add"><Fa :icon="faPlus"/> {{ $ts.add }}</MkButton>
+	<MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
 
 	<div class="_content">
 		<XAntenna v-if="draft" :antenna="draft" @created="onAntennaCreated" style="margin-bottom: var(--margin);"/>
@@ -14,7 +14,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSatellite, faPlus } from '@fortawesome/free-solid-svg-icons';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkButton from '@client/components/ui/button.vue';
 import XAntenna from './index.antenna.vue';
@@ -31,9 +30,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.manageAntennas,
-				icon: faSatellite,
+				icon: 'fas fa-satellite',
 				action: {
-					icon: faPlus,
+					icon: 'fas fa-plus',
 					handler: this.create
 				}
 			},
@@ -42,7 +41,6 @@ export default defineComponent({
 				limit: 10,
 			},
 			draft: null,
-			faSatellite, faPlus
 		};
 	},
 
diff --git a/src/client/pages/my-clips/index.vue b/src/client/pages/my-clips/index.vue
index 09cd7f828af0bbdc8b326fafbac57edaf0189a12..c4ca474748b3518372d4be7ce8a32214cfe69b0f 100644
--- a/src/client/pages/my-clips/index.vue
+++ b/src/client/pages/my-clips/index.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="_section qtcaoidl">
-	<MkButton @click="create" primary class="add"><Fa :icon="faPlus"/> {{ $ts.add }}</MkButton>
+	<MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.add }}</MkButton>
 
 	<div class="_content">
 		<MkPagination :pagination="pagination" #default="{items}" ref="list" class="list">
@@ -15,7 +15,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlus, faPaperclip } from '@fortawesome/free-solid-svg-icons';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkButton from '@client/components/ui/button.vue';
 import * as os from '@client/os';
@@ -31,9 +30,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.clip,
-				icon: faPaperclip,
+				icon: 'fas fa-paperclip',
 				action: {
-					icon: faPlus,
+					icon: 'fas fa-plus',
 					handler: this.create
 				}
 			},
@@ -42,7 +41,6 @@ export default defineComponent({
 				limit: 10,
 			},
 			draft: null,
-			faPlus
 		};
 	},
 
diff --git a/src/client/pages/my-groups/group.vue b/src/client/pages/my-groups/group.vue
index 90a60e5e2b159298edde03d39b45cc0575b04025..bd5537cbfa3c113b91b686ac879d63c4a0a7b41b 100644
--- a/src/client/pages/my-groups/group.vue
+++ b/src/client/pages/my-groups/group.vue
@@ -23,7 +23,7 @@
 							<MkAcct :user="user" class="acct"/>
 						</div>
 						<div class="action">
-							<button class="_button" @click="removeUser(user)"><Fa :icon="faTimes"/></button>
+							<button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button>
 						</div>
 					</div>
 				</div>
@@ -35,7 +35,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faTimes, faUsers } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import MkButton from '@client/components/ui/button.vue';
 import * as os from '@client/os';
@@ -57,11 +56,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: computed(() => this.group ? {
 				title: this.group.name,
-				icon: faUsers,
+				icon: 'fas fa-users',
 			} : null),
 			group: null,
 			users: [],
-			faTimes, faUsers
 		};
 	},
 
diff --git a/src/client/pages/my-groups/index.vue b/src/client/pages/my-groups/index.vue
index 5125ce3f4fb5cebfb9c46cc57e76f1c2294a853c..9f153ff9ccf4d3acd5748d73d29f61f4fe4bf0fb 100644
--- a/src/client/pages/my-groups/index.vue
+++ b/src/client/pages/my-groups/index.vue
@@ -4,13 +4,13 @@
 		<MkTab v-model:value="tab">
 			<option value="owned">{{ $ts.ownedGroups }}</option>
 			<option value="joined">{{ $ts.joinedGroups }}</option>
-			<option value="invites"><Fa :icon="faEnvelopeOpenText"/> {{ $ts.invites }}</option>
+			<option value="invites"><i class="fas fa-envelope-open-text"></i> {{ $ts.invites }}</option>
 		</MkTab>
 	</div>
 
 	<div class="_section">
 		<div class="_content" v-if="tab === 'owned'">
-			<MkButton @click="create" primary style="margin: 0 auto var(--margin) auto;"><Fa :icon="faPlus"/> {{ $ts.createGroup }}</MkButton>
+			<MkButton @click="create" primary style="margin: 0 auto var(--margin) auto;"><i class="fas fa-plus"></i> {{ $ts.createGroup }}</MkButton>
 
 			<MkPagination :pagination="ownedPagination" #default="{items}" ref="owned">
 				<div class="_card" v-for="group in items" :key="group.id">
@@ -35,8 +35,8 @@
 					<div class="_title">{{ invitation.group.name }}</div>
 					<div class="_content"><MkAvatars :user-ids="invitation.group.userIds"/></div>
 					<div class="_footer">
-						<MkButton @click="acceptInvite(invitation)" primary inline><Fa :icon="faCheck"/> {{ $ts.accept }}</MkButton>
-						<MkButton @click="rejectInvite(invitation)" primary inline><Fa :icon="faBan"/> {{ $ts.reject }}</MkButton>
+						<MkButton @click="acceptInvite(invitation)" primary inline><i class="fas fa-check"></i> {{ $ts.accept }}</MkButton>
+						<MkButton @click="rejectInvite(invitation)" primary inline><i class="fas fa-ban"></i> {{ $ts.reject }}</MkButton>
 					</div>
 				</div>
 			</MkPagination>
@@ -47,7 +47,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faUsers, faPlus, faEnvelopeOpenText } from '@fortawesome/free-solid-svg-icons';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkButton from '@client/components/ui/button.vue';
 import MkContainer from '@client/components/ui/container.vue';
@@ -69,7 +68,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.groups,
-				icon: faUsers
+				icon: 'fas fa-users'
 			},
 			tab: 'owned',
 			ownedPagination: {
@@ -84,7 +83,6 @@ export default defineComponent({
 				endpoint: 'i/user-group-invites',
 				limit: 10,
 			},
-			faUsers, faPlus, faEnvelopeOpenText
 		};
 	},
 
diff --git a/src/client/pages/my-lists/index.vue b/src/client/pages/my-lists/index.vue
index e680b90d1aed59b6e09c156c14699be953d97a66..2b60917060703a4ae4bd593a5a9767467fe0a3c2 100644
--- a/src/client/pages/my-lists/index.vue
+++ b/src/client/pages/my-lists/index.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="qkcjvfiv _section">
-	<MkButton @click="create" primary class="add"><Fa :icon="faPlus"/> {{ $ts.createList }}</MkButton>
+	<MkButton @click="create" primary class="add"><i class="fas fa-plus"></i> {{ $ts.createList }}</MkButton>
 
 	<MkPagination :pagination="pagination" #default="{items}" class="lists _content" ref="list">
 		<div class="list _panel" v-for="(list, i) in items" :key="list.id">
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faListUl, faPlus } from '@fortawesome/free-solid-svg-icons';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkButton from '@client/components/ui/button.vue';
 import * as os from '@client/os';
@@ -28,9 +27,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.manageLists,
-				icon: faListUl,
+				icon: 'fas fa-list-ul',
 				action: {
-					icon: faPlus,
+					icon: 'fas fa-plus',
 					handler: this.create
 				}
 			},
@@ -38,7 +37,6 @@ export default defineComponent({
 				endpoint: 'users/lists/list',
 				limit: 10,
 			},
-			faListUl, faPlus
 		};
 	},
 
diff --git a/src/client/pages/my-lists/list.vue b/src/client/pages/my-lists/list.vue
index 2892150ffec079b7e8db534e399f623f32afa96a..049d370b4efb2d3b65dab2cfbf75c05eb5c47927 100644
--- a/src/client/pages/my-lists/list.vue
+++ b/src/client/pages/my-lists/list.vue
@@ -22,7 +22,7 @@
 							<MkAcct :user="user" class="acct"/>
 						</div>
 						<div class="action">
-							<button class="_button" @click="removeUser(user)"><Fa :icon="faTimes"/></button>
+							<button class="_button" @click="removeUser(user)"><i class="fas fa-times"></i></button>
 						</div>
 					</div>
 				</div>
@@ -34,7 +34,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faTimes, faListUl } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import MkButton from '@client/components/ui/button.vue';
 import * as os from '@client/os';
@@ -49,11 +48,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: computed(() => this.list ? {
 				title: this.list.name,
-				icon: faListUl,
+				icon: 'fas fa-list-ul',
 			} : null),
 			list: null,
 			users: [],
-			faTimes, faListUl
 		};
 	},
 
diff --git a/src/client/pages/not-found.vue b/src/client/pages/not-found.vue
index b13bdac2b8a7e4144be53946199267a1277d23b0..5e7fe17f7534e05f872bf367d1b430f3fa88262b 100644
--- a/src/client/pages/not-found.vue
+++ b/src/client/pages/not-found.vue
@@ -9,7 +9,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 import * as symbols from '@client/symbols';
 
@@ -18,7 +17,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.notFound,
-				icon: faExclamationTriangle
+				icon: 'fas fa-exclamation-triangle'
 			},
 		}
 	},
diff --git a/src/client/pages/note.vue b/src/client/pages/note.vue
index 279dd9666114b8287a3e5f356372d349079d80be..ce4af4eb4e81f332044e66920cec0561486a78e7 100644
--- a/src/client/pages/note.vue
+++ b/src/client/pages/note.vue
@@ -7,7 +7,7 @@
 			</div>
 
 			<div class="main _gap">
-				<MkButton v-if="!showNext && hasNext" class="load next" @click="showNext = true"><Fa :icon="faChevronUp"/></MkButton>
+				<MkButton v-if="!showNext && hasNext" class="load next" @click="showNext = true"><i class="fas fa-chevron-up"></i></MkButton>
 				<div class="_content _gap">
 					<MkRemoteCaution v-if="note.user.host != null" :href="note.url || note.uri" class="_gap"/>
 					<XNoteDetailed v-model:note="note" :key="note.id" class="_gap"/>
@@ -22,7 +22,7 @@
 						</div>
 					</MkA>
 				</div>
-				<MkButton v-if="!showPrev && hasPrev" class="load prev" @click="showPrev = true"><Fa :icon="faChevronDown"/></MkButton>
+				<MkButton v-if="!showPrev && hasPrev" class="load prev" @click="showPrev = true"><i class="fas fa-chevron-down"></i></MkButton>
 			</div>
 
 			<div class="_gap" v-if="showPrev">
@@ -37,7 +37,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faChevronUp, faChevronDown } from '@fortawesome/free-solid-svg-icons';
 import XNote from '@client/components/note.vue';
 import XNoteDetailed from '@client/components/note-detailed.vue';
 import XNotes from '@client/components/notes.vue';
@@ -95,7 +94,6 @@ export default defineComponent({
 					sinceId: this.note.id,
 				})
 			},
-			faChevronUp, faChevronDown
 		};
 	},
 	watch: {
diff --git a/src/client/pages/notifications.vue b/src/client/pages/notifications.vue
index 25605988edc7748c707ff5e9fa59b544c53a9f24..38797d746e1693f8013352275911ec27e693c4a0 100644
--- a/src/client/pages/notifications.vue
+++ b/src/client/pages/notifications.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBell, faCheck } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XNotifications from '@client/components/notifications.vue';
 import * as os from '@client/os';
@@ -21,10 +20,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.notifications,
-				icon: faBell,
+				icon: 'fas fa-bell',
 				actions: [{
 					text: this.$ts.markAllAsRead,
-					icon: faCheck,
+					icon: 'fas fa-check',
 					handler: () => {
 						os.apiWithDialog('notifications/mark-all-as-read');
 					}
diff --git a/src/client/pages/page-editor/els/page-editor.el.button.vue b/src/client/pages/page-editor/els/page-editor.el.button.vue
index 1515187676e24da4e50a0ad7cda6a33dc944a616..6e9036faac0105c36da963d4498aa669c1ddc7bf 100644
--- a/src/client/pages/page-editor/els/page-editor.el.button.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.button.vue
@@ -1,6 +1,6 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faBolt"/> {{ $ts._pages.blocks.button }}</template>
+	<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.button }}</template>
 
 	<section class="xfhsjczc">
 		<MkInput v-model:value="value.text"><span>{{ $ts._pages.blocks._button.text }}</span></MkInput>
@@ -39,7 +39,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBolt } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkSelect from '@client/components/ui/select.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -62,7 +61,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBolt
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.canvas.vue b/src/client/pages/page-editor/els/page-editor.el.canvas.vue
index 9d4b4c76d2699b1cc23197c34d4d6a2dd26cba12..59d29b9b71ba312d1bee2dc3c013f25b635380cc 100644
--- a/src/client/pages/page-editor/els/page-editor.el.canvas.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.canvas.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faPaintBrush"/> {{ $ts._pages.blocks.canvas }}</template>
+	<template #header><i class="fas fa-paint-brush"></i> {{ $ts._pages.blocks.canvas }}</template>
 
 	<section style="padding: 0 16px 0 16px;">
-		<MkInput v-model:value="value.name"><template #prefix><Fa :icon="faMagic"/></template><span>{{ $ts._pages.blocks._canvas.id }}</span></MkInput>
+		<MkInput v-model:value="value.name"><template #prefix><i class="fas fa-magic"></i></template><span>{{ $ts._pages.blocks._canvas.id }}</span></MkInput>
 		<MkInput v-model:value="value.width" type="number"><span>{{ $ts._pages.blocks._canvas.width }}</span><template #suffix>px</template></MkInput>
 		<MkInput v-model:value="value.height" type="number"><span>{{ $ts._pages.blocks._canvas.height }}</span><template #suffix>px</template></MkInput>
 	</section>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPaintBrush, faMagic } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkInput from '@client/components/ui/input.vue';
 import * as os from '@client/os';
@@ -30,7 +29,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faPaintBrush, faMagic
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.counter.vue b/src/client/pages/page-editor/els/page-editor.el.counter.vue
index e16962aee92845d5d7798a58cae6e64fd27cb912..3394817b53031b726b32559e8b9c5ca55a2db3bb 100644
--- a/src/client/pages/page-editor/els/page-editor.el.counter.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.counter.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faBolt"/> {{ $ts._pages.blocks.counter }}</template>
+	<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.counter }}</template>
 
 	<section style="padding: 0 16px 0 16px;">
-		<MkInput v-model:value="value.name"><template #prefix><Fa :icon="faMagic"/></template><span>{{ $ts._pages.blocks._counter.name }}</span></MkInput>
+		<MkInput v-model:value="value.name"><template #prefix><i class="fas fa-magic"></i></template><span>{{ $ts._pages.blocks._counter.name }}</span></MkInput>
 		<MkInput v-model:value="value.text"><span>{{ $ts._pages.blocks._counter.text }}</span></MkInput>
 		<MkInput v-model:value="value.inc" type="number"><span>{{ $ts._pages.blocks._counter.inc }}</span></MkInput>
 	</section>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkInput from '@client/components/ui/input.vue';
 import * as os from '@client/os';
@@ -30,7 +29,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBolt, faMagic
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.if.vue b/src/client/pages/page-editor/els/page-editor.el.if.vue
index 0cbfaa7eb859dc30fd3efbaa956a597ecec24873..7f4ed458aa2c1cd516c446ca82935cff2d63f5a8 100644
--- a/src/client/pages/page-editor/els/page-editor.el.if.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.if.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faQuestion"/> {{ $ts._pages.blocks.if }}</template>
+	<template #header><i class="fas fa-question"></i> {{ $ts._pages.blocks.if }}</template>
 	<template #func>
 		<button @click="add()" class="_button">
-			<Fa :icon="faPlus"/>
+			<i class="fas fa-plus"></i>
 		</button>
 	</template>
 
@@ -27,7 +27,6 @@
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
 import { v4 as uuid } from 'uuid';
-import { faPlus, faQuestion } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkSelect from '@client/components/ui/select.vue';
 import * as os from '@client/os';
@@ -51,7 +50,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faPlus, faQuestion
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.image.vue b/src/client/pages/page-editor/els/page-editor.el.image.vue
index 1a96e42679e873d1d5e2ecf11c0846618f113abb..d96879f50d41e9689daba2fbb0dd68b1b8a53814 100644
--- a/src/client/pages/page-editor/els/page-editor.el.image.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.image.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faImage"/> {{ $ts._pages.blocks.image }}</template>
+	<template #header><i class="fas fa-image"></i> {{ $ts._pages.blocks.image }}</template>
 	<template #func>
 		<button @click="choose()">
-			<Fa :icon="faFolderOpen"/>
+			<i class="fas fa-folder-open"></i>
 		</button>
 	</template>
 
@@ -15,8 +15,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPencilAlt } from '@fortawesome/free-solid-svg-icons';
-import { faImage, faFolderOpen } from '@fortawesome/free-regular-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkDriveFileThumbnail from '@client/components/drive-file-thumbnail.vue';
 import * as os from '@client/os';
@@ -35,7 +33,6 @@ export default defineComponent({
 	data() {
 		return {
 			file: null,
-			faPencilAlt, faImage, faFolderOpen
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.note.vue b/src/client/pages/page-editor/els/page-editor.el.note.vue
index 3f7eaf7572984cf48752bf4f688e98e1fbfa76da..d4801f30591510f23a68fb824c381e6ff41d5fa9 100644
--- a/src/client/pages/page-editor/els/page-editor.el.note.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.note.vue
@@ -1,6 +1,6 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faStickyNote"/> {{ $ts._pages.blocks.note }}</template>
+	<template #header><i class="fas fa-sticky-note"></i> {{ $ts._pages.blocks.note }}</template>
 
 	<section style="padding: 0 16px 0 16px;">
 		<MkInput v-model:value="id">
@@ -17,7 +17,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faStickyNote } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkSwitch from '@client/components/ui/switch.vue';
@@ -40,7 +39,6 @@ export default defineComponent({
 		return {
 			id: this.value.note,
 			note: null,
-			faStickyNote
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.number-input.vue b/src/client/pages/page-editor/els/page-editor.el.number-input.vue
index 76c35d4406fb15d4ec2e77ee678d6cc8ae8df228..8058d941c18731151a33295a5eb2aaf0778b080d 100644
--- a/src/client/pages/page-editor/els/page-editor.el.number-input.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.number-input.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faBolt"/> {{ $ts._pages.blocks.numberInput }}</template>
+	<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.numberInput }}</template>
 
 	<section style="padding: 0 16px 0 16px;">
-		<MkInput v-model:value="value.name"><template #prefix><Fa :icon="faMagic"/></template><span>{{ $ts._pages.blocks._numberInput.name }}</span></MkInput>
+		<MkInput v-model:value="value.name"><template #prefix><i class="fas fa-magic"></i></template><span>{{ $ts._pages.blocks._numberInput.name }}</span></MkInput>
 		<MkInput v-model:value="value.text"><span>{{ $ts._pages.blocks._numberInput.text }}</span></MkInput>
 		<MkInput v-model:value="value.default" type="number"><span>{{ $ts._pages.blocks._numberInput.default }}</span></MkInput>
 	</section>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkInput from '@client/components/ui/input.vue';
 import * as os from '@client/os';
@@ -30,7 +29,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBolt, faMagic
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.post.vue b/src/client/pages/page-editor/els/page-editor.el.post.vue
index 51c5481d54ac0c854174b5800a2a5ab76ed43d50..1ed7f860c88aa1c2b2701ecfbd511bac9224fe03 100644
--- a/src/client/pages/page-editor/els/page-editor.el.post.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.post.vue
@@ -1,6 +1,6 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faPaperPlane"/> {{ $ts._pages.blocks.post }}</template>
+	<template #header><i class="fas fa-paper-plane"></i> {{ $ts._pages.blocks.post }}</template>
 
 	<section style="padding: 16px;">
 		<MkTextarea v-model:value="value.text">{{ $ts._pages.blocks._post.text }}</MkTextarea>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPaperPlane } from '@fortawesome/free-regular-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -32,7 +31,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faPaperPlane
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.radio-button.vue b/src/client/pages/page-editor/els/page-editor.el.radio-button.vue
index 82b09a62901be83c52e667e7fab92d000d2ff814..97715ed69c591ec6d2524041afa079966b5d380c 100644
--- a/src/client/pages/page-editor/els/page-editor.el.radio-button.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.radio-button.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faBolt"/> {{ $ts._pages.blocks.radioButton }}</template>
+	<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.radioButton }}</template>
 
 	<section style="padding: 0 16px 16px 16px;">
-		<MkInput v-model:value="value.name"><template #prefix><Fa :icon="faMagic"/></template><span>{{ $ts._pages.blocks._radioButton.name }}</span></MkInput>
+		<MkInput v-model:value="value.name"><template #prefix><i class="fas fa-magic"></i></template><span>{{ $ts._pages.blocks._radioButton.name }}</span></MkInput>
 		<MkInput v-model:value="value.title"><span>{{ $ts._pages.blocks._radioButton.title }}</span></MkInput>
 		<MkTextarea v-model:value="values"><span>{{ $ts._pages.blocks._radioButton.values }}</span></MkTextarea>
 		<MkInput v-model:value="value.default"><span>{{ $ts._pages.blocks._radioButton.default }}</span></MkInput>
@@ -13,7 +13,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -31,7 +30,6 @@ export default defineComponent({
 	data() {
 		return {
 			values: '',
-			faBolt, faMagic
 		};
 	},
 	watch: {
diff --git a/src/client/pages/page-editor/els/page-editor.el.section.vue b/src/client/pages/page-editor/els/page-editor.el.section.vue
index 96f468b13aa8e789cee5b28227c659402fd0502f..16ef2598f9ec18911a516a2a23f78d8d15913fb8 100644
--- a/src/client/pages/page-editor/els/page-editor.el.section.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.section.vue
@@ -1,12 +1,12 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faStickyNote"/> {{ value.title }}</template>
+	<template #header><i class="fas fa-sticky-note"></i> {{ value.title }}</template>
 	<template #func>
 		<button @click="rename()" class="_button">
-			<Fa :icon="faPencilAlt"/>
+			<i class="fas fa-pencil-alt"></i>
 		</button>
 		<button @click="add()" class="_button">
-			<Fa :icon="faPlus"/>
+			<i class="fas fa-plus"></i>
 		</button>
 	</template>
 
@@ -19,8 +19,6 @@
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
 import { v4 as uuid } from 'uuid';
-import { faPlus, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
-import { faStickyNote } from '@fortawesome/free-regular-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import * as os from '@client/os';
 
@@ -43,7 +41,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faStickyNote, faPlus, faPencilAlt
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.switch.vue b/src/client/pages/page-editor/els/page-editor.el.switch.vue
index 56b9f1561cbed15961e4e12b855808c830874377..564d5e22c34ce4feec8aabac4344c42a57dfde93 100644
--- a/src/client/pages/page-editor/els/page-editor.el.switch.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.switch.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faBolt"/> {{ $ts._pages.blocks.switch }}</template>
+	<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.switch }}</template>
 
 	<section class="kjuadyyj">
-		<MkInput v-model:value="value.name"><template #prefix><Fa :icon="faMagic"/></template><span>{{ $ts._pages.blocks._switch.name }}</span></MkInput>
+		<MkInput v-model:value="value.name"><template #prefix><i class="fas fa-magic"></i></template><span>{{ $ts._pages.blocks._switch.name }}</span></MkInput>
 		<MkInput v-model:value="value.text"><span>{{ $ts._pages.blocks._switch.text }}</span></MkInput>
 		<MkSwitch v-model:value="value.default"><span>{{ $ts._pages.blocks._switch.default }}</span></MkSwitch>
 	</section>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkSwitch from '@client/components/ui/switch.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -31,7 +30,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBolt, faMagic
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.text-input.vue b/src/client/pages/page-editor/els/page-editor.el.text-input.vue
index cb8cb83aa71ac399c044beb1563a9fc5762f113e..4435d9b841ae1411e9ad9481687ff3b3dccc96db 100644
--- a/src/client/pages/page-editor/els/page-editor.el.text-input.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.text-input.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faBolt"/> {{ $ts._pages.blocks.textInput }}</template>
+	<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.textInput }}</template>
 
 	<section style="padding: 0 16px 0 16px;">
-		<MkInput v-model:value="value.name"><template #prefix><Fa :icon="faMagic"/></template><span>{{ $ts._pages.blocks._textInput.name }}</span></MkInput>
+		<MkInput v-model:value="value.name"><template #prefix><i class="fas fa-magic"></i></template><span>{{ $ts._pages.blocks._textInput.name }}</span></MkInput>
 		<MkInput v-model:value="value.text"><span>{{ $ts._pages.blocks._textInput.text }}</span></MkInput>
 		<MkInput v-model:value="value.default" type="text"><span>{{ $ts._pages.blocks._textInput.default }}</span></MkInput>
 	</section>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkInput from '@client/components/ui/input.vue';
 import * as os from '@client/os';
@@ -30,7 +29,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBolt, faMagic
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.text.vue b/src/client/pages/page-editor/els/page-editor.el.text.vue
index bd2c9c46dc3ecbb36eb6f052bfbdaf5ed6b542f5..668dd5f52debe8d3c17f88021b496121e27a1a37 100644
--- a/src/client/pages/page-editor/els/page-editor.el.text.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.text.vue
@@ -1,6 +1,6 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faAlignLeft"/> {{ $ts._pages.blocks.text }}</template>
+	<template #header><i class="fas fa-align-left"></i> {{ $ts._pages.blocks.text }}</template>
 
 	<section class="vckmsadr">
 		<textarea v-model="value.text"></textarea>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAlignLeft } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import * as os from '@client/os';
 
@@ -27,7 +26,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faAlignLeft,
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue b/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue
index 8c4ff234089ca633862c7e13ee5b6f11d4b11b15..cf3b9f93f4590eb34014596dfa065e147513d2bd 100644
--- a/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.textarea-input.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faBolt"/> {{ $ts._pages.blocks.textareaInput }}</template>
+	<template #header><i class="fas fa-bolt"></i> {{ $ts._pages.blocks.textareaInput }}</template>
 
 	<section style="padding: 0 16px 16px 16px;">
-		<MkInput v-model:value="value.name"><template #prefix><Fa :icon="faMagic"/></template><span>{{ $ts._pages.blocks._textareaInput.name }}</span></MkInput>
+		<MkInput v-model:value="value.name"><template #prefix><i class="fas fa-magic"></i></template><span>{{ $ts._pages.blocks._textareaInput.name }}</span></MkInput>
 		<MkInput v-model:value="value.text"><span>{{ $ts._pages.blocks._textareaInput.text }}</span></MkInput>
 		<MkTextarea v-model:value="value.default"><span>{{ $ts._pages.blocks._textareaInput.default }}</span></MkTextarea>
 	</section>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBolt, faMagic } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
 import MkInput from '@client/components/ui/input.vue';
@@ -31,7 +30,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBolt, faMagic
 		};
 	},
 
diff --git a/src/client/pages/page-editor/els/page-editor.el.textarea.vue b/src/client/pages/page-editor/els/page-editor.el.textarea.vue
index 042b2837315f315c32a0474c5715d049f7755d43..a29d5bd3f2665f763401cae0fc2669fb2de2ab03 100644
--- a/src/client/pages/page-editor/els/page-editor.el.textarea.vue
+++ b/src/client/pages/page-editor/els/page-editor.el.textarea.vue
@@ -1,6 +1,6 @@
 <template>
 <XContainer @remove="() => $emit('remove')" :draggable="true">
-	<template #header><Fa :icon="faAlignLeft"/> {{ $ts._pages.blocks.textarea }}</template>
+	<template #header><i class="fas fa-align-left"></i> {{ $ts._pages.blocks.textarea }}</template>
 
 	<section class="ihymsbbe">
 		<textarea v-model="value.text"></textarea>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAlignLeft } from '@fortawesome/free-solid-svg-icons';
 import XContainer from '../page-editor.container.vue';
 import * as os from '@client/os';
 
@@ -27,7 +26,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faAlignLeft,
 		};
 	},
 
diff --git a/src/client/pages/page-editor/page-editor.container.vue b/src/client/pages/page-editor/page-editor.container.vue
index 46e2dca1570fd5ac31f22939284ece8af319cd02..afd261fac7664a6f387755f5826b92c7b5f952d9 100644
--- a/src/client/pages/page-editor/page-editor.container.vue
+++ b/src/client/pages/page-editor/page-editor.container.vue
@@ -5,14 +5,14 @@
 		<div class="buttons">
 			<slot name="func"></slot>
 			<button v-if="removable" @click="remove()" class="_button">
-				<Fa :icon="faTrashAlt"/>
+				<i class="fas fa-trash-alt"></i>
 			</button>
 			<button v-if="draggable" class="drag-handle _button">
-				<Fa :icon="faBars"/>
+				<i class="fas fa-bars"></i>
 			</button>
 			<button @click="toggleContent(!showBody)" class="_button">
-				<template v-if="showBody"><Fa :icon="faAngleUp"/></template>
-				<template v-else><Fa :icon="faAngleDown"/></template>
+				<template v-if="showBody"><i class="fas fa-angle-up"></i></template>
+				<template v-else><i class="fas fa-angle-down"></i></template>
 			</button>
 		</div>
 	</header>
@@ -26,8 +26,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBars, faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
-import { faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 
 export default defineComponent({
 	props: {
@@ -56,7 +54,6 @@ export default defineComponent({
 	data() {
 		return {
 			showBody: this.expanded,
-			faTrashAlt, faBars, faAngleUp, faAngleDown
 		};
 	},
 	methods: {
@@ -105,7 +102,7 @@ export default defineComponent({
 			font-weight: bold;
 			box-shadow: 0 1px rgba(#000, 0.07);
 
-			> [data-icon] {
+			> i {
 				margin-right: 6px;
 			}
 
diff --git a/src/client/pages/page-editor/page-editor.script-block.vue b/src/client/pages/page-editor/page-editor.script-block.vue
index 10d5311cde3858a8d3ff9458fd2bffdf90c6677c..65ac731e47fb67f74e20aad24839f55de35107ff 100644
--- a/src/client/pages/page-editor/page-editor.script-block.vue
+++ b/src/client/pages/page-editor/page-editor.script-block.vue
@@ -1,9 +1,9 @@
 <template>
 <XContainer :removable="removable" @remove="() => $emit('remove')" :error="error" :warn="warn" :draggable="draggable">
-	<template #header><Fa v-if="icon" :icon="icon"/> <template v-if="title">{{ title }} <span class="turmquns" v-if="typeText">({{ typeText }})</span></template><template v-else-if="typeText">{{ typeText }}</template></template>
+	<template #header><i v-if="icon" :class="icon"></i> <template v-if="title">{{ title }} <span class="turmquns" v-if="typeText">({{ typeText }})</span></template><template v-else-if="typeText">{{ typeText }}</template></template>
 	<template #func>
 		<button @click="changeType()" class="_button">
-			<Fa :icon="faPencilAlt"/>
+			<i class="fas fa-pencil-alt"></i>
 		</button>
 	</template>
 
@@ -57,7 +57,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faPencilAlt, faPlug } from '@fortawesome/free-solid-svg-icons';
 import { v4 as uuid } from 'uuid';
 import XContainer from './page-editor.container.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
@@ -109,14 +108,13 @@ export default defineComponent({
 			error: null,
 			warn: null,
 			slots: '',
-			faPencilAlt
 		};
 	},
 
 	computed: {
 		icon(): any {
 			if (this.value.type === null) return null;
-			if (this.value.type.startsWith('fn:')) return faPlug;
+			if (this.value.type.startsWith('fn:')) return 'fas fa-plug';
 			return blockDefs.find(x => x.type === this.value.type).icon;
 		},
 		typeText(): any {
diff --git a/src/client/pages/page-editor/page-editor.vue b/src/client/pages/page-editor/page-editor.vue
index 4583863a1c8e91462b05a773633a6ad1550c87ac..e96e1faaf2752b65b57f5b0b83965a676a94e6d0 100644
--- a/src/client/pages/page-editor/page-editor.vue
+++ b/src/client/pages/page-editor/page-editor.vue
@@ -1,15 +1,15 @@
 <template>
 <div class="_root">
-	<MkA class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><Fa :icon="faExternalLinkSquareAlt"/> {{ $ts._pages.viewPage }}</MkA>
+	<MkA class="view" v-if="pageId" :to="`/@${ author.username }/pages/${ currentName }`"><i class="fas fa-external-link-square-alt"></i> {{ $ts._pages.viewPage }}</MkA>
 
 	<div class="buttons" style="margin: 16px;">
-		<MkButton inline @click="save" primary class="save" v-if="!readonly"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-		<MkButton inline @click="duplicate" class="duplicate" v-if="pageId"><Fa :icon="faCopy"/> {{ $ts.duplicate }}</MkButton>
-		<MkButton inline @click="del" class="delete" v-if="pageId && !readonly"><Fa :icon="faTrashAlt"/> {{ $ts.delete }}</MkButton>
+		<MkButton inline @click="save" primary class="save" v-if="!readonly"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
+		<MkButton inline @click="duplicate" class="duplicate" v-if="pageId"><i class="fas fa-copy"></i> {{ $ts.duplicate }}</MkButton>
+		<MkButton inline @click="del" class="delete" v-if="pageId && !readonly"><i class="fas fa-trash-alt"></i> {{ $ts.delete }}</MkButton>
 	</div>
 
 	<MkContainer :foldable="true" :expanded="true" class="_gap">
-		<template #header><Fa :icon="faCog"/> {{ $ts._pages.pageSetting }}</template>
+		<template #header><i class="fas fa-cog"></i> {{ $ts._pages.pageSetting }}</template>
 		<div style="padding: 16px;">
 			<MkInput v-model:value="title">
 				<span>{{ $ts._pages.title }}</span>
@@ -35,26 +35,26 @@
 			<MkSwitch v-model:value="hideTitleWhenPinned">{{ $ts._pages.hideTitleWhenPinned }}</MkSwitch>
 
 			<div class="eyeCatch">
-				<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><Fa :icon="faPlus"/> {{ $ts._pages.eyeCatchingImageSet }}</MkButton>
+				<MkButton v-if="eyeCatchingImageId == null && !readonly" @click="setEyeCatchingImage"><i class="fas fa-plus"></i> {{ $ts._pages.eyeCatchingImageSet }}</MkButton>
 				<div v-else-if="eyeCatchingImage">
 					<img :src="eyeCatchingImage.url" :alt="eyeCatchingImage.name" style="max-width: 100%;"/>
-					<MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><Fa :icon="faTrashAlt"/> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton>
+					<MkButton @click="removeEyeCatchingImage()" v-if="!readonly"><i class="fas fa-trash-alt"></i> {{ $ts._pages.eyeCatchingImageRemove }}</MkButton>
 				</div>
 			</div>
 		</div>
 	</MkContainer>
 
 	<MkContainer :foldable="true" :expanded="true" class="_gap">
-		<template #header><Fa :icon="faStickyNote"/> {{ $ts._pages.contents }}</template>
+		<template #header><i class="fas fa-sticky-note"></i> {{ $ts._pages.contents }}</template>
 		<div style="padding: 16px;">
 			<XBlocks class="content" v-model:value="content" :hpml="hpml"/>
 
-			<MkButton @click="add()" v-if="!readonly"><Fa :icon="faPlus"/></MkButton>
+			<MkButton @click="add()" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
 		</div>
 	</MkContainer>
 
 	<MkContainer :foldable="true" class="_gap">
-		<template #header><Fa :icon="faMagic"/> {{ $ts._pages.variables }}</template>
+		<template #header><i class="fas fa-magic"></i> {{ $ts._pages.variables }}</template>
 		<div class="qmuvgica">
 			<XDraggable tag="div" class="variables" v-show="variables.length > 0" v-model="variables" item-key="name" handle=".drag-handle" :group="{ name: 'variables' }" animation="150" swap-threshold="0.5">
 				<template #item="{element}">
@@ -70,12 +70,12 @@
 				</template>
 			</XDraggable>
 
-			<MkButton @click="addVariable()" class="add" v-if="!readonly"><Fa :icon="faPlus"/></MkButton>
+			<MkButton @click="addVariable()" class="add" v-if="!readonly"><i class="fas fa-plus"></i></MkButton>
 		</div>
 	</MkContainer>
 
 	<MkContainer :foldable="true" :expanded="true" class="_gap">
-		<template #header><Fa :icon="faCode"/> {{ $ts.script }}</template>
+		<template #header><i class="fas fa-code"></i> {{ $ts.script }}</template>
 		<div>
 			<MkTextarea class="_code" v-model:value="script"/>
 		</div>
@@ -91,8 +91,6 @@ import 'prismjs/components/prism-clike';
 import 'prismjs/components/prism-javascript';
 import 'prismjs/themes/prism-okaidia.css';
 import 'vue-prism-editor/dist/prismeditor.min.css';
-import { faICursor, faPlus, faMagic, faCog, faCode, faExternalLinkSquareAlt, faPencilAlt, faCopy } from '@fortawesome/free-solid-svg-icons';
-import { faSave, faStickyNote, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import { v4 as uuid } from 'uuid';
 import XVariable from './page-editor.script-block.vue';
 import XBlocks from './page-editor.blocks.vue';
@@ -143,7 +141,7 @@ export default defineComponent({
 				}
 				return {
 					title: title,
-					icon: faPencilAlt,
+					icon: 'fas fa-pencil-alt',
 				};
 			}),
 			author: this.$i,
@@ -164,7 +162,6 @@ export default defineComponent({
 			hpml: null,
 			script: '',
 			url,
-			faPlus, faICursor, faSave, faStickyNote, faMagic, faCog, faTrashAlt, faExternalLinkSquareAlt, faCode, faCopy
 		};
 	},
 
@@ -471,7 +468,7 @@ export default defineComponent({
 			font-weight: bold;
 			box-shadow: 0 1px rgba(#000, 0.07);
 
-			> [data-icon] {
+			> i {
 				margin-right: 6px;
 			}
 
diff --git a/src/client/pages/page.vue b/src/client/pages/page.vue
index d7b570e5f4ed86e2f74843252cb704d3ad516e99..f25ed511841f6aa406505a7de46b9901cc194556 100644
--- a/src/client/pages/page.vue
+++ b/src/client/pages/page.vue
@@ -14,8 +14,8 @@
 			<small style="display: block; opacity: 0.7; margin-top: 1em;">@{{ page.user.username }}</small>
 		</div>
 		<div class="like">
-			<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><Fa :icon="faHeartS"/><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
-			<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><Fa :icon="faHeartR"/><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
+			<MkButton class="button" @click="unlike()" v-if="page.isLiked" v-tooltip="$ts._pages.unlike" primary><i class="fas fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
+			<MkButton class="button" @click="like()" v-else v-tooltip="$ts._pages.like"><i class="far fa-heart"></i><span class="count" v-if="page.likedCount > 0">{{ page.likedCount }}</span></MkButton>
 		</div>
 		<div class="links">
 			<MkA :to="`/@${username}/pages/${pageName}/view-source`" class="link">{{ $ts._pages.viewSource }}</MkA>
@@ -27,16 +27,14 @@
 		</div>
 	</div>
 	<div class="footer">
-		<div><Fa :icon="faClock"/> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
-		<div v-if="page.createdAt != page.updatedAt"><Fa :icon="faClock"/> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
+		<div><i class="far fa-clock"></i> {{ $ts.createdAt }}: <MkTime :time="page.createdAt" mode="detail"/></div>
+		<div v-if="page.createdAt != page.updatedAt"><i class="far fa-clock"></i> {{ $ts.updatedAt }}: <MkTime :time="page.updatedAt" mode="detail"/></div>
 	</div>
 </div>
 </template>
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faHeart as faHeartS } from '@fortawesome/free-solid-svg-icons';
-import { faHeart as faHeartR, faClock } from '@fortawesome/free-regular-svg-icons';
 import XPage from '@client/components/page/page.vue';
 import MkButton from '@client/components/ui/button.vue';
 import * as os from '@client/os';
@@ -71,7 +69,6 @@ export default defineComponent({
 				},
 			} : null),
 			page: null,
-			faHeartS, faHeartR, faClock,
 		};
 	},
 
diff --git a/src/client/pages/pages.vue b/src/client/pages/pages.vue
index 8aea7e6b95346249499e2f9788b4cb4d6f9e46ce..52a860be13a5e414a350017019fce7c5389b6625 100644
--- a/src/client/pages/pages.vue
+++ b/src/client/pages/pages.vue
@@ -1,9 +1,9 @@
 <template>
 <div>
 	<MkTab v-model:value="tab" v-if="$i">
-		<option value="featured"><Fa :icon="faFireAlt"/> {{ $ts._pages.featured }}</option>
-		<option value="my"><Fa :icon="faEdit"/> {{ $ts._pages.my }}</option>
-		<option value="liked"><Fa :icon="faHeart"/> {{ $ts._pages.liked }}</option>
+		<option value="featured"><i class="fas fa-fire-alt"></i> {{ $ts._pages.featured }}</option>
+		<option value="my"><i class="fas fa-edit"></i> {{ $ts._pages.my }}</option>
+		<option value="liked"><i class="fas fa-heart"></i> {{ $ts._pages.liked }}</option>
 	</MkTab>
 
 	<div class="_section">
@@ -14,7 +14,7 @@
 		</div>
 
 		<div class="rknalgpo _content my" v-if="tab === 'my'">
-			<MkButton class="new" @click="create()"><Fa :icon="faPlus"/></MkButton>
+			<MkButton class="new" @click="create()"><i class="fas fa-plus"></i></MkButton>
 			<MkPagination :pagination="myPagesPagination" #default="{items}">
 				<MkPagePreview v-for="page in items" class="ckltabjg" :page="page" :key="page.id"/>
 			</MkPagination>
@@ -31,8 +31,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlus, faEdit, faFireAlt } from '@fortawesome/free-solid-svg-icons';
-import { faStickyNote, faHeart } from '@fortawesome/free-regular-svg-icons';
 import MkPagePreview from '@client/components/page-preview.vue';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkButton from '@client/components/ui/button.vue';
@@ -47,9 +45,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.pages,
-				icon: faStickyNote,
+				icon: 'fas fa-sticky-note',
 				actions: [{
-					icon: faPlus,
+					icon: 'fas fa-plus',
 					text: this.$ts.create,
 					handler: this.create
 				}]
@@ -67,7 +65,6 @@ export default defineComponent({
 				endpoint: 'i/page-likes',
 				limit: 5,
 			},
-			faStickyNote, faPlus, faEdit, faHeart, faFireAlt
 		};
 	},
 	methods: {
diff --git a/src/client/pages/preview.vue b/src/client/pages/preview.vue
index bd4e08db62907456cc43df9d55ce44619bc3eb86..3df446e67696f9f109c93b9aa97918753d81fd71 100644
--- a/src/client/pages/preview.vue
+++ b/src/client/pages/preview.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faEye } from '@fortawesome/free-solid-svg-icons';
 import MkSample from '@client/components/sample.vue';
 import * as symbols from '@client/symbols';
 
@@ -19,7 +18,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.preview,
-				icon: faEye,
+				icon: 'fas fa-eye',
 			},
 		}
 	},
diff --git a/src/client/pages/reversi/game.board.vue b/src/client/pages/reversi/game.board.vue
index a466527c012e6280a930ae16037e4db63f08ee3d..78bcf0341352cd94dcd853396e59d365760670e3 100644
--- a/src/client/pages/reversi/game.board.vue
+++ b/src/client/pages/reversi/game.board.vue
@@ -40,8 +40,8 @@
 						<img v-if="stone === false" :src="whiteUser.avatarUrl" alt="white">
 					</template>
 					<template v-else>
-						<fa v-if="stone === true" :icon="fasCircle"/>
-						<fa v-if="stone === false" :icon="farCircle"/>
+						<i v-if="stone === true" class="fas fa-circle"></i>
+						<i v-if="stone === false" class="far fa-circle"></i>
 					</template>
 				</div>
 			</div>
@@ -63,12 +63,12 @@
 	<div class="player" v-if="game.isEnded">
 		<span>{{ logPos }} / {{ logs.length }}</span>
 		<div class="buttons" v-if="!autoplaying">
-			<MkButton inline @click="logPos = 0" :disabled="logPos == 0"><fa :icon="faAngleDoubleLeft"/></MkButton>
-			<MkButton inline @click="logPos--" :disabled="logPos == 0"><fa :icon="faAngleLeft"/></MkButton>
-			<MkButton inline @click="logPos++" :disabled="logPos == logs.length"><fa :icon="faAngleRight"/></MkButton>
-			<MkButton inline @click="logPos = logs.length" :disabled="logPos == logs.length"><fa :icon="faAngleDoubleRight"/></MkButton>
+			<MkButton inline @click="logPos = 0" :disabled="logPos == 0"><i class="fas fa-angle-double-left"></i></MkButton>
+			<MkButton inline @click="logPos--" :disabled="logPos == 0"><i class="fas fa-angle-left"></i></MkButton>
+			<MkButton inline @click="logPos++" :disabled="logPos == logs.length"><i class="fas fa-angle-right"></i></MkButton>
+			<MkButton inline @click="logPos = logs.length" :disabled="logPos == logs.length"><i class="fas fa-angle-double-right"></i></MkButton>
 		</div>
-		<MkButton @click="autoplay()" :disabled="autoplaying" style="margin: var(--margin) auto 0 auto;"><fa :icon="faPlay"/></MkButton>
+		<MkButton @click="autoplay()" :disabled="autoplaying" style="margin: var(--margin) auto 0 auto;"><i class="fas fa-play"></i></MkButton>
 	</div>
 
 	<div class="info">
@@ -85,9 +85,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAngleDoubleLeft, faAngleLeft, faAngleRight, faAngleDoubleRight, faPlay } from '@fortawesome/free-solid-svg-icons';
-import { faCircle as fasCircle } from '@fortawesome/free-solid-svg-icons';
-import { faCircle as farCircle } from '@fortawesome/free-regular-svg-icons';
 import * as CRC32 from 'crc-32';
 import Reversi, { Color } from '../../../games/reversi/core';
 import { url } from '@client/config';
@@ -120,7 +117,6 @@ export default defineComponent({
 			logPos: 0,
 			watchers: [],
 			pollingClock: null,
-			faAngleDoubleLeft, faAngleLeft, faAngleRight, faAngleDoubleRight, fasCircle, farCircle, faPlay
 		};
 	},
 
diff --git a/src/client/pages/reversi/game.setting.vue b/src/client/pages/reversi/game.setting.vue
index c7c2937ba838d1beb8621832d94218c96013bf24..1a2abba79527c3c3329c1ee5404c950078093b16 100644
--- a/src/client/pages/reversi/game.setting.vue
+++ b/src/client/pages/reversi/game.setting.vue
@@ -17,11 +17,11 @@
 			</header>
 
 			<div>
-				<div class="random" v-if="game.map == null"><fa icon="dice"/></div>
+				<div class="random" v-if="game.map == null"><i class="fas fa-dice"></i></div>
 				<div class="board" v-else :style="{ 'grid-template-rows': `repeat(${ game.map.length }, 1fr)`, 'grid-template-columns': `repeat(${ game.map[0].length }, 1fr)` }">
 					<div v-for="(x, i) in game.map.join('')" :class="{ none: x == ' ' }" @click="onPixelClick(i, x)">
-						<fa v-if="x == 'b'" :icon="fasCircle"/>
-						<fa v-if="x == 'w'" :icon="farCircle"/>
+						<i v-if="x === 'b'" class="fas fa-circle"></i>
+						<i v-if="x === 'w'" class="far fa-circle"></i>
 					</div>
 				</div>
 			</div>
@@ -125,8 +125,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCircle as fasCircle } from '@fortawesome/free-solid-svg-icons';
-import { faCircle as farCircle } from '@fortawesome/free-regular-svg-icons';
 import * as maps from '../../../games/reversi/maps';
 import MkButton from '@client/components/ui/button.vue';
 import MkSwitch from '@client/components/ui/switch.vue';
diff --git a/src/client/pages/reversi/game.vue b/src/client/pages/reversi/game.vue
index 896dbc39cc7c97a6c08a1a41e4985b9eaebe056e..62c99d775531fb1860e12f4214d48b445d016deb 100644
--- a/src/client/pages/reversi/game.vue
+++ b/src/client/pages/reversi/game.vue
@@ -9,7 +9,6 @@ import { defineComponent } from 'vue';
 import GameSetting from './game.setting.vue';
 import GameBoard from './game.board.vue';
 import * as os from '@client/os';
-import { faGamepad } from '@fortawesome/free-solid-svg-icons';
 import * as symbols from '@client/symbols';
 
 export default defineComponent({
@@ -29,7 +28,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts._reversi.reversi,
-				icon: faGamepad
+				icon: 'fas fa-gamepad'
 			},
 			game: null,
 			connection: null,
diff --git a/src/client/pages/reversi/index.vue b/src/client/pages/reversi/index.vue
index 59b228f5f6713548094dbada6d33a6edf9a2f8df..37126fca10013c3a8bfc7d90ab843579a9900d11 100644
--- a/src/client/pages/reversi/index.vue
+++ b/src/client/pages/reversi/index.vue
@@ -64,7 +64,6 @@ import { defineComponent } from 'vue';
 import * as os from '@client/os';
 import MkButton from '@client/components/ui/button.vue';
 import MkFolder from '@client/components/ui/folder.vue';
-import { faGamepad } from '@fortawesome/free-solid-svg-icons';
 import * as symbols from '@client/symbols';
 
 export default defineComponent({
@@ -78,7 +77,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts._reversi.reversi,
-				icon: faGamepad
+				icon: 'fas fa-gamepad'
 			},
 			games: [],
 			gamesFetching: true,
diff --git a/src/client/pages/room/room.vue b/src/client/pages/room/room.vue
index e1de52b8f1fa2854d7cf554f4d2ed203dcaeb8ce..ea34ef11b5bd49ca6a8b93fd507baeaaab1f948c 100644
--- a/src/client/pages/room/room.vue
+++ b/src/client/pages/room/room.vue
@@ -17,18 +17,18 @@
 			</template>
 		</div>
 		<div class="_content">
-			<MkButton inline @click="translate()" :primary="isTranslateMode"><Fa :icon="faArrowsAlt"/> {{ $ts._rooms.translate }}</MkButton>
-			<MkButton inline @click="rotate()" :primary="isRotateMode"><Fa :icon="faUndo"/> {{ $ts._rooms.rotate }}</MkButton>
-			<MkButton inline v-if="isTranslateMode || isRotateMode" @click="exit()"><Fa :icon="faBan"/> {{ $ts._rooms.exit }}</MkButton>
+			<MkButton inline @click="translate()" :primary="isTranslateMode"><i class="fas fa-arrows-alt"></i> {{ $ts._rooms.translate }}</MkButton>
+			<MkButton inline @click="rotate()" :primary="isRotateMode"><i class="fas fa-undo"></i> {{ $ts._rooms.rotate }}</MkButton>
+			<MkButton inline v-if="isTranslateMode || isRotateMode" @click="exit()"><i class="fas fa-ban"></i> {{ $ts._rooms.exit }}</MkButton>
 		</div>
 		<div class="_content">
-			<MkButton @click="remove()"><Fa :icon="faTrashAlt"/> {{ $ts._rooms.remove }}</MkButton>
+			<MkButton @click="remove()"><i class="fas fa-trash-alt"></i> {{ $ts._rooms.remove }}</MkButton>
 		</div>
 	</div>
 
 	<div class="menu _section" v-if="isMyRoom">
 		<div class="_content">
-			<MkButton @click="add()"><Fa :icon="faBoxOpen"/> {{ $ts._rooms.addFurniture }}</MkButton>
+			<MkButton @click="add()"><i class="fas fa-box-open"></i> {{ $ts._rooms.addFurniture }}</MkButton>
 		</div>
 		<div class="_content">
 			<MkSelect :value="roomType" @update:value="updateRoomType($event)">
@@ -42,8 +42,8 @@
 			</label>
 		</div>
 		<div class="_content">
-			<MkButton inline :disabled="!changed" primary @click="save()"><Fa :icon="faSave"/> {{ $ts.save }}</MkButton>
-			<MkButton inline @click="clear()"><Fa :icon="faBroom"/> {{ $ts._rooms.clear }}</MkButton>
+			<MkButton inline :disabled="!changed" primary @click="save()"><i class="fas fa-save"></i> {{ $ts.save }}</MkButton>
+			<MkButton inline @click="clear()"><i class="fas fa-broom"></i> {{ $ts._rooms.clear }}</MkButton>
 		</div>
 	</div>
 </div>
@@ -55,8 +55,6 @@ import { Room } from '@client/scripts/room/room';
 import parseAcct from '@/misc/acct/parse';
 import XPreview from './preview.vue';
 const storeItems = require('@client/scripts/room/furnitures.json5');
-import { faBoxOpen, faUndo, faArrowsAlt, faBan, faBroom } from '@fortawesome/free-solid-svg-icons';
-import { faSave, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import { query as urlQuery } from '../../../prelude/url';
 import MkButton from '@client/components/ui/button.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -98,7 +96,6 @@ export default defineComponent({
 			isRotateMode: false,
 			isMyRoom: false,
 			changed: false,
-			faBoxOpen, faSave, faTrashAlt, faUndo, faArrowsAlt, faBan, faBroom,
 		};
 	},
 
diff --git a/src/client/pages/scratchpad.vue b/src/client/pages/scratchpad.vue
index 1a863e6b2ecccd5b84bc7099ca2cc7c28018d49b..99164ec51fcd82e2157f2e8f97f50daa9a95caf4 100644
--- a/src/client/pages/scratchpad.vue
+++ b/src/client/pages/scratchpad.vue
@@ -2,11 +2,11 @@
 <div class="iltifgqe">
 	<div class="editor _panel _gap">
 		<PrismEditor class="_code code" v-model="code" :highlight="highlighter" :line-numbers="false"/>
-		<MkButton style="position: absolute; top: 8px; right: 8px;" @click="run()" primary><Fa :icon="faPlay"/></MkButton>
+		<MkButton style="position: absolute; top: 8px; right: 8px;" @click="run()" primary><i class="fas fa-play"></i></MkButton>
 	</div>
 
 	<MkContainer :foldable="true" class="_gap">
-		<template #header><Fa fixed-width/>{{ $ts.output }}</template>
+		<template #header>{{ $ts.output }}</template>
 		<div class="bepmlvbi">
 			<div v-for="log in logs" class="log" :key="log.id" :class="{ print: log.print }">{{ log.text }}</div>
 		</div>
@@ -20,7 +20,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTerminal, faPlay } from '@fortawesome/free-solid-svg-icons';
 import 'prismjs';
 import { highlight, languages } from 'prismjs/components/prism-core';
 import 'prismjs/components/prism-clike';
@@ -46,11 +45,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.scratchpad,
-				icon: faTerminal,
+				icon: 'fas fa-terminal',
 			},
 			code: '',
 			logs: [],
-			faTerminal, faPlay
 		}
 	},
 
diff --git a/src/client/pages/search.vue b/src/client/pages/search.vue
index b670714730f288c838945e1dbddab0ba054c74c3..bf228576be9aedefedcc983381df5cabf995812e 100644
--- a/src/client/pages/search.vue
+++ b/src/client/pages/search.vue
@@ -8,7 +8,6 @@
 
 <script lang="ts">
 import { computed, defineComponent } from 'vue';
-import { faSearch } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XNotes from '@client/components/notes.vue';
 import * as symbols from '@client/symbols';
@@ -22,7 +21,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: computed(() => this.$t('searchWith', { q: this.$route.query.q })),
-				icon: faSearch
+				icon: 'fas fa-search'
 			},
 			pagination: {
 				endpoint: 'notes/search',
diff --git a/src/client/pages/settings/2fa.vue b/src/client/pages/settings/2fa.vue
index 361611bcb242282080d705a02d29e1f808152330..aa14f91d711df7a6546ea2f19867c77abeea3ef0 100644
--- a/src/client/pages/settings/2fa.vue
+++ b/src/client/pages/settings/2fa.vue
@@ -1,6 +1,6 @@
 <template>
 <section class="_card">
-	<div class="_title"><Fa :icon="faLock"/> {{ $ts.twoStepAuthentication }}</div>
+	<div class="_title"><i class="fas fa-lock"></i> {{ $ts.twoStepAuthentication }}</div>
 	<div class="_content">
 		<MkButton v-if="!data && !$i.twoFactorEnabled" @click="register">{{ $ts._2fa.registerDevice }}</MkButton>
 		<template v-if="$i.twoFactorEnabled">
@@ -28,7 +28,7 @@
 				<ol v-if="registration && !registration.error">
 					<li v-if="registration.stage >= 0">
 						{{ $ts.tapSecurityKey }}
-						<Fa icon="spinner" pulse fixed-width v-if="registration.saving && registration.stage == 0" />
+						<i v-if="registration.saving && registration.stage == 0" class="fas fa-spinner fa-pulse fa-fw"></i>
 					</li>
 					<li v-if="registration.stage >= 1">
 						<MkForm :disabled="registration.stage != 1 || registration.saving">
@@ -36,7 +36,7 @@
 								<span>{{ $ts.securityKeyName }}</span>
 							</MkInput>
 							<MkButton @click="registerKey" :disabled="keyName.length == 0">{{ $ts.registerSecurityKey }}</MkButton>
-							<Fa icon="spinner" pulse fixed-width v-if="registration.saving && registration.stage == 1" />
+							<i v-if="registration.saving && registration.stage == 1" class="fas fa-spinner fa-pulse fa-fw"></i>
 						</MkForm>
 					</li>
 				</ol>
@@ -68,7 +68,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faLock } from '@fortawesome/free-solid-svg-icons';
 import { hostname } from '@client/config';
 import { byteify, hexify, stringify } from '@client/scripts/2fa';
 import MkButton from '@client/components/ui/button.vue';
@@ -93,7 +92,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.twoStepAuthentication,
-				icon: faLock
+				icon: 'fas fa-lock'
 			},
 			data: null,
 			supportsCredentials: !!navigator.credentials,
@@ -101,7 +100,6 @@ export default defineComponent({
 			registration: null,
 			keyName: '',
 			token: null,
-			faLock
 		};
 	},
 
diff --git a/src/client/pages/settings/account-info.vue b/src/client/pages/settings/account-info.vue
index 955a0f7845bc07a725142c45c3a879e8e3654bbe..4d851b7b1278da050b0f8968457b6529d9b5237d 100644
--- a/src/client/pages/settings/account-info.vue
+++ b/src/client/pages/settings/account-info.vue
@@ -132,7 +132,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -162,7 +161,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.accountInfo,
-				icon: faInfoCircle
+				icon: 'fas fa-info-circle'
 			},
 			stats: null
 		}
diff --git a/src/client/pages/settings/accounts.vue b/src/client/pages/settings/accounts.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a3fa0d4eb0784decf464f95ac5397359b58ee393
--- /dev/null
+++ b/src/client/pages/settings/accounts.vue
@@ -0,0 +1,148 @@
+<template>
+<FormBase>
+	<FormSuspense :p="init">
+		<FormButton @click="addAccount" primary><i class="fas fa-plus"></i> {{ $ts.addAccount }}</FormButton>
+
+		<div class="_formItem _button" v-for="account in accounts" :key="account.id" @click="menu(account, $event)">
+			<div class="_formPanel lcjjdxlm">
+				<div class="avatar">
+					<MkAvatar :user="account" class="avatar"/>
+				</div>
+				<div class="body">
+					<div class="name">
+						<MkUserName :user="account"/>
+					</div>
+					<div class="acct">
+						<MkAcct :user="account"/>
+					</div>
+				</div>
+			</div>
+		</div>
+	</FormSuspense>
+</FormBase>
+</template>
+
+<script lang="ts">
+import { defineComponent } from 'vue';
+import FormSuspense from '@client/components/form/suspense.vue';
+import FormLink from '@client/components/form/link.vue';
+import FormBase from '@client/components/form/base.vue';
+import FormGroup from '@client/components/form/group.vue';
+import FormButton from '@client/components/form/button.vue';
+import * as os from '@client/os';
+import * as symbols from '@client/symbols';
+import { getAccounts, addAccount, login } from '@client/account';
+
+export default defineComponent({
+	components: {
+		FormBase,
+		FormSuspense,
+		FormButton,
+	},
+
+	emits: ['info'],
+
+	data() {
+		return {
+			[symbols.PAGE_INFO]: {
+				title: this.$ts.accounts,
+				icon: 'fas fa-users',
+			},
+			storedAccounts: getAccounts().filter(x => x.id !== this.$i.id),
+			accounts: null,
+			init: () => os.api('users/show', {
+				userIds: this.storedAccounts.map(x => x.id)
+			}).then(accounts => {
+				this.accounts = accounts;
+			}),
+		};
+	},
+
+	mounted() {
+		this.$emit('info', this[symbols.PAGE_INFO]);
+	},
+
+	methods: {
+		menu(account, ev) {
+			os.modalMenu([{
+				text: this.$ts.switch,
+				icon: 'fas fa-exchange-alt',
+				action: () => this.switchAccount(account),
+			}, {
+				text: this.$ts.remove,
+				icon: 'fas fa-trash-alt',
+				danger: true,
+				action: () => this.removeAccount(account),
+			}], ev.currentTarget || ev.target);
+		},
+
+		addAccount(ev) {
+			os.modalMenu([{
+				text: this.$ts.existingAccount,
+				action: () => { this.addExistingAccount(); },
+			}, {
+				text: this.$ts.createAccount,
+				action: () => { this.createAccount(); },
+			}], ev.currentTarget || ev.target);
+		},
+
+		addExistingAccount() {
+			os.popup(import('@client/components/signin-dialog.vue'), {}, {
+				done: res => {
+					addAccount(res.id, res.i);
+					os.success();
+				},
+			}, 'closed');
+		},
+
+		createAccount() {
+			os.popup(import('@client/components/signup-dialog.vue'), {}, {
+				done: res => {
+					addAccount(res.id, res.i);
+					this.switchAccountWithToken(res.i);
+				},
+			}, 'closed');
+		},
+
+		switchAccount(account: any) {
+			const storedAccounts = getAccounts();
+			const token = storedAccounts.find(x => x.id === account.id).token;
+			this.switchAccountWithToken(token);
+		},
+
+		switchAccountWithToken(token: string) {
+			login(token);
+		},
+	}
+});
+</script>
+
+<style lang="scss" scoped>
+.lcjjdxlm {
+	display: flex;
+	padding: 16px;
+
+	> .avatar {
+		display: block;
+		flex-shrink: 0;
+		margin: 0 12px 0 0;
+
+		> .avatar {
+			width: 50px;
+			height: 50px;
+		}
+	}
+
+	> .body {
+		display: flex;
+		flex-direction: column;
+		justify-content: center;
+		width: calc(100% - 62px);
+		position: relative;
+
+		> .name {
+			font-weight: bold;
+		}
+	}
+}
+</style>
diff --git a/src/client/pages/settings/api.vue b/src/client/pages/settings/api.vue
index 9b5339987041a1f1016e250ce72e5ef928d857f7..396d4405c3c12d97835441128c057cab28b6ac8c 100644
--- a/src/client/pages/settings/api.vue
+++ b/src/client/pages/settings/api.vue
@@ -8,7 +8,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faKey } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -31,7 +30,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: 'API',
-				icon: faKey
+				icon: 'fas fa-key'
 			},
 			isDesktop: window.innerWidth >= 1100,
 		};
diff --git a/src/client/pages/settings/apps.vue b/src/client/pages/settings/apps.vue
index 82bf9b7f8f4a97ece00eb18f46fdca8a9f5b6a5f..c864920ce1b047d91fb42349b8a33d00126597e9 100644
--- a/src/client/pages/settings/apps.vue
+++ b/src/client/pages/settings/apps.vue
@@ -22,7 +22,7 @@
 						<div><MkTime :time="token.lastUsedAt"/></div>
 					</div>
 					<div class="actions">
-						<button class="_button" @click="revoke(token)"><Fa :icon="faTrashAlt"/></button>
+						<button class="_button" @click="revoke(token)"><i class="fas fa-trash-alt"></i></button>
 					</div>
 					<details>
 						<summary>{{ $ts.details }}</summary>
@@ -39,7 +39,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTrashAlt, faPlug } from '@fortawesome/free-solid-svg-icons';
 import FormPagination from '@client/components/form/pagination.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -61,7 +60,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.installedApps,
-				icon: faPlug,
+				icon: 'fas fa-plug',
 			},
 			pagination: {
 				endpoint: 'i/apps',
@@ -70,7 +69,6 @@ export default defineComponent({
 					sort: '+lastUsedAt'
 				}
 			},
-			faTrashAlt, faPlug
 		};
 	},
 
diff --git a/src/client/pages/settings/deck.vue b/src/client/pages/settings/deck.vue
index 84992adc09e437a80436cddcd569c7b635f988f4..05f3061ca1bebf7a14b34bf04bb651b1998c982b 100644
--- a/src/client/pages/settings/deck.vue
+++ b/src/client/pages/settings/deck.vue
@@ -31,7 +31,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faImage, faCog, faColumns } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormLink from '@client/components/form/link.vue';
 import FormRadios from '@client/components/form/radios.vue';
@@ -59,9 +58,8 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.deck,
-				icon: faColumns
+				icon: 'fas fa-columns'
 			},
-			faImage, faCog,
 		}
 	},
 
diff --git a/src/client/pages/settings/drive.vue b/src/client/pages/settings/drive.vue
index 675b025ab88f7beccf4f791951c0880df83367d3..3da2a21dc7aaffd4fecdc3945f93a30a762b772f 100644
--- a/src/client/pages/settings/drive.vue
+++ b/src/client/pages/settings/drive.vue
@@ -27,7 +27,7 @@
 	<FormButton :center="false" @click="chooseUploadFolder()" primary>
 		{{ $ts.uploadFolder }}
 		<template #suffix>{{ uploadFolder ? uploadFolder.name : '-' }}</template>
-		<template #suffixIcon><Fa :icon="faFolderOpen"/></template>
+		<template #suffixIcon><i class="fas fa-folder-open"></i></template>
 	</FormButton>
 </FormBase>
 </template>
@@ -36,8 +36,6 @@
 import { defineComponent } from 'vue';
 import * as tinycolor from 'tinycolor2';
 import ApexCharts from 'apexcharts';
-import { faCloud, faFolderOpen } from '@fortawesome/free-solid-svg-icons';
-import { faClock, faEyeSlash, faTrashAlt } from '@fortawesome/free-regular-svg-icons';
 import FormButton from '@client/components/form/button.vue';
 import FormGroup from '@client/components/form/group.vue';
 import FormKeyValueView from '@client/components/form/key-value-view.vue';
@@ -60,13 +58,12 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.drive,
-				icon: faCloud
+				icon: 'fas fa-cloud'
 			},
 			fetching: true,
 			usage: null,
 			capacity: null,
 			uploadFolder: null,
-			faCloud, faClock, faEyeSlash, faFolderOpen, faTrashAlt
 		}
 	},
 
diff --git a/src/client/pages/settings/email-address.vue b/src/client/pages/settings/email-address.vue
index 97c5d396ceefdf52846502ce60c396c2b5c20af8..28eeeb6b73f679b848c51fdfd7af58b19451feda 100644
--- a/src/client/pages/settings/email-address.vue
+++ b/src/client/pages/settings/email-address.vue
@@ -13,8 +13,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCog } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faEnvelope } from '@fortawesome/free-regular-svg-icons';
 import FormButton from '@client/components/form/button.vue';
 import FormInput from '@client/components/form/input.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -36,11 +34,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.emailAddress,
-				icon: faEnvelope
+				icon: 'fas fa-envelope'
 			},
 			emailAddress: null,
 			code: null,
-			faCog
 		}
 	},
 
diff --git a/src/client/pages/settings/email-notification.vue b/src/client/pages/settings/email-notification.vue
index cc28bac4b08af8f2298002fa4f1ced52e94b2f60..ac3402568a75a85c0bb6fc1ada659b3557eaa5ef 100644
--- a/src/client/pages/settings/email-notification.vue
+++ b/src/client/pages/settings/email-notification.vue
@@ -25,8 +25,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCog } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faEnvelope } from '@fortawesome/free-regular-svg-icons';
 import FormButton from '@client/components/form/button.vue';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -49,7 +47,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.emailNotification,
-				icon: faEnvelope
+				icon: 'fas fa-envelope'
 			},
 
 			mention: this.$i.emailNotificationTypes.includes('mention'),
diff --git a/src/client/pages/settings/email.vue b/src/client/pages/settings/email.vue
index 04f433f9ae31fea526daaa636a0c15e2c92f2d34..aa20d9d94e639ffedb18d99f4986be5743a1393a 100644
--- a/src/client/pages/settings/email.vue
+++ b/src/client/pages/settings/email.vue
@@ -3,14 +3,14 @@
 	<FormGroup>
 		<template #label>{{ $ts.emailAddress }}</template>
 		<FormLink to="/settings/email/address">
-			<template v-if="$i.email && !$i.emailVerified" #icon><Fa :icon="faExclamationTriangle" style="color: var(--warn);"/></template>
-			<template v-else-if="$i.email && $i.emailVerified" #icon><Fa :icon="faCheck" style="color: var(--success);"/></template>
+			<template v-if="$i.email && !$i.emailVerified" #icon><i class="fas fa-exclamation-triangle" style="color: var(--warn);"></i></template>
+			<template v-else-if="$i.email && $i.emailVerified" #icon><i class="fas fa-check" style="color: var(--success);"></i></template>
 			{{ $i.email || $ts.notSet }}
 		</FormLink>
 	</FormGroup>
 
 	<FormLink to="/settings/email/notification">
-		<template #icon><Fa :icon="faBell"/></template>
+		<template #icon><i class="fas fa-bell"></i></template>
 		{{ $ts.emailNotification }}
 	</FormLink>
 
@@ -22,8 +22,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCog, faExclamationTriangle, faCheck } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faEnvelope } from '@fortawesome/free-regular-svg-icons';
 import FormButton from '@client/components/form/button.vue';
 import FormLink from '@client/components/form/link.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -47,9 +45,8 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.email,
-				icon: faEnvelope
+				icon: 'fas fa-envelope'
 			},
-			faCog, faExclamationTriangle, faCheck, faBell
 		}
 	},
 
diff --git a/src/client/pages/settings/experimental-features.vue b/src/client/pages/settings/experimental-features.vue
index 25453b7e105b2eb66356d093e7fa5efc906832c9..f8d5e419e94610d3d88ef3acb6b30505619606f0 100644
--- a/src/client/pages/settings/experimental-features.vue
+++ b/src/client/pages/settings/experimental-features.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faFlask } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -34,7 +33,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.experimentalFeatures,
-				icon: faFlask
+				icon: 'fas fa-flask'
 			},
 			stats: null
 		}
diff --git a/src/client/pages/settings/general.vue b/src/client/pages/settings/general.vue
index 2963ddf432b520f748f439808cf352df31c6031b..fdbae0b8a1792c272e47f01f888a9df940531cf3 100644
--- a/src/client/pages/settings/general.vue
+++ b/src/client/pages/settings/general.vue
@@ -83,7 +83,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faImage, faCog, faColumns, faCogs } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormRadios from '@client/components/form/radios.vue';
@@ -117,13 +116,12 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.general,
-				icon: faCogs
+				icon: 'fas fa-cogs'
 			},
 			langs,
 			lang: localStorage.getItem('lang'),
 			fontSize: localStorage.getItem('fontSize'),
 			useSystemFont: localStorage.getItem('useSystemFont') != null,
-			faImage, faCog, faColumns
 		}
 	},
 
diff --git a/src/client/pages/settings/import-export.vue b/src/client/pages/settings/import-export.vue
index 1591a9d548fd9b85637251567e184c38d65d133d..e77efb4429d82081a505ccc25194e17c7bc9d6b3 100644
--- a/src/client/pages/settings/import-export.vue
+++ b/src/client/pages/settings/import-export.vue
@@ -2,32 +2,31 @@
 <FormBase>
 	<FormGroup>
 		<template #label>{{ $ts._exportOrImport.allNotes }}</template>
-		<FormButton @click="doExport('notes')"><Fa :icon="faDownload"/> {{ $ts.export }}</FormButton>
+		<FormButton @click="doExport('notes')"><i class="fas fa-download"></i> {{ $ts.export }}</FormButton>
 	</FormGroup>
 	<FormGroup>
 		<template #label>{{ $ts._exportOrImport.followingList }}</template>
-		<FormButton @click="doExport('following')"><Fa :icon="faDownload"/> {{ $ts.export }}</FormButton>
-		<FormButton @click="doImport('following', $event)"><Fa :icon="faUpload"/> {{ $ts.import }}</FormButton>
+		<FormButton @click="doExport('following')"><i class="fas fa-download"></i> {{ $ts.export }}</FormButton>
+		<FormButton @click="doImport('following', $event)"><i class="fas fa-upload"></i> {{ $ts.import }}</FormButton>
 	</FormGroup>
 	<FormGroup>
 		<template #label>{{ $ts._exportOrImport.userLists }}</template>
-		<FormButton @click="doExport('user-lists')"><Fa :icon="faDownload"/> {{ $ts.export }}</FormButton>
-		<FormButton @click="doImport('user-lists', $event)"><Fa :icon="faUpload"/> {{ $ts.import }}</FormButton>
+		<FormButton @click="doExport('user-lists')"><i class="fas fa-download"></i> {{ $ts.export }}</FormButton>
+		<FormButton @click="doImport('user-lists', $event)"><i class="fas fa-upload"></i> {{ $ts.import }}</FormButton>
 	</FormGroup>
 	<FormGroup>
 		<template #label>{{ $ts._exportOrImport.muteList }}</template>
-		<FormButton @click="doExport('mute')"><Fa :icon="faDownload"/> {{ $ts.export }}</FormButton>
+		<FormButton @click="doExport('mute')"><i class="fas fa-download"></i> {{ $ts.export }}</FormButton>
 	</FormGroup>
 	<FormGroup>
 		<template #label>{{ $ts._exportOrImport.blockingList }}</template>
-		<FormButton @click="doExport('blocking')"><Fa :icon="faDownload"/> {{ $ts.export }}</FormButton>
+		<FormButton @click="doExport('blocking')"><i class="fas fa-download"></i> {{ $ts.export }}</FormButton>
 	</FormGroup>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faDownload, faUpload, faBoxes } from '@fortawesome/free-solid-svg-icons';
 import FormSelect from '@client/components/form/select.vue';
 import FormButton from '@client/components/form/button.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -49,9 +48,8 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.importAndExport,
-				icon: faBoxes
+				icon: 'fas fa-boxes'
 			},
-			faDownload, faUpload, faBoxes
 		}
 	},
 
diff --git a/src/client/pages/settings/index.vue b/src/client/pages/settings/index.vue
index eb7469c861d10cd9e6a935436b9d05fbaf162fdb..049e912898e31e1cd2418e6ff431566aefe81d3d 100644
--- a/src/client/pages/settings/index.vue
+++ b/src/client/pages/settings/index.vue
@@ -2,32 +2,40 @@
 <div class="vvcocwet" :class="{ wide: !narrow }" ref="el">
 	<div class="nav" v-if="!narrow || page == null">
 		<FormBase>
+			<FormGroup>
+				<div class="_formItem">
+					<div class="_formPanel lwjxoukj">
+						<MkAvatar :user="$i" class="avatar"/>
+					</div>
+				</div>
+				<FormLink :active="page === 'accounts'" replace to="/settings/accounts"><template #icon><i class="fas fa-users"></i></template>{{ $ts.accounts }}</FormLink>
+			</FormGroup>
 			<FormGroup>
 				<template #label>{{ $ts.basicSettings }}</template>
-				<FormLink :active="page === 'profile'" replace to="/settings/profile"><template #icon><Fa :icon="faUser"/></template>{{ $ts.profile }}</FormLink>
-				<FormLink :active="page === 'privacy'" replace to="/settings/privacy"><template #icon><Fa :icon="faLockOpen"/></template>{{ $ts.privacy }}</FormLink>
-				<FormLink :active="page === 'reaction'" replace to="/settings/reaction"><template #icon><Fa :icon="faLaugh"/></template>{{ $ts.reaction }}</FormLink>
-				<FormLink :active="page === 'drive'" replace to="/settings/drive"><template #icon><Fa :icon="faCloud"/></template>{{ $ts.drive }}</FormLink>
-				<FormLink :active="page === 'notifications'" replace to="/settings/notifications"><template #icon><Fa :icon="faBell"/></template>{{ $ts.notifications }}</FormLink>
-				<FormLink :active="page === 'email'" replace to="/settings/email"><template #icon><Fa :icon="faEnvelope"/></template>{{ $ts.email }}</FormLink>
-				<FormLink :active="page === 'integration'" replace to="/settings/integration"><template #icon><Fa :icon="faShareAlt"/></template>{{ $ts.integration }}</FormLink>
-				<FormLink :active="page === 'security'" replace to="/settings/security"><template #icon><Fa :icon="faLock"/></template>{{ $ts.security }}</FormLink>
+				<FormLink :active="page === 'profile'" replace to="/settings/profile"><template #icon><i class="fas fa-user"></i></template>{{ $ts.profile }}</FormLink>
+				<FormLink :active="page === 'privacy'" replace to="/settings/privacy"><template #icon><i class="fas fa-lock-open"></i></template>{{ $ts.privacy }}</FormLink>
+				<FormLink :active="page === 'reaction'" replace to="/settings/reaction"><template #icon><i class="fas fa-laugh"></i></template>{{ $ts.reaction }}</FormLink>
+				<FormLink :active="page === 'drive'" replace to="/settings/drive"><template #icon><i class="fas fa-cloud"></i></template>{{ $ts.drive }}</FormLink>
+				<FormLink :active="page === 'notifications'" replace to="/settings/notifications"><template #icon><i class="fas fa-bell"></i></template>{{ $ts.notifications }}</FormLink>
+				<FormLink :active="page === 'email'" replace to="/settings/email"><template #icon><i class="fas fa-envelope"></i></template>{{ $ts.email }}</FormLink>
+				<FormLink :active="page === 'integration'" replace to="/settings/integration"><template #icon><i class="fas fa-share-alt"></i></template>{{ $ts.integration }}</FormLink>
+				<FormLink :active="page === 'security'" replace to="/settings/security"><template #icon><i class="fas fa-lock"></i></template>{{ $ts.security }}</FormLink>
 			</FormGroup>
 			<FormGroup>
 				<template #label>{{ $ts.clientSettings }}</template>
-				<FormLink :active="page === 'general'" replace to="/settings/general"><template #icon><Fa :icon="faCogs"/></template>{{ $ts.general }}</FormLink>
-				<FormLink :active="page === 'theme'" replace to="/settings/theme"><template #icon><Fa :icon="faPalette"/></template>{{ $ts.theme }}</FormLink>
-				<FormLink :active="page === 'sidebar'" replace to="/settings/sidebar"><template #icon><Fa :icon="faListUl"/></template>{{ $ts.sidebar }}</FormLink>
-				<FormLink :active="page === 'sounds'" replace to="/settings/sounds"><template #icon><Fa :icon="faMusic"/></template>{{ $ts.sounds }}</FormLink>
-				<FormLink :active="page === 'plugin'" replace to="/settings/plugin"><template #icon><Fa :icon="faPlug"/></template>{{ $ts.plugins }}</FormLink>
+				<FormLink :active="page === 'general'" replace to="/settings/general"><template #icon><i class="fas fa-cogs"></i></template>{{ $ts.general }}</FormLink>
+				<FormLink :active="page === 'theme'" replace to="/settings/theme"><template #icon><i class="fas fa-palette"></i></template>{{ $ts.theme }}</FormLink>
+				<FormLink :active="page === 'sidebar'" replace to="/settings/sidebar"><template #icon><i class="fas fa-list-ul"></i></template>{{ $ts.sidebar }}</FormLink>
+				<FormLink :active="page === 'sounds'" replace to="/settings/sounds"><template #icon><i class="fas fa-music"></i></template>{{ $ts.sounds }}</FormLink>
+				<FormLink :active="page === 'plugin'" replace to="/settings/plugin"><template #icon><i class="fas fa-plug"></i></template>{{ $ts.plugins }}</FormLink>
 			</FormGroup>
 			<FormGroup>
 				<template #label>{{ $ts.otherSettings }}</template>
-				<FormLink :active="page === 'import-export'" replace to="/settings/import-export"><template #icon><Fa :icon="faBoxes"/></template>{{ $ts.importAndExport }}</FormLink>
-				<FormLink :active="page === 'mute-block'" replace to="/settings/mute-block"><template #icon><Fa :icon="faBan"/></template>{{ $ts.muteAndBlock }}</FormLink>
-				<FormLink :active="page === 'word-mute'" replace to="/settings/word-mute"><template #icon><Fa :icon="faCommentSlash"/></template>{{ $ts.wordMute }}</FormLink>
-				<FormLink :active="page === 'api'" replace to="/settings/api"><template #icon><Fa :icon="faKey"/></template>API</FormLink>
-				<FormLink :active="page === 'other'" replace to="/settings/other"><template #icon><Fa :icon="faEllipsisH"/></template>{{ $ts.other }}</FormLink>
+				<FormLink :active="page === 'import-export'" replace to="/settings/import-export"><template #icon><i class="fas fa-boxes"></i></template>{{ $ts.importAndExport }}</FormLink>
+				<FormLink :active="page === 'mute-block'" replace to="/settings/mute-block"><template #icon><i class="fas fa-ban"></i></template>{{ $ts.muteAndBlock }}</FormLink>
+				<FormLink :active="page === 'word-mute'" replace to="/settings/word-mute"><template #icon><i class="fas fa-comment-slash"></i></template>{{ $ts.wordMute }}</FormLink>
+				<FormLink :active="page === 'api'" replace to="/settings/api"><template #icon><i class="fas fa-key"></i></template>API</FormLink>
+				<FormLink :active="page === 'other'" replace to="/settings/other"><template #icon><i class="fas fa-ellipsis-h"></i></template>{{ $ts.other }}</FormLink>
 			</FormGroup>
 			<FormGroup>
 				<FormButton @click="clear">{{ $ts.clearCache }}</FormButton>
@@ -45,8 +53,6 @@
 
 <script lang="ts">
 import { computed, defineAsyncComponent, defineComponent, nextTick, onMounted, reactive, ref, watch } from 'vue';
-import { faCog, faPalette, faPlug, faUser, faListUl, faLock, faCommentSlash, faMusic, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faCloud } from '@fortawesome/free-solid-svg-icons';
-import { faLaugh, faBell, faEnvelope } from '@fortawesome/free-regular-svg-icons';
 import { i18n } from '@client/i18n';
 import FormLink from '@client/components/form/link.vue';
 import FormGroup from '@client/components/form/group.vue';
@@ -75,7 +81,7 @@ export default defineComponent({
 	setup(props, context) {
 		const indexInfo = {
 			title: i18n.locale.settings,
-			icon: faCog
+			icon: 'fas fa-cog'
 		};
 		const INFO = ref(indexInfo);
 		const page = ref(props.initialPage);
@@ -89,6 +95,7 @@ export default defineComponent({
 		const component = computed(() => {
 			if (page.value == null) return null;
 			switch (page.value) {
+				case 'accounts': return defineAsyncComponent(() => import('./accounts.vue'));
 				case 'profile': return defineAsyncComponent(() => import('./profile.vue'));
 				case 'privacy': return defineAsyncComponent(() => import('./privacy.vue'));
 				case 'reaction': return defineAsyncComponent(() => import('./reaction.vue'));
@@ -183,7 +190,6 @@ export default defineComponent({
 				localStorage.removeItem('theme');
 				unisonReload();
 			},
-			faPalette, faPlug, faUser, faListUl, faLock, faLaugh, faCommentSlash, faMusic, faBell, faCogs, faEllipsisH, faBan, faShareAlt, faLockOpen, faKey, faBoxes, faEnvelope, faCloud,
 		};
 	},
 });
@@ -212,4 +218,15 @@ export default defineComponent({
 		}
 	}
 }
+
+.lwjxoukj {
+	padding: 16px;
+
+	> .avatar {
+		display: block;
+		margin: auto;
+		width: 42px;
+		height: 42px;
+	}
+}
 </style>
diff --git a/src/client/pages/settings/integration.vue b/src/client/pages/settings/integration.vue
index 49f955bc350d5a7dfc16b354283f3c177e1f5cdd..2d2be04051689991cfa2eda1c729380de1ae3052 100644
--- a/src/client/pages/settings/integration.vue
+++ b/src/client/pages/settings/integration.vue
@@ -1,7 +1,7 @@
 <template>
 <FormBase>
 	<div class="_formItem" v-if="enableTwitterIntegration">
-		<div class="_formLabel"><Fa :icon="faTwitter"/> Twitter</div>
+		<div class="_formLabel"><i class="fab fa-twitter"></i> Twitter</div>
 		<div class="_formPanel" style="padding: 16px;">
 			<p v-if="integrations.twitter">{{ $ts.connectedTo }}: <a :href="`https://twitter.com/${integrations.twitter.screenName}`" rel="nofollow noopener" target="_blank">@{{ integrations.twitter.screenName }}</a></p>
 			<MkButton v-if="integrations.twitter" @click="disconnectTwitter" danger>{{ $ts.disconnectSerice }}</MkButton>
@@ -10,7 +10,7 @@
 	</div>
 
 	<div class="_formItem" v-if="enableDiscordIntegration">
-		<div class="_formLabel"><Fa :icon="faDiscord"/> Discord</div>
+		<div class="_formLabel"><i class="fab fa-discord"></i> Discord</div>
 		<div class="_formPanel" style="padding: 16px;">
 			<p v-if="integrations.discord">{{ $ts.connectedTo }}: <a :href="`https://discord.com/users/${integrations.discord.id}`" rel="nofollow noopener" target="_blank">@{{ integrations.discord.username }}#{{ integrations.discord.discriminator }}</a></p>
 			<MkButton v-if="integrations.discord" @click="disconnectDiscord" danger>{{ $ts.disconnectSerice }}</MkButton>
@@ -19,7 +19,7 @@
 	</div>
 
 	<div class="_formItem" v-if="enableGithubIntegration">
-		<div class="_formLabel"><Fa :icon="faGithub"/> GitHub</div>
+		<div class="_formLabel"><i class="fab fa-github"></i> GitHub</div>
 		<div class="_formPanel" style="padding: 16px;">
 			<p v-if="integrations.github">{{ $ts.connectedTo }}: <a :href="`https://github.com/${integrations.github.login}`" rel="nofollow noopener" target="_blank">@{{ integrations.github.login }}</a></p>
 			<MkButton v-if="integrations.github" @click="disconnectGithub" danger>{{ $ts.disconnectSerice }}</MkButton>
@@ -31,8 +31,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faShareAlt } from '@fortawesome/free-solid-svg-icons';
-import { faTwitter, faDiscord, faGithub } from '@fortawesome/free-brands-svg-icons';
 import { apiUrl } from '@client/config';
 import FormBase from '@client/components/form/base.vue';
 import MkButton from '@client/components/ui/button.vue';
@@ -51,7 +49,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.integration,
-				icon: faShareAlt
+				icon: 'fas fa-share-alt'
 			},
 			apiUrl,
 			twitterForm: null,
@@ -60,7 +58,6 @@ export default defineComponent({
 			enableTwitterIntegration: false,
 			enableDiscordIntegration: false,
 			enableGithubIntegration: false,
-			faShareAlt, faTwitter, faDiscord, faGithub
 		};
 	},
 
diff --git a/src/client/pages/settings/mute-block.vue b/src/client/pages/settings/mute-block.vue
index 11450e049b1e92ab5cb080baa03fe3faddffe347..dde0199e187bbd2f9d36a0eeac2a013af715b3a3 100644
--- a/src/client/pages/settings/mute-block.vue
+++ b/src/client/pages/settings/mute-block.vue
@@ -33,7 +33,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBan } from '@fortawesome/free-solid-svg-icons';
 import MkPagination from '@client/components/ui/pagination.vue';
 import MkTab from '@client/components/tab.vue';
 import FormInfo from '@client/components/form/info.vue';
@@ -60,7 +59,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.muteAndBlock,
-				icon: faBan
+				icon: 'fas fa-ban'
 			},
 			tab: 'mute',
 			mutingPagination: {
diff --git a/src/client/pages/settings/notifications.vue b/src/client/pages/settings/notifications.vue
index ea72bcfee8ba1ad96a05f64bd9cc391657920e44..ec95452ba21dbe3eacc628c0af5886b44a718943 100644
--- a/src/client/pages/settings/notifications.vue
+++ b/src/client/pages/settings/notifications.vue
@@ -11,8 +11,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCog } from '@fortawesome/free-solid-svg-icons';
-import { faBell } from '@fortawesome/free-regular-svg-icons';
 import FormButton from '@client/components/form/button.vue';
 import FormLink from '@client/components/form/link.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -35,9 +33,8 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.notifications,
-				icon: faBell
+				icon: 'fas fa-bell'
 			},
-			faCog
 		}
 	},
 
diff --git a/src/client/pages/settings/other.vue b/src/client/pages/settings/other.vue
index 2bd9c2476ce54361a4490b2ba417386732bd767d..f73ff9cb21d4b08e80bddcb079e0550d9317ce72 100644
--- a/src/client/pages/settings/other.vue
+++ b/src/client/pages/settings/other.vue
@@ -21,10 +21,10 @@
 		</template>
 	</FormGroup>
 
-	<FormLink to="/settings/registry"><template #icon><Fa :icon="faCogs"/></template>{{ $ts.registry }}</FormLink>
+	<FormLink to="/settings/registry"><template #icon><i class="fas fa-cogs"></i></template>{{ $ts.registry }}</FormLink>
 
-	<FormLink to="/bios" behavior="browser"><template #icon><Fa :icon="faDoorOpen"/></template>BIOS</FormLink>
-	<FormLink to="/cli" behavior="browser"><template #icon><Fa :icon="faDoorOpen"/></template>CLI</FormLink>
+	<FormLink to="/bios" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>BIOS</FormLink>
+	<FormLink to="/cli" behavior="browser"><template #icon><i class="fas fa-door-open"></i></template>CLI</FormLink>
 
 	<FormButton @click="closeAccount" danger>{{ $ts.closeAccount }}</FormButton>
 </FormBase>
@@ -32,7 +32,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faEllipsisH, faCogs, faDoorOpen } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -62,10 +61,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.other,
-				icon: faEllipsisH
+				icon: 'fas fa-ellipsis-h'
 			},
 			debug,
-			faCogs, faDoorOpen,
 		}
 	},
 
diff --git a/src/client/pages/settings/plugin.install.vue b/src/client/pages/settings/plugin.install.vue
index bc80188fc6271108a7ef9f289c50bd43a3e948f8..30cbf58ad792fdb6b5840b4239dcf466f5634f15 100644
--- a/src/client/pages/settings/plugin.install.vue
+++ b/src/client/pages/settings/plugin.install.vue
@@ -8,13 +8,12 @@
 		</FormTextarea>
 	</FormGroup>
 
-	<FormButton @click="install" :disabled="code == null" primary inline><Fa :icon="faCheck"/> {{ $ts.install }}</FormButton>
+	<FormButton @click="install" :disabled="code == null" primary inline><i class="fas fa-check"></i> {{ $ts.install }}</FormButton>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye } from '@fortawesome/free-solid-svg-icons';
 import { AiScript, parse } from '@syuilo/aiscript';
 import { serialize } from '@syuilo/aiscript/built/serializer';
 import { v4 as uuid } from 'uuid';
@@ -49,10 +48,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts._plugin.install,
-				icon: faDownload
+				icon: 'fas fa-download'
 			},
 			code: null,
-			faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye
 		}
 	},
 
diff --git a/src/client/pages/settings/plugin.manage.vue b/src/client/pages/settings/plugin.manage.vue
index d7aabe560ecc44a993b76cde6d68abf5b4678c4e..3df87ca084e5225acceef107c9dc9ab436b7ea81 100644
--- a/src/client/pages/settings/plugin.manage.vue
+++ b/src/client/pages/settings/plugin.manage.vue
@@ -22,8 +22,8 @@
 		</div>
 		<div class="_formItem">
 			<div class="_formPanel" style="padding: 16px;">
-				<MkButton @click="config(plugin)" inline v-if="plugin.config"><Fa :icon="faCog"/> {{ $ts.settings }}</MkButton>
-				<MkButton @click="uninstall(plugin)" inline danger><Fa :icon="faTrashAlt"/> {{ $ts.uninstall }}</MkButton>
+				<MkButton @click="config(plugin)" inline v-if="plugin.config"><i class="fas fa-cog"></i> {{ $ts.settings }}</MkButton>
+				<MkButton @click="uninstall(plugin)" inline danger><i class="fas fa-trash-alt"></i> {{ $ts.uninstall }}</MkButton>
 			</div>
 		</div>
 	</FormGroup>
@@ -32,7 +32,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkTextarea from '@client/components/ui/textarea.vue';
 import MkSelect from '@client/components/ui/select.vue';
@@ -59,10 +58,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts._plugin.manage,
-				icon: faPlug
+				icon: 'fas fa-plug'
 			},
 			plugins: ColdDeviceStorage.get('plugins'),
-			faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog
 		}
 	},
 
diff --git a/src/client/pages/settings/plugin.vue b/src/client/pages/settings/plugin.vue
index bee4e57ec334bed22f9d8969c374de90fd562c4d..13eaca07fd971403f8e3582838480b6e7a9ee537 100644
--- a/src/client/pages/settings/plugin.vue
+++ b/src/client/pages/settings/plugin.vue
@@ -1,13 +1,12 @@
 <template>
 <FormBase>
-	<FormLink to="/settings/plugin/install"><template #icon><Fa :icon="faDownload"/></template>{{ $ts._plugin.install }}</FormLink>
-	<FormLink to="/settings/plugin/manage"><template #icon><Fa :icon="faFolderOpen"/></template>{{ $ts._plugin.manage }}<template #suffix>{{ plugins }}</template></FormLink>
+	<FormLink to="/settings/plugin/install"><template #icon><i class="fas fa-download"></i></template>{{ $ts._plugin.install }}</FormLink>
+	<FormLink to="/settings/plugin/manage"><template #icon><i class="fas fa-folder-open"></i></template>{{ $ts._plugin.manage }}<template #suffix>{{ plugins }}</template></FormLink>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog } from '@fortawesome/free-solid-svg-icons';
 import FormBase from '@client/components/form/base.vue';
 import FormGroup from '@client/components/form/group.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -27,10 +26,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.plugins,
-				icon: faPlug
+				icon: 'fas fa-plug'
 			},
 			plugins: ColdDeviceStorage.get('plugins').length,
-			faPlug, faSave, faTrashAlt, faFolderOpen, faDownload, faCog
 		}
 	},
 
diff --git a/src/client/pages/settings/privacy.vue b/src/client/pages/settings/privacy.vue
index c8df37841072580da82ba9daf4e5959311893edf..4095e744c239b9ae9f7b8c59654e98269d785ef3 100644
--- a/src/client/pages/settings/privacy.vue
+++ b/src/client/pages/settings/privacy.vue
@@ -33,7 +33,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faLockOpen } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -56,7 +55,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.privacy,
-				icon: faLockOpen
+				icon: 'fas fa-lock-open'
 			},
 			isLocked: false,
 			autoAcceptFollowed: false,
diff --git a/src/client/pages/settings/profile.vue b/src/client/pages/settings/profile.vue
index 5ec580a206cd34aa8cf2bff1a943abf2bb5cce04..de7e86bd12457edac2199f81c44d8825ba6505f9 100644
--- a/src/client/pages/settings/profile.vue
+++ b/src/client/pages/settings/profile.vue
@@ -19,12 +19,12 @@
 
 	<FormInput v-model:value="location" manual-save>
 		<span>{{ $ts.location }}</span>
-		<template #prefix><Fa :icon="faMapMarkerAlt"/></template>
+		<template #prefix><i class="fas fa-map-marker-alt"></i></template>
 	</FormInput>
 
 	<FormInput v-model:value="birthday" type="date" manual-save>
 		<span>{{ $ts.birthday }}</span>
-		<template #prefix><Fa :icon="faBirthdayCake"/></template>
+		<template #prefix><i class="fas fa-birthday-cake"></i></template>
 	</FormInput>
 
 	<FormSelect v-model:value="lang">
@@ -47,8 +47,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faUnlockAlt, faCogs, faUser, faMapMarkerAlt, faBirthdayCake } from '@fortawesome/free-solid-svg-icons';
-import { faSave } from '@fortawesome/free-regular-svg-icons';
 import FormButton from '@client/components/form/button.vue';
 import FormInput from '@client/components/form/input.vue';
 import FormTextarea from '@client/components/form/textarea.vue';
@@ -78,7 +76,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.profile,
-				icon: faUser
+				icon: 'fas fa-user'
 			},
 			host,
 			langs,
@@ -101,7 +99,6 @@ export default defineComponent({
 			isCat: false,
 			alwaysMarkNsfw: false,
 			saving: false,
-			faSave, faUnlockAlt, faCogs, faUser, faMapMarkerAlt, faBirthdayCake
 		}
 	},
 
diff --git a/src/client/pages/settings/reaction.vue b/src/client/pages/settings/reaction.vue
index 0293f53fa84c36a9db499a8e8f36433233f62534..9bffd5f90301e6af76b036c3d5ac4640b81b4062 100644
--- a/src/client/pages/settings/reaction.vue
+++ b/src/client/pages/settings/reaction.vue
@@ -10,7 +10,7 @@
 					</button>
 				</template>
 				<template #footer>
-					<button class="_button add" @click="chooseEmoji"><Fa :icon="faPlus"/></button>
+					<button class="_button add" @click="chooseEmoji"><i class="fas fa-plus"></i></button>
 				</template>
 			</XDraggable>
 		</div>
@@ -29,15 +29,13 @@
 		<option :value="2">{{ $ts.medium }}</option>
 		<option :value="3">{{ $ts.large }}</option>
 	</FormRadios>
-	<FormButton @click="preview"><Fa :icon="faEye"/> {{ $ts.preview }}</FormButton>
-	<FormButton danger @click="setDefault"><Fa :icon="faUndo"/> {{ $ts.default }}</FormButton>
+	<FormButton @click="preview"><i class="fas fa-eye"></i> {{ $ts.preview }}</FormButton>
+	<FormButton danger @click="setDefault"><i class="fas fa-undo"></i> {{ $ts.default }}</FormButton>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faLaugh, faSave, faEye } from '@fortawesome/free-regular-svg-icons';
-import { faUndo, faPlus } from '@fortawesome/free-solid-svg-icons';
 import XDraggable from 'vuedraggable';
 import FormInput from '@client/components/form/input.vue';
 import FormRadios from '@client/components/form/radios.vue';
@@ -62,14 +60,13 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.reaction,
-				icon: faLaugh,
+				icon: 'fas fa-laugh',
 				action: {
-					icon: faEye,
+					icon: 'fas fa-eye',
 					handler: this.preview
 				}
 			},
 			reactions: JSON.parse(JSON.stringify(this.$store.state.reactions)),
-			faLaugh, faSave, faEye, faUndo, faPlus
 		}
 	},
 
diff --git a/src/client/pages/settings/registry.keys.vue b/src/client/pages/settings/registry.keys.vue
index 5cdfdc1332c45b3e732c62ff60fa76209b06fee5..f71589ba4f5b34fe6c6b3e6f14612b4cbf631a2e 100644
--- a/src/client/pages/settings/registry.keys.vue
+++ b/src/client/pages/settings/registry.keys.vue
@@ -22,7 +22,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faCogs } from '@fortawesome/free-solid-svg-icons';
 import * as JSON5 from 'json5';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
@@ -57,7 +56,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.registry,
-				icon: faCogs
+				icon: 'fas fa-cogs'
 			},
 			keys: null,
 		}
diff --git a/src/client/pages/settings/registry.value.vue b/src/client/pages/settings/registry.value.vue
index 7d5756af991375a8b5a1cec43e80bb186f761d04..48245ae99fb935ec2da89b255d3987d02a18adb0 100644
--- a/src/client/pages/settings/registry.value.vue
+++ b/src/client/pages/settings/registry.value.vue
@@ -22,7 +22,7 @@
 			<FormTextarea tall v-model:value="valueForEditor" class="_monospace" style="tab-size: 2;">
 				<span>{{ $ts.value }} (JSON)</span>
 			</FormTextarea>
-			<FormButton @click="save" primary><Fa :icon="faSave"/> {{ $ts.save }}</FormButton>
+			<FormButton @click="save" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
 		</FormGroup>
 
 		<FormKeyValueView>
@@ -30,14 +30,13 @@
 			<template #value><MkTime :time="value.updatedAt" mode="detail"/></template>
 		</FormKeyValueView>
 
-		<FormButton danger @click="del"><Fa :icon="faTrash"/> {{ $ts.delete }}</FormButton>
+		<FormButton danger @click="del"><i class="fas fa-trash"></i> {{ $ts.delete }}</FormButton>
 	</template>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faCogs, faSave, faTrash } from '@fortawesome/free-solid-svg-icons';
 import * as JSON5 from 'json5';
 import FormInfo from '@client/components/form/info.vue';
 import FormSwitch from '@client/components/form/switch.vue';
@@ -77,11 +76,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.registry,
-				icon: faCogs
+				icon: 'fas fa-cogs'
 			},
 			value: null,
 			valueForEditor: null,
-			faSave, faTrash,
 		}
 	},
 
diff --git a/src/client/pages/settings/registry.vue b/src/client/pages/settings/registry.vue
index 085389fc9527550d54cf005438bbf3d0f39ba25b..5ba1bc751b93102537bc42afceb15bdf32f2c6c6 100644
--- a/src/client/pages/settings/registry.vue
+++ b/src/client/pages/settings/registry.vue
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faCogs } from '@fortawesome/free-solid-svg-icons';
 import * as JSON5 from 'json5';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
@@ -39,7 +38,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.registry,
-				icon: faCogs
+				icon: 'fas fa-cogs'
 			},
 			scopes: null,
 		}
diff --git a/src/client/pages/settings/security.vue b/src/client/pages/settings/security.vue
index 64733c55a2fddc4643558b599637ea5f949c833f..b70fa5a9f30cc3a342dba1b112d7f434a6fb3e73 100644
--- a/src/client/pages/settings/security.vue
+++ b/src/client/pages/settings/security.vue
@@ -1,15 +1,15 @@
 <template>
 <FormBase>
 	<X2fa/>
-	<FormLink to="/settings/2fa"><template #icon><Fa :icon="faMobileAlt"/></template>{{ $ts.twoStepAuthentication }}</FormLink>
+	<FormLink to="/settings/2fa"><template #icon><i class="fas fa-mobile-alt"></i></template>{{ $ts.twoStepAuthentication }}</FormLink>
 	<FormButton primary @click="change()">{{ $ts.changePassword }}</FormButton>
 	<FormPagination :pagination="pagination">
 		<template #label>{{ $ts.signinHistory }}</template>
 		<template #default="{items}">
 			<div class="_formPanel timnmucd" v-for="item in items" :key="item.id">
 				<header>
-					<Fa class="icon succ" :icon="faCheck" v-if="item.success"/>
-					<Fa class="icon fail" :icon="faTimesCircle" v-else/>
+					<i v-if="item.success" class="fas fa-check icon succ"></i>
+					<i v-else class="fas fa-times-circle icon fail"></i>
 					<code class="ip _monospace">{{ item.ip }}</code>
 					<MkTime :time="item.createdAt" class="time"/>
 				</header>
@@ -17,7 +17,7 @@
 		</template>
 	</FormPagination>
 	<FormGroup>
-		<FormButton danger @click="regenerateToken"><Fa :icon="faSyncAlt"/> {{ $ts.regenerateLoginToken }}</FormButton>
+		<FormButton danger @click="regenerateToken"><i class="fas fa-sync-alt"></i> {{ $ts.regenerateLoginToken }}</FormButton>
 		<template #caption>{{ $ts.regenerateLoginTokenDescription }}</template>
 	</FormGroup>
 </FormBase>
@@ -25,7 +25,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCheck, faTimesCircle, faLock, faSyncAlt, faMobileAlt } from '@fortawesome/free-solid-svg-icons';
 import FormBase from '@client/components/form/base.vue';
 import FormLink from '@client/components/form/link.vue';
 import FormGroup from '@client/components/form/group.vue';
@@ -49,13 +48,12 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.security,
-				icon: faLock
+				icon: 'fas fa-lock'
 			},
 			pagination: {
 				endpoint: 'i/signin-history',
 				limit: 5,
 			},
-			faLock, faSyncAlt, faCheck, faTimesCircle, faMobileAlt,
 		}
 	},
 
diff --git a/src/client/pages/settings/sidebar.vue b/src/client/pages/settings/sidebar.vue
index adeec2f636dc5457e073ad3265e480b16616a9ba..f0172e945f0806bd622f4bc8e426c89a795a395d 100644
--- a/src/client/pages/settings/sidebar.vue
+++ b/src/client/pages/settings/sidebar.vue
@@ -12,14 +12,13 @@
 		<!-- <MkRadio v-model="sidebarDisplay" value="hide" disabled>{{ $ts._sidebar.hide }}</MkRadio>--> <!-- TODO: サイドバーを完全に隠せるようにすると、別途ハンバーガーボタンのようなものをUIに表示する必要があり面倒 -->
 	</FormRadios>
 
-	<FormButton @click="save()" primary><Fa :icon="faSave"/> {{ $ts.save }}</FormButton>
-	<FormButton @click="reset()" danger><Fa :icon="faRedo"/> {{ $ts.default }}</FormButton>
+	<FormButton @click="save()" primary><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
+	<FormButton @click="reset()" danger><i class="fas fa-redo"></i> {{ $ts.default }}</FormButton>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faListUl, faSave, faRedo } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormTextarea from '@client/components/form/textarea.vue';
 import FormRadios from '@client/components/form/radios.vue';
@@ -45,11 +44,10 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.sidebar,
-				icon: faListUl
+				icon: 'fas fa-list-ul'
 			},
 			menuDef: sidebarDef,
 			items: '',
-			faSave, faRedo
 		}
 	},
 
diff --git a/src/client/pages/settings/sounds.vue b/src/client/pages/settings/sounds.vue
index 54be0031156fe89a03439a3c919ed813b49503a5..f56ec4cd89def80aea129645373ed7b76b7da767 100644
--- a/src/client/pages/settings/sounds.vue
+++ b/src/client/pages/settings/sounds.vue
@@ -1,7 +1,7 @@
 <template>
 <FormBase>
 	<FormRange v-model:value="masterVolume" :min="0" :max="1" :step="0.05">
-		<template #label><Fa :icon="volumeIcon" :key="volumeIcon"/> {{ $ts.masterVolume }}</template>
+		<template #label><i class="fas fa-volume-icon"></i> {{ $ts.masterVolume }}</template>
 	</FormRange>
 
 	<FormGroup>
@@ -9,17 +9,16 @@
 		<FormButton v-for="type in Object.keys(sounds)" :key="type" :center="false" @click="edit(type)">
 			{{ $t('_sfx.' + type) }}
 			<template #suffix>{{ sounds[type].type || $ts.none }}</template>
-			<template #suffixIcon><Fa :icon="faChevronDown"/></template>
+			<template #suffixIcon><i class="fas fa-chevron-down"></i></template>
 		</FormButton>
 	</FormGroup>
 
-	<FormButton @click="reset()" danger><Fa :icon="faRedo"/> {{ $ts.default }}</FormButton>
+	<FormButton @click="reset()" danger><i class="fas fa-redo"></i> {{ $ts.default }}</FormButton>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faMusic, faPlay, faVolumeUp, faVolumeMute, faChevronDown, faRedo } from '@fortawesome/free-solid-svg-icons';
 import FormRange from '@client/components/form/range.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -71,10 +70,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.sounds,
-				icon: faMusic
+				icon: 'fas fa-music'
 			},
 			sounds: {},
-			faMusic, faPlay, faVolumeUp, faVolumeMute, faChevronDown, faRedo,
 		}
 	},
 
@@ -84,7 +82,7 @@ export default defineComponent({
 			set(value) { ColdDeviceStorage.set('sound_masterVolume', value); }
 		},
 		volumeIcon() {
-			return this.masterVolume === 0 ? faVolumeMute : faVolumeUp;
+			return this.masterVolume === 0 ? 'fas fa-volume-mute' : 'fas fa-volume-up';
 		}
 	},
 
diff --git a/src/client/pages/settings/theme.install.vue b/src/client/pages/settings/theme.install.vue
index 744d1aba4491cd9b7316d2d329e0dad9caa1d805..d719cc801fa05e95f8499df7b0d6d4032c4ec75b 100644
--- a/src/client/pages/settings/theme.install.vue
+++ b/src/client/pages/settings/theme.install.vue
@@ -4,16 +4,15 @@
 		<FormTextarea v-model:value="installThemeCode">
 			<span>{{ $ts._theme.code }}</span>
 		</FormTextarea>
-		<FormButton @click="() => preview(installThemeCode)" :disabled="installThemeCode == null" inline><Fa :icon="faEye"/> {{ $ts.preview }}</FormButton>
+		<FormButton @click="() => preview(installThemeCode)" :disabled="installThemeCode == null" inline><i class="fas fa-eye"></i> {{ $ts.preview }}</FormButton>
 	</FormGroup>
 
-	<FormButton @click="() => install(installThemeCode)" :disabled="installThemeCode == null" primary inline><Fa :icon="faCheck"/> {{ $ts.install }}</FormButton>
+	<FormButton @click="() => install(installThemeCode)" :disabled="installThemeCode == null" primary inline><i class="fas fa-check"></i> {{ $ts.install }}</FormButton>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye } from '@fortawesome/free-solid-svg-icons';
 import * as JSON5 from 'json5';
 import FormTextarea from '@client/components/form/textarea.vue';
 import FormSelect from '@client/components/form/select.vue';
@@ -45,10 +44,9 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts._theme.install,
-				icon: faDownload
+				icon: 'fas fa-download'
 			},
 			installThemeCode: null,
-			faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye
 		}
 	},
 
diff --git a/src/client/pages/settings/theme.manage.vue b/src/client/pages/settings/theme.manage.vue
index ea9d5949ffcb6ebf71aff23b7d5603eeb887e768..7cc7a0169a8771fe5bd6ef66d2990591d5c8447e 100644
--- a/src/client/pages/settings/theme.manage.vue
+++ b/src/client/pages/settings/theme.manage.vue
@@ -20,14 +20,13 @@
 			<span>{{ $ts._theme.code }}</span>
 			<template #desc><button @click="copyThemeCode()" class="_textButton">{{ $ts.copy }}</button></template>
 		</FormTextarea>
-		<FormButton @click="uninstall()" danger v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><Fa :icon="faTrashAlt"/> {{ $ts.uninstall }}</FormButton>
+		<FormButton @click="uninstall()" danger v-if="!builtinThemes.some(t => t.id == selectedTheme.id)"><i class="fas fa-trash-alt"></i> {{ $ts.uninstall }}</FormButton>
 	</template>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye } from '@fortawesome/free-solid-svg-icons';
 import * as JSON5 from 'json5';
 import FormTextarea from '@client/components/form/textarea.vue';
 import FormSelect from '@client/components/form/select.vue';
@@ -60,12 +59,11 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts._theme.manage,
-				icon: faFolderOpen
+				icon: 'fas fa-folder-open'
 			},
 			installedThemes: getThemes(),
 			builtinThemes,
 			selectedThemeId: null,
-			faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye
 		}
 	},
 
diff --git a/src/client/pages/settings/theme.vue b/src/client/pages/settings/theme.vue
index 606e10ab7ab6a69de0f8e9bbf7d7698a4eea75f7..1eb0d68be5d751639b14a760ae6a6ec9ff594962 100644
--- a/src/client/pages/settings/theme.vue
+++ b/src/client/pages/settings/theme.vue
@@ -71,22 +71,21 @@
 	<FormButton primary v-else @click="wallpaper = null">{{ $ts.removeWallpaper }}</FormButton>
 
 	<FormGroup>
-		<FormLink to="https://assets.msky.cafe/theme/list" external><template #icon><Fa :icon="faGlobe"/></template>{{ $ts._theme.explore }}</FormLink>
-		<FormLink to="/settings/theme/install"><template #icon><Fa :icon="faDownload"/></template>{{ $ts._theme.install }}</FormLink>
+		<FormLink to="https://assets.msky.cafe/theme/list" external><template #icon><i class="fas fa-globe"></i></template>{{ $ts._theme.explore }}</FormLink>
+		<FormLink to="/settings/theme/install"><template #icon><i class="fas fa-download"></i></template>{{ $ts._theme.install }}</FormLink>
 	</FormGroup>
 
 	<FormGroup>
-		<FormLink to="/theme-editor"><template #icon><Fa :icon="faPaintRoller"/></template>{{ $ts._theme.make }}</FormLink>
-		<!--<FormLink to="/advanced-theme-editor"><template #icon><Fa :icon="faPaintRoller"/></template>{{ $ts._theme.make }} ({{ $ts.advanced }})</FormLink>-->
+		<FormLink to="/theme-editor"><template #icon><i class="fas fa-paint-roller"></i></template>{{ $ts._theme.make }}</FormLink>
+		<!--<FormLink to="/advanced-theme-editor"><template #icon><i class="fas fa-paint-roller"></i></template>{{ $ts._theme.make }} ({{ $ts.advanced }})</FormLink>-->
 	</FormGroup>
 
-	<FormLink to="/settings/theme/manage"><template #icon><Fa :icon="faFolderOpen"/></template>{{ $ts._theme.manage }}<template #suffix>{{ themesCount }}</template></FormLink>
+	<FormLink to="/settings/theme/manage"><template #icon><i class="fas fa-folder-open"></i></template>{{ $ts._theme.manage }}<template #suffix>{{ themesCount }}</template></FormLink>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { computed, defineComponent, onActivated, onMounted, ref, watch } from 'vue';
-import { faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye, faGlobe, faPaintRoller } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormBase from '@client/components/form/base.vue';
@@ -117,7 +116,7 @@ export default defineComponent({
 	setup(props, { emit }) {
 		const INFO = {
 			title: i18n.locale.theme,
-			icon: faPalette
+			icon: 'fas fa-palette'
 		};
 
 		const installedThemes = ref(getThemes());
@@ -191,7 +190,6 @@ export default defineComponent({
 					wallpaper.value = file.url;
 				});
 			},
-			faPalette, faDownload, faFolderOpen, faCheck, faTrashAlt, faEye, faGlobe, faPaintRoller,
 		};
 	}
 });
diff --git a/src/client/pages/settings/update.vue b/src/client/pages/settings/update.vue
index d7b2adae56440958d8723a14c9d99fdd01a951d4..8000327d0cbbf64cd304ef5d6160ad8c05649514 100644
--- a/src/client/pages/settings/update.vue
+++ b/src/client/pages/settings/update.vue
@@ -30,7 +30,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faInfoCircle, faSyncAlt } from '@fortawesome/free-solid-svg-icons';
 import FormSwitch from '@client/components/form/switch.vue';
 import FormSelect from '@client/components/form/select.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -61,7 +60,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: 'Misskey Update',
-				icon: faSyncAlt
+				icon: 'fas fa-sync-alt'
 			},
 			version,
 			instanceName,
diff --git a/src/client/pages/settings/word-mute.vue b/src/client/pages/settings/word-mute.vue
index 79de2ebbdf885b984d27b3ebde1ab75a28f835e9..fe3fece844cc0149056d6220fc0ece41fe31809f 100644
--- a/src/client/pages/settings/word-mute.vue
+++ b/src/client/pages/settings/word-mute.vue
@@ -25,14 +25,13 @@
 				</FormKeyValueView>
 			</div>
 		</div>
-		<FormButton @click="save()" primary inline :disabled="!changed"><Fa :icon="faSave"/> {{ $ts.save }}</FormButton>
+		<FormButton @click="save()" primary inline :disabled="!changed"><i class="fas fa-save"></i> {{ $ts.save }}</FormButton>
 	</FormBase>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCommentSlash, faSave } from '@fortawesome/free-solid-svg-icons';
 import FormTextarea from '@client/components/form/textarea.vue';
 import FormBase from '@client/components/form/base.vue';
 import FormKeyValueView from '@client/components/form/key-value-view.vue';
@@ -59,14 +58,13 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.wordMute,
-				icon: faCommentSlash
+				icon: 'fas fa-comment-slash'
 			},
 			tab: 'soft',
 			softMutedWords: '',
 			hardMutedWords: '',
 			hardWordMutedNotesCount: null,
 			changed: false,
-			faSave,
 		}
 	},
 
diff --git a/src/client/pages/share.vue b/src/client/pages/share.vue
index 313b73b9cb984628c00c22b373941b92707cbf76..67e598fa8f7edc70df6b964882e2e9ecc6914e86 100644
--- a/src/client/pages/share.vue
+++ b/src/client/pages/share.vue
@@ -13,7 +13,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faShareAlt } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import XPostForm from '@client/components/post-form.vue';
 import * as os from '@client/os';
@@ -29,7 +28,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.share,
-				icon: faShareAlt
+				icon: 'fas fa-share-alt'
 			},
 			title: null,
 			text: null,
@@ -37,7 +36,6 @@ export default defineComponent({
 			initialText: null,
 			posted: false,
 
-			faShareAlt
 		}
 	},
 
diff --git a/src/client/pages/tag.vue b/src/client/pages/tag.vue
index 813181dd1f70fa601a3ec5ffdeb05e5c6a84623b..3ca9fe5c0c2299a94cce1a8dd42c39f49e7baeb8 100644
--- a/src/client/pages/tag.vue
+++ b/src/client/pages/tag.vue
@@ -6,7 +6,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faHashtag } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XNotes from '@client/components/notes.vue';
 import * as symbols from '@client/symbols';
@@ -27,7 +26,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.tag,
-				icon: faHashtag
+				icon: 'fas fa-hashtag'
 			},
 			pagination: {
 				endpoint: 'notes/search-by-tag',
@@ -36,7 +35,6 @@ export default defineComponent({
 					tag: this.tag,
 				})
 			},
-			faHashtag
 		};
 	},
 
diff --git a/src/client/pages/test.vue b/src/client/pages/test.vue
index 252fa1c828fa6a85cf91415f053c49f967855bcb..9a06d31090c2e4b495cebc4cbce50d2160f2032a 100644
--- a/src/client/pages/test.vue
+++ b/src/client/pages/test.vue
@@ -132,7 +132,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import MkSwitch from '@client/components/ui/switch.vue';
@@ -154,7 +153,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: 'TEST',
-				icon: faExclamationTriangle
+				icon: 'fas fa-exclamation-triangle'
 			},
 			dialogTitle: 'Hello',
 			dialogBody: 'World!',
diff --git a/src/client/pages/theme-editor.vue b/src/client/pages/theme-editor.vue
index db273746a8ebf24b53c7122e5c105b8633e4a04c..ce8bae4ff538ac8b524fb65724a754ac80c38cea 100644
--- a/src/client/pages/theme-editor.vue
+++ b/src/client/pages/theme-editor.vue
@@ -42,7 +42,7 @@
 		</FormTextarea>
 		<FormButton @click="applyThemeCode" primary>{{ $ts.apply }}</FormButton>
 	</FormGroup>
-	<FormButton v-else @click="codeEnabled = true"><Fa :icon="faCode"/> {{ $ts.editCode }}</FormButton>
+	<FormButton v-else @click="codeEnabled = true"><i class="fas fa-code"></i> {{ $ts.editCode }}</FormButton>
 
 	<FormGroup v-if="descriptionEnabled">
 		<FormTextarea v-model:value="description">
@@ -52,15 +52,14 @@
 	<FormButton v-else @click="descriptionEnabled = true">{{ $ts.addDescription }}</FormButton>
 
 	<FormGroup>
-		<FormButton @click="showPreview"><Fa :icon="faEye"/> {{ $ts.preview }}</FormButton>
-		<FormButton @click="saveAs" primary><Fa :icon="faSave"/> {{ $ts.saveAs }}</FormButton>
+		<FormButton @click="showPreview"><i class="fas fa-eye"></i> {{ $ts.preview }}</FormButton>
+		<FormButton @click="saveAs" primary><i class="fas fa-save"></i> {{ $ts.saveAs }}</FormButton>
 	</FormGroup>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPalette, faSave, faEye, faCode } from '@fortawesome/free-solid-svg-icons';
 import { toUnicode } from 'punycode/';
 import * as tinycolor from 'tinycolor2';
 import { v4 as uuid} from 'uuid';
@@ -90,7 +89,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.themeEditor,
-				icon: faPalette,
+				icon: 'fas fa-palette',
 			},
 			theme: {
 				base: 'light',
@@ -129,7 +128,6 @@ export default defineComponent({
 				{ color: 'pink', forLight: '#84667d', forDark: '#e4d1e0', forPreview: '#b12390' },
 			],
 			changed: false,
-			faPalette, faSave, faEye, faCode,
 		}
 	},
 
diff --git a/src/client/pages/timeline.tutorial.vue b/src/client/pages/timeline.tutorial.vue
index bcbf16acc76b5466c39c1da05bb7f450fdb97e8d..620994c0da403121ca47c13cec7022a0dd373609 100644
--- a/src/client/pages/timeline.tutorial.vue
+++ b/src/client/pages/timeline.tutorial.vue
@@ -1,6 +1,6 @@
 <template>
 <div class="_card tbkwesmv">
-	<div class="_title"><Fa :icon="faInfoCircle"/> {{ $ts._tutorial.title }}</div>
+	<div class="_title"><i class="fas fa-info-circle"></i> {{ $ts._tutorial.title }}</div>
 	<div class="_content" v-if="tutorial === 0">
 		<div>{{ $ts._tutorial.step1_1 }}</div>
 		<div>{{ $ts._tutorial.step1_2 }}</div>
@@ -52,22 +52,21 @@
 	<div class="_footer navigation">
 		<div class="step">
 			<button class="arrow _button" @click="tutorial--" :disabled="tutorial === 0">
-				<Fa :icon="faChevronLeft"/>
+				<i class="fas fa-chevron-left"></i>
 			</button>
 			<span>{{ tutorial + 1 }} / 7</span>
 			<button class="arrow _button" @click="tutorial++" :disabled="tutorial === 6">
-				<Fa :icon="faChevronRight"/>
+				<i class="fas fa-chevron-right"></i>
 			</button>
 		</div>
-		<MkButton class="ok" @click="tutorial = -1" primary v-if="tutorial === 6"><Fa :icon="faCheck"/> {{ $ts.gotIt }}</MkButton>
-		<MkButton class="ok" @click="tutorial++" primary v-else><Fa :icon="faCheck"/> {{ $ts.next }}</MkButton>
+		<MkButton class="ok" @click="tutorial = -1" primary v-if="tutorial === 6"><i class="fas fa-check"></i> {{ $ts.gotIt }}</MkButton>
+		<MkButton class="ok" @click="tutorial++" primary v-else><i class="fas fa-check"></i> {{ $ts.next }}</MkButton>
 	</div>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faInfoCircle, faChevronLeft, faChevronRight, faCheck } from '@fortawesome/free-solid-svg-icons'
 import MkButton from '@client/components/ui/button.vue';
 
 export default defineComponent({
@@ -77,7 +76,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faInfoCircle, faChevronLeft, faChevronRight, faCheck
 		}
 	},
 
diff --git a/src/client/pages/timeline.vue b/src/client/pages/timeline.vue
index efad31c252d11aa258674bc6a92c566de4d0adae..5660d0099e8aaa0c602e2659f2d8cadf120f7a5a 100644
--- a/src/client/pages/timeline.vue
+++ b/src/client/pages/timeline.vue
@@ -4,18 +4,18 @@
 	<XPostForm v-if="$store.reactiveState.showFixedPostForm.value" class="post-form _block" fixed/>
 	<div class="tabs _block">
 		<div class="left">
-			<button class="_button tab" @click="() => { src = 'home'; saveSrc(); }" :class="{ active: src === 'home' }" v-tooltip="$ts._timelines.home"><Fa :icon="faHome"/></button>
-			<button class="_button tab" @click="() => { src = 'local'; saveSrc(); }" :class="{ active: src === 'local' }" v-tooltip="$ts._timelines.local" v-if="isLocalTimelineAvailable"><Fa :icon="faComments"/></button>
-			<button class="_button tab" @click="() => { src = 'social'; saveSrc(); }" :class="{ active: src === 'social' }" v-tooltip="$ts._timelines.social" v-if="isLocalTimelineAvailable"><Fa :icon="faShareAlt"/></button>
-			<button class="_button tab" @click="() => { src = 'global'; saveSrc(); }" :class="{ active: src === 'global' }" v-tooltip="$ts._timelines.global" v-if="isGlobalTimelineAvailable"><Fa :icon="faGlobe"/></button>
+			<button class="_button tab" @click="() => { src = 'home'; saveSrc(); }" :class="{ active: src === 'home' }" v-tooltip="$ts._timelines.home"><i class="fas fa-home"></i></button>
+			<button class="_button tab" @click="() => { src = 'local'; saveSrc(); }" :class="{ active: src === 'local' }" v-tooltip="$ts._timelines.local" v-if="isLocalTimelineAvailable"><i class="fas fa-comments"></i></button>
+			<button class="_button tab" @click="() => { src = 'social'; saveSrc(); }" :class="{ active: src === 'social' }" v-tooltip="$ts._timelines.social" v-if="isLocalTimelineAvailable"><i class="fas fa-share-alt"></i></button>
+			<button class="_button tab" @click="() => { src = 'global'; saveSrc(); }" :class="{ active: src === 'global' }" v-tooltip="$ts._timelines.global" v-if="isGlobalTimelineAvailable"><i class="fas fa-globe"></i></button>
 			<span class="divider"></span>
-			<button class="_button tab" @click="() => { src = 'mentions'; saveSrc(); }" :class="{ active: src === 'mentions' }" v-tooltip="$ts.mentions"><Fa :icon="faAt"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadMentions"/></button>
-			<button class="_button tab" @click="() => { src = 'directs'; saveSrc(); }" :class="{ active: src === 'directs' }" v-tooltip="$ts.directNotes"><Fa :icon="faEnvelope"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadSpecifiedNotes"/></button>
+			<button class="_button tab" @click="() => { src = 'mentions'; saveSrc(); }" :class="{ active: src === 'mentions' }" v-tooltip="$ts.mentions"><i class="fas fa-at"></i><i v-if="$i.hasUnreadMentions" class="fas fa-circle i"></i></button>
+			<button class="_button tab" @click="() => { src = 'directs'; saveSrc(); }" :class="{ active: src === 'directs' }" v-tooltip="$ts.directNotes"><i class="fas fa-envelope"></i><i v-if="$i.hasUnreadSpecifiedNotes" class="fas fa-circle i"></i></button>
 		</div>
 		<div class="right">
-			<button class="_button tab" @click="chooseChannel" :class="{ active: src === 'channel' }" v-tooltip="$ts.channel"><Fa :icon="faSatelliteDish"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadChannel"/></button>
-			<button class="_button tab" @click="chooseAntenna" :class="{ active: src === 'antenna' }" v-tooltip="$ts.antennas"><Fa :icon="faSatellite"/><Fa :icon="faCircle" class="i" v-if="$i.hasUnreadAntenna"/></button>
-			<button class="_button tab" @click="chooseList" :class="{ active: src === 'list' }" v-tooltip="$ts.lists"><Fa :icon="faListUl"/></button>
+			<button class="_button tab" @click="chooseChannel" :class="{ active: src === 'channel' }" v-tooltip="$ts.channel"><i class="fas fa-satellite-dish"></i><i v-if="$i.hasUnreadChannel" class="fas fa-circle i"></i></button>
+			<button class="_button tab" @click="chooseAntenna" :class="{ active: src === 'antenna' }" v-tooltip="$ts.antennas"><i class="fas fa-satellite"></i><i v-if="$i.hasUnreadAntenna" class="fas fa-circle i"></i></button>
+			<button class="_button tab" @click="chooseList" :class="{ active: src === 'list' }" v-tooltip="$ts.lists"><i class="fas fa-list-ul"></i></button>
 		</div>
 	</div>
 	<XTimeline ref="tl"
@@ -36,8 +36,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent, computed } from 'vue';
-import { faAngleDown, faAngleUp, faHome, faShareAlt, faGlobe, faListUl, faSatellite, faSatelliteDish, faCircle, faEllipsisH, faPencilAlt, faAt } from '@fortawesome/free-solid-svg-icons';
-import { faComments, faEnvelope, faCalendarAlt } from '@fortawesome/free-regular-svg-icons';
 import Progress from '@client/scripts/loading';
 import XTimeline from '@client/components/timeline.vue';
 import XPostForm from '@client/components/post-form.vue';
@@ -64,14 +62,13 @@ export default defineComponent({
 			queue: 0,
 			[symbols.PAGE_INFO]: computed(() => ({
 				title: this.$ts.timeline,
-				icon: this.src === 'local' ? faComments : this.src === 'social' ? faShareAlt : this.src === 'global' ? faGlobe : faHome,
+				icon: this.src === 'local' ? 'fas fa-comments' : this.src === 'social' ? 'fas fa-share-alt' : this.src === 'global' ? 'fas fa-globe' : 'fas fa-home',
 				actions: [{
-					icon: faCalendarAlt,
+					icon: 'fas fa-calendar-alt',
 					text: this.$ts.jumpToSpecifiedDate,
 					handler: this.timetravel
 				}]
 			})),
-			faAngleDown, faAngleUp, faHome, faShareAlt, faGlobe, faComments, faListUl, faSatellite, faSatelliteDish, faCircle, faEllipsisH, faAt, faEnvelope,
 		};
 	},
 
diff --git a/src/client/pages/user-ap-info.vue b/src/client/pages/user-ap-info.vue
index 648ecdb10ac79287f88e8982211d32d007bef89d..c08a3525711233b626cb8c1b948626470c7d3648 100644
--- a/src/client/pages/user-ap-info.vue
+++ b/src/client/pages/user-ap-info.vue
@@ -58,7 +58,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent } from 'vue';
-import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
 import FormObjectView from '@client/components/form/object-view.vue';
 import FormTextarea from '@client/components/form/textarea.vue';
 import FormLink from '@client/components/form/link.vue';
@@ -96,7 +95,7 @@ export default defineComponent({
 		return {
 			[symbols.PAGE_INFO]: {
 				title: this.$ts.userInfo,
-				icon: faInfoCircle
+				icon: 'fas fa-info-circle'
 			},
 			user: null,
 			apPromiseFactory: null,
diff --git a/src/client/pages/user-info.vue b/src/client/pages/user-info.vue
index 06f2e4270dce98b4c50ecee8270d180619dc3fe6..51bd5016bbe4e3f58df6bd6b4fdd91d3bf29397b 100644
--- a/src/client/pages/user-info.vue
+++ b/src/client/pages/user-info.vue
@@ -1,12 +1,34 @@
 <template>
 <FormBase>
-	<FormGroup v-if="user">
-		<template #label><MkAcct :user="user"/></template>
+	<FormSuspense :p="init">
+		<div class="_formItem aeakzknw">
+			<MkAvatar class="avatar" :user="user" :show-indicator="true"/>
+		</div>
 
-		<FormKeyValueView>
-			<template #key>ID</template>
-			<template #value><span class="_monospace">{{ user.id }}</span></template>
-		</FormKeyValueView>
+		<FormLink :to="userPage(user)">Profile</FormLink>
+
+		<FormGroup>
+			<FormKeyValueView>
+				<template #key>Acct</template>
+				<template #value><span class="_monospace">{{ acct(user) }}</span></template>
+			</FormKeyValueView>
+
+			<FormKeyValueView>
+				<template #key>ID</template>
+				<template #value><span class="_monospace">{{ user.id }}</span></template>
+			</FormKeyValueView>
+		</FormGroup>
+
+		<FormGroup v-if="iAmModerator">
+			<FormSwitch v-if="user.host == null && $i.isAdmin && (moderator || !user.isAdmin)" @update:value="toggleModerator" v-model:value="moderator">{{ $ts.moderator }}</FormSwitch>
+			<FormSwitch @update:value="toggleSilence" v-model:value="silenced">{{ $ts.silence }}</FormSwitch>
+			<FormSwitch @update:value="toggleSuspend" v-model:value="suspended">{{ $ts.suspend }}</FormSwitch>
+		</FormGroup>
+
+		<FormGroup>
+			<FormButton v-if="user.host != null" @click="updateRemoteUser"><i class="fas fa-sync"></i> {{ $ts.updateRemoteUser }}</FormButton>
+			<FormButton v-if="user.host == null && iAmModerator" @click="resetPassword"><i class="fas fa-key"></i> {{ $ts.resetPassword }}</FormButton>
+		</FormGroup>
 
 		<FormGroup>
 			<FormLink :to="`/user-ap-info/${user.id}`">ActivityPub</FormLink>
@@ -28,15 +50,15 @@
 		<FormObjectView tall :value="user">
 			<span>Raw</span>
 		</FormObjectView>
-	</FormGroup>
+	</FormSuspense>
 </FormBase>
 </template>
 
 <script lang="ts">
 import { computed, defineAsyncComponent, defineComponent } from 'vue';
-import { faExternalLinkAlt, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
 import FormObjectView from '@client/components/form/object-view.vue';
 import FormTextarea from '@client/components/form/textarea.vue';
+import FormSwitch from '@client/components/form/switch.vue';
 import FormLink from '@client/components/form/link.vue';
 import FormBase from '@client/components/form/base.vue';
 import FormGroup from '@client/components/form/group.vue';
@@ -48,11 +70,13 @@ import number from '@client/filters/number';
 import bytes from '@client/filters/bytes';
 import * as symbols from '@client/symbols';
 import { url } from '@client/config';
+import { userPage, acct } from '@client/filters/user';
 
 export default defineComponent({
 	components: {
 		FormBase,
 		FormTextarea,
+		FormSwitch,
 		FormObjectView,
 		FormButton,
 		FormLink,
@@ -71,33 +95,151 @@ export default defineComponent({
 	data() {
 		return {
 			[symbols.PAGE_INFO]: computed(() => ({
-				title: this.$ts.userInfo,
-				icon: faInfoCircle,
+				title: this.user ? acct(this.user) : this.$ts.userInfo,
+				icon: 'fas fa-info-circle',
 				actions: this.user ? [this.user.url ? {
 					text: this.user.url,
-					icon: faExternalLinkAlt,
+					icon: 'fas fa-external-link-alt',
 					handler: () => {
 						window.open(this.user.url, '_blank');
 					}
 				} : undefined].filter(x => x !== undefined) : [],
 			})),
+			init: null,
 			user: null,
+			info: null,
+			moderator: false,
+			silenced: false,
+			suspended: false,
+		}
+	},
+
+	computed: {
+		iAmModerator(): boolean {
+			return this.$i && (this.$i.isAdmin || this.$i.isModerator);
 		}
 	},
 
-	mounted() {
-		this.fetch();
+	watch: {
+		userId: {
+			handler() {
+				this.init = this.createFetcher();
+			},
+			immediate: true
+		}
 	},
 
 	methods: {
 		number,
 		bytes,
+		userPage,
+		acct,
+
+		createFetcher() {
+			if (this.iAmModerator) {
+				return () => Promise.all([os.api('users/show', {
+					userId: this.userId
+				}), os.api('admin/show-user', {
+					userId: this.userId
+				})]).then(([user, info]) => {
+					this.user = user;
+					this.info = info;
+					this.moderator = this.info.isModerator;
+					this.silenced = this.info.isSilenced;
+					this.suspended = this.info.isSuspended;
+				});
+			} else {
+				return () => os.api('users/show', {
+					userId: this.userId
+				}).then((user) => {
+					this.user = user;
+				});
+			}
+		},
+
+		refreshUser() {
+			this.init = this.createFetcher();
+		},
 
-		async fetch() {
-			this.user = await os.api('users/show', {
-				userId: this.userId
+		async updateRemoteUser() {
+			await os.apiWithDialog('federation/update-remote-user', { userId: this.user.id });
+			this.refreshUser();
+		},
+
+		async resetPassword() {
+			os.apiWithDialog('admin/reset-password', {
+				userId: this.user.id,
+			}, undefined, ({ password }) => {
+				os.dialog({
+					type: 'success',
+					text: this.$t('newPasswordIs', { password })
+				});
 			});
-		}
+		},
+
+		async toggleSilence(v) {
+			const confirm = await os.dialog({
+				type: 'warning',
+				showCancelButton: true,
+				text: v ? this.$ts.silenceConfirm : this.$ts.unsilenceConfirm,
+			});
+			if (confirm.canceled) {
+				this.silenced = !v;
+			} else {
+				await os.api(v ? 'admin/silence-user' : 'admin/unsilence-user', { userId: this.user.id });
+				await this.refreshUser();
+			}
+		},
+
+		async toggleSuspend(v) {
+			const confirm = await os.dialog({
+				type: 'warning',
+				showCancelButton: true,
+				text: v ? this.$ts.suspendConfirm : this.$ts.unsuspendConfirm,
+			});
+			if (confirm.canceled) {
+				this.suspended = !v;
+			} else {
+				await os.api(v ? 'admin/suspend-user' : 'admin/unsuspend-user', { userId: this.user.id });
+				await this.refreshUser();
+			}
+		},
+
+		async toggleModerator(v) {
+			await os.api(v ? 'admin/moderators/add' : 'admin/moderators/remove', { userId: this.user.id });
+			await this.refreshUser();
+		},
+
+		async deleteAllFiles() {
+			const confirm = await os.dialog({
+				type: 'warning',
+				showCancelButton: true,
+				text: this.$ts.deleteAllFilesConfirm,
+			});
+			if (confirm.canceled) return;
+			const process = async () => {
+				await os.api('admin/delete-all-files-of-a-user', { userId: this.user.id });
+				os.success();
+			};
+			await process().catch(e => {
+				os.dialog({
+					type: 'error',
+					text: e.toString()
+				});
+			});
+			await this.refreshUser();
+		},
 	}
 });
 </script>
+
+<style lang="scss" scoped>
+.aeakzknw {
+	> .avatar {
+		display: block;
+		margin: 0 auto;
+		width: 64px;
+		height: 64px;
+	}
+}
+</style>
diff --git a/src/client/pages/user/index.activity.vue b/src/client/pages/user/index.activity.vue
index 3eca1ab210aa767a215f1a1667b505a3d0d78b71..9101c8ae5f7a8128a16a1bc92b5380cd9c9208e9 100644
--- a/src/client/pages/user/index.activity.vue
+++ b/src/client/pages/user/index.activity.vue
@@ -1,6 +1,6 @@
 <template>
 <MkContainer>
-	<template #header><Fa :icon="faChartBar" style="margin-right: 0.5em;"/>{{ $ts.activity }}</template>
+	<template #header><i class="fas fa-chart-bar" style="margin-right: 0.5em;"></i>{{ $ts.activity }}</template>
 
 	<div style="padding: 8px;">
 		<div ref="chart"></div>
@@ -11,7 +11,6 @@
 <script lang="ts">
 import { defineComponent } from 'vue';
 import ApexCharts from 'apexcharts';
-import { faChartBar } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 import MkContainer from '@client/components/ui/container.vue';
 
@@ -35,7 +34,6 @@ export default defineComponent({
 			fetching: true,
 			data: [],
 			peak: null,
-			faChartBar,
 		};
 	},
 	mounted() {
diff --git a/src/client/pages/user/index.photos.vue b/src/client/pages/user/index.photos.vue
index 21d84cef4f8cebf2620b0bf7dbb694b815198b35..a899b116e5259280da0df36cbc441cb18616342b 100644
--- a/src/client/pages/user/index.photos.vue
+++ b/src/client/pages/user/index.photos.vue
@@ -1,6 +1,6 @@
 <template>
 <MkContainer :max-height="300" :foldable="true">
-	<template #header><Fa :icon="faImage" style="margin-right: 0.5em;"/>{{ $ts.images }}</template>
+	<template #header><i class="fas fa-image" style="margin-right: 0.5em;"></i>{{ $ts.images }}</template>
 	<div class="ujigsodd">
 		<MkLoading v-if="fetching"/>
 		<div class="stream" v-if="!fetching && images.length > 0">
@@ -19,7 +19,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faImage } from '@fortawesome/free-solid-svg-icons';
 import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
 import notePage from '../../filters/note';
 import * as os from '@client/os';
@@ -41,7 +40,6 @@ export default defineComponent({
 		return {
 			fetching: true,
 			images: [],
-			faImage
 		};
 	},
 	mounted() {
diff --git a/src/client/pages/user/index.vue b/src/client/pages/user/index.vue
index 92656fff2cdabfc511fd2f7d7dc77fb5b4c4c02a..207b44f631bb49e7003159abefb6e45a5c518f0d 100644
--- a/src/client/pages/user/index.vue
+++ b/src/client/pages/user/index.vue
@@ -34,15 +34,15 @@
 				</div>
 				<div class="fields system">
 					<dl class="field" v-if="user.location">
-						<dt class="name"><Fa :icon="faMapMarker" fixed-width/> {{ $ts.location }}</dt>
+						<dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ $ts.location }}</dt>
 						<dd class="value">{{ user.location }}</dd>
 					</dl>
 					<dl class="field" v-if="user.birthday">
-						<dt class="name"><Fa :icon="faBirthdayCake" fixed-width/> {{ $ts.birthday }}</dt>
+						<dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ $ts.birthday }}</dt>
 						<dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ $t('yearsOld', { age }) }})</dd>
 					</dl>
 					<dl class="field">
-						<dt class="name"><Fa :icon="faCalendarAlt" fixed-width/> {{ $ts.registeredDate }}</dt>
+						<dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ $ts.registeredDate }}</dt>
 						<dd class="value">{{ new Date(user.createdAt).toLocaleString() }} (<MkTime :time="user.createdAt"/>)</dd>
 					</dl>
 				</div>
@@ -62,19 +62,19 @@
 			<div class="main">
 				<div class="nav _gap">
 					<MkA :to="userPage(user)" :class="{ active: page === 'index' }" class="link">
-						<Fa :icon="faCommentAlt" class="icon"/>
+						<i class="fas fa-comment-alt icon"></i>
 						<span>{{ $ts.notes }}</span>
 					</MkA>
 					<MkA :to="userPage(user, 'clips')" :class="{ active: page === 'clips' }" class="link">
-						<Fa :icon="faPaperclip" class="icon"/>
+						<i class="fas fa-paperclip icon"></i>
 						<span>{{ $ts.clips }}</span>
 					</MkA>
 					<MkA :to="userPage(user, 'pages')" :class="{ active: page === 'pages' }" class="link">
-						<Fa :icon="faFileAlt" class="icon"/>
+						<i class="fas fa-file-alt icon"></i>
 						<span>{{ $ts.pages }}</span>
 					</MkA>
 					<div class="actions">
-						<button @click="menu" class="menu _button"><Fa :icon="faEllipsisH"/></button>
+						<button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
 						<MkFollowButton v-if="!$i || $i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" large class="koudoku"/>
 					</div>
 				</div>
@@ -95,8 +95,8 @@
 	</div>
 	<div class="ftskorzw narrow _root" v-else-if="user && narrow === true" v-size="{ max: [500] }">
 		<!-- TODO -->
-		<!-- <div class="punished" v-if="user.isSuspended"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/> {{ $ts.userSuspended }}</div> -->
-		<!-- <div class="punished" v-if="user.isSilenced"><Fa :icon="faExclamationTriangle" style="margin-right: 8px;"/> {{ $ts.userSilenced }}</div> -->
+		<!-- <div class="punished" v-if="user.isSuspended"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSuspended }}</div> -->
+		<!-- <div class="punished" v-if="user.isSilenced"><i class="fas fa-exclamation-triangle" style="margin-right: 8px;"></i> {{ $ts.userSilenced }}</div> -->
 
 		<div class="profile">
 			<MkRemoteCaution v-if="user.host != null" :href="user.url" class="warn"/>
@@ -109,15 +109,15 @@
 						<MkUserName class="name" :user="user" :nowrap="true"/>
 						<div class="bottom">
 							<span class="username"><MkAcct :user="user" :detail="true" /></span>
-							<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><Fa :icon="faBookmark"/></span>
-							<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><Fa :icon="farBookmark"/></span>
-							<span v-if="user.isLocked" :title="$ts.isLocked"><Fa :icon="faLock"/></span>
-							<span v-if="user.isBot" :title="$ts.isBot"><Fa :icon="faRobot"/></span>
+							<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
+							<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
+							<span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
+							<span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
 						</div>
 					</div>
 					<span class="followed" v-if="$i && $i.id != user.id && user.isFollowed">{{ $ts.followsYou }}</span>
 					<div class="actions" v-if="$i">
-						<button @click="menu" class="menu _button"><Fa :icon="faEllipsisH"/></button>
+						<button @click="menu" class="menu _button"><i class="fas fa-ellipsis-h"></i></button>
 						<MkFollowButton v-if="$i.id != user.id" :user="user" :inline="true" :transparent="false" :full="true" class="koudoku"/>
 					</div>
 				</div>
@@ -126,10 +126,10 @@
 					<MkUserName :user="user" :nowrap="false" class="name"/>
 					<div class="bottom">
 						<span class="username"><MkAcct :user="user" :detail="true" /></span>
-						<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><Fa :icon="faBookmark"/></span>
-						<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><Fa :icon="farBookmark"/></span>
-						<span v-if="user.isLocked" :title="$ts.isLocked"><Fa :icon="faLock"/></span>
-						<span v-if="user.isBot" :title="$ts.isBot"><Fa :icon="faRobot"/></span>
+						<span v-if="user.isAdmin" :title="$ts.isAdmin" style="color: var(--badge);"><i class="fas fa-bookmark"></i></span>
+						<span v-if="!user.isAdmin && user.isModerator" :title="$ts.isModerator" style="color: var(--badge);"><i class="far fa-bookmark"></i></span>
+						<span v-if="user.isLocked" :title="$ts.isLocked"><i class="fas fa-lock"></i></span>
+						<span v-if="user.isBot" :title="$ts.isBot"><i class="fas fa-robot"></i></span>
 					</div>
 				</div>
 				<div class="description">
@@ -138,15 +138,15 @@
 				</div>
 				<div class="fields system">
 					<dl class="field" v-if="user.location">
-						<dt class="name"><Fa :icon="faMapMarker" fixed-width/> {{ $ts.location }}</dt>
+						<dt class="name"><i class="fas fa-map-marker fa-fw"></i> {{ $ts.location }}</dt>
 						<dd class="value">{{ user.location }}</dd>
 					</dl>
 					<dl class="field" v-if="user.birthday">
-						<dt class="name"><Fa :icon="faBirthdayCake" fixed-width/> {{ $ts.birthday }}</dt>
+						<dt class="name"><i class="fas fa-birthday-cake fa-fw"></i> {{ $ts.birthday }}</dt>
 						<dd class="value">{{ user.birthday.replace('-', '/').replace('-', '/') }} ({{ $t('yearsOld', { age }) }})</dd>
 					</dl>
 					<dl class="field">
-						<dt class="name"><Fa :icon="faCalendarAlt" fixed-width/> {{ $ts.registeredDate }}</dt>
+						<dt class="name"><i class="fas fa-calendar-alt fa-fw"></i> {{ $ts.registeredDate }}</dt>
 						<dd class="value">{{ new Date(user.createdAt).toLocaleString() }} (<MkTime :time="user.createdAt"/>)</dd>
 					</dl>
 				</div>
@@ -180,22 +180,22 @@
 		<div class="contents">
 			<div class="nav _gap">
 				<MkA :to="userPage(user)" :class="{ active: page === 'index' }" class="link">
-					<Fa :icon="faCommentAlt" class="icon"/>
+					<i class="fas fa-comment-alt icon"></i>
 					<span>{{ $ts.notes }}</span>
 				</MkA>
 				<MkA :to="userPage(user, 'clips')" :class="{ active: page === 'clips' }" class="link">
-					<Fa :icon="faPaperclip" class="icon"/>
+					<i class="fas fa-paperclip icon"></i>
 					<span>{{ $ts.clips }}</span>
 				</MkA>
 				<MkA :to="userPage(user, 'pages')" :class="{ active: page === 'pages' }" class="link">
-					<Fa :icon="faFileAlt" class="icon"/>
+					<i class="fas fa-file-alt icon"></i>
 					<span>{{ $ts.pages }}</span>
 				</MkA>
 			</div>
 
 			<template v-if="page === 'index'">
 				<div>
-					<div v-if="user.pinnedNotes.length > 0">
+					<div v-if="user.pinnedNotes.length > 0" class="_gap">
 						<XNote v-for="note in user.pinnedNotes" class="note _block" :note="note" @update:note="pinnedNoteUpdated(note, $event)" :key="note.id" :pinned="true"/>
 					</div>
 					<MkInfo v-else-if="$i && $i.id === user.id">{{ $ts.userPagePinTip }}</MkInfo>
@@ -219,8 +219,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent, computed } from 'vue';
-import { faExclamationTriangle, faEllipsisH, faRobot, faLock, faBookmark, faChartBar, faImage, faBirthdayCake, faMapMarker, faPaperclip, faFileAlt } from '@fortawesome/free-solid-svg-icons';
-import { faCalendarAlt, faBookmark as farBookmark, faCommentAlt } from '@fortawesome/free-regular-svg-icons';
 import * as age from 's-age';
 import XUserTimeline from './index.timeline.vue';
 import XNote from '@client/components/note.vue';
@@ -284,7 +282,6 @@ export default defineComponent({
 			error: null,
 			parallaxAnimationId: null,
 			narrow: null,
-			faExclamationTriangle, faEllipsisH, faRobot, faLock, faBookmark, farBookmark, faChartBar, faImage, faBirthdayCake, faMapMarker, faCalendarAlt, faCommentAlt, faPaperclip, faFileAlt,
 		};
 	},
 
diff --git a/src/client/pages/v.vue b/src/client/pages/v.vue
index 37a850b6252e7261ecd58183693841d13dadf274..4440e8070e6ec392eb3009834d88f0e5ee5a3a1c 100644
--- a/src/client/pages/v.vue
+++ b/src/client/pages/v.vue
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faInfoCircle } from '@fortawesome/free-solid-svg-icons';
 import { version } from '@client/config';
 import * as symbols from '@client/symbols';
 
@@ -24,7 +23,6 @@ export default defineComponent({
 				icon: null
 			},
 			version,
-			faInfoCircle
 		}
 	},
 });
diff --git a/src/client/pages/welcome.entrance.a.vue b/src/client/pages/welcome.entrance.a.vue
index 7b02c4492368893d569421c9a972616b38915a26..da3c69426575ae64dc6ec8700b69145fcc5513ce 100644
--- a/src/client/pages/welcome.entrance.a.vue
+++ b/src/client/pages/welcome.entrance.a.vue
@@ -43,7 +43,7 @@
 						<template #n><b>{{ onlineUsersCount }}</b></template>
 					</I18n>
 				</div>
-				<button class="_button _acrylic menu" @click="showMenu"><Fa :icon="faEllipsisH"/></button>
+				<button class="_button _acrylic menu" @click="showMenu"><i class="fas fa-ellipsis-h"></i></button>
 			</div>
 		</div>
 	</div>
@@ -52,7 +52,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faEllipsisH, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
 import { toUnicode } from 'punycode/';
 import XSigninDialog from '@client/components/signin-dialog.vue';
 import XSignupDialog from '@client/components/signup-dialog.vue';
@@ -80,7 +79,6 @@ export default defineComponent({
 			stats: null,
 			tags: [],
 			onlineUsersCount: null,
-			faEllipsisH
 		};
 	},
 
@@ -121,19 +119,19 @@ export default defineComponent({
 		showMenu(ev) {
 			os.modalMenu([{
 				text: this.$t('aboutX', { x: instanceName }),
-				icon: faInfoCircle,
+				icon: 'fas fa-info-circle',
 				action: () => {
 					os.pageWindow('/about');
 				}
 			}, {
 				text: this.$ts.aboutMisskey,
-				icon: faInfoCircle,
+				icon: 'fas fa-info-circle',
 				action: () => {
 					os.pageWindow('/about-misskey');
 				}
 			}, null, {
 				text: this.$ts.help,
-				icon: faQuestionCircle,
+				icon: 'fas fa-question-circle',
 				action: () => {
 					os.pageWindow('/docs');
 				}
diff --git a/src/client/pages/welcome.entrance.b.vue b/src/client/pages/welcome.entrance.b.vue
index d8622e4d8e652083c12bef050c029799f04d7c1c..d108eb7d94e033b44c69b83fdd413b374b0ec12d 100644
--- a/src/client/pages/welcome.entrance.b.vue
+++ b/src/client/pages/welcome.entrance.b.vue
@@ -36,7 +36,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faEllipsisH, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
 import { toUnicode } from 'punycode/';
 import XSigninDialog from '@client/components/signin-dialog.vue';
 import XSignupDialog from '@client/components/signup-dialog.vue';
@@ -64,7 +63,6 @@ export default defineComponent({
 			stats: null,
 			tags: [],
 			onlineUsersCount: null,
-			faEllipsisH
 		};
 	},
 
@@ -105,19 +103,19 @@ export default defineComponent({
 		showMenu(ev) {
 			os.modalMenu([{
 				text: this.$t('aboutX', { x: instanceName }),
-				icon: faInfoCircle,
+				icon: 'fas fa-info-circle',
 				action: () => {
 					os.pageWindow('/about');
 				}
 			}, {
 				text: this.$ts.aboutMisskey,
-				icon: faInfoCircle,
+				icon: 'fas fa-info-circle',
 				action: () => {
 					os.pageWindow('/about-misskey');
 				}
 			}, null, {
 				text: this.$ts.help,
-				icon: faQuestionCircle,
+				icon: 'fas fa-question-circle',
 				action: () => {
 					os.pageWindow('/docs');
 				}
diff --git a/src/client/pages/welcome.entrance.c.vue b/src/client/pages/welcome.entrance.c.vue
index 47ddf9e5ed5e0d4a497bd88b41ba6d8f4805df50..93811e98fb5dbc04961940b16368b1c838377c27 100644
--- a/src/client/pages/welcome.entrance.c.vue
+++ b/src/client/pages/welcome.entrance.c.vue
@@ -40,7 +40,7 @@
 							<template #n><b>{{ onlineUsersCount }}</b></template>
 						</I18n>
 					</div>
-					<button class="_button _acrylic menu" @click="showMenu"><Fa :icon="faEllipsisH"/></button>
+					<button class="_button _acrylic menu" @click="showMenu"><i class="fas fa-ellipsis-h"></i></button>
 				</div>
 			</div>
 			<nav class="nav">
@@ -56,7 +56,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faEllipsisH, faInfoCircle, faQuestionCircle } from '@fortawesome/free-solid-svg-icons';
 import { toUnicode } from 'punycode/';
 import XSigninDialog from '@client/components/signin-dialog.vue';
 import XSignupDialog from '@client/components/signup-dialog.vue';
@@ -84,7 +83,6 @@ export default defineComponent({
 			stats: null,
 			tags: [],
 			onlineUsersCount: null,
-			faEllipsisH
 		};
 	},
 
@@ -125,19 +123,19 @@ export default defineComponent({
 		showMenu(ev) {
 			os.modalMenu([{
 				text: this.$t('aboutX', { x: instanceName }),
-				icon: faInfoCircle,
+				icon: 'fas fa-info-circle',
 				action: () => {
 					os.pageWindow('/about');
 				}
 			}, {
 				text: this.$ts.aboutMisskey,
-				icon: faInfoCircle,
+				icon: 'fas fa-info-circle',
 				action: () => {
 					os.pageWindow('/about-misskey');
 				}
 			}, null, {
 				text: this.$ts.help,
-				icon: faQuestionCircle,
+				icon: 'fas fa-question-circle',
 				action: () => {
 					os.pageWindow('/docs');
 				}
diff --git a/src/client/pages/welcome.setup.vue b/src/client/pages/welcome.setup.vue
index db64f6b1944e14c78fd0e224fbae11f70cfca81e..2a71e2311ca0e6dc59ba5c594a477cff3023aa86 100644
--- a/src/client/pages/welcome.setup.vue
+++ b/src/client/pages/welcome.setup.vue
@@ -10,7 +10,7 @@
 		</MkInput>
 		<MkInput v-model:value="password" type="password">
 			<span>{{ $ts.password }}</span>
-			<template #prefix><Fa :icon="faLock"/></template>
+			<template #prefix><i class="fas fa-lock"></i></template>
 		</MkInput>
 		<footer>
 			<MkButton primary type="submit" :disabled="submitting">{{ submitting ? $ts.processing : $ts.done }}<MkEllipsis v-if="submitting"/></MkButton>
@@ -21,7 +21,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faLock } from '@fortawesome/free-solid-svg-icons';
 import MkButton from '@client/components/ui/button.vue';
 import MkInput from '@client/components/ui/input.vue';
 import { host } from '@client/config';
@@ -40,7 +39,6 @@ export default defineComponent({
 			password: '',
 			submitting: false,
 			host,
-			faLock
 		}
 	},
 
diff --git a/src/client/router.ts b/src/client/router.ts
index bf45c806e21fd2a632a4c35365c96223f6208aed..26a4dac4994807b1ddf83dce8ffa436a052e927a 100644
--- a/src/client/router.ts
+++ b/src/client/router.ts
@@ -59,17 +59,8 @@ export const router = createRouter({
 		{ path: '/my/antennas', component: page('my-antennas/index') },
 		{ path: '/my/clips', component: page('my-clips/index') },
 		{ path: '/scratchpad', component: page('scratchpad') },
+		{ path: '/instance/:page(.*)?', component: page('instance/index'), props: route => ({ initialPage: route.params.page || null }) },
 		{ path: '/instance', component: page('instance/index') },
-		{ path: '/instance/emojis', component: page('instance/emojis') },
-		{ path: '/instance/users', component: page('instance/users') },
-		{ path: '/instance/logs', component: page('instance/logs') },
-		{ path: '/instance/files', component: page('instance/files') },
-		{ path: '/instance/queue', component: page('instance/queue') },
-		{ path: '/instance/settings', component: page('instance/settings') },
-		{ path: '/instance/federation', component: page('instance/federation') },
-		{ path: '/instance/relays', component: page('instance/relays') },
-		{ path: '/instance/announcements', component: page('instance/announcements') },
-		{ path: '/instance/abuses', component: page('instance/abuses') },
 		{ path: '/notes/:note', name: 'note', component: page('note'), props: route => ({ noteId: route.params.note }) },
 		{ path: '/tags/:tag', component: page('tag'), props: route => ({ tag: route.params.tag }) },
 		{ path: '/user-info/:user', component: page('user-info'), props: route => ({ userId: route.params.user }) },
diff --git a/src/client/scripts/get-user-menu.ts b/src/client/scripts/get-user-menu.ts
index 0496e8750263c7643211f77b35b0eea13f05b83b..ceb2bfe1730342403f1a86d359b19696223eca67 100644
--- a/src/client/scripts/get-user-menu.ts
+++ b/src/client/scripts/get-user-menu.ts
@@ -1,5 +1,3 @@
-import { faAt, faListUl, faEye, faEyeSlash, faBan, faPencilAlt, faComments, faUsers, faMicrophoneSlash, faPlug, faExclamationCircle, faInfoCircle } from '@fortawesome/free-solid-svg-icons';
-import { faSnowflake, faEnvelope } from '@fortawesome/free-regular-svg-icons';
 import { i18n } from '@client/i18n';
 import copyToClipboard from '@client/scripts/copy-to-clipboard';
 import { host } from '@client/config';
@@ -121,62 +119,62 @@ export function getUserMenu(user) {
 	}
 
 	let menu = [{
-		icon: faAt,
+		icon: 'fas fa-at',
 		text: i18n.locale.copyUsername,
 		action: () => {
 			copyToClipboard(`@${user.username}@${user.host || host}`);
 		}
 	}, {
-		icon: faInfoCircle,
+		icon: 'fas fa-info-circle',
 		text: i18n.locale.info,
 		action: () => {
 			os.pageWindow(`/user-info/${user.id}`);
 		}
 	}, {
-		icon: faEnvelope,
+		icon: 'fas fa-envelope',
 		text: i18n.locale.sendMessage,
 		action: () => {
 			os.post({ specified: user });
 		}
 	}, meId != user.id ? {
 		type: 'link',
-		icon: faComments,
+		icon: 'fas fa-comments',
 		text: i18n.locale.startMessaging,
 		to: '/my/messaging/' + getAcct(user),
 	} : undefined, null, {
-		icon: faListUl,
+		icon: 'fas fa-list-ul',
 		text: i18n.locale.addToList,
 		action: pushList
 	}, meId != user.id ? {
-		icon: faUsers,
+		icon: 'fas fa-users',
 		text: i18n.locale.inviteToGroup,
 		action: inviteGroup
 	} : undefined] as any;
 
 	if ($i && meId != user.id) {
 		menu = menu.concat([null, {
-			icon: user.isMuted ? faEye : faEyeSlash,
+			icon: user.isMuted ? 'fas fa-eye' : 'fas fa-eye-slash',
 			text: user.isMuted ? i18n.locale.unmute : i18n.locale.mute,
 			action: toggleMute
 		}, {
-			icon: faBan,
+			icon: 'fas fa-ban',
 			text: user.isBlocking ? i18n.locale.unblock : i18n.locale.block,
 			action: toggleBlock
 		}]);
 
 		menu = menu.concat([null, {
-			icon: faExclamationCircle,
+			icon: 'fas fa-exclamation-circle',
 			text: i18n.locale.reportAbuse,
 			action: reportAbuse
 		}]);
 
 		if ($i && ($i.isAdmin || $i.isModerator)) {
 			menu = menu.concat([null, {
-				icon: faMicrophoneSlash,
+				icon: 'fas fa-microphone-slash',
 				text: user.isSilenced ? i18n.locale.unsilence : i18n.locale.silence,
 				action: toggleSilence
 			}, {
-				icon: faSnowflake,
+				icon: 'fas fa-snowflake',
 				text: user.isSuspended ? i18n.locale.unsuspend : i18n.locale.suspend,
 				action: toggleSuspend
 			}]);
@@ -185,7 +183,7 @@ export function getUserMenu(user) {
 
 	if ($i && meId === user.id) {
 		menu = menu.concat([null, {
-			icon: faPencilAlt,
+			icon: 'fas fa-pencil-alt',
 			text: i18n.locale.editProfile,
 			action: () => {
 				router.push('/settings/profile');
@@ -195,7 +193,7 @@ export function getUserMenu(user) {
 
 	if (userActions.length > 0) {
 		menu = menu.concat([null, ...userActions.map(action => ({
-			icon: faPlug,
+			icon: 'fas fa-plug',
 			text: action.title,
 			action: () => {
 				action.handler(user);
diff --git a/src/client/scripts/hpml/index.ts b/src/client/scripts/hpml/index.ts
index 924cd32eb59d766a30afe229ed380a635105e513..ac81eac2d987e1579ac6b9d2b1cbd140ffc452ed 100644
--- a/src/client/scripts/hpml/index.ts
+++ b/src/client/scripts/hpml/index.ts
@@ -3,14 +3,6 @@
  */
 
 import autobind from 'autobind-decorator';
-import {
-	faMagic,
-	faSquareRootAlt,
-	faAlignLeft,
-	faList,
-	faQuoteRight,
-	faSortNumericUp,
-} from '@fortawesome/free-solid-svg-icons';
 import { Hpml } from './evaluator';
 import { funcDefs } from './lib';
 
@@ -22,13 +14,13 @@ export type Fn = {
 export type Type = 'string' | 'number' | 'boolean' | 'stringArray' | null;
 
 export const literalDefs: Record<string, { out: any; category: string; icon: any; }> = {
-	text:          { out: 'string',      category: 'value', icon: faQuoteRight, },
-	multiLineText: { out: 'string',      category: 'value', icon: faAlignLeft, },
-	textList:      { out: 'stringArray', category: 'value', icon: faList, },
-	number:        { out: 'number',      category: 'value', icon: faSortNumericUp, },
-	ref:           { out: null,          category: 'value', icon: faMagic, },
-	aiScriptVar:   { out: null,          category: 'value', icon: faMagic, },
-	fn:            { out: 'function',    category: 'value', icon: faSquareRootAlt, },
+	text:          { out: 'string',      category: 'value', icon: 'fas fa-quote-right', },
+	multiLineText: { out: 'string',      category: 'value', icon: 'fas fa-align-left', },
+	textList:      { out: 'stringArray', category: 'value', icon: 'fas fa-list', },
+	number:        { out: 'number',      category: 'value', icon: 'fas fa-sort-numeric-up', },
+	ref:           { out: null,          category: 'value', icon: 'fas fa-magic', },
+	aiScriptVar:   { out: null,          category: 'value', icon: 'fas fa-magic', },
+	fn:            { out: 'function',    category: 'value', icon: 'fas fa-square-root-alt', },
 };
 
 export const blockDefs = [
diff --git a/src/client/scripts/hpml/lib.ts b/src/client/scripts/hpml/lib.ts
index 745456218410753d425f5730e5cd7454159a6916..150a04732f6d497fb4c86210366a2f976da7a633 100644
--- a/src/client/scripts/hpml/lib.ts
+++ b/src/client/scripts/hpml/lib.ts
@@ -6,27 +6,6 @@ import { Fn, HpmlScope } from '.';
 import { Expr } from './expr';
 import * as seedrandom from 'seedrandom';
 
-import {
-	faShareAlt,
-	faPlus,
-	faMinus,
-	faTimes,
-	faDivide,
-	faQuoteRight,
-	faEquals,
-	faGreaterThan,
-	faLessThan,
-	faGreaterThanEqual,
-	faLessThanEqual,
-	faNotEqual,
-	faDice,
-	faExchangeAlt,
-	faRecycle,
-	faIndent,
-	faCalculator,
-} from '@fortawesome/free-solid-svg-icons';
-import { faFlag } from '@fortawesome/free-regular-svg-icons';
-
 // https://stackoverflow.com/questions/38493564/chart-area-background-color-chartjs
 Chart.pluginService.register({
 	beforeDraw: (chart, easing) => {
@@ -148,43 +127,43 @@ export function initAiLib(hpml: Hpml) {
 }
 
 export const funcDefs: Record<string, { in: any[]; out: any; category: string; icon: any; }> = {
-	if:              { in: ['boolean', 0, 0],              out: 0,             category: 'flow',       icon: faShareAlt, },
-	for:             { in: ['number', 'function'],         out: null,          category: 'flow',       icon: faRecycle, },
-	not:             { in: ['boolean'],                    out: 'boolean',     category: 'logical',    icon: faFlag, },
-	or:              { in: ['boolean', 'boolean'],         out: 'boolean',     category: 'logical',    icon: faFlag, },
-	and:             { in: ['boolean', 'boolean'],         out: 'boolean',     category: 'logical',    icon: faFlag, },
-	add:             { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: faPlus, },
-	subtract:        { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: faMinus, },
-	multiply:        { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: faTimes, },
-	divide:          { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: faDivide, },
-	mod:             { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: faDivide, },
-	round:           { in: ['number'],                     out: 'number',      category: 'operation',  icon: faCalculator, },
-	eq:              { in: [0, 0],                         out: 'boolean',     category: 'comparison', icon: faEquals, },
-	notEq:           { in: [0, 0],                         out: 'boolean',     category: 'comparison', icon: faNotEqual, },
-	gt:              { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: faGreaterThan, },
-	lt:              { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: faLessThan, },
-	gtEq:            { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: faGreaterThanEqual, },
-	ltEq:            { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: faLessThanEqual, },
-	strLen:          { in: ['string'],                     out: 'number',      category: 'text',       icon: faQuoteRight, },
-	strPick:         { in: ['string', 'number'],           out: 'string',      category: 'text',       icon: faQuoteRight, },
-	strReplace:      { in: ['string', 'string', 'string'], out: 'string',      category: 'text',       icon: faQuoteRight, },
-	strReverse:      { in: ['string'],                     out: 'string',      category: 'text',       icon: faQuoteRight, },
-	join:            { in: ['stringArray', 'string'],      out: 'string',      category: 'text',       icon: faQuoteRight, },
-	stringToNumber:  { in: ['string'],                     out: 'number',      category: 'convert',    icon: faExchangeAlt, },
-	numberToString:  { in: ['number'],                     out: 'string',      category: 'convert',    icon: faExchangeAlt, },
-	splitStrByLine:  { in: ['string'],                     out: 'stringArray', category: 'convert',    icon: faExchangeAlt, },
-	pick:            { in: [null, 'number'],               out: null,          category: 'list',       icon: faIndent, },
-	listLen:         { in: [null],                         out: 'number',      category: 'list',       icon: faIndent, },
-	rannum:          { in: ['number', 'number'],           out: 'number',      category: 'random',     icon: faDice, },
-	dailyRannum:     { in: ['number', 'number'],           out: 'number',      category: 'random',     icon: faDice, },
-	seedRannum:      { in: [null, 'number', 'number'],     out: 'number',      category: 'random',     icon: faDice, },
-	random:          { in: ['number'],                     out: 'boolean',     category: 'random',     icon: faDice, },
-	dailyRandom:     { in: ['number'],                     out: 'boolean',     category: 'random',     icon: faDice, },
-	seedRandom:      { in: [null, 'number'],               out: 'boolean',     category: 'random',     icon: faDice, },
-	randomPick:      { in: [0],                            out: 0,             category: 'random',     icon: faDice, },
-	dailyRandomPick: { in: [0],                            out: 0,             category: 'random',     icon: faDice, },
-	seedRandomPick:  { in: [null, 0],                      out: 0,             category: 'random',     icon: faDice, },
-	DRPWPM:      { in: ['stringArray'],                out: 'string',      category: 'random',     icon: faDice, }, // dailyRandomPickWithProbabilityMapping
+	if:              { in: ['boolean', 0, 0],              out: 0,             category: 'flow',       icon: 'fas fa-share-alt', },
+	for:             { in: ['number', 'function'],         out: null,          category: 'flow',       icon: 'fas fa-recycle', },
+	not:             { in: ['boolean'],                    out: 'boolean',     category: 'logical',    icon: 'fas fa-flag', },
+	or:              { in: ['boolean', 'boolean'],         out: 'boolean',     category: 'logical',    icon: 'fas fa-flag', },
+	and:             { in: ['boolean', 'boolean'],         out: 'boolean',     category: 'logical',    icon: 'fas fa-flag', },
+	add:             { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: 'fas fa-plus', },
+	subtract:        { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: 'fas fa-minus', },
+	multiply:        { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: 'fas fa-times', },
+	divide:          { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: 'fas fa-divide', },
+	mod:             { in: ['number', 'number'],           out: 'number',      category: 'operation',  icon: 'fas fa-divide', },
+	round:           { in: ['number'],                     out: 'number',      category: 'operation',  icon: 'fas fa-calculator', },
+	eq:              { in: [0, 0],                         out: 'boolean',     category: 'comparison', icon: 'fas fa-equals', },
+	notEq:           { in: [0, 0],                         out: 'boolean',     category: 'comparison', icon: 'fas fa-not-equal', },
+	gt:              { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: 'fas fa-greater-than', },
+	lt:              { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: 'fas fa-less-than', },
+	gtEq:            { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: 'fas fa-greater-than-equal', },
+	ltEq:            { in: ['number', 'number'],           out: 'boolean',     category: 'comparison', icon: 'fas fa-less-than-equal', },
+	strLen:          { in: ['string'],                     out: 'number',      category: 'text',       icon: 'fas fa-quote-right', },
+	strPick:         { in: ['string', 'number'],           out: 'string',      category: 'text',       icon: 'fas fa-quote-right', },
+	strReplace:      { in: ['string', 'string', 'string'], out: 'string',      category: 'text',       icon: 'fas fa-quote-right', },
+	strReverse:      { in: ['string'],                     out: 'string',      category: 'text',       icon: 'fas fa-quote-right', },
+	join:            { in: ['stringArray', 'string'],      out: 'string',      category: 'text',       icon: 'fas fa-quote-right', },
+	stringToNumber:  { in: ['string'],                     out: 'number',      category: 'convert',    icon: 'fas fa-exchange-alt', },
+	numberToString:  { in: ['number'],                     out: 'string',      category: 'convert',    icon: 'fas fa-exchange-alt', },
+	splitStrByLine:  { in: ['string'],                     out: 'stringArray', category: 'convert',    icon: 'fas fa-exchange-alt', },
+	pick:            { in: [null, 'number'],               out: null,          category: 'list',       icon: 'fas fa-indent', },
+	listLen:         { in: [null],                         out: 'number',      category: 'list',       icon: 'fas fa-indent', },
+	rannum:          { in: ['number', 'number'],           out: 'number',      category: 'random',     icon: 'fas fa-dice', },
+	dailyRannum:     { in: ['number', 'number'],           out: 'number',      category: 'random',     icon: 'fas fa-dice', },
+	seedRannum:      { in: [null, 'number', 'number'],     out: 'number',      category: 'random',     icon: 'fas fa-dice', },
+	random:          { in: ['number'],                     out: 'boolean',     category: 'random',     icon: 'fas fa-dice', },
+	dailyRandom:     { in: ['number'],                     out: 'boolean',     category: 'random',     icon: 'fas fa-dice', },
+	seedRandom:      { in: [null, 'number'],               out: 'boolean',     category: 'random',     icon: 'fas fa-dice', },
+	randomPick:      { in: [0],                            out: 0,             category: 'random',     icon: 'fas fa-dice', },
+	dailyRandomPick: { in: [0],                            out: 0,             category: 'random',     icon: 'fas fa-dice', },
+	seedRandomPick:  { in: [null, 0],                      out: 0,             category: 'random',     icon: 'fas fa-dice', },
+	DRPWPM:      { in: ['stringArray'],                out: 'string',      category: 'random',     icon: 'fas fa-dice', }, // dailyRandomPickWithProbabilityMapping
 };
 
 export function initHpmlLib(expr: Expr, scope: HpmlScope, randomSeed: string, visitor?: any) {
diff --git a/src/client/scripts/lookup-user.ts b/src/client/scripts/lookup-user.ts
new file mode 100644
index 0000000000000000000000000000000000000000..269777d874b6c16b2b6fc99e1871beb9a1140336
--- /dev/null
+++ b/src/client/scripts/lookup-user.ts
@@ -0,0 +1,37 @@
+import parseAcct from '@/misc/acct/parse';
+import { i18n } from '@client/i18n';
+import * as os from '@client/os';
+
+export async function lookupUser() {
+	const { canceled, result } = await os.dialog({
+		title: i18n.locale.usernameOrUserId,
+		input: true
+	});
+	if (canceled) return;
+
+	const show = (user) => {
+		os.pageWindow(`/user-info/${user.id}`);
+	};
+
+	const usernamePromise = os.api('users/show', parseAcct(result));
+	const idPromise = os.api('users/show', { userId: result });
+	let _notFound = false;
+	const notFound = () => {
+		if (_notFound) {
+			os.dialog({
+				type: 'error',
+				text: i18n.locale.noSuchUser
+			});
+		} else {
+			_notFound = true;
+		}
+	};
+	usernamePromise.then(show).catch(e => {
+		if (e.code === 'NO_SUCH_USER') {
+			notFound();
+		}
+	});
+	idPromise.then(show).catch(e => {
+		notFound();
+	});
+}
diff --git a/src/client/scripts/search.ts b/src/client/scripts/search.ts
index 829065534c3e3f3e020ca2c0f2f7af7bcc93692e..2221f5f279c216fe17c12fdc7af2eb13d726b2b7 100644
--- a/src/client/scripts/search.ts
+++ b/src/client/scripts/search.ts
@@ -1,4 +1,3 @@
-import { faHistory } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 import { i18n } from '@client/i18n';
 import { router } from '@client/router';
@@ -37,7 +36,7 @@ export async function search() {
 		// TODO
 		//v.$root.$emit('warp', date);
 		os.dialog({
-			icon: faHistory,
+			icon: 'fas fa-history',
 			iconOnly: true, autoClose: true
 		});
 		return;
diff --git a/src/client/scripts/select-file.ts b/src/client/scripts/select-file.ts
index 03ac863aa0c61de7bf4bfce1b32c97ff3a1e2ae9..c193e7dc711b72c9260ec362ba6f6ba4140d9125 100644
--- a/src/client/scripts/select-file.ts
+++ b/src/client/scripts/select-file.ts
@@ -1,4 +1,3 @@
-import { faUpload, faCloud, faLink } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 import { i18n } from '@client/i18n';
 
@@ -73,15 +72,15 @@ export function selectFile(src: any, label: string | null, multiple = false) {
 			type: 'label'
 		} : undefined, {
 			text: i18n.locale.upload,
-			icon: faUpload,
+			icon: 'fas fa-upload',
 			action: chooseFileFromPc
 		}, {
 			text: i18n.locale.fromDrive,
-			icon: faCloud,
+			icon: 'fas fa-cloud',
 			action: chooseFileFromDrive
 		}, {
 			text: i18n.locale.fromUrl,
-			icon: faLink,
+			icon: 'fas fa-link',
 			action: chooseFileFromUrl
 		}], src);
 	});
diff --git a/src/client/sidebar.ts b/src/client/sidebar.ts
index 09b69fd8152258dabe84be5ca5a2d0e4989685f1..e5105f13b4578dbd13380ea2fc2c4f2bcfb0b400 100644
--- a/src/client/sidebar.ts
+++ b/src/client/sidebar.ts
@@ -1,5 +1,3 @@
-import { faBell, faComments, faEnvelope } from '@fortawesome/free-regular-svg-icons';
-import { faAt, faBroadcastTower, faCloud, faColumns, faDoorClosed, faFileAlt, faFireAlt, faGamepad, faHashtag, faListUl, faPaperclip, faSatellite, faSatelliteDish, faSearch, faStar, faTerminal, faUserClock, faUsers } from '@fortawesome/free-solid-svg-icons';
 import { computed } from 'vue';
 import { search } from '@client/scripts/search';
 import * as os from '@client/os';
@@ -10,125 +8,125 @@ import { unisonReload } from '@client/scripts/unison-reload';
 export const sidebarDef = {
 	notifications: {
 		title: 'notifications',
-		icon: faBell,
+		icon: 'fas fa-bell',
 		show: computed(() => $i != null),
 		indicated: computed(() => $i != null && $i.hasUnreadNotification),
 		to: '/my/notifications',
 	},
 	messaging: {
 		title: 'messaging',
-		icon: faComments,
+		icon: 'fas fa-comments',
 		show: computed(() => $i != null),
 		indicated: computed(() => $i != null && $i.hasUnreadMessagingMessage),
 		to: '/my/messaging',
 	},
 	drive: {
 		title: 'drive',
-		icon: faCloud,
+		icon: 'fas fa-cloud',
 		show: computed(() => $i != null),
 		to: '/my/drive',
 	},
 	followRequests: {
 		title: 'followRequests',
-		icon: faUserClock,
+		icon: 'fas fa-user-clock',
 		show: computed(() => $i != null && $i.isLocked),
 		indicated: computed(() => $i != null && $i.hasPendingReceivedFollowRequest),
 		to: '/my/follow-requests',
 	},
 	featured: {
 		title: 'featured',
-		icon: faFireAlt,
+		icon: 'fas fa-fire-alt',
 		to: '/featured',
 	},
 	explore: {
 		title: 'explore',
-		icon: faHashtag,
+		icon: 'fas fa-hashtag',
 		to: '/explore',
 	},
 	announcements: {
 		title: 'announcements',
-		icon: faBroadcastTower,
+		icon: 'fas fa-broadcast-tower',
 		indicated: computed(() => $i != null && $i.hasUnreadAnnouncement),
 		to: '/announcements',
 	},
 	search: {
 		title: 'search',
-		icon: faSearch,
+		icon: 'fas fa-search',
 		action: () => search(),
 	},
 	lists: {
 		title: 'lists',
-		icon: faListUl,
+		icon: 'fas fa-list-ul',
 		show: computed(() => $i != null),
 		to: '/my/lists',
 	},
 	groups: {
 		title: 'groups',
-		icon: faUsers,
+		icon: 'fas fa-users',
 		show: computed(() => $i != null),
 		to: '/my/groups',
 	},
 	antennas: {
 		title: 'antennas',
-		icon: faSatellite,
+		icon: 'fas fa-satellite',
 		show: computed(() => $i != null),
 		to: '/my/antennas',
 	},
 	mentions: {
 		title: 'mentions',
-		icon: faAt,
+		icon: 'fas fa-at',
 		show: computed(() => $i != null),
 		indicated: computed(() => $i != null && $i.hasUnreadMentions),
 		to: '/my/mentions',
 	},
 	messages: {
 		title: 'directNotes',
-		icon: faEnvelope,
+		icon: 'fas fa-envelope',
 		show: computed(() => $i != null),
 		indicated: computed(() => $i != null && $i.hasUnreadSpecifiedNotes),
 		to: '/my/messages',
 	},
 	favorites: {
 		title: 'favorites',
-		icon: faStar,
+		icon: 'fas fa-star',
 		show: computed(() => $i != null),
 		to: '/my/favorites',
 	},
 	pages: {
 		title: 'pages',
-		icon: faFileAlt,
+		icon: 'fas fa-file-alt',
 		to: '/pages',
 	},
 	clips: {
 		title: 'clip',
-		icon: faPaperclip,
+		icon: 'fas fa-paperclip',
 		show: computed(() => $i != null),
 		to: '/my/clips',
 	},
 	channels: {
 		title: 'channel',
-		icon: faSatelliteDish,
+		icon: 'fas fa-satellite-dish',
 		to: '/channels',
 	},
 	games: {
 		title: 'games',
-		icon: faGamepad,
+		icon: 'fas fa-gamepad',
 		to: '/games/reversi',
 	},
 	scratchpad: {
 		title: 'scratchpad',
-		icon: faTerminal,
+		icon: 'fas fa-terminal',
 		to: '/scratchpad',
 	},
 	rooms: {
 		title: 'rooms',
-		icon: faDoorClosed,
+		icon: 'fas fa-door-closed',
 		show: computed(() => $i != null),
 		to: computed(() => `/@${$i.username}/room`),
 	},
 	ui: {
 		title: 'switchUi',
-		icon: faColumns,
+		icon: 'fas fa-columns',
 		action: (ev) => {
 			os.modalMenu([{
 				text: i18n.locale.default,
diff --git a/src/client/style.scss b/src/client/style.scss
index ab8da9ccfa2c73e05c399c8ace3c07741a78f4cb..07b80d553f6ab3275f53d34723ae6b26b2da18c1 100644
--- a/src/client/style.scss
+++ b/src/client/style.scss
@@ -520,3 +520,27 @@ hr {
 		transform: scale3d(1, 1, 1);
 	}
 }
+
+._anime_bounce {
+  animation: bounce ease 0.7s;
+  animation-iteration-count: 1;
+  transform-origin: 50% 50%;
+}
+._anime_bounce_ready {
+	transform:  scaleX(0.90) scaleY(0.90) ;
+}
+
+@keyframes bounce{
+  0% {
+    transform:  scaleX(0.90) scaleY(0.90) ;
+  }
+  19% {
+    transform:  scaleX(1.10) scaleY(1.10) ;
+  }
+  48% {
+    transform:  scaleX(0.95) scaleY(0.95) ;
+  }
+  100% {
+    transform:  scaleX(1.00) scaleY(1.00) ;
+  }
+}
diff --git a/src/client/ui/_common_/header.vue b/src/client/ui/_common_/header.vue
index 493deaeb965aa76e1934dfbbe5231ba5058ce602..83aa669b44f2ad36d486340d61e1faf46625bab7 100644
--- a/src/client/ui/_common_/header.vue
+++ b/src/client/ui/_common_/header.vue
@@ -1,12 +1,12 @@
 <template>
 <div class="fdidabkb" :class="{ center }" :style="`--height:${height};`" :key="key">
 	<transition :name="$store.state.animation ? 'header' : ''" mode="out-in" appear>
-		<button class="_button back" v-if="withBack && canBack" @click.stop="back()" v-tooltip="$ts.goBack"><Fa :icon="faChevronLeft"/></button>
+		<button class="_button back" v-if="withBack && canBack" @click.stop="back()" v-tooltip="$ts.goBack"><i class="fas fa-chevron-left"></i></button>
 	</transition>
 	<template v-if="info">
 		<div class="titleContainer">
 			<div class="title">
-				<Fa v-if="info.icon" :icon="info.icon" :key="info.icon" class="icon"/>
+				<i v-if="info.icon" class="icon" :class="info.icon"></i>
 				<MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
 				<MkUserName v-if="info.userName" :user="info.userName" :nowrap="false" class="text"/>
 				<span v-else-if="info.title" class="text">{{ info.title }}</span>
@@ -14,9 +14,9 @@
 		</div>
 		<div class="buttons">
 			<template v-if="info.actions && showActions">
-				<button v-for="action in info.actions" class="_button button" @click.stop="action.handler" v-tooltip="action.text"><Fa :icon="action.icon"/></button>
+				<button v-for="action in info.actions" class="_button button" @click.stop="action.handler" v-tooltip="action.text"><i :class="action.icon"></i></button>
 			</template>
-			<button v-if="showMenu" class="_button button" @click.stop="menu"><Fa :icon="faEllipsisH"/></button>
+			<button v-if="showMenu" class="_button button" @click.stop="menu"><i class="fas fa-ellipsis-h"></i></button>
 		</div>
 	</template>
 </div>
@@ -24,7 +24,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faChevronLeft, faCircle, faShareAlt, faEllipsisH } from '@fortawesome/free-solid-svg-icons';
 import { modalMenu } from '@client/os';
 import { url } from '@client/config';
 
@@ -51,7 +50,6 @@ export default defineComponent({
 			showActions: false,
 			height: 0,
 			key: 0,
-			faChevronLeft, faCircle, faShareAlt, faEllipsisH,
 		};
 	},
 
@@ -111,7 +109,7 @@ export default defineComponent({
 				if (menu.length > 0) menu.push(null);
 				menu.push({
 					text: this.$ts.share,
-					icon: faShareAlt,
+					icon: 'fas fa-share-alt',
 					action: this.share
 				});
 			}
diff --git a/src/client/ui/_common_/sidebar.vue b/src/client/ui/_common_/sidebar.vue
index 6243d6fcc2c545d22a238fa234988ab8cf95f4fc..df118771472462e02caa1db9fda5734254ba0f28 100644
--- a/src/client/ui/_common_/sidebar.vue
+++ b/src/client/ui/_common_/sidebar.vue
@@ -15,28 +15,28 @@
 					<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
 				</button>
 				<MkA class="item index" active-class="active" to="/" exact>
-					<Fa :icon="faHome" fixed-width/><span class="text">{{ $ts.timeline }}</span>
+					<i class="fas fa-home fa-fw"></i><span class="text">{{ $ts.timeline }}</span>
 				</MkA>
 				<template v-for="item in menu">
 					<div v-if="item === '-'" class="divider"></div>
 					<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'MkA' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to">
-						<Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $ts[menuDef[item].title] }}</span>
-						<i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i>
+						<i class="fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span>
+						<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
 					</component>
 				</template>
 				<div class="divider"></div>
-				<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$i.isAdmin || $i.isModerator" @click="oepnInstanceMenu">
-					<Fa :icon="faServer" fixed-width/><span class="text">{{ $ts.instance }}</span>
-				</button>
+				<MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/instance">
+					<i class="fas fa-server fa-fw"></i><span class="text">{{ $ts.instance }}</span>
+				</MkA>
 				<button class="item _button" @click="more">
-					<Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $ts.more }}</span>
-					<i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i>
+					<i class="fa fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span>
+					<span v-if="otherNavItemIndicated" class="indicator"><i class="fas fa-circle"></i></span>
 				</button>
 				<MkA class="item" active-class="active" to="/settings">
-					<Fa :icon="faCog" fixed-width/><span class="text">{{ $ts.settings }}</span>
+					<i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span>
 				</MkA>
 				<button class="item _button post" @click="post">
-					<Fa :icon="faPencilAlt" fixed-width/><span class="text">{{ $ts.note }}</span>
+					<i class="fas fa-pencil-alt fa-fw"></i><span class="text">{{ $ts.note }}</span>
 				</button>
 			</div>
 		</nav>
@@ -46,8 +46,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram, faStream, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
 import { host } from '@client/config';
 import { search } from '@client/scripts/search';
 import * as os from '@client/os';
@@ -72,7 +70,6 @@ export default defineComponent({
 			menuDef: sidebarDef,
 			iconOnly: false,
 			hidden: this.defaultHidden,
-			faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
 		};
 	},
 
@@ -159,12 +156,12 @@ export default defineComponent({
 				to: `/@${ this.$i.username }`,
 				avatar: this.$i,
 			}, null, ...accountItemPromises, {
-				icon: faPlus,
-				text: this.$ts.addAcount,
+				icon: 'fas fa-plus',
+				text: this.$ts.addAccount,
 				action: () => {
 					os.modalMenu([{
-						text: this.$ts.existingAcount,
-						action: () => { this.addAcount(); },
+						text: this.$ts.existingAccount,
+						action: () => { this.addAccount(); },
 					}, {
 						text: this.$ts.createAccount,
 						action: () => { this.createAccount(); },
@@ -175,71 +172,12 @@ export default defineComponent({
 			});
 		},
 
-		oepnInstanceMenu(ev) {
-			os.modalMenu([{
-				type: 'link',
-				text: this.$ts.dashboard,
-				to: '/instance',
-				icon: faTachometerAlt,
-			}, null, this.$i.isAdmin ? {
-				type: 'link',
-				text: this.$ts.settings,
-				to: '/instance/settings',
-				icon: faCog,
-			} : undefined, {
-				type: 'link',
-				text: this.$ts.customEmojis,
-				to: '/instance/emojis',
-				icon: faLaugh,
-			}, {
-				type: 'link',
-				text: this.$ts.users,
-				to: '/instance/users',
-				icon: faUsers,
-			}, {
-				type: 'link',
-				text: this.$ts.files,
-				to: '/instance/files',
-				icon: faCloud,
-			}, {
-				type: 'link',
-				text: this.$ts.jobQueue,
-				to: '/instance/queue',
-				icon: faExchangeAlt,
-			}, {
-				type: 'link',
-				text: this.$ts.federation,
-				to: '/instance/federation',
-				icon: faGlobe,
-			}, {
-				type: 'link',
-				text: this.$ts.relays,
-				to: '/instance/relays',
-				icon: faProjectDiagram,
-			}, {
-				type: 'link',
-				text: this.$ts.announcements,
-				to: '/instance/announcements',
-				icon: faBroadcastTower,
-			}, {
-				type: 'link',
-				text: this.$ts.abuseReports,
-				to: '/instance/abuses',
-				icon: faExclamationCircle,
-			}, {
-				type: 'link',
-				text: this.$ts.logs,
-				to: '/instance/logs',
-				icon: faStream,
-			}], ev.currentTarget || ev.target);
-		},
-
 		more(ev) {
 			os.popup(import('@client/components/launch-pad.vue'), {}, {
 			}, 'closed');
 		},
 
-		addAcount() {
+		addAccount() {
 			os.popup(import('@client/components/signin-dialog.vue'), {}, {
 				done: res => {
 					addAccount(res.id, res.i);
@@ -330,7 +268,7 @@ export default defineComponent({
 						font-size: $ui-font-size * 1.1;
 						line-height: 3.7rem;
 
-						> [data-icon],
+						> i,
 						> .avatar {
 							margin-right: 0;
 						}
@@ -397,11 +335,11 @@ export default defineComponent({
 				box-sizing: border-box;
 				color: var(--navFg);
 
-				> [data-icon] {
+				> i {
 					width: 32px;
 				}
 
-				> [data-icon],
+				> i,
 				> .avatar {
 					margin-right: $avatar-margin;
 				}
@@ -412,7 +350,7 @@ export default defineComponent({
 					vertical-align: middle;
 				}
 
-				> i {
+				> .indicator {
 					position: absolute;
 					top: 0;
 					left: 20px;
diff --git a/src/client/ui/_common_/upload.vue b/src/client/ui/_common_/upload.vue
index bd3b2cd6848a876397b76b0af5b755e7c46386d3..25a807cd3638547002fb6139f1b663c195b3d301 100644
--- a/src/client/ui/_common_/upload.vue
+++ b/src/client/ui/_common_/upload.vue
@@ -4,7 +4,7 @@
 		<li v-for="ctx in uploads" :key="ctx.id">
 			<div class="img" :style="{ backgroundImage: `url(${ ctx.img })` }"></div>
 			<div class="top">
-				<p class="name"><Fa :icon="faSpinner" pulse/>{{ ctx.name }}</p>
+				<p class="name"><i class="fas fa-spinner fa-pulse"></i>{{ ctx.name }}</p>
 				<p class="status">
 					<span class="initing" v-if="ctx.progressValue === undefined">{{ $ts.waiting }}<MkEllipsis/></span>
 					<span class="kb" v-if="ctx.progressValue !== undefined">{{ String(Math.floor(ctx.progressValue / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i> / {{ String(Math.floor(ctx.progressMax / 1024)).replace(/(\d)(?=(\d\d\d)+(?!\d))/g, '$1,') }}<i>KB</i></span>
@@ -19,14 +19,12 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSpinner } from '@fortawesome/free-solid-svg-icons';
 import * as os from '@client/os';
 
 export default defineComponent({
 	data() {
 		return {
 			uploads: os.uploads,
-			faSpinner
 		};
 	},
 });
@@ -92,7 +90,7 @@ export default defineComponent({
   overflow: hidden;
   flex-shrink: 1;
 }
-.mk-uploader > ol > li > .top > .name > [data-icon] {
+.mk-uploader > ol > li > .top > .name > i {
   margin-right: 4px;
 }
 .mk-uploader > ol > li > .top > .status {
diff --git a/src/client/ui/chat/date-separated-list.vue b/src/client/ui/chat/date-separated-list.vue
index 65deb9e1c23a605502b9de9959423c638a5a488c..b073a38eb11ba8bc6581dc12d264932468fdc08a 100644
--- a/src/client/ui/chat/date-separated-list.vue
+++ b/src/client/ui/chat/date-separated-list.vue
@@ -1,7 +1,5 @@
 <script lang="ts">
 import { defineComponent, h, TransitionGroup } from 'vue';
-import { faAngleUp, faAngleDown } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
 
 export default defineComponent({
 	props: {
@@ -57,17 +55,15 @@ export default defineComponent({
 					class: 'date'
 				}, [
 					h('span', [
-						h(FontAwesomeIcon, {
-							class: 'icon',
-							icon: faAngleUp,
+						h('i', {
+							class: 'fas fa-angle-up icon',
 						}),
 						getDateText(item.createdAt)
 					]),
 					h('span', [
 						getDateText(this.items[i + 1].createdAt),
-						h(FontAwesomeIcon, {
-							class: 'icon',
-							icon: faAngleDown,
+						h('i', {
+							class: 'fas fa-angle-down icon',
 						})
 					])
 				]));
diff --git a/src/client/ui/chat/index.vue b/src/client/ui/chat/index.vue
index d5c455d123e9296f9982eaa579491c6400ef43b0..b498d70a7517467065235f3785fe2501b475b031 100644
--- a/src/client/ui/chat/index.vue
+++ b/src/client/ui/chat/index.vue
@@ -10,63 +10,63 @@
 				</button>
 			</div>
 			<div class="right">
-				<MkA class="item" to="/my/messaging" v-tooltip="$ts.messaging"><Fa class="icon" :icon="faComments"/><i v-if="$i.hasUnreadMessagingMessage"><Fa :icon="faCircle"/></i></MkA>
-				<MkA class="item" to="/my/messages" v-tooltip="$ts.directNotes"><Fa class="icon" :icon="faEnvelope"/><i v-if="$i.hasUnreadSpecifiedNotes"><Fa :icon="faCircle"/></i></MkA>
-				<MkA class="item" to="/my/mentions" v-tooltip="$ts.mentions"><Fa class="icon" :icon="faAt"/><i v-if="$i.hasUnreadMentions"><Fa :icon="faCircle"/></i></MkA>
-				<MkA class="item" to="/my/notifications" v-tooltip="$ts.notifications"><Fa class="icon" :icon="faBell"/><i v-if="$i.hasUnreadNotification"><Fa :icon="faCircle"/></i></MkA>
+				<MkA class="item" to="/my/messaging" v-tooltip="$ts.messaging"><i class="fas fa-comments icon"></i><span v-if="$i.hasUnreadMessagingMessage" class="indicator"><i class="fas fa-circle"></i></span></MkA>
+				<MkA class="item" to="/my/messages" v-tooltip="$ts.directNotes"><i class="fas fa-envelope icon"></i><span v-if="$i.hasUnreadSpecifiedNotes" class="indicator"><i class="fas fa-circle"></i></span></MkA>
+				<MkA class="item" to="/my/mentions" v-tooltip="$ts.mentions"><i class="fas fa-at icon"></i><span v-if="$i.hasUnreadMentions" class="indicator"><i class="fas fa-circle"></i></span></MkA>
+				<MkA class="item" to="/my/notifications" v-tooltip="$ts.notifications"><i class="fas fa-bell icon"></i><span v-if="$i.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></MkA>
 			</div>
 		</header>
 		<div class="body">
 			<div class="container">
 				<div class="header">{{ $ts.timeline }}</div>
 				<div class="body">
-					<MkA to="/timeline/home" class="item" :class="{ active: tl === 'home' }"><Fa :icon="faHome" class="icon"/>{{ $ts._timelines.home }}</MkA>
-					<MkA to="/timeline/local" class="item" :class="{ active: tl === 'local' }"><Fa :icon="faComments" class="icon"/>{{ $ts._timelines.local }}</MkA>
-					<MkA to="/timeline/social" class="item" :class="{ active: tl === 'social' }"><Fa :icon="faShareAlt" class="icon"/>{{ $ts._timelines.social }}</MkA>
-					<MkA to="/timeline/global" class="item" :class="{ active: tl === 'global' }"><Fa :icon="faGlobe" class="icon"/>{{ $ts._timelines.global }}</MkA>
+					<MkA to="/timeline/home" class="item" :class="{ active: tl === 'home' }"><i class="fas fa-home icon"></i>{{ $ts._timelines.home }}</MkA>
+					<MkA to="/timeline/local" class="item" :class="{ active: tl === 'local' }"><i class="fas fa-comments icon"></i>{{ $ts._timelines.local }}</MkA>
+					<MkA to="/timeline/social" class="item" :class="{ active: tl === 'social' }"><i class="fas fa-share-alt icon"></i>{{ $ts._timelines.social }}</MkA>
+					<MkA to="/timeline/global" class="item" :class="{ active: tl === 'global' }"><i class="fas fa-globe icon"></i>{{ $ts._timelines.global }}</MkA>
 				</div>
 			</div>
 			<div class="container" v-if="followedChannels">
-				<div class="header">{{ $ts.channel }} ({{ $ts.following }})<button class="_button add" @click="addChannel"><Fa :icon="faPlus"/></button></div>
+				<div class="header">{{ $ts.channel }} ({{ $ts.following }})<button class="_button add" @click="addChannel"><i class="fas fa-plus"></i></button></div>
 				<div class="body">
-					<MkA v-for="channel in followedChannels" :key="channel.id" :to="`/channels/${ channel.id }`" class="item" :class="{ active: tl === `channel:${ channel.id }`, read: !channel.hasUnreadNote }"><Fa :icon="faSatelliteDish" class="icon"/>{{ channel.name }}</MkA>
+					<MkA v-for="channel in followedChannels" :key="channel.id" :to="`/channels/${ channel.id }`" class="item" :class="{ active: tl === `channel:${ channel.id }`, read: !channel.hasUnreadNote }"><i class="fas fa-satellite-dish icon"></i>{{ channel.name }}</MkA>
 				</div>
 			</div>
 			<div class="container" v-if="featuredChannels">
-				<div class="header">{{ $ts.channel }}<button class="_button add" @click="addChannel"><Fa :icon="faPlus"/></button></div>
+				<div class="header">{{ $ts.channel }}<button class="_button add" @click="addChannel"><i class="fas fa-plus"></i></button></div>
 				<div class="body">
-					<MkA v-for="channel in featuredChannels" :key="channel.id" :to="`/channels/${ channel.id }`" class="item" :class="{ active: tl === `channel:${ channel.id }` }"><Fa :icon="faSatelliteDish" class="icon"/>{{ channel.name }}</MkA>
+					<MkA v-for="channel in featuredChannels" :key="channel.id" :to="`/channels/${ channel.id }`" class="item" :class="{ active: tl === `channel:${ channel.id }` }"><i class="fas fa-satellite-dish icon"></i>{{ channel.name }}</MkA>
 				</div>
 			</div>
 			<div class="container" v-if="lists">
-				<div class="header">{{ $ts.lists }}<button class="_button add" @click="addList"><Fa :icon="faPlus"/></button></div>
+				<div class="header">{{ $ts.lists }}<button class="_button add" @click="addList"><i class="fas fa-plus"></i></button></div>
 				<div class="body">
-					<MkA v-for="list in lists" :key="list.id" :to="`/my/list/${ list.id }`" class="item" :class="{ active: tl === `list:${ list.id }` }"><Fa :icon="faListUl" class="icon"/>{{ list.name }}</MkA>
+					<MkA v-for="list in lists" :key="list.id" :to="`/my/list/${ list.id }`" class="item" :class="{ active: tl === `list:${ list.id }` }"><i class="fas fa-list-ul icon"></i>{{ list.name }}</MkA>
 				</div>
 			</div>
 			<div class="container" v-if="antennas">
-				<div class="header">{{ $ts.antennas }}<button class="_button add" @click="addAntenna"><Fa :icon="faPlus"/></button></div>
+				<div class="header">{{ $ts.antennas }}<button class="_button add" @click="addAntenna"><i class="fas fa-plus"></i></button></div>
 				<div class="body">
-					<MkA v-for="antenna in antennas" :key="antenna.id" :to="`/my/antenna/${ antenna.id }`" class="item" :class="{ active: tl === `antenna:${ antenna.id }` }"><Fa :icon="faSatellite" class="icon"/>{{ antenna.name }}</MkA>
+					<MkA v-for="antenna in antennas" :key="antenna.id" :to="`/my/antenna/${ antenna.id }`" class="item" :class="{ active: tl === `antenna:${ antenna.id }` }"><i class="fas fa-satellite icon"></i>{{ antenna.name }}</MkA>
 				</div>
 			</div>
 			<div class="container">
 				<div class="body">
-					<MkA to="/my/favorites" class="item"><Fa :icon="faStar" class="icon"/>{{ $ts.favorites }}</MkA>
+					<MkA to="/my/favorites" class="item"><i class="fas fa-star icon"></i>{{ $ts.favorites }}</MkA>
 				</div>
 			</div>
 		</div>
 		<footer class="footer">
 			<div class="left">
 				<button class="_button menu" @click="showMenu">
-					<Fa class="icon" :icon="faBars"/>
+					<i class="fas fa-bars icon"></i>
 				</button>
 			</div>
 			<div class="right">
 				<button class="_button item search" @click="search" v-tooltip="$ts.search">
-					<Fa :icon="faSearch"/>
+					<i class="fas fa-search"></i>
 				</button>
-				<MkA class="item" to="/settings" v-tooltip="$ts.settings"><Fa class="icon" :icon="faCog"/></MkA>
+				<MkA class="item" to="/settings" v-tooltip="$ts.settings"><i class="fas fa-cog icon"></i></MkA>
 			</div>
 		</footer>
 	</div>
@@ -75,23 +75,23 @@
 		<header class="header" ref="header" @click="onHeaderClick">
 			<div class="left">
 				<template v-if="tl === 'home'">
-					<Fa :icon="faHome" class="icon"/>
+					<i class="fas fa-home icon"></i>
 					<div class="title">{{ $ts._timelines.home }}</div>
 				</template>
 				<template v-else-if="tl === 'local'">
-					<Fa :icon="faComments" class="icon"/>
+					<i class="fas fa-comments icon"></i>
 					<div class="title">{{ $ts._timelines.local }}</div>
 				</template>
 				<template v-else-if="tl === 'social'">
-					<Fa :icon="faShareAlt" class="icon"/>
+					<i class="fas fa-share-alt icon"></i>
 					<div class="title">{{ $ts._timelines.social }}</div>
 				</template>
 				<template v-else-if="tl === 'global'">
-					<Fa :icon="faGlobe" class="icon"/>
+					<i class="fas fa-globe icon"></i>
 					<div class="title">{{ $ts._timelines.global }}</div>
 				</template>
 				<template v-else-if="tl.startsWith('channel:')">
-					<Fa :icon="faSatelliteDish" class="icon"/>
+					<i class="fas fa-satellite-dish icon"></i>
 					<div class="title" v-if="currentChannel">{{ currentChannel.name }}<div class="description">{{ currentChannel.description }}</div></div>
 				</template>
 			</div>
@@ -100,20 +100,20 @@
 				<div class="instance">{{ instanceName }}</div>
 				<XHeaderClock class="clock"/>
 				<button class="_button button timetravel" @click="timetravel" v-tooltip="$ts.jumpToSpecifiedDate">
-					<Fa :icon="faCalendarAlt"/>
+					<i class="fas fa-calendar-alt"></i>
 				</button>
 				<button class="_button button search" v-if="tl.startsWith('channel:') && currentChannel" @click="inChannelSearch" v-tooltip="$ts.inChannelSearch">
-					<Fa :icon="faSearch"/>
+					<i class="fas fa-search"></i>
 				</button>
 				<button class="_button button search" v-else @click="search" v-tooltip="$ts.search">
-					<Fa :icon="faSearch"/>
+					<i class="fas fa-search"></i>
 				</button>
 				<button class="_button button follow" v-if="tl.startsWith('channel:') && currentChannel" :class="{ followed: currentChannel.isFollowing }" @click="toggleChannelFollow" v-tooltip="currentChannel.isFollowing ? $ts.unfollow : $ts.follow">
-					<Fa v-if="currentChannel.isFollowing" :icon="faStar"/>
-					<Fa v-else :icon="farStar"/>
+					<i v-if="currentChannel.isFollowing" class="fas fa-star"></i>
+					<i v-else class="far fa-star"></i>
 				</button>
 				<button class="_button button menu" v-if="tl.startsWith('channel:') && currentChannel" @click="openChannelMenu">
-					<Fa :icon="faEllipsisH"/>
+					<i class="fas fa-ellipsis-h"></i>
 				</button>
 			</div>
 		</header>
@@ -133,8 +133,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faLayerGroup, faBars, faHome, faCircle, faWindowMaximize, faColumns, faPencilAlt, faShareAlt, faSatelliteDish, faListUl, faSatellite, faCog, faSearch, faPlus, faStar, faAt, faLink, faEllipsisH, faGlobe } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faStar as farStar, faEnvelope, faComments, faCalendarAlt } from '@fortawesome/free-regular-svg-icons';
 import { instanceName, url } from '@client/config';
 import XSidebar from '@client/ui/_common_/sidebar.vue';
 import XWidgets from './widgets.vue';
@@ -195,7 +193,6 @@ export default defineComponent({
 			menuDef: sidebarDef,
 			sideViewOpening: false,
 			instanceName,
-			faLayerGroup, faBars, faBell, faHome, faCircle, faPencilAlt, faShareAlt, faSatelliteDish, faListUl, faSatellite, faCog, faSearch, faPlus, faStar, farStar, faAt, faLink, faEllipsisH, faGlobe, faComments, faEnvelope, faCalendarAlt,
 		};
 	},
 
@@ -293,7 +290,7 @@ export default defineComponent({
 		openChannelMenu(ev) {
 			os.modalMenu([{
 				text: this.$ts.copyUrl,
-				icon: faLink,
+				icon: 'fas fa-link',
 				action: () => {
 					copyToClipboard(`${url}/channels/${this.currentChannel.id}`);
 				}
@@ -323,13 +320,13 @@ export default defineComponent({
 				type: 'label',
 				text: path,
 			}, {
-				icon: faColumns,
+				icon: 'fas fa-columns',
 				text: this.$ts.openInSideView,
 				action: () => {
 					this.$refs.side.navigate(path);
 				}
 			}, {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts.openInWindow,
 				action: () => {
 					os.pageWindow(path);
@@ -398,7 +395,7 @@ export default defineComponent({
 						margin: auto;
 					}
 
-					> i {
+					> .indicator {
 						position: absolute;
 						top: 8px;
 						right: 8px;
diff --git a/src/client/ui/chat/note-header.vue b/src/client/ui/chat/note-header.vue
index be08183d39af56596ed5c66bc622c1cd0342ac13..e40f22f588047a18b534472fad8e82a1f97c65db 100644
--- a/src/client/ui/chat/note-header.vue
+++ b/src/client/ui/chat/note-header.vue
@@ -5,27 +5,25 @@
 	</MkA>
 	<span class="is-bot" v-if="note.user.isBot">bot</span>
 	<span class="username"><MkAcct :user="note.user"/></span>
-	<span class="admin" v-if="note.user.isAdmin"><Fa :icon="faBookmark"/></span>
-	<span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><Fa :icon="farBookmark"/></span>
+	<span class="admin" v-if="note.user.isAdmin"><i class="fas fa-bookmark"></i></span>
+	<span class="moderator" v-if="!note.user.isAdmin && note.user.isModerator"><i class="far fa-bookmark"></i></span>
 	<div class="info">
-		<span class="mobile" v-if="note.viaMobile"><Fa :icon="faMobileAlt"/></span>
+		<span class="mobile" v-if="note.viaMobile"><i class="fas fa-mobile-alt"></i></span>
 		<MkA class="created-at" :to="notePage(note)">
 			<MkTime :time="note.createdAt"/>
 		</MkA>
 		<span class="visibility" v-if="note.visibility !== 'public'">
-			<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
-			<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
-			<Fa v-if="note.visibility === 'specified'" :icon="faEnvelope"/>
+			<i v-if="note.visibility === 'home'" class="fas fa-home"></i>
+			<i v-else-if="note.visibility === 'followers'" class="fas fa-unlock"></i>
+			<i v-else-if="note.visibility === 'specified'" class="fas fa-envelope"></i>
 		</span>
-		<span class="localOnly" v-if="note.localOnly"><Fa :icon="faBiohazard"/></span>
+		<span class="localOnly" v-if="note.localOnly"><i class="fas fa-biohazard"></i></span>
 	</div>
 </header>
 </template>
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark, faBiohazard } from '@fortawesome/free-solid-svg-icons';
-import { faBookmark as farBookmark } from '@fortawesome/free-regular-svg-icons';
 import notePage from '@client/filters/note';
 import { userPage } from '@client/filters/user';
 import * as os from '@client/os';
@@ -40,7 +38,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faHome, faUnlock, faEnvelope, faMobileAlt, faBookmark, farBookmark, faBiohazard
 		};
 	},
 
diff --git a/src/client/ui/chat/note.vue b/src/client/ui/chat/note.vue
index 77b7440ca1c37b3d57c84b98d36d673d08907c36..7a525d9edbf5e1c6ea92a4660c690ec7996f54df 100644
--- a/src/client/ui/chat/note.vue
+++ b/src/client/ui/chat/note.vue
@@ -8,12 +8,12 @@
 	v-hotkey="keymap"
 >
 	<XSub :note="appearNote.reply" class="reply-to" v-if="appearNote.reply"/>
-	<div class="info" v-if="pinned"><Fa :icon="faThumbtack"/> {{ $ts.pinnedNote }}</div>
-	<div class="info" v-if="appearNote._prId_"><Fa :icon="faBullhorn"/> {{ $ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ $ts.hideThisNote }} <Fa :icon="faTimes"/></button></div>
-	<div class="info" v-if="appearNote._featuredId_"><Fa :icon="faBolt"/> {{ $ts.featured }}</div>
+	<div class="info" v-if="pinned"><i class="fas fa-thumbtack"></i> {{ $ts.pinnedNote }}</div>
+	<div class="info" v-if="appearNote._prId_"><i class="fas fa-bullhorn"></i> {{ $ts.promotion }}<button class="_textButton hide" @click="readPromo()">{{ $ts.hideThisNote }} <i class="fas fa-times"></i></button></div>
+	<div class="info" v-if="appearNote._featuredId_"><i class="fas fa-bolt"></i> {{ $ts.featured }}</div>
 	<div class="renote" v-if="isRenote">
 		<MkAvatar class="avatar" :user="note.user"/>
-		<Fa :icon="faRetweet"/>
+		<i class="fas fa-retweet"></i>
 		<I18n :src="$ts.renotedBy" tag="span">
 			<template #user>
 				<MkA class="name" :to="userPage(note.user)" v-user-preview="note.userId">
@@ -23,15 +23,15 @@
 		</I18n>
 		<div class="info">
 			<button class="_button time" @click="showRenoteMenu()" ref="renoteTime">
-				<Fa class="dropdownIcon" v-if="isMyRenote" :icon="faEllipsisH"/>
+				<i v-if="isMyRenote" class="fas fa-ellipsis-h dropdownIcon"></i>
 				<MkTime :time="note.createdAt"/>
 			</button>
 			<span class="visibility" v-if="note.visibility !== 'public'">
-				<Fa v-if="note.visibility === 'home'" :icon="faHome"/>
-				<Fa v-if="note.visibility === 'followers'" :icon="faUnlock"/>
-				<Fa v-if="note.visibility === 'specified'" :icon="faEnvelope"/>
+				<i v-if="note.visibility === 'home'" class="fas fa-home"></i>
+				<i v-else-if="note.visibility === 'followers'" class="fas fa-unlock"></i>
+				<i v-else-if="note.visibility === 'specified'" class="fas fa-envelope"></i>
 			</span>
-			<span class="localOnly" v-if="note.localOnly"><Fa :icon="faBiohazard"/></span>
+			<span class="localOnly" v-if="note.localOnly"><i class="fas fa-biohazard"></i></span>
 		</div>
 	</div>
 	<article class="article" @contextmenu.stop="onContextmenu">
@@ -47,7 +47,7 @@
 				<div class="content" :class="{ collapsed }" v-show="appearNote.cw == null || showContent">
 					<div class="text">
 						<span v-if="appearNote.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
-						<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><Fa :icon="faReply"/></MkA>
+						<MkA class="reply" v-if="appearNote.replyId" :to="`/notes/${appearNote.replyId}`"><i class="fas fa-reply"></i></MkA>
 						<Mfm v-if="appearNote.text" :text="appearNote.text" :author="appearNote.user" :i="$i" :custom-emojis="appearNote.emojis"/>
 						<a class="rp" v-if="appearNote.renote != null">RN:</a>
 					</div>
@@ -61,29 +61,29 @@
 						<span>{{ $ts.showMore }}</span>
 					</button>
 				</div>
-				<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><Fa :icon="faSatelliteDish"/> {{ appearNote.channel.name }}</MkA>
+				<MkA v-if="appearNote.channel && !inChannel" class="channel" :to="`/channels/${appearNote.channel.id}`"><i class="fas fa-satellite-dish"></i> {{ appearNote.channel.name }}</MkA>
 			</div>
 			<XReactionsViewer :note="appearNote" ref="reactionsViewer"/>
 			<footer class="footer _panel">
 				<button @click="reply()" class="button _button" v-tooltip="$ts.reply">
-					<template v-if="appearNote.reply"><Fa :icon="faReplyAll"/></template>
-					<template v-else><Fa :icon="faReply"/></template>
+					<template v-if="appearNote.reply"><i class="fas fa-reply-all"></i></template>
+					<template v-else><i class="fas fa-reply"></i></template>
 					<p class="count" v-if="appearNote.repliesCount > 0">{{ appearNote.repliesCount }}</p>
 				</button>
 				<button v-if="canRenote" @click="renote()" class="button _button" ref="renoteButton" v-tooltip="$ts.renote">
-					<Fa :icon="faRetweet"/><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
+					<i class="fas fa-retweet"></i><p class="count" v-if="appearNote.renoteCount > 0">{{ appearNote.renoteCount }}</p>
 				</button>
 				<button v-else class="button _button">
-					<Fa :icon="faBan"/>
+					<i class="fas fa-ban"></i>
 				</button>
 				<button v-if="appearNote.myReaction == null" class="button _button" @click="react()" ref="reactButton" v-tooltip="$ts.reaction">
-					<Fa :icon="faPlus"/>
+					<i class="fas fa-plus"></i>
 				</button>
 				<button v-if="appearNote.myReaction != null" class="button _button reacted" @click="undoReact(appearNote)" ref="reactButton" v-tooltip="$ts.reaction">
-					<Fa :icon="faMinus"/>
+					<i class="fas fa-minus"></i>
 				</button>
 				<button class="button _button" @click="menu()" ref="menuButton">
-					<Fa :icon="faEllipsisH"/>
+					<i class="fas fa-ellipsis-h"></i>
 				</button>
 			</footer>
 		</div>
@@ -102,8 +102,6 @@
 
 <script lang="ts">
 import { defineAsyncComponent, defineComponent, markRaw } from 'vue';
-import { faSatelliteDish, faBolt, faTimes, faBullhorn, faStar, faLink, faExternalLinkSquareAlt, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faQuoteRight, faInfoCircle, faBiohazard, faPlug, faExclamationCircle, faPaperclip, faShareAlt } from '@fortawesome/free-solid-svg-icons';
-import { faCopy, faTrashAlt, faEdit, faEye, faEyeSlash } from '@fortawesome/free-regular-svg-icons';
 import * as mfm from 'mfm-js';
 import { sum } from '../../../prelude/array';
 import XSub from './note.sub.vue';
@@ -124,14 +122,6 @@ import { noteActions, noteViewInterruptors } from '@client/store';
 import { reactionPicker } from '@client/scripts/reaction-picker';
 import { extractUrlFromMfm } from '@/misc/extract-url-from-mfm';
 
-function markRawAll(...xs) {
-	for (const x of xs) {
-		markRaw(x);
-	}
-}
-
-markRawAll(faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish);
-
 export default defineComponent({
 	components: {
 		XSub,
@@ -174,7 +164,6 @@ export default defineComponent({
 			isDeleted: false,
 			muted: false,
 			operating: false,
-			faEdit, faBolt, faTimes, faBullhorn, faPlus, faMinus, faRetweet, faReply, faReplyAll, faEllipsisH, faHome, faUnlock, faEnvelope, faThumbtack, faBan, faBiohazard, faPlug, faSatelliteDish
 		};
 	},
 
@@ -445,7 +434,7 @@ export default defineComponent({
 			this.blur();
 			os.modalMenu([{
 				text: this.$ts.renote,
-				icon: faRetweet,
+				icon: 'fas fa-retweet',
 				action: () => {
 					os.api('notes/create', {
 						renoteId: this.appearNote.id
@@ -453,7 +442,7 @@ export default defineComponent({
 				}
 			}, {
 				text: this.$ts.quote,
-				icon: faQuoteRight,
+				icon: 'fas fa-quote-right',
 				action: () => {
 					os.post({
 						renote: this.appearNote,
@@ -593,62 +582,62 @@ export default defineComponent({
 				});
 
 				menu = [{
-					icon: faCopy,
+					icon: 'fas fa-copy',
 					text: this.$ts.copyContent,
 					action: this.copyContent
 				}, {
-					icon: faLink,
+					icon: 'fas fa-link',
 					text: this.$ts.copyLink,
 					action: this.copyLink
 				}, (this.appearNote.url || this.appearNote.uri) ? {
-					icon: faExternalLinkSquareAlt,
+					icon: 'fas fa-external-link-square-alt',
 					text: this.$ts.showOnRemote,
 					action: () => {
 						window.open(this.appearNote.url || this.appearNote.uri, '_blank');
 					}
 				} : undefined,
 				{
-					icon: faShareAlt,
+					icon: 'fas fa-share-alt',
 					text: this.$ts.share,
 					action: this.share
 				},
 				null,
 				statePromise.then(state => state.isFavorited ? {
-					icon: faStar,
+					icon: 'fas fa-star',
 					text: this.$ts.unfavorite,
 					action: () => this.toggleFavorite(false)
 				} : {
-					icon: faStar,
+					icon: 'fas fa-star',
 					text: this.$ts.favorite,
 					action: () => this.toggleFavorite(true)
 				}),
 				{
-					icon: faPaperclip,
+					icon: 'fas fa-paperclip',
 					text: this.$ts.clip,
 					action: () => this.clip()
 				},
 				(this.appearNote.userId != this.$i.id) ? statePromise.then(state => state.isWatching ? {
-					icon: faEyeSlash,
+					icon: 'fas fa-eye-slash',
 					text: this.$ts.unwatch,
 					action: () => this.toggleWatch(false)
 				} : {
-					icon: faEye,
+					icon: 'fas fa-eye',
 					text: this.$ts.watch,
 					action: () => this.toggleWatch(true)
 				}) : undefined,
 				this.appearNote.userId == this.$i.id ? (this.$i.pinnedNoteIds || []).includes(this.appearNote.id) ? {
-					icon: faThumbtack,
+					icon: 'fas fa-thumbtack',
 					text: this.$ts.unpin,
 					action: () => this.togglePin(false)
 				} : {
-					icon: faThumbtack,
+					icon: 'fas fa-thumbtack',
 					text: this.$ts.pin,
 					action: () => this.togglePin(true)
 				} : undefined,
 				...(this.$i.isModerator || this.$i.isAdmin ? [
 					null,
 					{
-						icon: faBullhorn,
+						icon: 'fas fa-bullhorn',
 						text: this.$ts.promote,
 						action: this.promote
 					}]
@@ -657,7 +646,7 @@ export default defineComponent({
 				...(this.appearNote.userId != this.$i.id ? [
 					null,
 					{
-						icon: faExclamationCircle,
+						icon: 'fas fa-exclamation-circle',
 						text: this.$ts.reportAbuse,
 						action: () => {
 							const u = `${url}/notes/${this.appearNote.id}`;
@@ -672,12 +661,12 @@ export default defineComponent({
 				...(this.appearNote.userId == this.$i.id || this.$i.isModerator || this.$i.isAdmin ? [
 					null,
 					this.appearNote.userId == this.$i.id ? {
-						icon: faEdit,
+						icon: 'fas fa-edit',
 						text: this.$ts.deleteAndEdit,
 						action: this.delEdit
 					} : undefined,
 					{
-						icon: faTrashAlt,
+						icon: 'fas fa-trash-alt',
 						text: this.$ts.delete,
 						danger: true,
 						action: this.del
@@ -687,15 +676,15 @@ export default defineComponent({
 				.filter(x => x !== undefined);
 			} else {
 				menu = [{
-					icon: faCopy,
+					icon: 'fas fa-copy',
 					text: this.$ts.copyContent,
 					action: this.copyContent
 				}, {
-					icon: faLink,
+					icon: 'fas fa-link',
 					text: this.$ts.copyLink,
 					action: this.copyLink
 				}, (this.appearNote.url || this.appearNote.uri) ? {
-					icon: faExternalLinkSquareAlt,
+					icon: 'fas fa-external-link-square-alt',
 					text: this.$ts.showOnRemote,
 					action: () => {
 						window.open(this.appearNote.url || this.appearNote.uri, '_blank');
@@ -706,7 +695,7 @@ export default defineComponent({
 
 			if (noteActions.length > 0) {
 				menu = menu.concat([null, ...noteActions.map(action => ({
-					icon: faPlug,
+					icon: 'fas fa-plug',
 					text: action.title,
 					action: () => {
 						action.handler(this.appearNote);
@@ -749,7 +738,7 @@ export default defineComponent({
 			if (!this.isMyRenote) return;
 			os.modalMenu([{
 				text: this.$ts.unrenote,
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				danger: true,
 				action: () => {
 					os.api('notes/delete', {
@@ -792,7 +781,7 @@ export default defineComponent({
 		async clip() {
 			const clips = await os.api('clips/list');
 			os.modalMenu([{
-				icon: faPlus,
+				icon: 'fas fa-plus',
 				text: this.$ts.createNew,
 				action: async () => {
 					const { canceled, result } = await os.form(this.$ts.createNewClip, {
@@ -914,7 +903,7 @@ export default defineComponent({
 		white-space: pre;
 		color: #d28a3f;
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 		}
 
@@ -952,7 +941,7 @@ export default defineComponent({
 			border-radius: 6px;
 		}
 
-		> [data-icon] {
+		> i {
 			margin-right: 4px;
 		}
 
diff --git a/src/client/ui/chat/post-form.vue b/src/client/ui/chat/post-form.vue
index a9413ea8bc83a05edcccd13e80f23c9acf3de10e..6030166fc5a06a2e9f711399110b7a52536ad3ef 100644
--- a/src/client/ui/chat/post-form.vue
+++ b/src/client/ui/chat/post-form.vue
@@ -6,15 +6,15 @@
 	@drop.stop="onDrop"
 >
 	<div class="form">
-		<div class="with-quote" v-if="quoteId"><Fa icon="quote-left"/> {{ $ts.quoteAttached }}<button @click="quoteId = null"><Fa icon="times"/></button></div>
+		<div class="with-quote" v-if="quoteId"><i class="fas fa-quote-left"></i> {{ $ts.quoteAttached }}<button @click="quoteId = null"><i class="fas fa-times"></i></button></div>
 		<div v-if="visibility === 'specified'" class="to-specified">
 			<span style="margin-right: 8px;">{{ $ts.recipient }}</span>
 			<div class="visibleUsers">
 				<span v-for="u in visibleUsers" :key="u.id">
 					<MkAcct :user="u"/>
-					<button class="_button" @click="removeVisibleUser(u)"><Fa :icon="faTimes"/></button>
+					<button class="_button" @click="removeVisibleUser(u)"><i class="fas fa-times"></i></button>
 				</span>
-				<button @click="addVisibleUser" class="_buttonPrimary"><Fa :icon="faPlus" fixed-width/></button>
+				<button @click="addVisibleUser" class="_buttonPrimary"><i class="fas fa-plus fa-fw"></i></button>
 			</div>
 		</div>
 		<input v-show="useCw" ref="cw" class="cw" v-model="cw" :placeholder="$ts.annotation" @keydown="onKeydown">
@@ -23,23 +23,23 @@
 		<XPollEditor v-if="poll" :poll="poll" @destroyed="poll = null" @updated="onPollUpdate"/>
 		<footer>
 			<div class="left">
-				<button class="_button" @click="chooseFileFrom" v-tooltip="$ts.attachFile"><Fa :icon="faPhotoVideo"/></button>
-				<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><Fa :icon="faPollH"/></button>
-				<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$ts.useCw"><Fa :icon="faEyeSlash"/></button>
-				<button class="_button" @click="insertMention" v-tooltip="$ts.mention"><Fa :icon="faAt"/></button>
-				<button class="_button" @click="insertEmoji" v-tooltip="$ts.emoji"><Fa :icon="faLaughSquint"/></button>
-				<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><Fa :icon="faPlug"/></button>
+				<button class="_button" @click="chooseFileFrom" v-tooltip="$ts.attachFile"><i class="fas fa-photo-video"></i></button>
+				<button class="_button" @click="togglePoll" :class="{ active: poll }" v-tooltip="$ts.poll"><i class="fas fa-poll-h"></i></button>
+				<button class="_button" @click="useCw = !useCw" :class="{ active: useCw }" v-tooltip="$ts.useCw"><i class="fas fa-eye-slash"></i></button>
+				<button class="_button" @click="insertMention" v-tooltip="$ts.mention"><i class="fas fa-at"></i></button>
+				<button class="_button" @click="insertEmoji" v-tooltip="$ts.emoji"><i class="fas fa-laugh-squint"></i></button>
+				<button class="_button" @click="showActions" v-tooltip="$ts.plugin" v-if="postFormActions.length > 0"><i class="fas fa-plug"></i></button>
 			</div>
 			<div class="right">
 				<span class="text-count" :class="{ over: textLength > max }">{{ max - textLength }}</span>
-				<span class="local-only" v-if="localOnly"><Fa :icon="faBiohazard"/></span>
+				<span class="local-only" v-if="localOnly"><i class="fas fa-biohazard"></i></span>
 				<button class="_button visibility" @click="setVisibility" ref="visibilityButton" v-tooltip="$ts.visibility" :disabled="channel != null">
-					<span v-if="visibility === 'public'"><Fa :icon="faGlobe"/></span>
-					<span v-if="visibility === 'home'"><Fa :icon="faHome"/></span>
-					<span v-if="visibility === 'followers'"><Fa :icon="faUnlock"/></span>
-					<span v-if="visibility === 'specified'"><Fa :icon="faEnvelope"/></span>
+					<span v-if="visibility === 'public'"><i class="fas fa-globe"></i></span>
+					<span v-if="visibility === 'home'"><i class="fas fa-home"></i></span>
+					<span v-if="visibility === 'followers'"><i class="fas fa-unlock"></i></span>
+					<span v-if="visibility === 'specified'"><i class="fas fa-envelope"></i></span>
 				</button>
-				<button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<Fa :icon="reply ? faReply : renote ? faQuoteRight : faPaperPlane"/></button>
+				<button class="submit _buttonPrimary" :disabled="!canPost" @click="post">{{ submitText }}<i :class="reply ? 'fas fa-reply' : renote ? 'fas fa-quote-right' : 'fas fa-paper-plane'"></i></button>
 			</div>
 		</footer>
 	</div>
@@ -48,8 +48,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faPlus, faPhotoVideo, faAt, faBiohazard, faPlug } from '@fortawesome/free-solid-svg-icons';
-import { faEyeSlash, faLaughSquint } from '@fortawesome/free-regular-svg-icons';
 import insertTextAtCursor from 'insert-text-at-cursor';
 import { length } from 'stringz';
 import { toASCII } from 'punycode/';
@@ -138,7 +136,6 @@ export default defineComponent({
 				}
 			}),
 			postFormActions,
-			faReply, faQuoteRight, faPaperPlane, faTimes, faUpload, faPollH, faGlobe, faHome, faUnlock, faEnvelope, faEyeSlash, faLaughSquint, faPlus, faPhotoVideo, faAt, faBiohazard, faPlug
 		};
 	},
 
@@ -767,7 +764,7 @@ export default defineComponent({
 						opacity: 0.7;
 					}
 
-					> [data-icon] {
+					> i {
 						margin-left: 6px;
 					}
 				}
diff --git a/src/client/ui/chat/side.vue b/src/client/ui/chat/side.vue
index 2f182175ba8f47a4acc47c891f99e5cdfb87161e..8cc69fee8ce5b8a7c1bd0e2a53588da8c04d2c06 100644
--- a/src/client/ui/chat/side.vue
+++ b/src/client/ui/chat/side.vue
@@ -1,9 +1,9 @@
 <template>
 <div class="mrajymqm _narrow_" v-if="component">
 	<header class="header" @contextmenu.prevent.stop="onContextmenu">
-		<button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button>
+		<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
 		<XHeader class="title" :info="pageInfo" :with-back="false" :center="false"/>
-		<button class="_button" @click="close()"><Fa :icon="faTimes"/></button>
+		<button class="_button" @click="close()"><i class="fas fa-times"></i></button>
 	</header>
 	<component :is="component" v-bind="props" :ref="changePage"/>
 </div>
@@ -11,7 +11,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTimes, faChevronLeft, faExpandAlt, faWindowMaximize, faExternalLinkAlt, faLink } from '@fortawesome/free-solid-svg-icons';
 import XHeader from '../_common_/header.vue';
 import * as os from '@client/os';
 import copyToClipboard from '@client/scripts/copy-to-clipboard';
@@ -39,7 +38,6 @@ export default defineComponent({
 			props: {},
 			pageInfo: null,
 			history: [],
-			faTimes, faChevronLeft,
 		};
 	},
 
@@ -82,28 +80,28 @@ export default defineComponent({
 				type: 'label',
 				text: this.path,
 			}, {
-				icon: faExpandAlt,
+				icon: 'fas fa-expand-alt',
 				text: this.$ts.showInPage,
 				action: () => {
 					this.$router.push(this.path);
 					this.close();
 				}
 			}, {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts.openInWindow,
 				action: () => {
 					os.pageWindow(this.path);
 					this.close();
 				}
 			}, null, {
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				text: this.$ts.openInNewTab,
 				action: () => {
 					window.open(this.url, '_blank');
 					this.close();
 				}
 			}, {
-				icon: faLink,
+				icon: 'fas fa-link',
 				text: this.$ts.copyLink,
 				action: () => {
 					copyToClipboard(this.url);
diff --git a/src/client/ui/chat/sub-note-content.vue b/src/client/ui/chat/sub-note-content.vue
index e530a88172e94f946808e34e435cd2634b598f2c..8a3cf1160f648331715bd3d5a2ee29f9becc24e2 100644
--- a/src/client/ui/chat/sub-note-content.vue
+++ b/src/client/ui/chat/sub-note-content.vue
@@ -3,7 +3,7 @@
 	<div class="body">
 		<span v-if="note.isHidden" style="opacity: 0.5">({{ $ts.private }})</span>
 		<span v-if="note.deletedAt" style="opacity: 0.5">({{ $ts.deleted }})</span>
-		<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><Fa :icon="faReply"/></MkA>
+		<MkA class="reply" v-if="note.replyId" :to="`/notes/${note.replyId}`"><i class="fas fa-reply"></i></MkA>
 		<Mfm v-if="note.text" :text="note.text" :author="note.user" :i="$i" :custom-emojis="note.emojis"/>
 		<MkA class="rp" v-if="note.renoteId" :to="`/notes/${note.renoteId}`">RN: ...</MkA>
 	</div>
@@ -20,7 +20,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faReply } from '@fortawesome/free-solid-svg-icons';
 import XPoll from '@client/components/poll.vue';
 import XMediaList from '@client/components/media-list.vue';
 import * as os from '@client/os';
@@ -38,7 +37,6 @@ export default defineComponent({
 	},
 	data() {
 		return {
-			faReply
 		};
 	}
 });
diff --git a/src/client/ui/deck.vue b/src/client/ui/deck.vue
index 0429dbc9b13cdd8c37e9b21f6fe67fc794f34ade..935445a54db66591dc582a16400347efa8c3538c 100644
--- a/src/client/ui/deck.vue
+++ b/src/client/ui/deck.vue
@@ -22,8 +22,8 @@
 		/>
 	</template>
 
-	<button v-if="$i" class="nav _button" @click="showNav()"><Fa :icon="faBars"/><i v-if="navIndicated"><Fa :icon="faCircle"/></i></button>
-	<button v-if="$i" class="post _buttonPrimary" @click="post()"><Fa :icon="faPencilAlt"/></button>
+	<button v-if="$i" class="nav _button" @click="showNav()"><i class="fas fa-bars"></i><span v-if="navIndicated" class="indicator"><i class="fas fa-circle"></i></span></button>
+	<button v-if="$i" class="post _buttonPrimary" @click="post()"><i class="fas fa-pencil-alt"></i></button>
 
 	<XCommon/>
 </div>
@@ -31,8 +31,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faPlus, faPencilAlt, faChevronLeft, faBars, faCircle } from '@fortawesome/free-solid-svg-icons';
-import {  } from '@fortawesome/free-regular-svg-icons';
 import { v4 as uuid } from 'uuid';
 import { host } from '@client/config';
 import DeckColumnCore from '@client/ui/deck/column-core.vue';
@@ -64,7 +62,6 @@ export default defineComponent({
 			host: host,
 			menuDef: sidebarDef,
 			wallpaper: localStorage.getItem('wallpaper') != null,
-			faPlus, faPencilAlt, faChevronLeft, faBars, faCircle
 		};
 	},
 
@@ -219,7 +216,7 @@ export default defineComponent({
 			background: var(--X2);
 		}
 
-		> i {
+		> .indicator {
 			position: absolute;
 			top: 0;
 			left: 0;
diff --git a/src/client/ui/deck/antenna-column.vue b/src/client/ui/deck/antenna-column.vue
index 0de870233a4bae79a01d2c4f94349272f67d9428..3abd3d3a45bac46acf73ff3c2b5f9371c21a9e09 100644
--- a/src/client/ui/deck/antenna-column.vue
+++ b/src/client/ui/deck/antenna-column.vue
@@ -1,7 +1,7 @@
 <template>
 <XColumn :func="{ handler: setAntenna, title: $ts.selectAntenna }" :column="column" :is-stacked="isStacked">
 	<template #header>
-		<Fa :icon="faSatellite"/><span style="margin-left: 8px;">{{ column.name }}</span>
+		<i class="fas fa-satellite"></i><span style="margin-left: 8px;">{{ column.name }}</span>
 	</template>
 
 	<XTimeline v-if="column.antennaId" ref="timeline" src="antenna" :antenna="column.antennaId" @after="() => $emit('loaded')"/>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSatellite, faCog } from '@fortawesome/free-solid-svg-icons';
 import XColumn from './column.vue';
 import XTimeline from '@client/components/timeline.vue';
 import * as os from '@client/os';
@@ -35,7 +34,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faSatellite
 		};
 	},
 
diff --git a/src/client/ui/deck/column.vue b/src/client/ui/deck/column.vue
index 7a08b65a647206aa95f2c4dea1b0fceda03ba784..eaf928069855aa39ae049bd28010bbf81b829ab8 100644
--- a/src/client/ui/deck/column.vue
+++ b/src/client/ui/deck/column.vue
@@ -15,14 +15,14 @@
 		@contextmenu.prevent.stop="onContextmenu"
 	>
 		<button class="toggleActive _button" @click="toggleActive" v-if="isStacked && !isMainColumn">
-			<template v-if="active"><Fa :icon="faAngleUp"/></template>
-			<template v-else><Fa :icon="faAngleDown"/></template>
+			<template v-if="active"><i class="fas fa-angle-up"></i></template>
+			<template v-else><i class="fas fa-angle-down"></i></template>
 		</button>
 		<div class="action">
 			<slot name="action"></slot>
 		</div>
 		<span class="header"><slot name="header"></slot></span>
-		<button v-if="func" class="menu _button" v-tooltip="func.title" @click.stop="func.handler"><Fa :icon="func.icon || faCog"/></button>
+		<button v-if="func" class="menu _button" v-tooltip="func.title" @click.stop="func.handler"><i :class="func.icon || 'fas fa-cog'"></i></button>
 	</header>
 	<div ref="body" v-show="active">
 		<slot></slot>
@@ -32,8 +32,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faArrowUp, faArrowDown, faAngleUp, faAngleDown, faCaretDown, faArrowRight, faArrowLeft, faPencilAlt, faCog } from '@fortawesome/free-solid-svg-icons';
-import { faWindowMaximize, faTrashAlt, faWindowRestore } from '@fortawesome/free-regular-svg-icons';
 import * as os from '@client/os';
 import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from './deck-store';
 import { deckStore } from './deck-store';
@@ -73,7 +71,6 @@ export default defineComponent({
 			dragging: false,
 			draghover: false,
 			dropready: false,
-			faArrowUp, faArrowDown, faAngleUp, faAngleDown, faCaretDown, faCog,
 		};
 	},
 
@@ -134,7 +131,7 @@ export default defineComponent({
 
 		getMenu() {
 			const items = [{
-				icon: faPencilAlt,
+				icon: 'fas fa-pencil-alt',
 				text: this.$ts.edit,
 				action: async () => {
 					const { canceled, result } = await os.form(this.column.name, {
@@ -158,43 +155,43 @@ export default defineComponent({
 					updateColumn(this.column.id, result);
 				}
 			}, null, {
-				icon: faArrowLeft,
+				icon: 'fas fa-arrow-left',
 				text: this.$ts._deck.swapLeft,
 				action: () => {
 					swapLeftColumn(this.column.id);
 				}
 			}, {
-				icon: faArrowRight,
+				icon: 'fas fa-arrow-right',
 				text: this.$ts._deck.swapRight,
 				action: () => {
 					swapRightColumn(this.column.id);
 				}
 			}, this.isStacked ? {
-				icon: faArrowUp,
+				icon: 'fas fa-arrow-up',
 				text: this.$ts._deck.swapUp,
 				action: () => {
 					swapUpColumn(this.column.id);
 				}
 			} : undefined, this.isStacked ? {
-				icon: faArrowDown,
+				icon: 'fas fa-arrow-down',
 				text: this.$ts._deck.swapDown,
 				action: () => {
 					swapDownColumn(this.column.id);
 				}
 			} : undefined, null, {
-				icon: faWindowRestore,
+				icon: 'fas fa-window-restore',
 				text: this.$ts._deck.stackLeft,
 				action: () => {
 					stackLeftColumn(this.column.id);
 				}
 			}, this.isStacked ? {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts._deck.popRight,
 				action: () => {
 					popRightColumn(this.column.id);
 				}
 			} : undefined, null, {
-				icon: faTrashAlt,
+				icon: 'fas fa-trash-alt',
 				text: this.$ts.remove,
 				danger: true,
 				action: () => {
diff --git a/src/client/ui/deck/direct-column.vue b/src/client/ui/deck/direct-column.vue
index 6fceae4ed7ac5815dcd2e49fea0b1398e8ba30b6..5b4b02932b404c7c369dbd65a29ac1cbac70bb6e 100644
--- a/src/client/ui/deck/direct-column.vue
+++ b/src/client/ui/deck/direct-column.vue
@@ -1,6 +1,6 @@
 <template>
 <XColumn :column="column" :is-stacked="isStacked">
-	<template #header><Fa :icon="faEnvelope" style="margin-right: 8px;"/>{{ column.name }}</template>
+	<template #header><i class="fas fa-envelope" style="margin-right: 8px;"></i>{{ column.name }}</template>
 
 	<XNotes :pagination="pagination" @before="before()" @after="after()"/>
 </XColumn>
@@ -8,7 +8,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faEnvelope } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XColumn from './column.vue';
 import XNotes from '@client/components/notes.vue';
@@ -40,7 +39,6 @@ export default defineComponent({
 					visibility: 'specified'
 				})
 			},
-			faEnvelope
 		}
 	},
 
diff --git a/src/client/ui/deck/list-column.vue b/src/client/ui/deck/list-column.vue
index c70abc9f6e466ffaaed2978e26cecb3f9e772f58..450280b863ce3c3c4397443e668f148d5cb6a722 100644
--- a/src/client/ui/deck/list-column.vue
+++ b/src/client/ui/deck/list-column.vue
@@ -1,7 +1,7 @@
 <template>
 <XColumn :func="{ handler: setList, title: $ts.selectList }" :column="column" :is-stacked="isStacked">
 	<template #header>
-		<Fa :icon="faListUl"/><span style="margin-left: 8px;">{{ column.name }}</span>
+		<i class="fas fa-list-ul"></i><span style="margin-left: 8px;">{{ column.name }}</span>
 	</template>
 
 	<XTimeline v-if="column.listId" ref="timeline" src="list" :list="column.listId" @after="() => $emit('loaded')"/>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faListUl, faCog } from '@fortawesome/free-solid-svg-icons';
 import XColumn from './column.vue';
 import XTimeline from '@client/components/timeline.vue';
 import * as os from '@client/os';
@@ -35,7 +34,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faListUl
 		};
 	},
 
diff --git a/src/client/ui/deck/main-column.vue b/src/client/ui/deck/main-column.vue
index 2206fa5e13fa413cd0e8c9daf6906d6d792523ee..75cf94aaed9c4a94190cdfb2cdd1b48aa3927554 100644
--- a/src/client/ui/deck/main-column.vue
+++ b/src/client/ui/deck/main-column.vue
@@ -16,7 +16,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faWindowMaximize } from '@fortawesome/free-solid-svg-icons';
 import XColumn from './column.vue';
 import XNotes from '@client/components/notes.vue';
 import XHeader from '@client/ui/_common_/header.vue';
@@ -72,7 +71,7 @@ export default defineComponent({
 				type: 'label',
 				text: path,
 			}, {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts.openInWindow,
 				action: () => {
 					os.pageWindow(path);
diff --git a/src/client/ui/deck/mentions-column.vue b/src/client/ui/deck/mentions-column.vue
index 996123cb1f05815773e9cc3f57235ac8e552855c..053ef918f096dff56058fa3651471a4782f4718b 100644
--- a/src/client/ui/deck/mentions-column.vue
+++ b/src/client/ui/deck/mentions-column.vue
@@ -1,6 +1,6 @@
 <template>
 <XColumn :column="column" :is-stacked="isStacked">
-	<template #header><Fa :icon="faAt" style="margin-right: 8px;"/>{{ column.name }}</template>
+	<template #header><i class="fas fa-at" style="margin-right: 8px;"></i>{{ column.name }}</template>
 
 	<XNotes :pagination="pagination" @before="before()" @after="after()"/>
 </XColumn>
@@ -8,7 +8,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAt } from '@fortawesome/free-solid-svg-icons';
 import Progress from '@client/scripts/loading';
 import XColumn from './column.vue';
 import XNotes from '@client/components/notes.vue';
diff --git a/src/client/ui/deck/notifications-column.vue b/src/client/ui/deck/notifications-column.vue
index 1b29a2d54f00230956adb93ab3f543cb53cf3658..c24bf7ab1029c1523eca9149e41a8948cac76734 100644
--- a/src/client/ui/deck/notifications-column.vue
+++ b/src/client/ui/deck/notifications-column.vue
@@ -1,6 +1,6 @@
 <template>
 <XColumn :column="column" :is-stacked="isStacked" :func="{ handler: func, title: $ts.notificationSetting }">
-	<template #header><Fa :icon="faBell" style="margin-right: 8px;"/>{{ column.name }}</template>
+	<template #header><i class="fas fa-bell" style="margin-right: 8px;"></i>{{ column.name }}</template>
 
 	<XNotifications :include-types="column.includingTypes"/>
 </XColumn>
@@ -8,8 +8,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCog } from '@fortawesome/free-solid-svg-icons';
-import { faBell } from '@fortawesome/free-regular-svg-icons';
 import XColumn from './column.vue';
 import XNotifications from '@client/components/notifications.vue';
 import * as os from '@client/os';
@@ -34,7 +32,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBell
 		}
 	},
 
diff --git a/src/client/ui/deck/tl-column.vue b/src/client/ui/deck/tl-column.vue
index d4908d0edfae2bff82604ad6a459284e0b08294c..370f7d507f2400cf61c584f824f9aa884450bb7e 100644
--- a/src/client/ui/deck/tl-column.vue
+++ b/src/client/ui/deck/tl-column.vue
@@ -1,16 +1,16 @@
 <template>
 <XColumn :func="{ handler: setType, title: $ts.timeline }" :column="column" :is-stacked="isStacked" :indicated="indicated" @change-active-state="onChangeActiveState">
 	<template #header>
-		<Fa v-if="column.tl === 'home'" :icon="faHome"/>
-		<Fa v-else-if="column.tl === 'local'" :icon="faComments"/>
-		<Fa v-else-if="column.tl === 'social'" :icon="faShareAlt"/>
-		<Fa v-else-if="column.tl === 'global'" :icon="faGlobe"/>
+		<i v-if="column.tl === 'home'" class="fas fa-home"></i>
+		<i v-else-if="column.tl === 'local'" class="fas fa-comments"></i>
+		<i v-else-if="column.tl === 'social'" class="fas fa-share-alt"></i>
+		<i v-else-if="column.tl === 'global'" class="fas fa-globe"></i>
 		<span style="margin-left: 8px;">{{ column.name }}</span>
 	</template>
 
 	<div class="iwaalbte" v-if="disabled">
 		<p>
-			<Fa :icon="faMinusCircle"/>
+			<i class="fas fa-minus-circle"></i>
 			{{ $t('disabled-timeline.title') }}
 		</p>
 		<p class="desc">{{ $t('disabled-timeline.description') }}</p>
@@ -21,7 +21,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faMinusCircle, faHome, faComments, faShareAlt, faGlobe, faCog } from '@fortawesome/free-solid-svg-icons';
 import XColumn from './column.vue';
 import XTimeline from '@client/components/timeline.vue';
 import * as os from '@client/os';
@@ -49,7 +48,6 @@ export default defineComponent({
 			disabled: false,
 			indicated: false,
 			columnActive: true,
-			faMinusCircle, faHome, faComments, faShareAlt, faGlobe,
 		};
 	},
 
diff --git a/src/client/ui/deck/widgets-column.vue b/src/client/ui/deck/widgets-column.vue
index 992845ff7eacb029d7788789d4c4b8c4cb34af25..47d7e7e314fd81a48308f82550ebf193481ec0e4 100644
--- a/src/client/ui/deck/widgets-column.vue
+++ b/src/client/ui/deck/widgets-column.vue
@@ -1,6 +1,6 @@
 <template>
 <XColumn :func="{ handler: func, title: $ts.editWidgets }" :naked="true" :column="column" :is-stacked="isStacked">
-	<template #header><Fa :icon="faWindowMaximize" style="margin-right: 8px;"/>{{ column.name }}</template>
+	<template #header><i class="fas fa-window-maximize" style="margin-right: 8px;"></i>{{ column.name }}</template>
 
 	<div class="wtdtxvec">
 		<XWidgets :edit="edit" :widgets="column.widgets" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="edit = false"/>
@@ -10,7 +10,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faWindowMaximize, faTimes, faCog, faPlus } from '@fortawesome/free-solid-svg-icons';
 import XWidgets from '@client/components/widgets.vue';
 import XColumn from './column.vue';
 import { addColumnWidget, removeColumnWidget, setColumnWidgets, updateColumnWidget } from './deck-store';
@@ -35,7 +34,6 @@ export default defineComponent({
 	data() {
 		return {
 			edit: false,
-			faWindowMaximize, faTimes, faPlus
 		};
 	},
 
diff --git a/src/client/ui/default.side.vue b/src/client/ui/default.side.vue
index 89b648244fbbeae7ff13039597870758d0d911a7..5c8de80378bd4cdb2daff3ae645dfba34a7c55c7 100644
--- a/src/client/ui/default.side.vue
+++ b/src/client/ui/default.side.vue
@@ -2,10 +2,10 @@
 <div class="qvzfzxam _narrow_" v-if="component">
 	<div class="container">
 		<header class="header" @contextmenu.prevent.stop="onContextmenu">
-			<button class="_button" @click="back()" v-if="history.length > 0"><Fa :icon="faChevronLeft"/></button>
+			<button class="_button" @click="back()" v-if="history.length > 0"><i class="fas fa-chevron-left"></i></button>
 			<button class="_button" style="pointer-events: none;" v-else><!-- マージンのバランスを取るためのダミー --></button>
 			<XHeader class="title" :info="pageInfo" :with-back="false"/>
-			<button class="_button" @click="close()"><Fa :icon="faTimes"/></button>
+			<button class="_button" @click="close()"><i class="fas fa-times"></i></button>
 		</header>
 		<component :is="component" v-bind="props" :ref="changePage"/>
 	</div>
@@ -14,7 +14,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTimes, faChevronLeft, faExpandAlt, faWindowMaximize, faExternalLinkAlt, faLink } from '@fortawesome/free-solid-svg-icons';
 import XHeader from './_common_/header.vue';
 import * as os from '@client/os';
 import copyToClipboard from '@client/scripts/copy-to-clipboard';
@@ -42,7 +41,6 @@ export default defineComponent({
 			props: {},
 			pageInfo: null,
 			history: [],
-			faTimes, faChevronLeft,
 		};
 	},
 
@@ -83,28 +81,28 @@ export default defineComponent({
 				type: 'label',
 				text: this.path,
 			}, {
-				icon: faExpandAlt,
+				icon: 'fas fa-expand-alt',
 				text: this.$ts.showInPage,
 				action: () => {
 					this.$router.push(this.path);
 					this.close();
 				}
 			}, {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts.openInWindow,
 				action: () => {
 					os.pageWindow(this.path);
 					this.close();
 				}
 			}, null, {
-				icon: faExternalLinkAlt,
+				icon: 'fas fa-external-link-alt',
 				text: this.$ts.openInNewTab,
 				action: () => {
 					window.open(this.url, '_blank');
 					this.close();
 				}
 			}, {
-				icon: faLink,
+				icon: 'fas fa-link',
 				text: this.$ts.copyLink,
 				action: () => {
 					copyToClipboard(this.url);
diff --git a/src/client/ui/default.sidebar.vue b/src/client/ui/default.sidebar.vue
index 3e956679cd18e81ee406085d18b47a6c946b5822..a55a1770ff8907752c07b797fa644b7cdcea1a66 100644
--- a/src/client/ui/default.sidebar.vue
+++ b/src/client/ui/default.sidebar.vue
@@ -1,34 +1,34 @@
 <template>
 <div class="npcljfve" :class="{ iconOnly }">
-	<button class="item _button account" @click="openAccountMenu">
+	<button class="item _button account" @click="openAccountMenu" v-click-anime>
 		<MkAvatar :user="$i" class="avatar"/><MkAcct class="text" :user="$i"/>
 	</button>
 	<div class="post" @click="post">
 		<MkButton class="button" primary full>
-			<Fa :icon="faPencilAlt" fixed-width/><span class="text" v-if="!iconOnly">{{ $ts.note }}</span>
+			<i class="fas fa-pencil-alt fa-fw"></i><span class="text" v-if="!iconOnly">{{ $ts.note }}</span>
 		</MkButton>
 	</div>
 	<div class="divider"></div>
-	<MkA class="item index" active-class="active" to="/" exact>
-		<Fa :icon="faHome" fixed-width/><span class="text">{{ $ts.timeline }}</span>
+	<MkA class="item index" active-class="active" to="/" exact v-click-anime>
+		<i class="fas fa-home fa-fw"></i><span class="text">{{ $ts.timeline }}</span>
 	</MkA>
 	<template v-for="item in menu">
 		<div v-if="item === '-'" class="divider"></div>
-		<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'MkA' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to">
-			<Fa :icon="menuDef[item].icon" fixed-width/><span class="text">{{ $ts[menuDef[item].title] }}</span>
-			<i v-if="menuDef[item].indicated"><Fa :icon="faCircle"/></i>
+		<component v-else-if="menuDef[item] && (menuDef[item].show !== false)" :is="menuDef[item].to ? 'MkA' : 'button'" class="item _button" :class="item" active-class="active" v-on="menuDef[item].action ? { click: menuDef[item].action } : {}" :to="menuDef[item].to" v-click-anime>
+			<i class="fa-fw" :class="menuDef[item].icon"></i><span class="text">{{ $ts[menuDef[item].title] }}</span>
+			<span v-if="menuDef[item].indicated" class="indicator"><i class="fas fa-circle"></i></span>
 		</component>
 	</template>
 	<div class="divider"></div>
-	<button class="item _button" :class="{ active: $route.path === '/instance' || $route.path.startsWith('/instance/') }" v-if="$i.isAdmin || $i.isModerator" @click="oepnInstanceMenu">
-		<Fa :icon="faServer" fixed-width/><span class="text">{{ $ts.instance }}</span>
-	</button>
-	<button class="item _button" @click="more">
-		<Fa :icon="faEllipsisH" fixed-width/><span class="text">{{ $ts.more }}</span>
-		<i v-if="otherNavItemIndicated"><Fa :icon="faCircle"/></i>
+	<MkA v-if="$i.isAdmin || $i.isModerator" class="item" active-class="active" to="/instance" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime>
+		<i class="fas fa-server fa-fw"></i><span class="text">{{ $ts.instance }}</span>
+	</MkA>
+	<button class="item _button" @click="more" v-click-anime>
+		<i class="fas fa-ellipsis-h fa-fw"></i><span class="text">{{ $ts.more }}</span>
+		<span v-if="otherNavItemIndicated" class="indicator"><i class="fas fa-circle"></i></span>
 	</button>
-	<MkA class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null">
-		<Fa :icon="faCog" fixed-width/><span class="text">{{ $ts.settings }}</span>
+	<MkA class="item" active-class="active" to="/settings" :behavior="settingsWindowed ? 'modalWindow' : null" v-click-anime>
+		<i class="fas fa-cog fa-fw"></i><span class="text">{{ $ts.settings }}</span>
 	</MkA>
 	<div class="divider"></div>
 	<div class="foo">
@@ -40,8 +40,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faGripVertical, faChevronLeft, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faListUl, faPlus, faUserClock, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faInfoCircle, faQuestionCircle, faProjectDiagram, faStream, faExclamationCircle } from '@fortawesome/free-solid-svg-icons';
-import { faBell, faEnvelope, faLaugh, faComments } from '@fortawesome/free-regular-svg-icons';
 import { host } from '@client/config';
 import { search } from '@client/scripts/search';
 import * as os from '@client/os';
@@ -65,7 +63,6 @@ export default defineComponent({
 			menuDef: sidebarDef,
 			iconOnly: false,
 			settingsWindowed: false,
-			faGripVertical, faChevronLeft, faComments, faHashtag, faBroadcastTower, faFireAlt, faEllipsisH, faPencilAlt, faBars, faTimes, faBell, faSearch, faUserCog, faCog, faUser, faHome, faStar, faCircle, faAt, faEnvelope, faListUl, faPlus, faUserClock, faLaugh, faUsers, faTachometerAlt, faExchangeAlt, faGlobe, faChartBar, faCloud, faServer, faProjectDiagram
 		};
 	},
 
@@ -143,12 +140,12 @@ export default defineComponent({
 				to: `/@${ this.$i.username }`,
 				avatar: this.$i,
 			}, null, ...accountItemPromises, {
-				icon: faPlus,
-				text: this.$ts.addAcount,
+				icon: 'fas fa-plus',
+				text: this.$ts.addAccount,
 				action: () => {
 					os.modalMenu([{
-						text: this.$ts.existingAcount,
-						action: () => { this.addAcount(); },
+						text: this.$ts.existingAccount,
+						action: () => { this.addAccount(); },
 					}, {
 						text: this.$ts.createAccount,
 						action: () => { this.createAccount(); },
@@ -159,71 +156,12 @@ export default defineComponent({
 			});
 		},
 
-		oepnInstanceMenu(ev) {
-			os.modalMenu([{
-				type: 'link',
-				text: this.$ts.dashboard,
-				to: '/instance',
-				icon: faTachometerAlt,
-			}, null, this.$i.isAdmin ? {
-				type: 'link',
-				text: this.$ts.settings,
-				to: '/instance/settings',
-				icon: faCog,
-			} : undefined, {
-				type: 'link',
-				text: this.$ts.customEmojis,
-				to: '/instance/emojis',
-				icon: faLaugh,
-			}, {
-				type: 'link',
-				text: this.$ts.users,
-				to: '/instance/users',
-				icon: faUsers,
-			}, {
-				type: 'link',
-				text: this.$ts.files,
-				to: '/instance/files',
-				icon: faCloud,
-			}, {
-				type: 'link',
-				text: this.$ts.jobQueue,
-				to: '/instance/queue',
-				icon: faExchangeAlt,
-			}, {
-				type: 'link',
-				text: this.$ts.federation,
-				to: '/instance/federation',
-				icon: faGlobe,
-			}, {
-				type: 'link',
-				text: this.$ts.relays,
-				to: '/instance/relays',
-				icon: faProjectDiagram,
-			}, {
-				type: 'link',
-				text: this.$ts.announcements,
-				to: '/instance/announcements',
-				icon: faBroadcastTower,
-			}, {
-				type: 'link',
-				text: this.$ts.abuseReports,
-				to: '/instance/abuses',
-				icon: faExclamationCircle,
-			}, {
-				type: 'link',
-				text: this.$ts.logs,
-				to: '/instance/logs',
-				icon: faStream,
-			}], ev.currentTarget || ev.target);
-		},
-
 		more(ev) {
 			os.popup(import('@client/components/launch-pad.vue'), {}, {
 			}, 'closed');
 		},
 
-		addAcount() {
+		addAccount() {
 			os.popup(import('@client/components/signin-dialog.vue'), {}, {
 				done: res => {
 					addAccount(res.id, res.i);
@@ -289,7 +227,7 @@ export default defineComponent({
 			font-size: $ui-font-size * 1.1;
 			line-height: 3.7rem;
 
-			> [data-icon],
+			> i,
 			> .avatar {
 				margin-right: 0;
 			}
@@ -344,11 +282,11 @@ export default defineComponent({
 		text-align: left;
 		box-sizing: border-box;
 
-		> [data-icon] {
+		> i {
 			width: 32px;
 		}
 
-		> [data-icon],
+		> i,
 		> .avatar {
 			margin-right: $avatar-margin;
 		}
@@ -359,7 +297,7 @@ export default defineComponent({
 			vertical-align: middle;
 		}
 
-		> i {
+		> .indicator {
 			position: absolute;
 			top: 0;
 			left: 20px;
diff --git a/src/client/ui/default.vue b/src/client/ui/default.vue
index c3dce0f3230c7e405317a9a64b544f1ee33c9123..0cc969272ae9c4b6c1b6e3a36eb56b15da065d57 100644
--- a/src/client/ui/default.vue
+++ b/src/client/ui/default.vue
@@ -26,11 +26,11 @@
 	</div>
 
 	<div class="buttons" v-if="isMobile">
-		<button class="button nav _button" @click="showDrawerNav" ref="navButton"><Fa :icon="faBars"/><i v-if="navIndicated"><Fa :icon="faCircle"/></i></button>
-		<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><Fa :icon="faHome"/></button>
-		<button class="button notifications _button" @click="$router.push('/my/notifications')"><Fa :icon="faBell"/><i v-if="$i.hasUnreadNotification"><Fa :icon="faCircle"/></i></button>
-		<button class="button widget _button" @click="widgetsShowing = true"><Fa :icon="faLayerGroup"/></button>
-		<button class="button post _button" @click="post"><Fa :icon="faPencilAlt"/></button>
+		<button class="button nav _button" @click="showDrawerNav" ref="navButton"><i class="fas fa-bars"></i><span v-if="navIndicated" class="indicator"><i class="fas fa-circle"></i></span></button>
+		<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><i class="fas fa-home"></i></button>
+		<button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button>
+		<button class="button widget _button" @click="widgetsShowing = true"><i class="fas fa-layer-group"></i></button>
+		<button class="button post _button" @click="post"><i class="fas fa-pencil-alt"></i></button>
 	</div>
 
 	<XDrawerSidebar ref="drawerNav" class="sidebar" v-if="isMobile"/>
@@ -53,8 +53,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faLayerGroup, faBars, faHome, faCircle, faWindowMaximize, faExpand, faPencilAlt, faCompress } from '@fortawesome/free-solid-svg-icons';
-import { faBell } from '@fortawesome/free-regular-svg-icons';
 import { instanceName } from '@client/config';
 import { StickySidebar } from '@client/scripts/sticky-sidebar';
 import XSidebar from './default.sidebar.vue';
@@ -86,7 +84,6 @@ export default defineComponent({
 			widgetsShowing: false,
 			fullView: false,
 			wallpaper: localStorage.getItem('wallpaper') != null,
-			faLayerGroup, faBars, faBell, faHome, faCircle, faPencilAlt,
 		};
 	},
 
@@ -175,13 +172,13 @@ export default defineComponent({
 				type: 'label',
 				text: path,
 			}, {
-				icon: this.fullView ? faCompress : faExpand,
+				icon: this.fullView ? 'fas fa-compress' : 'fas fa-expand',
 				text: this.fullView ? this.$ts.quitFullView : this.$ts.fullView,
 				action: () => {
 					this.fullView = !this.fullView;
 				}
 			}, {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts.openInWindow,
 				action: () => {
 					os.pageWindow(path);
@@ -221,6 +218,8 @@ export default defineComponent({
 	$widgets-hide-threshold: 1200px;
 	$nav-icon-only-width: 78px; // TODO: どこかに集約したい
 
+	--panelShadow: none;
+
 	// ほんとは単に 100vh と書きたいところだが... https://css-tricks.com/the-trick-to-viewport-units-on-mobile/
 	min-height: calc(var(--vh, 1vh) * 100);
 	box-sizing: border-box;
@@ -253,7 +252,7 @@ export default defineComponent({
 		display: flex;
 		justify-content: center;
 		max-width: 100%;
-		margin: 32px 0;
+		//margin: 32px 0;
 
 		&.fullView {
 			margin: 0;
@@ -279,6 +278,8 @@ export default defineComponent({
 			width: 750px;
 			margin: 0 16px 0 0;
 			background: var(--bg);
+			box-shadow: 0 0 0 1px var(--divider);
+			border-radius: 0;
 			--margin: 12px;
 
 			> .header {
@@ -311,12 +312,17 @@ export default defineComponent({
 		> .widgets {
 			//--panelShadow: none;
 			width: 300px;
+			margin-top: 16px;
 
 			@media (max-width: $widgets-hide-threshold) {
 				display: none;
 			}
 		}
 
+		> .sidebar {
+			margin-top: 16px;
+		}
+
 		@media (max-width: 850px) {
 			margin: 0;
 
@@ -372,7 +378,7 @@ export default defineComponent({
 				background: var(--X2);
 			}
 
-			> i {
+			> .indicator {
 				position: absolute;
 				top: 0;
 				left: 0;
diff --git a/src/client/ui/default.widgets.vue b/src/client/ui/default.widgets.vue
index e5a04193872f310c3878b406d4b73276368452a3..cabd83937e837d21bba783ee3e69a4b4a99c3bcd 100644
--- a/src/client/ui/default.widgets.vue
+++ b/src/client/ui/default.widgets.vue
@@ -2,14 +2,13 @@
 <div class="efzpzdvf">
 	<XWidgets class="widgets" :edit="editMode" :widgets="$store.reactiveState.widgets.value" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
 
-	<button v-if="editMode" @click="editMode = false" class="_textButton edit" style="font-size: 0.9em;"><Fa :icon="faCheck"/> {{ $ts.editWidgetsExit }}</button>
-	<button v-else @click="editMode = true" class="_textButton edit" style="font-size: 0.9em;"><Fa :icon="faPencilAlt"/> {{ $ts.editWidgets }}</button>
+	<button v-if="editMode" @click="editMode = false" class="_textButton edit" style="font-size: 0.9em;"><i class="fas fa-check"></i> {{ $ts.editWidgetsExit }}</button>
+	<button v-else @click="editMode = true" class="_textButton edit" style="font-size: 0.9em;"><i class="fas fa-pencil-alt"></i> {{ $ts.editWidgets }}</button>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faPencilAlt, faPlus, faBars, faTimes, faCheck } from '@fortawesome/free-solid-svg-icons';
 import XWidgets from '@client/components/widgets.vue';
 import * as os from '@client/os';
 
@@ -23,7 +22,6 @@ export default defineComponent({
 	data() {
 		return {
 			editMode: false,
-			faPencilAlt, faPlus, faBars, faTimes, faCheck,
 		};
 	},
 
diff --git a/src/client/ui/universal.vue b/src/client/ui/universal.vue
index 6df09937dff53c8d7d09fde73849d8e0cf1602bf..a44dfc42f00f0be358d887e528cf5fb27d915e25 100644
--- a/src/client/ui/universal.vue
+++ b/src/client/ui/universal.vue
@@ -27,14 +27,14 @@
 	</div>
 
 	<div class="buttons" :class="{ navHidden }">
-		<button class="button nav _button" @click="showNav" ref="navButton"><Fa :icon="faBars"/><i v-if="navIndicated"><Fa :icon="faCircle"/></i></button>
-		<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><Fa :icon="faHome"/></button>
-		<button class="button notifications _button" @click="$router.push('/my/notifications')"><Fa :icon="faBell"/><i v-if="$i.hasUnreadNotification"><Fa :icon="faCircle"/></i></button>
-		<button class="button widget _button" @click="widgetsShowing = true"><Fa :icon="faLayerGroup"/></button>
-		<button class="button post _button" @click="post"><Fa :icon="faPencilAlt"/></button>
+		<button class="button nav _button" @click="showNav" ref="navButton"><i class="fas fa-bars"></i><span v-if="navIndicated" class="indicator"><i class="fas fa-circle"></i></span></button>
+		<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><i class="fas fa-home"></i></button>
+		<button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button>
+		<button class="button widget _button" @click="widgetsShowing = true"><i class="fas fa-layer-group"></i></button>
+		<button class="button post _button" @click="post"><i class="fas fa-pencil-alt"></i></button>
 	</div>
 
-	<button class="widgetButton _button" :class="{ navHidden }" @click="widgetsShowing = true"><Fa :icon="faLayerGroup"/></button>
+	<button class="widgetButton _button" :class="{ navHidden }" @click="widgetsShowing = true"><i class="fas fa-layer-group"></i></button>
 
 	<transition name="tray-back">
 		<div class="tray-back _modalBg"
@@ -54,8 +54,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faLayerGroup, faBars, faHome, faCircle, faWindowMaximize, faColumns, faPencilAlt } from '@fortawesome/free-solid-svg-icons';
-import { faBell } from '@fortawesome/free-regular-svg-icons';
 import { instanceName } from '@client/config';
 import { StickySidebar } from '@client/scripts/sticky-sidebar';
 import XSidebar from '@client/ui/_common_/sidebar.vue';
@@ -93,7 +91,6 @@ export default defineComponent({
 			navHidden: false,
 			widgetsShowing: false,
 			wallpaper: localStorage.getItem('wallpaper') != null,
-			faLayerGroup, faBars, faBell, faHome, faCircle, faPencilAlt,
 		};
 	},
 
@@ -201,13 +198,13 @@ export default defineComponent({
 				type: 'label',
 				text: path,
 			}, {
-				icon: faColumns,
+				icon: 'fas fa-columns',
 				text: this.$ts.openInSideView,
 				action: () => {
 					this.$refs.side.navigate(path);
 				}
 			}, {
-				icon: faWindowMaximize,
+				icon: 'fas fa-window-maximize',
 				text: this.$ts.openInWindow,
 				action: () => {
 					os.pageWindow(path);
@@ -378,7 +375,7 @@ export default defineComponent({
 				background: var(--X2);
 			}
 
-			> i {
+			> .indicator {
 				position: absolute;
 				top: 0;
 				left: 0;
diff --git a/src/client/ui/universal.widgets.vue b/src/client/ui/universal.widgets.vue
index 35d3442bb2f9f9e0be6bdd1676214371cf1ef9df..28b14749d1762c3f1c446a929dc1ca9efb60c85d 100644
--- a/src/client/ui/universal.widgets.vue
+++ b/src/client/ui/universal.widgets.vue
@@ -2,14 +2,13 @@
 <div class="efzpzdvf">
 	<XWidgets :edit="editMode" :widgets="$store.reactiveState.widgets.value" @add-widget="addWidget" @remove-widget="removeWidget" @update-widget="updateWidget" @update-widgets="updateWidgets" @exit="editMode = false"/>
 
-	<button v-if="editMode" @click="editMode = false" class="_textButton" style="font-size: 0.9em;"><Fa :icon="faCheck"/> {{ $ts.editWidgetsExit }}</button>
-	<button v-else @click="editMode = true" class="_textButton" style="font-size: 0.9em;"><Fa :icon="faPencilAlt"/> {{ $ts.editWidgets }}</button>
+	<button v-if="editMode" @click="editMode = false" class="_textButton" style="font-size: 0.9em;"><i class="fas fa-check"></i> {{ $ts.editWidgetsExit }}</button>
+	<button v-else @click="editMode = true" class="_textButton" style="font-size: 0.9em;"><i class="fas fa-pencil-alt"></i> {{ $ts.editWidgets }}</button>
 </div>
 </template>
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faPencilAlt, faPlus, faBars, faTimes, faCheck } from '@fortawesome/free-solid-svg-icons';
 import XWidgets from '@client/components/widgets.vue';
 import * as os from '@client/os';
 
@@ -23,7 +22,6 @@ export default defineComponent({
 	data() {
 		return {
 			editMode: false,
-			faPencilAlt, faPlus, faBars, faTimes, faCheck,
 		};
 	},
 
diff --git a/src/client/ui/visitor/a.vue b/src/client/ui/visitor/a.vue
index 1b080c9e825e3173f920077705666d0b85c384c4..1dcb803eb19df8383661c89e117f701498ce5071 100644
--- a/src/client/ui/visitor/a.vue
+++ b/src/client/ui/visitor/a.vue
@@ -41,7 +41,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { } from '@fortawesome/free-solid-svg-icons';
 import { host, instanceName } from '@client/config';
 import { search } from '@client/scripts/search';
 import * as os from '@client/os';
diff --git a/src/client/ui/visitor/b.vue b/src/client/ui/visitor/b.vue
index da2ae4518017989b26761ca7ccefb922faa40cb8..0a70e5e1d1c0996fb99dbda6c1a73cfac183ffe0 100644
--- a/src/client/ui/visitor/b.vue
+++ b/src/client/ui/visitor/b.vue
@@ -35,10 +35,10 @@
 
 	<transition name="tray">
 		<div v-if="showMenu" class="menu">
-			<MkA to="/" class="link" active-class="active"><Fa :icon="faHome" class="icon"/>{{ $ts.home }}</MkA>
-			<MkA to="/explore" class="link" active-class="active"><Fa :icon="faHashtag" class="icon"/>{{ $ts.explore }}</MkA>
-			<MkA to="/featured" class="link" active-class="active"><Fa :icon="faFireAlt" class="icon"/>{{ $ts.featured }}</MkA>
-			<MkA to="/channels" class="link" active-class="active"><Fa :icon="faSatelliteDish" class="icon"/>{{ $ts.channel }}</MkA>
+			<MkA to="/" class="link" active-class="active"><i class="fas fa-home icon"></i>{{ $ts.home }}</MkA>
+			<MkA to="/explore" class="link" active-class="active"><i class="fas fa-hashtag icon"></i>{{ $ts.explore }}</MkA>
+			<MkA to="/featured" class="link" active-class="active"><i class="fas fa-fire-alt icon"></i>{{ $ts.featured }}</MkA>
+			<MkA to="/channels" class="link" active-class="active"><i class="fas fa-satellite-dish icon"></i>{{ $ts.channel }}</MkA>
 			<div class="action">
 				<button class="_buttonPrimary" @click="signup()">{{ $ts.signup }}</button>
 				<button class="_button" @click="signin()">{{ $ts.login }}</button>
@@ -50,7 +50,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { } from '@fortawesome/free-solid-svg-icons';
 import { host, instanceName } from '@client/config';
 import { search } from '@client/scripts/search';
 import * as os from '@client/os';
diff --git a/src/client/ui/visitor/header.vue b/src/client/ui/visitor/header.vue
index 42598ce1c054b4c144f1cf133b4549289252cbc5..1effadf4f73c642e5d0f98f4d7bd7c317843475d 100644
--- a/src/client/ui/visitor/header.vue
+++ b/src/client/ui/visitor/header.vue
@@ -2,21 +2,21 @@
 <div class="sqxihjet">
 	<div class="wide" v-if="narrow === false">
 		<div class="content">
-			<MkA to="/" class="link" active-class="active"><Fa :icon="faHome" class="icon"/>{{ $ts.home }}</MkA>
-			<MkA to="/explore" class="link" active-class="active"><Fa :icon="faHashtag" class="icon"/>{{ $ts.explore }}</MkA>
-			<MkA to="/featured" class="link" active-class="active"><Fa :icon="faFireAlt" class="icon"/>{{ $ts.featured }}</MkA>
-			<MkA to="/channels" class="link" active-class="active"><Fa :icon="faSatelliteDish" class="icon"/>{{ $ts.channel }}</MkA>
+			<MkA to="/" class="link" active-class="active"><i class="fas fa-home icon"></i>{{ $ts.home }}</MkA>
+			<MkA to="/explore" class="link" active-class="active"><i class="fas fa-hashtag icon"></i>{{ $ts.explore }}</MkA>
+			<MkA to="/featured" class="link" active-class="active"><i class="fas fa-fire-alt icon"></i>{{ $ts.featured }}</MkA>
+			<MkA to="/channels" class="link" active-class="active"><i class="fas fa-satellite-dish icon"></i>{{ $ts.channel }}</MkA>
 			<div class="page active link" v-if="info">
 				<div class="title">
-					<Fa v-if="info.icon" :icon="info.icon" :key="info.icon" class="icon"/>
+					<i v-if="info.icon" class="icon" :class="info.icon"></i>
 					<MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
 					<span v-if="info.title" class="text">{{ info.title }}</span>
 					<MkUserName v-else-if="info.userName" :user="info.userName" :nowrap="false" class="text"/>
 				</div>
-				<button class="_button action" v-if="info.action" @click.stop="info.action.handler"><Fa :icon="info.action.icon" :key="info.action.icon"/></button>
+				<button class="_button action" v-if="info.action" @click.stop="info.action.handler"><!-- TODO --></button>
 			</div>
 			<div class="right">
-				<button class="_button search" @click="search()"><Fa :icon="faSearch" class="icon"/><span>{{ $ts.search }}</span></button>
+				<button class="_button search" @click="search()"><i class="fas fa-search icon"></i><span>{{ $ts.search }}</span></button>
 				<button class="_buttonPrimary signup" @click="signup()">{{ $ts.signup }}</button>
 				<button class="_button login" @click="signin()">{{ $ts.login }}</button>
 			</div>
@@ -24,16 +24,16 @@
 	</div>
 	<div class="narrow" v-else-if="narrow === true">
 		<button class="menu _button" @click="$parent.showMenu = true">
-			<Fa :icon="faBars" class="icon"/>
+			<i class="fas fa-bars icon"></i>
 		</button>
 		<div class="title" v-if="info">
-			<Fa v-if="info.icon" :icon="info.icon" :key="info.icon" class="icon"/>
+			<i v-if="info.icon" class="icon" :class="info.icon"></i>
 			<MkAvatar v-else-if="info.avatar" class="avatar" :user="info.avatar" :disable-preview="true" :show-indicator="true"/>
 			<span v-if="info.title" class="text">{{ info.title }}</span>
 			<MkUserName v-else-if="info.userName" :user="info.userName" :nowrap="false" class="text"/>
 		</div>
 		<button class="action _button" v-if="info && info.action" @click.stop="info.action.handler">
-			<Fa :icon="info.action.icon" :key="info.action.icon" class="icon"/>
+			<!-- TODO -->
 		</button>
 	</div>
 </div>
@@ -41,7 +41,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faSearch, faHome, faFireAlt, faHashtag, faSatelliteDish, faBars } from '@fortawesome/free-solid-svg-icons';
 import XSigninDialog from '@client/components/signin-dialog.vue';
 import XSignupDialog from '@client/components/signup-dialog.vue';
 import * as os from '@client/os';
@@ -58,7 +57,6 @@ export default defineComponent({
 		return {
 			narrow: null,
 			showMenu: false,
-			faSearch, faHome, faFireAlt, faHashtag, faSatelliteDish, faBars,
 		};
 	},
 
diff --git a/src/client/ui/visitor/kanban.vue b/src/client/ui/visitor/kanban.vue
index 2ed8cf4bc03fd6fb5dec35705f3d1437491d377a..ffa7a3d1ff145d4d2ff83858b333c170795e8d3c 100644
--- a/src/client/ui/visitor/kanban.vue
+++ b/src/client/ui/visitor/kanban.vue
@@ -38,7 +38,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { } from '@fortawesome/free-solid-svg-icons';
 import { host, instanceName } from '@client/config';
 import * as os from '@client/os';
 import MkPagination from '@client/components/ui/pagination.vue';
diff --git a/src/client/ui/zen.vue b/src/client/ui/zen.vue
index af3e53225e5ec874c3c84ea82714c478356757b9..6e7382b0d3ed5de103d0f187f2a594846a5dad6a 100644
--- a/src/client/ui/zen.vue
+++ b/src/client/ui/zen.vue
@@ -23,8 +23,6 @@
 
 <script lang="ts">
 import { defineComponent, defineAsyncComponent } from 'vue';
-import { faLayerGroup, faBars, faHome, faCircle } from '@fortawesome/free-solid-svg-icons';
-import { faBell } from '@fortawesome/free-regular-svg-icons';
 import { host } from '@client/config';
 import XHeader from './_common_/header.vue';
 import XCommon from './_common_/common.vue';
@@ -40,7 +38,6 @@ export default defineComponent({
 		return {
 			host: host,
 			pageInfo: null,
-			faLayerGroup, faBars, faBell, faHome, faCircle,
 		};
 	},
 
diff --git a/src/client/widgets/activity.vue b/src/client/widgets/activity.vue
index 9623765e40a9f7f839c310b38adf023f7e0d632d..cc8d4debd099f3e168bf7e93fd1bce2f2f2b3b77 100644
--- a/src/client/widgets/activity.vue
+++ b/src/client/widgets/activity.vue
@@ -1,7 +1,7 @@
 <template>
 <MkContainer :show-header="props.showHeader" :naked="props.transparent">
-	<template #header><Fa :icon="faChartBar"/>{{ $ts._widgets.activity }}</template>
-	<template #func><button @click="toggleView()" class="_button"><Fa :icon="faSort"/></button></template>
+	<template #header><i class="fas fa-chart-bar"></i>{{ $ts._widgets.activity }}</template>
+	<template #func><button @click="toggleView()" class="_button"><i class="fas fa-sort"></i></button></template>
 
 	<div>
 		<MkLoading v-if="fetching"/>
@@ -15,7 +15,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faChartBar, faSort } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import define from './define';
 import XCalendar from './activity.calendar.vue';
@@ -52,7 +51,6 @@ export default defineComponent({
 		return {
 			fetching: true,
 			activity: null,
-			faChartBar, faSort
 		};
 	},
 	mounted() {
diff --git a/src/client/widgets/aiscript.vue b/src/client/widgets/aiscript.vue
index f24e03359399b17fbaf0dcd47307d3d39a8e7a53..2ea6d09ff53f74ed65f59e13eb8cd4d2466d59dc 100644
--- a/src/client/widgets/aiscript.vue
+++ b/src/client/widgets/aiscript.vue
@@ -1,6 +1,6 @@
 <template>
 <MkContainer :show-header="props.showHeader">
-	<template #header><Fa :icon="faTerminal"/>{{ $ts._widgets.aiscript }}</template>
+	<template #header><i class="fas fa-terminal"></i>{{ $ts._widgets.aiscript }}</template>
 
 	<div class="uylguesu _monospace">
 		<textarea v-model="props.script" placeholder="(1 + 1)"></textarea>
@@ -14,7 +14,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faTerminal } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import define from './define';
 import * as os from '@client/os';
@@ -46,7 +45,6 @@ export default defineComponent({
 	data() {
 		return {
 			logs: [],
-			faTerminal
 		};
 	},
 
diff --git a/src/client/widgets/federation.vue b/src/client/widgets/federation.vue
index eb17915f0870b9c921d1c4bfbe98d25a0e66e2a5..3f2e1e691d38dd8e62a47d7eee5644de29927cbf 100644
--- a/src/client/widgets/federation.vue
+++ b/src/client/widgets/federation.vue
@@ -1,6 +1,6 @@
 <template>
 <MkContainer :show-header="props.showHeader" :foldable="foldable" :scrollable="scrollable">
-	<template #header><Fa :icon="faGlobe"/>{{ $ts._widgets.federation }}</template>
+	<template #header><i class="fas fa-globe"></i>{{ $ts._widgets.federation }}</template>
 
 	<div class="wbrkwalb">
 		<MkLoading v-if="fetching"/>
@@ -20,7 +20,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faGlobe } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import define from './define';
 import MkMiniChart from '@client/components/mini-chart.vue';
@@ -58,7 +57,6 @@ export default defineComponent({
 			instances: [],
 			charts: [],
 			fetching: true,
-			faGlobe
 		};
 	},
 	mounted() {
diff --git a/src/client/widgets/job-queue.vue b/src/client/widgets/job-queue.vue
index 007fd412c848204842f2d0f712de57441bdfa58c..31a322e6e2180a4ba092c10628849afe7a6190e7 100644
--- a/src/client/widgets/job-queue.vue
+++ b/src/client/widgets/job-queue.vue
@@ -1,7 +1,7 @@
 <template>
 <div class="mkw-jobQueue _monospace" :class="{ _panel: !props.transparent }">
 	<div class="inbox">
-		<div class="label">Inbox queue<Fa :icon="faExclamationTriangle" v-if="inbox.waiting > 0" class="icon"/></div>
+		<div class="label">Inbox queue<i v-if="inbox.waiting > 0" class="fas fa-exclamation-triangle icon"></i></div>
 		<div class="values">
 			<div>
 				<div>Process</div>
@@ -22,7 +22,7 @@
 		</div>
 	</div>
 	<div class="deliver">
-		<div class="label">Deliver queue<Fa :icon="faExclamationTriangle" v-if="deliver.waiting > 0" class="icon"/></div>
+		<div class="label">Deliver queue<i v-if="deliver.waiting > 0" class="fas fa-exclamation-triangle icon"></i></div>
 		<div class="values">
 			<div>
 				<div>Process</div>
@@ -47,7 +47,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faExclamationTriangle } from '@fortawesome/free-solid-svg-icons';
 import define from './define';
 import * as os from '@client/os';
 import number from '@client/filters/number';
@@ -80,7 +79,6 @@ export default defineComponent({
 				delayed: 0,
 			},
 			prev: {},
-			faExclamationTriangle,
 		};
 	},
 	created() {
diff --git a/src/client/widgets/memo.vue b/src/client/widgets/memo.vue
index c3ab2934a8a7ef7d73f23a2b9780589face290b7..13ab628f24695c639f020695bf4acc5eec515989 100644
--- a/src/client/widgets/memo.vue
+++ b/src/client/widgets/memo.vue
@@ -1,6 +1,6 @@
 <template>
 <MkContainer :show-header="props.showHeader">
-	<template #header><Fa :icon="faStickyNote"/>{{ $ts._widgets.memo }}</template>
+	<template #header><i class="fas fa-sticky-note"></i>{{ $ts._widgets.memo }}</template>
 
 	<div class="otgbylcu">
 		<textarea v-model="text" :placeholder="$ts.placeholder" @input="onChange"></textarea>
@@ -11,7 +11,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faStickyNote } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import define from './define';
 import * as os from '@client/os';
@@ -37,7 +36,6 @@ export default defineComponent({
 			text: null,
 			changed: false,
 			timeoutId: null,
-			faStickyNote
 		};
 	},
 
diff --git a/src/client/widgets/notifications.vue b/src/client/widgets/notifications.vue
index 046556ef1c56781f6a24067cb15af6a3fde11a26..01c76850d8c12ab8123e19a9f9681c0d5f7332b8 100644
--- a/src/client/widgets/notifications.vue
+++ b/src/client/widgets/notifications.vue
@@ -1,7 +1,7 @@
 <template>
 <MkContainer :style="`height: ${props.height}px;`" :show-header="props.showHeader" :scrollable="true">
-	<template #header><Fa :icon="faBell"/>{{ $ts.notifications }}</template>
-	<template #func><button @click="configure()" class="_button"><Fa :icon="faCog"/></button></template>
+	<template #header><i class="fas fa-bell"></i>{{ $ts.notifications }}</template>
+	<template #func><button @click="configure()" class="_button"><i class="fas fa-cog"></i></button></template>
 
 	<div class="_flat_">
 		<XNotifications :include-types="props.includingTypes"/>
@@ -11,7 +11,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faBell, faCog } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import XNotifications from '@client/components/notifications.vue';
 import define from './define';
@@ -46,7 +45,6 @@ export default defineComponent({
 
 	data() {
 		return {
-			faBell, faCog
 		};
 	},
 
diff --git a/src/client/widgets/photos.vue b/src/client/widgets/photos.vue
index f1041b4ec258936e974fe9ed46ecaa828ead220f..65843385b613ed577bdbc8e263e7a24d1f5cfa40 100644
--- a/src/client/widgets/photos.vue
+++ b/src/client/widgets/photos.vue
@@ -1,6 +1,6 @@
 <template>
 <MkContainer :show-header="props.showHeader" :naked="props.transparent" :class="$style.root" :data-transparent="props.transparent ? true : null">
-	<template #header><Fa :icon="faCamera"/>{{ $ts._widgets.photos }}</template>
+	<template #header><i class="fas fa-camera"></i>{{ $ts._widgets.photos }}</template>
 
 	<div class="">
 		<MkLoading v-if="fetching"/>
@@ -16,7 +16,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faCamera } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import define from './define';
 import { getStaticImageUrl } from '@client/scripts/get-static-image-url';
@@ -46,7 +45,6 @@ export default defineComponent({
 			images: [],
 			fetching: true,
 			connection: null,
-			faCamera
 		};
 	},
 	mounted() {
diff --git a/src/client/widgets/rss.vue b/src/client/widgets/rss.vue
index 78ad390d275fb2f0b25f654ebbf84209761a1631..6d19a86dffa95ea6494aea428855b400466770f2 100644
--- a/src/client/widgets/rss.vue
+++ b/src/client/widgets/rss.vue
@@ -1,7 +1,7 @@
 <template>
 <MkContainer :show-header="props.showHeader">
-	<template #header><Fa :icon="faRssSquare"/>RSS</template>
-	<template #func><button class="_button" @click="setting"><Fa :icon="faCog"/></button></template>
+	<template #header><i class="fas fa-rss-square"></i>RSS</template>
+	<template #func><button class="_button" @click="setting"><i class="fas fa-cog"></i></button></template>
 
 	<div class="ekmkgxbj">
 		<MkLoading v-if="fetching"/>
@@ -14,7 +14,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faRssSquare, faCog } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import define from './define';
 import * as os from '@client/os';
@@ -43,7 +42,6 @@ export default defineComponent({
 			items: [],
 			fetching: true,
 			clock: null,
-			faRssSquare, faCog
 		};
 	},
 	mounted() {
diff --git a/src/client/widgets/server-metric/cpu.vue b/src/client/widgets/server-metric/cpu.vue
index f1574522c2d45cdd19247619a215b68e05e7d71b..4478ee30655e93e4d058ab89cf519ec698463ad7 100644
--- a/src/client/widgets/server-metric/cpu.vue
+++ b/src/client/widgets/server-metric/cpu.vue
@@ -2,7 +2,7 @@
 <div class="vrvdvrys">
 	<XPie class="pie" :value="usage"/>
 	<div>
-		<p><fa :icon="faMicrochip"/>CPU</p>
+		<p><i class="fas fa-microchip"></i>CPU</p>
 		<p>{{ meta.cpu.cores }} Logical cores</p>
 		<p>{{ meta.cpu.model }}</p>
 	</div>
@@ -11,7 +11,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faMicrochip } from '@fortawesome/free-solid-svg-icons';
 import XPie from './pie.vue';
 
 export default defineComponent({
@@ -29,7 +28,6 @@ export default defineComponent({
 	data() {
 		return {
 			usage: 0,
-			faMicrochip,
 		};
 	},
 	mounted() {
@@ -68,7 +66,7 @@ export default defineComponent({
 				font-weight: bold;
 				margin-bottom: 4px;
 
-				> [data-icon] {
+				> i {
 					margin-right: 4px;
 				}
 			}
diff --git a/src/client/widgets/server-metric/disk.vue b/src/client/widgets/server-metric/disk.vue
index fa5933e7b900e3d2cd1aa91b098b435025239e93..a3f5d0376bee62fddfdd409a3ba3c94737821a0b 100644
--- a/src/client/widgets/server-metric/disk.vue
+++ b/src/client/widgets/server-metric/disk.vue
@@ -2,7 +2,7 @@
 <div class="zbwaqsat">
 	<XPie class="pie" :value="usage"/>
 	<div>
-		<p><fa :icon="faHdd"/>Disk</p>
+		<p><i class="fas fa-hdd"></i>Disk</p>
 		<p>Total: {{ bytes(total, 1) }}</p>
 		<p>Free: {{ bytes(available, 1) }}</p>
 		<p>Used: {{ bytes(used, 1) }}</p>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faHdd } from '@fortawesome/free-solid-svg-icons';
 import XPie from './pie.vue';
 import bytes from '@client/filters/bytes';
 
@@ -31,7 +30,6 @@ export default defineComponent({
 			total: this.meta.fs.total,
 			used: this.meta.fs.used,
 			available: this.meta.fs.total - this.meta.fs.used,
-			faHdd,
 		};
 	},
 	methods: {
@@ -62,7 +60,7 @@ export default defineComponent({
 				font-weight: bold;
 				margin-bottom: 4px;
 
-				> [data-icon] {
+				> i {
 					margin-right: 4px;
 				}
 			}
diff --git a/src/client/widgets/server-metric/index.vue b/src/client/widgets/server-metric/index.vue
index 7f2aea6b49f6ce5dacda0f5d1a8dacab08002f0b..6331b5bdf1c913a07cbc1ccabf1e37234b58cfbb 100644
--- a/src/client/widgets/server-metric/index.vue
+++ b/src/client/widgets/server-metric/index.vue
@@ -1,7 +1,7 @@
 <template>
 <MkContainer :show-header="props.showHeader" :naked="props.transparent">
-	<template #header><Fa :icon="faServer"/>{{ $ts._widgets.serverMetric }}</template>
-	<template #func><button @click="toggleView()" class="_button"><Fa :icon="faSort"/></button></template>
+	<template #header><i class="fas fa-server"></i>{{ $ts._widgets.serverMetric }}</template>
+	<template #func><button @click="toggleView()" class="_button"><i class="fas fa-sort"></i></button></template>
 
 	<div class="mkw-serverMetric" v-if="meta">
 		<XCpuMemory v-if="props.view === 0" :connection="connection" :meta="meta"/>
@@ -15,7 +15,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faServer, faSort } from '@fortawesome/free-solid-svg-icons';
 import define from '../define';
 import MkContainer from '@client/components/ui/container.vue';
 import XCpuMemory from './cpu-mem.vue';
@@ -58,7 +57,6 @@ export default defineComponent({
 		return {
 			meta: null,
 			connection: null,
-			faServer, faSort,
 		};
 	},
 	created() {
diff --git a/src/client/widgets/server-metric/mem.vue b/src/client/widgets/server-metric/mem.vue
index 89fa8fef43945fdc74c5cb5ee5640bbcf0672e4a..92c0aa0c77fa271472737f8e21bdd346be3bd06e 100644
--- a/src/client/widgets/server-metric/mem.vue
+++ b/src/client/widgets/server-metric/mem.vue
@@ -2,7 +2,7 @@
 <div class="zlxnikvl">
 	<XPie class="pie" :value="usage"/>
 	<div>
-		<p><fa :icon="faMemory"/>RAM</p>
+		<p><i class="fas fa-memory"></i>RAM</p>
 		<p>Total: {{ bytes(total, 1) }}</p>
 		<p>Used: {{ bytes(used, 1) }}</p>
 		<p>Free: {{ bytes(free, 1) }}</p>
@@ -12,7 +12,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faMemory } from '@fortawesome/free-solid-svg-icons';
 import XPie from './pie.vue';
 import bytes from '@client/filters/bytes';
 
@@ -34,7 +33,6 @@ export default defineComponent({
 			total: 0,
 			used: 0,
 			free: 0,
-			faMemory,
 		};
 	},
 	mounted() {
@@ -77,7 +75,7 @@ export default defineComponent({
 				font-weight: bold;
 				margin-bottom: 4px;
 
-				> [data-icon] {
+				> i {
 					margin-right: 4px;
 				}
 			}
diff --git a/src/client/widgets/slideshow.vue b/src/client/widgets/slideshow.vue
index 69c5cc01b2c6e6ba4411d8b0c8eb68c3c35d7729..2f079e0d428559fa6ab7d74eecc7d11087020636 100644
--- a/src/client/widgets/slideshow.vue
+++ b/src/client/widgets/slideshow.vue
@@ -14,7 +14,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import {  } from '@fortawesome/free-solid-svg-icons';
 import define from './define';
 import * as os from '@client/os';
 
diff --git a/src/client/widgets/timeline.vue b/src/client/widgets/timeline.vue
index f1ddc9cb801f6cf69990a9198ac1546c3eda0f86..8548574afc0590b5cf6e5f63a4d43a31f8e25c06 100644
--- a/src/client/widgets/timeline.vue
+++ b/src/client/widgets/timeline.vue
@@ -2,14 +2,14 @@
 <MkContainer :show-header="props.showHeader" :style="`height: ${props.height}px;`" :scrollable="true">
 	<template #header>
 		<button @click="choose" class="_button">
-			<Fa v-if="props.src === 'home'" :icon="faHome"/>
-			<Fa v-if="props.src === 'local'" :icon="faComments"/>
-			<Fa v-if="props.src === 'social'" :icon="faShareAlt"/>
-			<Fa v-if="props.src === 'global'" :icon="faGlobe"/>
-			<Fa v-if="props.src === 'list'" :icon="faListUl"/>
-			<Fa v-if="props.src === 'antenna'" :icon="faSatellite"/>
+			<i v-if="props.src === 'home'" class="fas fa-home"></i>
+			<i v-else-if="props.src === 'local'" class="fas fa-comments"></i>
+			<i v-else-if="props.src === 'social'" class="fas fa-share-alt"></i>
+			<i v-else-if="props.src === 'global'" class="fas fa-globe"></i>
+			<i v-else-if="props.src === 'list'" class="fas fa-list-ul"></i>
+			<i v-else-if="props.src === 'antenna'" class="fas fa-satellite"></i>
 			<span style="margin-left: 8px;">{{ props.src === 'list' ? props.list.name : props.src === 'antenna' ? props.antenna.name : $t('_timelines.' + props.src) }}</span>
-			<Fa :icon="menuOpened ? faAngleUp : faAngleDown" style="margin-left: 8px;"/>
+			<i :class="menuOpened ? 'fas fa-angle-up' : 'fas fa-angle-down'" style="margin-left: 8px;"></i>
 		</button>
 	</template>
 
@@ -21,8 +21,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faAngleDown, faAngleUp, faHome, faShareAlt, faGlobe, faListUl, faSatellite } from '@fortawesome/free-solid-svg-icons';
-import { faComments } from '@fortawesome/free-regular-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import XTimeline from '@client/components/timeline.vue';
 import define from './define';
@@ -62,7 +60,6 @@ export default defineComponent({
 	data() {
 		return {
 			menuOpened: false,
-			faAngleDown, faAngleUp, faHome, faShareAlt, faGlobe, faComments, faListUl, faSatellite
 		};
 	},
 
@@ -75,7 +72,7 @@ export default defineComponent({
 			]);
 			const antennaItems = antennas.map(antenna => ({
 				text: antenna.name,
-				icon: faSatellite,
+				icon: 'fas fa-satellite',
 				action: () => {
 					this.props.antenna = antenna;
 					this.setSrc('antenna');
@@ -83,7 +80,7 @@ export default defineComponent({
 			}));
 			const listItems = lists.map(list => ({
 				text: list.name,
-				icon: faListUl,
+				icon: 'fas fa-list-ul',
 				action: () => {
 					this.props.list = list;
 					this.setSrc('list');
@@ -91,19 +88,19 @@ export default defineComponent({
 			}));
 			os.modalMenu([{
 				text: this.$ts._timelines.home,
-				icon: faHome,
+				icon: 'fas fa-home',
 				action: () => { this.setSrc('home') }
 			}, {
 				text: this.$ts._timelines.local,
-				icon: faComments,
+				icon: 'fas fa-comments',
 				action: () => { this.setSrc('local') }
 			}, {
 				text: this.$ts._timelines.social,
-				icon: faShareAlt,
+				icon: 'fas fa-share-alt',
 				action: () => { this.setSrc('social') }
 			}, {
 				text: this.$ts._timelines.global,
-				icon: faGlobe,
+				icon: 'fas fa-globe',
 				action: () => { this.setSrc('global') }
 			}, antennaItems.length > 0 ? null : undefined, ...antennaItems, listItems.length > 0 ? null : undefined, ...listItems], ev.currentTarget || ev.target).then(() => {
 				this.menuOpened = false;
diff --git a/src/client/widgets/trends.vue b/src/client/widgets/trends.vue
index cd7202f1f8c124ee6808ee75e5c2386caade31f3..8511bc718f667e50a295969b95b6525a82df28f8 100644
--- a/src/client/widgets/trends.vue
+++ b/src/client/widgets/trends.vue
@@ -1,6 +1,6 @@
 <template>
 <MkContainer :show-header="props.showHeader">
-	<template #header><Fa :icon="faHashtag"/>{{ $ts._widgets.trends }}</template>
+	<template #header><i class="fas fa-hashtag"></i>{{ $ts._widgets.trends }}</template>
 
 	<div class="wbrkwala">
 		<MkLoading v-if="fetching"/>
@@ -19,7 +19,6 @@
 
 <script lang="ts">
 import { defineComponent } from 'vue';
-import { faHashtag } from '@fortawesome/free-solid-svg-icons';
 import MkContainer from '@client/components/ui/container.vue';
 import define from './define';
 import MkMiniChart from '@client/components/mini-chart.vue';
@@ -44,7 +43,6 @@ export default defineComponent({
 		return {
 			stats: [],
 			fetching: true,
-			faHashtag
 		};
 	},
 	mounted() {
diff --git a/src/models/repositories/user.ts b/src/models/repositories/user.ts
index 0d59ed2545e31993cdae1f69079365cd4357986a..1ebc16a5638dcfa46de9ddad1770bb5799ba1d5e 100644
--- a/src/models/repositories/user.ts
+++ b/src/models/repositories/user.ts
@@ -147,7 +147,7 @@ export class UserRepository extends Repository<User> {
 	}
 
 	public getOnlineStatus(user: User): string {
-		if (user.hideOnlineStatus == null) return 'unknown';
+		if (user.hideOnlineStatus) return 'unknown';
 		if (user.lastActiveDate == null) return 'unknown';
 		const elapsed = Date.now() - user.lastActiveDate.getTime();
 		return (
diff --git a/src/server/api/endpoints/admin/update-remote-user.ts b/src/server/api/endpoints/federation/update-remote-user.ts
similarity index 94%
rename from src/server/api/endpoints/admin/update-remote-user.ts
rename to src/server/api/endpoints/federation/update-remote-user.ts
index 9577ac0a55bef69a076e17c01c75f12552bccf6a..1b7a9c4d5b9646bf8ea914de28143272f657ccdb 100644
--- a/src/server/api/endpoints/admin/update-remote-user.ts
+++ b/src/server/api/endpoints/federation/update-remote-user.ts
@@ -10,10 +10,9 @@ export const meta = {
 		'en-US': 'Update specified remote user information.'
 	},
 
-	tags: ['admin'],
+	tags: ['federation'],
 
 	requireCredential: true as const,
-	requireModerator: true,
 
 	params: {
 		userId: {
diff --git a/src/server/web/index.ts b/src/server/web/index.ts
index 953f2b47f1733bdfcf8b84007fec4e2ababac7ba..1caab14cc24fd16957410ee7585608174f0b46b1 100644
--- a/src/server/web/index.ts
+++ b/src/server/web/index.ts
@@ -99,7 +99,7 @@ router.get('/manifest.json', require('./manifest'));
 
 router.get('/robots.txt', async ctx => {
 	await send(ctx as any, '/robots.txt', {
-		root: assets
+		root: staticAssets
 	});
 });
 
diff --git a/src/server/web/views/base.pug b/src/server/web/views/base.pug
index 22d5fd0c677cdc77d31d01dc449290ab32da865b..8992f96db9d9bcfdcf6599d275a37cb69c9b0abc 100644
--- a/src/server/web/views/base.pug
+++ b/src/server/web/views/base.pug
@@ -2,9 +2,11 @@ block vars
 
 doctype html
 
-!= '\n<!-- Thank you for using Misskey! -->\n'
-!= '\n<!-- If you are reading this message... how about joining the development of Misskey? -->\n'
-!= '\n<!-- https://github.com/misskey-dev/misskey -->\n'
+!= '\n'
+!= '<!-- Thank you for using Misskey! -->\n'
+!= '<!-- If you are reading this message... how about joining the development of Misskey? -->\n'
+!= '<!-- https://github.com/misskey-dev/misskey -->'
+!= '\n'
 
 html
 
@@ -22,13 +24,15 @@ html
 		link(rel='prefetch' href='https://xn--931a.moe/assets/info.jpg')
 		link(rel='prefetch' href='https://xn--931a.moe/assets/not-found.jpg')
 		link(rel='prefetch' href='https://xn--931a.moe/assets/error.jpg')
+		link(rel='preload' href='https://use.fontawesome.com/releases/v5.15.3/css/all.css' as='style')
+		link(rel='stylesheet' href='https://use.fontawesome.com/releases/v5.15.3/css/all.css')
 
 		title
 			block title
 				= title || 'Misskey'
 
 		block desc
-			meta(name='description' content= desc || '✨🌎✨ A federated blogging platform ✨🚀✨')
+			meta(name='description' content= desc || '✨🌎✨ A interplanetary communication platform ✨🚀✨')
 
 		block meta
 
diff --git a/webpack.config.ts b/webpack.config.ts
index 9f2a3a89af20ed7c3bda1d704cba92f156dc3d61..296813caa0131ba5e238d9bfd9002a6e105c8aa1 100644
--- a/webpack.config.ts
+++ b/webpack.config.ts
@@ -70,7 +70,7 @@ module.exports = {
 					options: {
 						implementation: require('sass'),
 						sassOptions: {
-							fiber: require('fibers')
+							fiber: false
 						}
 					}
 				}]
@@ -88,7 +88,7 @@ module.exports = {
 					options: {
 						implementation: require('sass'),
 						sassOptions: {
-							fiber: require('fibers')
+							fiber: false
 						}
 					}
 				}]
diff --git a/yarn.lock b/yarn.lock
index ac5b283498dfb82f14472628a8a6aca65ce81687..8d17fc1bc221bba8d7ab982ffe70ec84e1093262 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -227,44 +227,6 @@
     minimatch "^3.0.4"
     strip-json-comments "^3.1.1"
 
-"@fortawesome/fontawesome-common-types@^0.2.35":
-  version "0.2.35"
-  resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.35.tgz#01dd3d054da07a00b764d78748df20daf2b317e9"
-  integrity sha512-IHUfxSEDS9dDGqYwIW7wTN6tn/O8E0n5PcAHz9cAaBoZw6UpG20IG/YM3NNLaGPwPqgjBAFjIURzqoQs3rrtuw==
-
-"@fortawesome/fontawesome-svg-core@1.2.35":
-  version "1.2.35"
-  resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.35.tgz#85aea8c25645fcec88d35f2eb1045c38d3e65cff"
-  integrity sha512-uLEXifXIL7hnh2sNZQrIJWNol7cTVIzwI+4qcBIq9QWaZqUblm0IDrtSqbNg+3SQf8SMGHkiSigD++rHmCHjBg==
-  dependencies:
-    "@fortawesome/fontawesome-common-types" "^0.2.35"
-
-"@fortawesome/free-brands-svg-icons@5.15.3":
-  version "5.15.3"
-  resolved "https://registry.yarnpkg.com/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.3.tgz#bec2821d23b9c667be1d192a6c5bfb2667e588eb"
-  integrity sha512-1hirPcbjj72ZJtFvdnXGPbAbpn3Ox6mH3g5STbANFp3vGSiE5u5ingAKV06mK6ZVqNYxUPlh4DlTnaIvLtF2kw==
-  dependencies:
-    "@fortawesome/fontawesome-common-types" "^0.2.35"
-
-"@fortawesome/free-regular-svg-icons@5.15.3":
-  version "5.15.3"
-  resolved "https://registry.yarnpkg.com/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.3.tgz#1ec4f2410ff638db549c5c5484fc60b66407dbe6"
-  integrity sha512-q4/p8Xehy9qiVTdDWHL4Z+o5PCLRChePGZRTXkl+/Z7erDVL8VcZUuqzJjs6gUz6czss4VIPBRdCz6wP37/zMQ==
-  dependencies:
-    "@fortawesome/fontawesome-common-types" "^0.2.35"
-
-"@fortawesome/free-solid-svg-icons@5.15.3":
-  version "5.15.3"
-  resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.3.tgz#52eebe354f60dc77e0bde934ffc5c75ffd04f9d8"
-  integrity sha512-XPeeu1IlGYqz4VWGRAT5ukNMd4VHUEEJ7ysZ7pSSgaEtNvSo+FLurybGJVmiqkQdK50OkSja2bfZXOeyMGRD8Q==
-  dependencies:
-    "@fortawesome/fontawesome-common-types" "^0.2.35"
-
-"@fortawesome/vue-fontawesome@3.0.0-3":
-  version "3.0.0-3"
-  resolved "https://registry.yarnpkg.com/@fortawesome/vue-fontawesome/-/vue-fontawesome-3.0.0-3.tgz#b658a7c1f35d4eb04ac85749da693be483442b25"
-  integrity sha512-fCM7+R9M7Y/ipKC5n9hukGpJHhe53JOENGqtku/KWtpXsnbGik3AS5zfJYEupV2uXOw/5S0RSSfttQ2hNIrmFA==
-
 "@jfonx/console-utils@^1.0.3":
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/@jfonx/console-utils/-/console-utils-1.0.3.tgz#cbb7f911e4191a4a2fe1ba4807d29f100b5d099f"
@@ -4326,13 +4288,6 @@ feed@4.2.2:
   dependencies:
     xml-js "^1.6.11"
 
-fibers@5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/fibers/-/fibers-5.0.0.tgz#3a60e0695b3ee5f6db94e62726716fa7a59acc41"
-  integrity sha512-UpGv/YAZp7mhKHxDvC1tColrroGRX90sSvh8RMZV9leo+e5+EkRVgCEZPlmXeo3BUNQTZxUaVdLskq1Q2FyCPg==
-  dependencies:
-    detect-libc "^1.0.3"
-
 figlet@^1.1.1:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.3.0.tgz#c49e3d92907ba13bebadc7124f76ba71f1f32ef0"
@@ -6695,10 +6650,10 @@ methods@^1.1.2:
   resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
   integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
 
-mfm-js@0.16.0:
-  version "0.16.0"
-  resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.16.0.tgz#71852124eba5564f8a94cd7476a4eaa4ddeed1cd"
-  integrity sha512-z33e1yPj9dLN+DjDHakhslvGhCnzTxsUNpodyFw3nemO6gnKOE1adUrm49jjB2boQxtBExKhH7FERMCsNFcpBQ==
+mfm-js@0.16.2:
+  version "0.16.2"
+  resolved "https://registry.yarnpkg.com/mfm-js/-/mfm-js-0.16.2.tgz#6dfa44a9b6ac0fd9d55d6f8c21eaa60c75bcd9fa"
+  integrity sha512-Ah/XTPsg88il3kRwXxY6QqlNGkc9ToWWFhW9BGBk6V6T108iLjS30pd79WL02Nd1tw1Jl/JduJMgpb5QzCE45w==
   dependencies:
     twemoji-parser "13.0.x"