diff --git a/CHANGELOG.md b/CHANGELOG.md
index 37f40667bf16058435082e8019241f298e6c73ac..ee98f4ccb99b66a0fb764f5ed65600432a5c67ce 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,7 +12,7 @@
 
 -->
 
-## 2023.11.0 (unreleased)
+## 2023.11.0
 
 ### Note
 - iOS 16.4未満を使用している場合はiOS 16.4以上にアップデートをお願いします
@@ -29,6 +29,7 @@
   - ユーザーが誤ったメールアドレスを入力した場合に招待コードが失効してしまう問題が解消されます。
 - Enhance: すでにフォローしたすべての人の返信をTLに追加できるように
 - Enhance: 未読の通知数を表示できるように
+- Enhance: 通知されず、確認の必要もないお知らせ(silence)を作成可能になりました
 - Enhance: ローカリゼーションの更新
 - Enhance: 依存関係の更新
 - Change: CWを使用する場合、注釈を空にすることは許可されなくなりました
@@ -50,7 +51,7 @@
 - Enhance: プラグインで`Plugin:register_note_view_interruptor`を用いてnoteの代わりにnullを返却することでノートを非表示にできるようになりました
 - Enhance: AiScript関数`Mk:nyaize()`が追加されました
 - Enhance: 情報→ツール はナビゲーションバーにツールとして独立した項目になりました
-- Enhance: ノート内のカスタム絵文字をクリックすることで、コピーおよびリアクションができるように
+- Enhance: ノート内の絵文字をクリックすることで、コピーおよびリアクションができるように
 - Enhance: その他細かなブラッシュアップ
 - Fix: 投稿フォームでのユーザー変更がプレビューに反映されない問題を修正
 - Fix: ユーザーページの ノート > ファイル付き タブにリプライが表示されてしまう
@@ -63,6 +64,7 @@
 - Fix: 11以上されているリアクションにおいてツールチップで示されるリアクション数が本来よりも1多い問題を修正 #12174
 - Fix: サイレンス状態で公開範囲のパブリックを選択できてしまう問題を修正 #12224
 - Fix: In deck layout, replies option is not saved after refresh
+- Fix: アーカイブしたお知らせがコントロールパネルに表示される問題を修正
 - Note: アップデート後、サウンドに関する設定が初期化されます
 
 ### Server
@@ -72,6 +74,7 @@
 - Enhance: プロフィールの自己紹介欄のMFMが連合するようになりました
 	- 相手がMisskey v2023.11.0以降である必要があります
 - Enhance: チャンネル取得時のパフォーマンスを向上
+- Enhance: AP: ApplicationタイプのアカウントをisBotとして扱うように
 - Fix: リストTLに自分のフォロワー限定投稿が含まれない問題を修正
 - Fix: ローカルタイムラインに投稿者自身の投稿への返信が含まれない問題を修正
 - Fix: 自分のフォローしているユーザーの自分のフォローしていないユーザーの visibility: followers な投稿への返信がストリーミングで流れてくる問題を修正
diff --git a/locales/fr-FR.yml b/locales/fr-FR.yml
index 9fea3df0067cfc3052f8b21c864404e12564514a..1a014d4dd0cd3279cba20bf8a3914381bb7f7068 100644
--- a/locales/fr-FR.yml
+++ b/locales/fr-FR.yml
@@ -1088,7 +1088,26 @@ _initialAccountSetting:
   profileSetting: "Paramètres du profil"
   privacySetting: "Paramètres de confidentialité"
   initialAccountSettingCompleted: "Configuration du profil terminée avec succès !"
+  startTutorial: "Démarrer le tutoriel"
   skipAreYouSure: "Désirez-vous ignorer la configuration du profil ?"
