diff --git a/.DS_Store b/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..f5ba9d7707d97a5c7a5be6dcd6bf3c309354af01
GIT binary patch
literal 8196
zcmeHLv2N5r5S_goA%O-&K@<sOsHhMT1tm^oC_({JDjJ0EF1kd?;S+a}(&3sOQJ_?*
z=-@A+bZJ2152*MB-t4ZeowcoWh$yos??gK@`<~yf*BKL$**F-j5v>r>5-zqkuA^&d
z?B}b|dVb^qtU*4}n2P=J+Sag`OdHWUpbDr0s(>n>3aA4Ag93PGb6e_o?>n#ds(>nR
zDHY)JA;HBq^|o}@9v$dx2>{#2ux<Dob%4!DyiL6=owcc$(^U_~ry5^k7?%!z!r`!~
zx23Z#os3H-<B^T8P>e-KUSh+^q|R!u3aA221-N!!q=z)5oZh$8@AqT>q{y<telfr}
z9=Y=QkM)!FX3Xf^nCVXVoxnb|eef95F3rU^gx7~Bn7{T(eERM21AmC!^b6cK7WZm}
zOFMKx1A$I=egQp-h&XI|4vi?mq$5i3p;rLIz2-E<Zzh<SFRP(XawyMg9enPj2+^B<
zf!j+lHTFSHGyJw`9%0}8I*<JlpQ^hPb4U*DF@i_pc?_`^bFkQsc-%~1S{{Kv;_;{6
zk0K`2f?8t)k6YgWgLN2DfhR+*!}6!^p)bO(bf|MXG^qUo_gccZ%UJsyxO?dNd3Z--
zu@e?<KWUHZ;L<W*2dkDy!LOe(zeTK!J1wwN0%qpv@yE}xKjie{!|vms)p-%j5whuu
z33!<7-XrF5g$^x~8SMou;5a>!-jD-4)fxr)A%pga03ZKd*mDDc+EjrHtH6R|zQXnY
zv+nQz7xw;?xGJCuoUefCXIt3@;(Tr0$mn4t!SxmwH;yZvwJGR0gvV_;4(rQtJC=A~
c>TT()O+}7Pg>{wuKll)!?|)tZZI@bszlT#i6951J

literal 0
HcmV?d00001

diff --git a/AGENTS.md b/AGENTS.md
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -155,7 +155,9 @@ Packaging facts the code relies on:
   `ai.storyteller.artcraft-launcher`, which toast notifications need. `portable.txt` beside the exe switches on portable mode
   (`ArtCraftLauncherData\` next to the exe).
 - The macOS bundle is `ArtCraft Launcher.app` (executable `Contents/MacOS/ArtCraft Launcher`), a
-  normal Dock app that can also sit in the menu bar: `LSUIElement` must never be set.
+  normal Dock app that can also sit in the menu bar: `LSUIElement` must never be set. The user
+  can hide the Dock icon while the window is put away in the menu bar; that switches the
+  activation policy at run time (`apps/artcraft-launcher/src/dock.rs`).
 - Linux: the tray uses StatusNotifierItem over D-Bus and notifications use
   `org.freedesktop.Notifications`, both in pure Rust (no GTK, appindicator or libdbus).
 - Inside the Flatpak launcher (`process::in_sandbox()`), apps normally install as host Flatpaks
diff --git a/apps/artcraft-launcher/Cargo.toml b/apps/artcraft-launcher/Cargo.toml
--- a/apps/artcraft-launcher/Cargo.toml
+++ b/apps/artcraft-launcher/Cargo.toml
@@ -39,13 +39,13 @@ zbus = "5"
 [target.'cfg(any(target_os = "macos", target_os = "windows"))'.dependencies]
 tray-icon = "0.25"
 
-# macOS only: which desktop (Space) the window shows on (spaces.rs) and the "Reduce motion"
-# setting (motion.rs). Safe AppKit calls only, and already in Cargo.lock through winit and
-# tray-icon; pinned exactly to those versions.
+# macOS only: which desktop (Space) the window shows on (spaces.rs), whether there's a Dock icon
+# (dock.rs) and the "Reduce motion" setting (motion.rs). Safe AppKit calls only, and already in
+# Cargo.lock through winit and tray-icon; pinned exactly to those versions.
 [target.'cfg(target_os = "macos")'.dependencies]
 objc2 = "=0.6.5"
 objc2-foundation = { version = "=0.3.2", default-features = false, features = ["std", "NSArray", "NSEnumerator"] }
-objc2-app-kit = { version = "=0.3.2", default-features = false, features = ["std", "NSAccessibility", "NSApplication", "NSResponder", "NSWindow", "NSWorkspace"] }
+objc2-app-kit = { version = "=0.3.2", default-features = false, features = ["std", "NSAccessibility", "NSApplication", "NSResponder", "NSRunningApplication", "NSWindow", "NSWorkspace"] }
 
 # Windows only: the "Animation effects" setting (motion.rs). Already in Cargo.lock through
 # artcraft-launcher-native.
diff --git a/apps/artcraft-launcher/src/dock.rs b/apps/artcraft-launcher/src/dock.rs
new file mode 100644
--- /dev/null
+++ b/apps/artcraft-launcher/src/dock.rs
@@ -0,0 +1,21 @@
+//! macOS only: whether the launcher has a Dock icon.
+//!
+//! The launcher is a normal Dock app (`LSUIElement` is never set). With "hide the Dock icon while
+//! the window is closed" on, it becomes a menu-bar-only (accessory) app while its window is put
+//! away in the menu bar, and a Dock app again when the window comes back. Other platforms have no
+//! Dock, so this module only exists on macOS.
+
+use objc2::MainThreadMarker;
+use objc2_app_kit::{NSApplication, NSApplicationActivationPolicy};
+
+/// Shows (`true`) or hides (`false`) the launcher's Dock icon, which also adds it to or takes it
+/// out of the app switcher (Cmd-Tab). Must run on the main thread, as the UI does; elsewhere it
+/// does nothing.
+pub fn show_icon(on: bool) {
+    let Some(mtm) = MainThreadMarker::new() else { return };
+    let policy = if on { NSApplicationActivationPolicy::Regular } else { NSApplicationActivationPolicy::Accessory };
+    let app = NSApplication::sharedApplication(mtm);
+    if app.activationPolicy() != policy && !app.setActivationPolicy(policy) {
+        log::warn!("couldn't {} the Dock icon", if on { "show" } else { "hide" });
+    }
+}
diff --git a/apps/artcraft-launcher/src/main.rs b/apps/artcraft-launcher/src/main.rs
--- a/apps/artcraft-launcher/src/main.rs
+++ b/apps/artcraft-launcher/src/main.rs
@@ -5,6 +5,8 @@
 #![cfg_attr(windows, windows_subsystem = "windows")]
 #![deny(clippy::unwrap_used, clippy::expect_used, clippy::panic, clippy::unimplemented, clippy::todo, clippy::unreachable)]
 
+#[cfg(target_os = "macos")]
+mod dock;
 mod logging;
 mod motion;
 mod settings_file;
@@ -331,6 +333,13 @@ enum OnClose {
     Quit,
 }
 
+/// Whether the Dock icon shows (macOS): always while the window is out, and while it is put away in
+/// the menu bar unless the user chose to hide it then.
+#[cfg_attr(not(target_os = "macos"), allow(dead_code))]
+fn shows_dock_icon(window_visible: bool, has_tray: bool, hide_dock_icon: bool) -> bool {
+    window_visible || !(has_tray && hide_dock_icon)
+}
+
 fn on_close(has_tray: bool, close_to_tray: bool, window_hides: bool) -> OnClose {
     if !(has_tray && close_to_tray) {
         OnClose::Quit
@@ -424,6 +433,10 @@ impl Host for DesktopHost {
         cfg!(target_os = "macos")
     }
 
+    fn has_dock(&self) -> bool {
+        cfg!(target_os = "macos")
+    }
+
     fn login_item(&self) -> Option<bool> {
         Some(login::is_enabled())
     }
@@ -625,6 +638,9 @@ struct Shell<'a> {
     /// The "show on the current desktop" setting last applied to the window (macOS).
     #[cfg_attr(not(target_os = "macos"), allow(dead_code))]
     applied_follow: Option<bool>,
+    /// Whether the Dock icon was last shown (macOS).
+    #[cfg_attr(not(target_os = "macos"), allow(dead_code))]
+    applied_dock: Option<bool>,
 }
 
 impl<'a> Shell<'a> {
@@ -632,7 +648,7 @@ impl<'a> Shell<'a> {
         let window_hides = window_can_hide(cc.display_handle().ok().map(|d| d.as_raw()));
         // Started hidden at login but there's no tray to come back from: show the window.
         let visible = !hidden || launcher.tray.is_none();
-        let mut shell = Self { launcher, window_hides, visible: true, quitting: false, applied_follow: None };
+        let mut shell = Self { launcher, window_hides, visible: true, quitting: false, applied_follow: None, applied_dock: None };
         if !visible {
             shell.put_away(&cc.egui_ctx);
         } else if hidden {
@@ -695,6 +711,16 @@ impl eframe::App for Shell<'_> {
                 Request::Quit => self.quit(ctx),
             }
         }
+        // After the requests, so a window being shown gets its Dock icon back before it comes out.
+        #[cfg(target_os = "macos")]
+        {
+            let settings = &self.launcher.ui.settings;
+            let on = shows_dock_icon(self.visible, self.launcher.tray.is_some(), settings.hide_dock_icon);
+            if self.applied_dock != Some(on) {
+                dock::show_icon(on);
+                self.applied_dock = Some(on);
+            }
+        }
         // The close button puts the window away in the tray unless the user chose to quit. That is
         // the window manager's button or the header's own (no decorations), which asks to close
         // with `ViewportCommand::Close` and arrives here the same way.
@@ -837,6 +863,15 @@ mod tests {
         }
     }
 
+    #[test]
+    fn the_dock_icon_hides_only_while_the_window_is_away_in_the_menu_bar() {
+        assert!(!shows_dock_icon(false, true, true));
+        // The window is out, the user keeps the icon, or there's no menu bar icon to come back from.
+        assert!(shows_dock_icon(true, true, true));
+        assert!(shows_dock_icon(false, true, false));
+        assert!(shows_dock_icon(false, false, true));
+    }
+
     #[test]
     fn the_tray_alone_waits_until_asked() {
         assert_eq!(tray_step(&[]), TrayStep::Stay);
@@ -965,7 +1000,8 @@ mod tests {
     fn quitting_overrides_a_close_to_the_tray() {
         let (mut launcher, _show, _) = launcher();
         let ctx = launcher.windowless.clone();
-        let mut shell = Shell { launcher: &mut launcher, window_hides: false, visible: true, quitting: false, applied_follow: None };
+        let mut shell =
+            Shell { launcher: &mut launcher, window_hides: false, visible: true, quitting: false, applied_follow: None, applied_dock: None };
         shell.put_away(&ctx);
         assert!(shell.launcher.closed_to_tray);
         shell.quit(&ctx);
@@ -976,7 +1012,8 @@ mod tests {
     fn a_window_that_hides_is_not_closed_to_the_tray() {
         let (mut launcher, _show, _) = launcher();
         let ctx = launcher.windowless.clone();
-        let mut shell = Shell { launcher: &mut launcher, window_hides: true, visible: true, quitting: false, applied_follow: None };
+        let mut shell =
+            Shell { launcher: &mut launcher, window_hides: true, visible: true, quitting: false, applied_follow: None, applied_dock: None };
         shell.put_away(&ctx);
         assert!(!shell.visible);
         assert!(!shell.launcher.closed_to_tray);
diff --git a/crates/native/src/self_update.rs b/crates/native/src/self_update.rs
--- a/crates/native/src/self_update.rs
+++ b/crates/native/src/self_update.rs
@@ -181,7 +181,8 @@ pub fn update(
         #[cfg(target_os = "macos")]
         Install::MacApp(bundle) => {
             let existing = Installed { version: None, source: InstallSource::MacApp, location: bundle.display().to_string(), package: None };
-            let placed = install::macos::install_dmg(&LAUNCHER, &file, Some(&existing), None, paths, &install::macos::Expect::release(release));
+            let placed =
+                install::macos::install_dmg(&LAUNCHER, &file, Some(&existing), None, false, paths, &install::macos::Expect::release(release));
             let _ = std::fs::remove_file(&file);
             let placed = placed?;
             relaunch_after_exit(pid, &[Path::new("/usr/bin/open").as_os_str(), placed.as_os_str()])
@@ -371,7 +372,7 @@ mod tests {
         let existing = Installed { version: None, source: InstallSource::MacApp, location: current.display().to_string(), package: None };
         // An unsigned test bundle: the signature check has its own tests in `install`.
         let expect = install::macos::Expect { team: None, version: None };
-        let placed = install::macos::install_dmg(&LAUNCHER, &dmg, Some(&existing), None, &Paths::under(dir.path()), &expect).unwrap();
+        let placed = install::macos::install_dmg(&LAUNCHER, &dmg, Some(&existing), None, false, &Paths::under(dir.path()), &expect).unwrap();
         assert_eq!(placed, current);
         assert_eq!(std::fs::read_to_string(current.join("Contents/MacOS/ArtCraft Launcher")).unwrap(), "0.2.0");
         assert_eq!(
diff --git a/crates/ui-egui/src/app.rs b/crates/ui-egui/src/app.rs
--- a/crates/ui-egui/src/app.rs
+++ b/crates/ui-egui/src/app.rs
@@ -46,6 +46,11 @@ pub trait Host {
     fn has_desktops(&self) -> bool {
         false
     }
+    /// The launcher has a Dock icon (macOS) that can be hidden while the window is put away in
+    /// the menu bar.
+    fn has_dock(&self) -> bool {
+        false
+    }
     /// `Some(enabled)` where starting at login is supported.
     fn login_item(&self) -> Option<bool> {
         None
diff --git a/crates/ui-egui/src/dialogs.rs b/crates/ui-egui/src/dialogs.rs
--- a/crates/ui-egui/src/dialogs.rs
+++ b/crates/ui-egui/src/dialogs.rs
@@ -439,6 +439,13 @@ impl LauncherUi {
             section(ui, tl!("Running in the background"));
             if host.has_tray() {
                 ui.checkbox(&mut self.settings.close_to_tray, tl!("Keep running in the tray when the window is closed"));
+                if host.has_dock() {
+                    ui.add_enabled(
+                        self.settings.close_to_tray,
+                        egui::Checkbox::new(&mut self.settings.hide_dock_icon, tl!("Hide the Dock icon while the window is closed")),
+                    )
+                    .on_hover_text(tl!("The launcher stays in the menu bar only. Its Dock icon comes back when you open the window."));
+                }
             }
             if host.has_desktops() {
                 ui.checkbox(&mut self.settings.show_on_current_desktop, tl!("Show the window on the current desktop"))
diff --git a/crates/ui-egui/src/i18n/cs.tsv b/crates/ui-egui/src/i18n/cs.tsv
--- a/crates/ui-egui/src/i18n/cs.tsv
+++ b/crates/ui-egui/src/i18n/cs.tsv
@@ -83,6 +83,8 @@
 	Running in the background	Běh na pozadí
 	Keep running in the tray when the window is closed	Po zavření okna ponechat spuštěné v oznamovací oblasti
 	Show the window on the current desktop	Zobrazit okno na aktuální ploše
+	Hide the Dock icon while the window is closed	Skrýt ikonu v Docku, když je okno zavřené
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	Launcher zůstane jen v řádku nabídek. Jeho ikona se do Docku vrátí, jakmile otevřete okno.
 	Start ArtCraft Launcher when I log in	Spouštět ArtCraft Launcher po přihlášení
 	Community	Komunita
 	Questions, ideas and news from the ArtCraft team	Dotazy, nápady a novinky od týmu ArtCraft
diff --git a/crates/ui-egui/src/i18n/de.tsv b/crates/ui-egui/src/i18n/de.tsv
--- a/crates/ui-egui/src/i18n/de.tsv
+++ b/crates/ui-egui/src/i18n/de.tsv
@@ -96,6 +96,8 @@
 	Running in the background	Im Hintergrund ausführen
 	Keep running in the tray when the window is closed	Beim Schließen des Fensters im Infobereich weiterlaufen
 	Show the window on the current desktop	Fenster auf dem aktuellen Schreibtisch zeigen
+	Hide the Dock icon while the window is closed	Dock-Symbol ausblenden, solange das Fenster geschlossen ist
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	Der Launcher bleibt dann nur in der Menüleiste. Sein Dock-Symbol erscheint wieder, sobald du das Fenster öffnest.
 	Start ArtCraft Launcher when I log in	ArtCraft Launcher bei der Anmeldung starten
 	Community	Community
 	Questions, ideas and news from the ArtCraft team	Fragen, Ideen und Neuigkeiten vom ArtCraft-Team
diff --git a/crates/ui-egui/src/i18n/es.tsv b/crates/ui-egui/src/i18n/es.tsv
--- a/crates/ui-egui/src/i18n/es.tsv
+++ b/crates/ui-egui/src/i18n/es.tsv
@@ -96,6 +96,8 @@
 	Running in the background	En segundo plano
 	Keep running in the tray when the window is closed	Seguir abierto en la bandeja del sistema al cerrar la ventana
 	Show the window on the current desktop	Mostrar la ventana en el escritorio actual
+	Hide the Dock icon while the window is closed	Ocultar el icono del Dock mientras la ventana está cerrada
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	ArtCraft Launcher se queda solo en la barra de menús. Su icono vuelve al Dock cuando abres la ventana.
 	Start ArtCraft Launcher when I log in	Abrir ArtCraft Launcher al iniciar sesión
 	Community	Comunidad
 	Questions, ideas and news from the ArtCraft team	Preguntas, ideas y noticias del equipo de ArtCraft
diff --git a/crates/ui-egui/src/i18n/fr.tsv b/crates/ui-egui/src/i18n/fr.tsv
--- a/crates/ui-egui/src/i18n/fr.tsv
+++ b/crates/ui-egui/src/i18n/fr.tsv
@@ -94,6 +94,8 @@
 	Running in the background	Exécution en arrière-plan
 	Keep running in the tray when the window is closed	Rester actif dans la zone de notification à la fermeture de la fenêtre
 	Show the window on the current desktop	Afficher la fenêtre sur le bureau actuel
+	Hide the Dock icon while the window is closed	Masquer l'icône du Dock quand la fenêtre est fermée
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	Le launcher reste uniquement dans la barre des menus. Son icône revient dans le Dock quand vous ouvrez la fenêtre.
 	Start ArtCraft Launcher when I log in	Lancer ArtCraft Launcher à l'ouverture de session
 	Community	Communauté
 	Questions, ideas and news from the ArtCraft team	Questions, idées et actualités de l'équipe ArtCraft
diff --git a/crates/ui-egui/src/i18n/hu.tsv b/crates/ui-egui/src/i18n/hu.tsv
--- a/crates/ui-egui/src/i18n/hu.tsv
+++ b/crates/ui-egui/src/i18n/hu.tsv
@@ -96,6 +96,8 @@
 	Running in the background	Futtatás a háttérben
 	Keep running in the tray when the window is closed	Az ablak bezárásakor kerüljön a tálcára
 	Show the window on the current desktop	Ablak megjelenítése az aktuális asztalon
+	Hide the Dock icon while the window is closed	Dock-ikon elrejtése, amíg az ablak zárva van
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	Az ArtCraft Launcher ilyenkor csak a menüsorban látható. A Dock-ikonja az ablak megnyitásakor visszatér.
 	Start ArtCraft Launcher when I log in	ArtCraft Launcher indítása bejelentkezéskor
 	Community	Közösség
 	Questions, ideas and news from the ArtCraft team	Kérdések, ötletek és hírek az ArtCraft csapatától
diff --git a/crates/ui-egui/src/i18n/ja.tsv b/crates/ui-egui/src/i18n/ja.tsv
--- a/crates/ui-egui/src/i18n/ja.tsv
+++ b/crates/ui-egui/src/i18n/ja.tsv
@@ -98,6 +98,8 @@
 	Running in the background	バックグラウンドで実行
 	Keep running in the tray when the window is closed	ウィンドウを閉じてもトレイで実行し続ける
 	Show the window on the current desktop	現在のデスクトップにウィンドウを表示
+	Hide the Dock icon while the window is closed	ウィンドウを閉じている間は Dock のアイコンを隠す
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	ランチャーはメニューバーにだけ表示されます。ウィンドウを開くと Dock のアイコンが戻ります。
 	Start ArtCraft Launcher when I log in	ログイン時に ArtCraft Launcher を起動
 	Community	コミュニティ
 	Questions, ideas and news from the ArtCraft team	ArtCraft チームからの質問、アイデア、ニュース
diff --git a/crates/ui-egui/src/i18n/pl.tsv b/crates/ui-egui/src/i18n/pl.tsv
--- a/crates/ui-egui/src/i18n/pl.tsv
+++ b/crates/ui-egui/src/i18n/pl.tsv
@@ -97,6 +97,8 @@
 	Running in the background	Działanie w tle
 	Keep running in the tray when the window is closed	Po zamknięciu okna działaj w zasobniku systemowym
 	Show the window on the current desktop	Pokaż okno na bieżącym pulpicie
+	Hide the Dock icon while the window is closed	Ukryj ikonę w Docku, gdy okno jest zamknięte
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	Launcher pozostaje wtedy tylko na pasku menu. Jego ikona wraca do Docka, gdy otworzysz okno.
 	Start ArtCraft Launcher when I log in	Uruchom ArtCraft Launcher po zalogowaniu
 	Community	Społeczność
 	Questions, ideas and news from the ArtCraft team	Pytania, pomysły i nowości od zespołu ArtCraft
diff --git a/crates/ui-egui/src/i18n/pt-BR.tsv b/crates/ui-egui/src/i18n/pt-BR.tsv
--- a/crates/ui-egui/src/i18n/pt-BR.tsv
+++ b/crates/ui-egui/src/i18n/pt-BR.tsv
@@ -84,6 +84,8 @@
 	Running in the background	Execução em segundo plano
 	Keep running in the tray when the window is closed	Continuar na bandeja do sistema ao fechar a janela
 	Show the window on the current desktop	Mostrar a janela na área de trabalho atual
+	Hide the Dock icon while the window is closed	Ocultar o ícone do Dock enquanto a janela estiver fechada
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	O launcher fica apenas na barra de menus. O ícone volta ao Dock quando você abre a janela.
 	Start ArtCraft Launcher when I log in	Iniciar o ArtCraft Launcher ao fazer login
 	Community	Comunidade
 	Questions, ideas and news from the ArtCraft team	Dúvidas, ideias e novidades da equipe ArtCraft
diff --git a/crates/ui-egui/src/i18n/ru.tsv b/crates/ui-egui/src/i18n/ru.tsv
--- a/crates/ui-egui/src/i18n/ru.tsv
+++ b/crates/ui-egui/src/i18n/ru.tsv
@@ -94,6 +94,8 @@
 	Running in the background	Работа в фоне
 	Keep running in the tray when the window is closed	Оставаться в трее при закрытии окна
 	Show the window on the current desktop	Показывать окно на текущем рабочем столе
+	Hide the Dock icon while the window is closed	Скрывать значок в Dock, пока окно закрыто
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	Лаунчер остаётся только в строке меню. Значок в Dock появится снова, когда вы откроете окно.
 	Start ArtCraft Launcher when I log in	Запускать ArtCraft Launcher при входе в систему
 	Community	Сообщество
 	Questions, ideas and news from the ArtCraft team	Вопросы, идеи и новости от команды ArtCraft
diff --git a/crates/ui-egui/src/i18n/zh-CN.tsv b/crates/ui-egui/src/i18n/zh-CN.tsv
--- a/crates/ui-egui/src/i18n/zh-CN.tsv
+++ b/crates/ui-egui/src/i18n/zh-CN.tsv
@@ -78,6 +78,8 @@
 	Running in the background	后台运行
 	Keep running in the tray when the window is closed	关闭窗口后继续在系统托盘中运行
 	Show the window on the current desktop	在当前桌面显示窗口
+	Hide the Dock icon while the window is closed	窗口关闭时隐藏程序坞图标
+	The launcher stays in the menu bar only. Its Dock icon comes back when you open the window.	启动器只保留在菜单栏中。打开窗口后，程序坞图标会重新出现。
 	Start ArtCraft Launcher when I log in	登录时启动 ArtCraft Launcher
 	Community	社区
 	Questions, ideas and news from the ArtCraft team	与 ArtCraft 团队交流问题、想法和动态
diff --git a/crates/ui-egui/src/settings.rs b/crates/ui-egui/src/settings.rs
--- a/crates/ui-egui/src/settings.rs
+++ b/crates/ui-egui/src/settings.rs
@@ -98,6 +98,8 @@ pub struct Settings {
     /// macOS: showing the window brings it to the current desktop (Space) instead of switching to
     /// the desktop it was on.
     pub show_on_current_desktop: bool,
+    /// macOS: while the window is put away in the menu bar, the launcher has no Dock icon.
+    pub hide_dock_icon: bool,
     pub check_every: CheckEvery,
     /// Automatically download and install updates when found.
     #[serde(default)]
@@ -179,6 +181,7 @@ impl Default for Settings {
             language: "auto".to_string(),
             close_to_tray: true,
             show_on_current_desktop: true,
+            hide_dock_icon: false,
             check_every: CheckEvery::Hour,
             auto_update: false,
             notify: true,
diff --git a/crates/ui-egui/tests/ui.rs b/crates/ui-egui/tests/ui.rs
--- a/crates/ui-egui/tests/ui.rs
+++ b/crates/ui-egui/tests/ui.rs
@@ -1018,6 +1018,62 @@ fn the_current_desktop_setting_is_only_offered_where_the_os_has_desktops() {
     assert!(Settings::default().show_on_current_desktop);
 }
 
+#[test]
+fn the_dock_icon_can_be_hidden_while_the_launcher_waits_in_the_menu_bar() {
+    const HIDE: &str = "Hide the Dock icon while the window is closed";
+    // NoHost has no Dock (Windows, Linux, web): no setting. It's off by default, so the Dock icon stays.
+    let (mut h, _) = harness(ViewMode::Grid, egui::Theme::Dark, true);
+    h.run_steps(6);
+    h.get_by_label("Settings").click();
+    h.run_steps(4);
+    assert!(h.query_by_label(HIDE).is_none());
+    assert!(!Settings::default().hide_dock_icon);
+
+    // macOS with a menu bar icon (DesktopHost::has_dock).
+    struct DockHost;
+    impl Host for DockHost {
+        fn has_tray(&self) -> bool {
+            true
+        }
+        fn has_dock(&self) -> bool {
+            true
+        }
+    }
+    let mut backend = Some(Fake {
+        events: events(),
+        sent: Rc::default(),
+        manage: true,
+        pictures: Rc::default(),
+        asked: Vec::new(),
+        clock: Rc::new(Cell::new(NOW)),
+    });
+    let mut h = Harness::builder().with_size(egui::vec2(1180.0, 900.0)).build_ui_state(
+        move |ui, state: &mut Option<LauncherUi>| {
+            if state.is_none()
+                && let Some(b) = backend.take()
+            {
+                *state = Some(LauncherUi::new(ui.ctx(), Box::new(b), Settings { notify: false, ..Settings::default() }));
+            }
+            if let Some(l) = state.as_mut() {
+                l.logic(&ui.ctx().clone(), &mut DockHost);
+                l.ui(ui, &mut DockHost);
+            }
+        },
+        None,
+    );
+    let hide_dock_icon = |h: &Harness<'_, Option<LauncherUi>>| h.state().as_ref().is_some_and(|l| l.settings.hide_dock_icon);
+    h.run_steps(6);
+    h.get_by_label("Settings").click();
+    h.run_steps(4);
+    h.get_by_label(HIDE).click();
+    h.run_steps(2);
+    assert!(hide_dock_icon(&h));
+    // Only meaningful while closing keeps the launcher in the menu bar.
+    h.get_by_label("Keep running in the tray when the window is closed").click();
+    h.run_steps(2);
+    assert!(h.get_by_label(HIDE).accesskit_node().is_disabled());
+}
+
 #[test]
 fn feed_announcements_and_alerts_show_until_dismissed() {
     use artcraft_launcher_core::feed::Notice;