+_initialTutorial:
+  title: "Tutoriel"
+  wellDone: "Bien joué !"
+  skipAreYouSure: "Quitter le tutoriel ?"
+  _landing:
+    title: "Bienvenue dans le tutoriel"
+    description: "Ici, vous pouvez apprendre l'utilisation de base de Misskey et ses fonctionnalités."
+  _note:
+    title: "Qu'est-ce que les notes ?"
+    description: "Les messages sur Misskey sont appelés des « notes » . Les notes sont classées par ordre chronologique sur le fil et sont mises à jour en temps réel."
+    reply: "Vous pouvez répondre aux messages. Vous pouvez également répondre aux réponses et poursuivre la conversation comme un fil de discussion."
+    renote: "Vous pouvez partager cette note sur votre propre fil. Vous pouvez aussi ajouter du texte en citant."
+    reaction: "Vous pouvez ajouter des réactions. Les détails sont expliqués à la page suivante."
+    menu: "Vous pouvez afficher les détails de la note, copier le lien et effectuer d'autres actions."
+  _reaction:
+    title: "Qu'est-ce que les réactions ?"
+    description: "Vous pouvez ajouter des « réactions » aux notes. Les réactions vous permettent d'exprimer à l'aise des nuances qui ne peuvent pas être exprimées par des mentions j'aime."
+    letsTryReacting: "Des réactions peuvent être ajoutées en cliquant sur le bouton « + » de la note. Essayez d'ajouter une réaction à cet exemple de note !"
 _serverSettings:
   iconUrl: "URL de l’icône"
   fanoutTimelineDescription: "Si activée, la performance de la récupération de la chronologie augmentera considérablement et la charge sur la base de données sera réduite. En revanche, l'utilisation de la mémoire de Redis augmentera. Considérez désactiver cette option si le serveur est bas en mémoire ou instable."
diff --git a/locales/index.d.ts b/locales/index.d.ts
index 9b73db2d4ceaed54d7ea8a00aa71375d819d2cb0..c5128965324527e05d5e3a2ba4132a5cb88b5994 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1202,6 +1202,8 @@ export interface Locale {
         "readConfirmText": string;
         "shouldNotBeUsedToPresentPermanentInfo": string;
         "dialogAnnouncementUxWarn": string;
+        "silence": string;
+        "silenceDescription": string;
     };
     "_initialAccountSetting": {
         "accountCreated": string;
diff --git a/locales/index.js b/locales/index.js
index 7801f1275bf84d337eb06a0eef7f246a99ce0814..67a406d98d977797fb3d05e16f20adad660f4851 100644
--- a/locales/index.js
+++ b/locales/index.js
@@ -53,6 +53,19 @@ const clean = (text) => text.replace(new RegExp(String.fromCodePoint(0x08), 'g')
 
 const locales = languages.reduce((a, c) => (a[c] = yaml.load(clean(fs.readFileSync(new URL(`${c}.yml`, import.meta.url), 'utf-8'))) || {}, a), {});
 
+// 空文字列が入ることがあり、フォールバックが動作しなくなるのでプロパティごと消す
+const removeEmpty = (obj) => {
+	for (const [k, v] of Object.entries(obj)) {
+		if (v === '') {
+			delete obj[k];
+		} else if (typeof v === 'object') {
+			removeEmpty(v);
+		}
+	}
+	return obj;
+};
+removeEmpty(locales);
+
 export default Object.entries(locales)
 	.reduce((a, [k ,v]) => (a[k] = (() => {
 		const [lang] = k.split('-');
@@ -63,7 +76,7 @@ export default Object.entries(locales)
 			default: return merge(
 				locales['ja-JP'],
 				locales['en-US'],
-				locales[`${lang}-${primaries[lang]}`] || {},
+				locales[`${lang}-${primaries[lang]}`] ?? {},
 				v
 			);
 		}
diff --git a/locales/it-IT.yml b/locales/it-IT.yml
index b87704d160d04f3794a87e5d99a4c8f53ad246ea..08cf0cb7070ae496d683f8def2098f6c22282d47 100644
--- a/locales/it-IT.yml
+++ b/locales/it-IT.yml
@@ -1157,6 +1157,7 @@ disableStreamingTimeline: "Disabilitare gli aggiornamenti della TL in tempo real
 useGroupedNotifications: "Mostra le notifiche raggruppate"
 signupPendingError: "Si è verificato un problema durante la verifica del tuo indirizzo email. Potrebbe essere scaduto il collegamento temporaneo."
 cwNotationRequired: "Devi indicare perché il contenuto è indicato come esplicito."
+doReaction: "Reagisci"
 _announcement:
   forExistingUsers: "Solo ai profili attuali"
   forExistingUsersDescription: "L'annuncio sarà visibile solo ai profili esistenti in questo momento. Se disabilitato, sarà visibile anche ai profili che verranno creati dopo la pubblicazione di questo annuncio."
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 8508f93575cf0496744159a3e906dccf28e7b288..4da044a6c809f95b3a5aa055c0a5353300915cd4 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1200,6 +1200,8 @@ _announcement:
   readConfirmText: "「{title}」の内容を読み、既読にします。"
   shouldNotBeUsedToPresentPermanentInfo: "特に新規ユーザーのUXを損ねる可能性が高いため、ストック情報ではなくフロー情報の掲示にお知らせを使用することを推奨します。"
   dialogAnnouncementUxWarn: "ダイアログ形式のお知らせが同時に2つ以上ある場合、UXに悪影響を及ぼす可能性が非常に高いため、使用は慎重に行うことを推奨します。"
+  silence: "非通知"
+  silenceDescription: "オンにすると、このお知らせは通知されず、既読にする必要もなくなります。"
 
 _initialAccountSetting:
   accountCreated: "アカウントの作成が完了しました!"
diff --git a/package.json b/package.json
index 12912f4153568dad903f936c906dd0fbfc6719c6..8a9d1c964354bf394dbc016412981fb53e014bbc 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "sharkey",
-	"version": "2023.11.0.beta3",
+	"version": "2023.11.0.beta4",
 	"codename": "shonk",
 	"repository": {
 		"type": "git",
diff --git a/packages/backend/migration/1699141698112-announcement-silence.js b/packages/backend/migration/1699141698112-announcement-silence.js
new file mode 100644
index 0000000000000000000000000000000000000000..eef9b076fc13aee09ce21ac149c0f7e02204f885
--- /dev/null
+++ b/packages/backend/migration/1699141698112-announcement-silence.js
@@ -0,0 +1,18 @@
+/*
+ * SPDX-FileCopyrightText: syuilo and other misskey contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+export class AnnouncementSilence1699141698112 {
+    name = 'AnnouncementSilence1699141698112'
+
+    async up(queryRunner) {
+        await queryRunner.query(`ALTER TABLE "announcement" ADD "silence" boolean NOT NULL DEFAULT false`);
+        await queryRunner.query(`CREATE INDEX "IDX_7b8d9225168e962f94ea517e00" ON "announcement" ("silence") `);
+    }
+
+    async down(queryRunner) {
+        await queryRunner.query(`DROP INDEX "public"."IDX_7b8d9225168e962f94ea517e00"`);
+        await queryRunner.query(`ALTER TABLE "announcement" DROP COLUMN "silence"`);
+    }
+}
diff --git a/packages/backend/src/core/AnnouncementService.ts b/packages/backend/src/core/AnnouncementService.ts
index ec1a082d781e0bd1696d6ec40d806752e5732465..8c348e595dab16deb0b71a99cc56f7d7ef213d19 100644
--- a/packages/backend/src/core/AnnouncementService.ts
+++ b/packages/backend/src/core/AnnouncementService.ts
@@ -47,6 +47,7 @@ export class AnnouncementService {
 
 		const q = this.announcementsRepository.createQueryBuilder('announcement')
 			.where('announcement.isActive = true')
+			.andWhere('announcement.silence = false')
 			.andWhere(new Brackets(qb => {
 				qb.orWhere('announcement.userId = :userId', { userId: user.id });
 				qb.orWhere('announcement.userId IS NULL');
@@ -73,6 +74,7 @@ export class AnnouncementService {
 			icon: values.icon,
 			display: values.display,
 			forExistingUsers: values.forExistingUsers,
+			silence: values.silence,
 			needConfirmationToRead: values.needConfirmationToRead,
 			userId: values.userId,
 		}).then(x => this.announcementsRepository.findOneByOrFail(x.identifiers[0]));
@@ -124,6 +126,7 @@ export class AnnouncementService {
 			display: values.display,
 			icon: values.icon,
 			forExistingUsers: values.forExistingUsers,
+			silence: values.silence,
 			needConfirmationToRead: values.needConfirmationToRead,
 			isActive: values.isActive,
 		});
@@ -210,6 +213,7 @@ export class AnnouncementService {
 			icon: announcement.icon,
 			display: announcement.display,
 			needConfirmationToRead: announcement.needConfirmationToRead,
+			silence: announcement.silence,
 			forYou: announcement.userId === me?.id,
 			isRead: reads.some(read => read.announcementId === announcement.id),
 		}));
diff --git a/packages/backend/src/core/activitypub/models/ApPersonService.ts b/packages/backend/src/core/activitypub/models/ApPersonService.ts
index a55181a9d174cdebc3a8b9da5371e0a113c423b9..cfb380a3229bd498de92e7a4f69dd0dbbfcb4668 100644
--- a/packages/backend/src/core/activitypub/models/ApPersonService.ts
+++ b/packages/backend/src/core/activitypub/models/ApPersonService.ts
@@ -272,7 +272,7 @@ export class ApPersonService implements OnModuleInit {
 
 		const tags = extractApHashtags(person.tag).map(normalizeForSearch).splice(0, 32);
 
-		const isBot = getApType(object) === 'Service';
+		const isBot = getApType(object) === 'Service' || getApType(object) === 'Application';
 
 		const bday = person['vcard:bday']?.match(/^\d{4}-\d{2}-\d{2}/);
 
@@ -473,7 +473,7 @@ export class ApPersonService implements OnModuleInit {
 			name: truncate(person.name, nameLength),
 			tags,
 			approved: true,
-			isBot: getApType(object) === 'Service',
+			isBot: getApType(object) === 'Service' || getApType(object) === 'Application',
 			isCat: (person as any).isCat === true,
 			speakAsCat: (person as any).speakAsCat != null ? (person as any).speakAsCat === true : (person as any).isCat === true,
 			isLocked: person.manuallyApprovesFollowers,
diff --git a/packages/backend/src/models/Announcement.ts b/packages/backend/src/models/Announcement.ts
index 05d5a086f140492bc615aee1182a363eeb022536..8f8be88fed504ed93929650cf0df0f31c18aecaf 100644
--- a/packages/backend/src/models/Announcement.ts
+++ b/packages/backend/src/models/Announcement.ts
@@ -66,6 +66,12 @@ export class MiAnnouncement {
 	})
 	public forExistingUsers: boolean;
 
+	@Index()
+	@Column('boolean', {
+		default: false,
+	})
+	public silence: boolean;
+
 	@Index()
 	@Column({
 		...id(),
diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts
index 253a29cf5a9ae9b9126c23614d42178befa0fbab..69c31a05eb792b5bb50dd308ed067d101217ff55 100644
--- a/packages/backend/src/server/api/endpoints/admin/announcements/create.ts
+++ b/packages/backend/src/server/api/endpoints/admin/announcements/create.ts
@@ -58,6 +58,7 @@ export const paramDef = {
 		icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'], default: 'info' },
 		display: { type: 'string', enum: ['normal', 'banner', 'dialog'], default: 'normal' },
 		forExistingUsers: { type: 'boolean', default: false },
+		silence: { type: 'boolean', default: false },
 		needConfirmationToRead: { type: 'boolean', default: false },
 		userId: { type: 'string', format: 'misskey:id', nullable: true, default: null },
 	},
@@ -78,6 +79,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				icon: ps.icon,
 				display: ps.display,
 				forExistingUsers: ps.forExistingUsers,
+				silence: ps.silence,
 				needConfirmationToRead: ps.needConfirmationToRead,
 				userId: ps.userId,
 			}, me);
diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
index fefc379c00fa5f90f4dff55fa9151cb36639097b..9630299a6e005c75b52f6e69586aaea63e006bb9 100644
--- a/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
+++ b/packages/backend/src/server/api/endpoints/admin/announcements/list.ts
@@ -86,6 +86,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 	) {
 		super(meta, paramDef, async (ps, me) => {
 			const query = this.queryService.makePaginationQuery(this.announcementsRepository.createQueryBuilder('announcement'), ps.sinceId, ps.untilId);
+			query.andWhere('announcement.isActive = true');
 			if (ps.userId) {
 				query.andWhere('announcement.userId = :userId', { userId: ps.userId });
 			} else {
@@ -113,6 +114,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				display: announcement.display,
 				isActive: announcement.isActive,
 				forExistingUsers: announcement.forExistingUsers,
+				silence: announcement.silence,
 				needConfirmationToRead: announcement.needConfirmationToRead,
 				userId: announcement.userId,
 				reads: reads.get(announcement)!,
diff --git a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts
index d36590c2640ca7301054be1d6a3b1dc94ffee84c..717866aeadba038501e17211aa69b16732ff10e5 100644
--- a/packages/backend/src/server/api/endpoints/admin/announcements/update.ts
+++ b/packages/backend/src/server/api/endpoints/admin/announcements/update.ts
@@ -35,6 +35,7 @@ export const paramDef = {
 		icon: { type: 'string', enum: ['info', 'warning', 'error', 'success'] },
 		display: { type: 'string', enum: ['normal', 'banner', 'dialog'] },
 		forExistingUsers: { type: 'boolean' },
+		silence: { type: 'boolean' },
 		needConfirmationToRead: { type: 'boolean' },
 		isActive: { type: 'boolean' },
 	},
@@ -63,6 +64,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				display: ps.display,
 				icon: ps.icon,
 				forExistingUsers: ps.forExistingUsers,
+				silence: ps.silence,
 				needConfirmationToRead: ps.needConfirmationToRead,
 				isActive: ps.isActive,
 			}, me);
diff --git a/packages/frontend/src/components/global/MkCondensedLine.vue b/packages/frontend/src/components/global/MkCondensedLine.vue
index ef1c931bc32877e783f5b44ea3d98c2d903e8f4e..2ed615f5ff41d8b8cc62810b25bb710ecb9bd915 100644
--- a/packages/frontend/src/components/global/MkCondensedLine.vue
+++ b/packages/frontend/src/components/global/MkCondensedLine.vue
@@ -18,10 +18,10 @@ interface Props {
 
 const contentSymbol = Symbol();
 const observer = new ResizeObserver((entries) => {
-  const results: {
-    container: HTMLSpanElement;
-    transform: string;
-  }[] = [];
+	const results: {
+		container: HTMLSpanElement;
+		transform: string;
+	}[] = [];
 	for (const entry of entries) {
 		const content = (entry.target[contentSymbol] ? entry.target : entry.target.firstElementChild) as HTMLSpanElement;
 		const props: Required<Props> = content[contentSymbol];
diff --git a/packages/frontend/src/components/global/MkEmoji.vue b/packages/frontend/src/components/global/MkEmoji.vue
index e06549a89129cd6102830f904faa11e1e3f80922..0855f20b8d7ee5b44562170db107843be6f2aefc 100644
--- a/packages/frontend/src/components/global/MkEmoji.vue
+++ b/packages/frontend/src/components/global/MkEmoji.vue
@@ -4,21 +4,28 @@ SPDX-License-Identifier: AGPL-3.0-only
 -->
 
 <template>
-<img v-if="!useOsNativeEmojis" :class="$style.root" :src="url" :alt="props.emoji" decoding="async" @pointerenter="computeTitle"/>
-<span v-else-if="useOsNativeEmojis" :alt="props.emoji" @pointerenter="computeTitle">{{ props.emoji }}</span>
+<img v-if="!useOsNativeEmojis" :class="$style.root" :src="url" :alt="props.emoji" decoding="async" @pointerenter="computeTitle" @click="onClick"/>
+<span v-else-if="useOsNativeEmojis" :alt="props.emoji" @pointerenter="computeTitle" @click="onClick">{{ props.emoji }}</span>
 <span v-else>{{ emoji }}</span>
 </template>
 
 <script lang="ts" setup>
-import { computed } from 'vue';
+import { computed, inject } from 'vue';
 import { char2twemojiFilePath, char2fluentEmojiFilePath } from '@/scripts/emoji-base.js';
 import { defaultStore } from '@/store.js';
 import { getEmojiName } from '@/scripts/emojilist.js';
+import * as os from '@/os.js';
+import copyToClipboard from '@/scripts/copy-to-clipboard.js';
+import { i18n } from '@/i18n.js';
 
 const props = defineProps<{
 	emoji: string;
+	menu?: boolean;
+	menuReaction?: boolean;
 }>();
 
+const react = inject<((name: string) => void) | null>('react', null);
+
 const char2path = defaultStore.state.emojiStyle === 'twemoji' ? char2twemojiFilePath : char2fluentEmojiFilePath;
 
 const useOsNativeEmojis = computed(() => defaultStore.state.emojiStyle === 'native');
@@ -31,6 +38,28 @@ function computeTitle(event: PointerEvent): void {
 	const title = getEmojiName(props.emoji as string) ?? props.emoji as string;
 	(event.target as HTMLElement).title = title;
 }
+
+function onClick(ev: MouseEvent) {
+	if (props.menu) {
+		os.popupMenu([{
+			type: 'label',
+			text: props.emoji,
+		}, {
+			text: i18n.ts.copy,
+			icon: 'ti ti-copy',
+			action: () => {
+				copyToClipboard(props.emoji);
+				os.success();
+			},
+		}, ...(props.menuReaction && react ? [{
+			text: i18n.ts.doReaction,
+			icon: 'ti ti-plus',
+			action: () => {
+				react(props.emoji);
+			},
+		}] : [])], ev.currentTarget ?? ev.target);
+	}
+}
 </script>
 
 <style lang="scss" module>
diff --git a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
index 53cf7c29655de409d08405f2dd189c2f26f95fcc..5ff20fbe9bebf773a12699ea64ad937e44f142ad 100644
--- a/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
+++ b/packages/frontend/src/components/global/MkMisskeyFlavoredMarkdown.ts
@@ -354,6 +354,8 @@ export default function(props: MfmProps) {
 				return [h(MkEmoji, {
 					key: Math.random(),
 					emoji: token.props.emoji,
+					menu: props.enableEmojiMenu,
+					menuReaction: props.enableEmojiMenuReaction,
 				})];
 			}
 
diff --git a/packages/frontend/src/pages/admin/announcements.vue b/packages/frontend/src/pages/admin/announcements.vue
index 4d71dd464fe14b6cc978dd304aa3c662b986fdc1..77649c6c4af209b40a4223c128ca8972160f2128 100644
--- a/packages/frontend/src/pages/admin/announcements.vue
+++ b/packages/frontend/src/pages/admin/announcements.vue
@@ -48,6 +48,9 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<MkSwitch v-model="announcement.forExistingUsers" :helpText="i18n.ts._announcement.forExistingUsersDescription">
 						{{ i18n.ts._announcement.forExistingUsers }}
 					</MkSwitch>
+					<MkSwitch v-model="announcement.silence" :helpText="i18n.ts._announcement.silenceDescription">
+						{{ i18n.ts._announcement.silence }}
+					</MkSwitch>
 					<MkSwitch v-model="announcement.needConfirmationToRead" :helpText="i18n.ts._announcement.needConfirmationToReadDescription">
 						{{ i18n.ts._announcement.needConfirmationToRead }}
 					</MkSwitch>
@@ -97,6 +100,7 @@ function add() {
 		icon: 'info',
 		display: 'normal',
 		forExistingUsers: false,
+		silence: false,
 		needConfirmationToRead: false,
 	});
 }
diff --git a/packages/frontend/src/pages/announcements.vue b/packages/frontend/src/pages/announcements.vue
index 95ad6909755662b0079566d1fb679ef5396fc35d..51e1efda53926703a0801f1f3e4f3765fa30561e 100644
--- a/packages/frontend/src/pages/announcements.vue
+++ b/packages/frontend/src/pages/announcements.vue
@@ -13,7 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<section v-for="announcement in items" :key="announcement.id" class="_panel" :class="$style.announcement">
 					<div v-if="announcement.forYou" :class="$style.forYou"><i class="ph-push-pin ph-bold ph-lg"></i> {{ i18n.ts.forYou }}</div>
 					<div :class="$style.header">
-						<span v-if="$i && !announcement.isRead" style="margin-right: 0.5em;">🆕</span>
+						<span v-if="$i && !announcement.silence && !announcement.isRead" style="margin-right: 0.5em;">🆕</span>
 						<span style="margin-right: 0.5em;">
 							<i v-if="announcement.icon === 'info'" class="ph-info ph-bold ph-lg"></i>
 							<i v-else-if="announcement.icon === 'warning'" class="ph-warning ph-bold ph-lg" style="color: var(--warn);"></i>
@@ -29,7 +29,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 							<MkTime :time="announcement.updatedAt ?? announcement.createdAt" mode="detail"/>
 						</div>
 					</div>
-					<div v-if="tab !== 'past' && $i && !announcement.isRead" :class="$style.footer">
+					<div v-if="tab !== 'past' && $i && !announcement.silence && !announcement.isRead" :class="$style.footer">
 						<MkButton primary @click="read(announcement)"><i class="ph-check ph-bold ph-lg"></i> {{ i18n.ts.gotIt }}</MkButton>
 					</div>
 				</section>
diff --git a/packages/frontend/src/pages/settings/profile.vue b/packages/frontend/src/pages/settings/profile.vue
index 4acb4a7c517daef3e90e612b9d13bac89172222d..b585333bbd98f576eac5ad17174071b48cd71563 100644
--- a/packages/frontend/src/pages/settings/profile.vue
+++ b/packages/frontend/src/pages/settings/profile.vue
@@ -100,7 +100,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 				:class="[$style.avatarDecoration, { [$style.avatarDecorationActive]: $i.avatarDecorations.some(x => x.id === avatarDecoration.id) }]"
 				@click="openDecoration(avatarDecoration)"
 			>
-				<div :class="$style.avatarDecorationName"><MkCondensedLine :minScale="2 / 3">{{ avatarDecoration.name }}</MkCondensedLine></div>
+				<div :class="$style.avatarDecorationName"><MkCondensedLine :minScale="0.5">{{ avatarDecoration.name }}</MkCondensedLine></div>
 				<MkAvatar style="width: 60px; height: 60px;" :user="$i" :decoration="{ url: avatarDecoration.url }" forceShowDecoration/>
 				<i v-if="avatarDecoration.roleIdsThatCanBeUsedThisDecoration.length > 0 && !$i.roles.some(r => avatarDecoration.roleIdsThatCanBeUsedThisDecoration.includes(r.id))" :class="$style.avatarDecorationLock" class="ph-lock ph-bold ph-lg"></i>
 			</div>