diff --git a/README.md b/README.md
index 13d78be..c8c99fb 100644
--- a/README.md
+++ b/README.md
@@ -173,3 +173,16 @@ The documentation content is dual-licensed under
and [MIT](https://opensource.org/licenses/MIT) for code samples.
Mobile documentation captures use the actual mobile shell with Android user-agent and touch emulation at a 412×915 CSS-pixel viewport. They use sample server state and are layout examples, not physical-device or Android permission-dialog captures.
+
+### Screenshot themes
+
+Current client screenshots use paired assets: `name.png` for light and
+`name-dark.png` for dark. Wrap both images in `.theme-screenshot` with
+`.screenshot-light` and `.screenshot-dark`; the site selects the matching
+image from Starlight’s `data-theme`, including system appearance. Preserve
+the same sample state in both captures.
+
+Screenshots show actual client components populated with local sample data.
+Mobile captures use the Android responsive shell in a browser, rather than
+a physical device. The live document example is a local document canvas;
+it does not demonstrate an active server plugin session.
diff --git a/public/mainpage-dark.png b/public/mainpage-dark.png
new file mode 100644
index 0000000..51bf9e5
Binary files /dev/null and b/public/mainpage-dark.png differ
diff --git a/public/mainpage.png b/public/mainpage.png
index 572bc04..04d4632 100644
Binary files a/public/mainpage.png and b/public/mainpage.png differ
diff --git a/public/preview-dark.png b/public/preview-dark.png
new file mode 100644
index 0000000..0ae36bb
Binary files /dev/null and b/public/preview-dark.png differ
diff --git a/public/preview.png b/public/preview.png
index 9bf0e7b..2d122ed 100644
Binary files a/public/preview.png and b/public/preview.png differ
diff --git a/public/screenshot-admin-acl-1-dark.png b/public/screenshot-admin-acl-1-dark.png
new file mode 100644
index 0000000..1bf6784
Binary files /dev/null and b/public/screenshot-admin-acl-1-dark.png differ
diff --git a/public/screenshot-admin-acl-1.png b/public/screenshot-admin-acl-1.png
index 6570145..e10da59 100644
Binary files a/public/screenshot-admin-acl-1.png and b/public/screenshot-admin-acl-1.png differ
diff --git a/public/screenshot-admin-bans-1-dark.png b/public/screenshot-admin-bans-1-dark.png
new file mode 100644
index 0000000..6790d97
Binary files /dev/null and b/public/screenshot-admin-bans-1-dark.png differ
diff --git a/public/screenshot-admin-bans-1.png b/public/screenshot-admin-bans-1.png
index 1aca903..e487884 100644
Binary files a/public/screenshot-admin-bans-1.png and b/public/screenshot-admin-bans-1.png differ
diff --git a/public/screenshot-admin-emotes-1-dark.png b/public/screenshot-admin-emotes-1-dark.png
new file mode 100644
index 0000000..9e30439
Binary files /dev/null and b/public/screenshot-admin-emotes-1-dark.png differ
diff --git a/public/screenshot-admin-emotes-1.png b/public/screenshot-admin-emotes-1.png
index f377732..3c1e322 100644
Binary files a/public/screenshot-admin-emotes-1.png and b/public/screenshot-admin-emotes-1.png differ
diff --git a/public/screenshot-admin-marketplace-1-dark.png b/public/screenshot-admin-marketplace-1-dark.png
new file mode 100644
index 0000000..526bc03
Binary files /dev/null and b/public/screenshot-admin-marketplace-1-dark.png differ
diff --git a/public/screenshot-admin-marketplace-1.png b/public/screenshot-admin-marketplace-1.png
index 6d00018..da9a17f 100644
Binary files a/public/screenshot-admin-marketplace-1.png and b/public/screenshot-admin-marketplace-1.png differ
diff --git a/public/screenshot-admin-onboarding-1-dark.png b/public/screenshot-admin-onboarding-1-dark.png
new file mode 100644
index 0000000..9ab8077
Binary files /dev/null and b/public/screenshot-admin-onboarding-1-dark.png differ
diff --git a/public/screenshot-admin-onboarding-1.png b/public/screenshot-admin-onboarding-1.png
index 59eb78f..b237c7a 100644
Binary files a/public/screenshot-admin-onboarding-1.png and b/public/screenshot-admin-onboarding-1.png differ
diff --git a/public/screenshot-admin-roles-1-dark.png b/public/screenshot-admin-roles-1-dark.png
new file mode 100644
index 0000000..cf2521b
Binary files /dev/null and b/public/screenshot-admin-roles-1-dark.png differ
diff --git a/public/screenshot-admin-roles-1.png b/public/screenshot-admin-roles-1.png
index 8009c28..18e8cf8 100644
Binary files a/public/screenshot-admin-roles-1.png and b/public/screenshot-admin-roles-1.png differ
diff --git a/public/screenshot-admin-users-1-dark.png b/public/screenshot-admin-users-1-dark.png
new file mode 100644
index 0000000..8a48157
Binary files /dev/null and b/public/screenshot-admin-users-1-dark.png differ
diff --git a/public/screenshot-admin-users-1.png b/public/screenshot-admin-users-1.png
index 976db4d..40072ac 100644
Binary files a/public/screenshot-admin-users-1.png and b/public/screenshot-admin-users-1.png differ
diff --git a/public/screenshot-getting-started-connect-1-dark.png b/public/screenshot-getting-started-connect-1-dark.png
new file mode 100644
index 0000000..8bf0500
Binary files /dev/null and b/public/screenshot-getting-started-connect-1-dark.png differ
diff --git a/public/screenshot-getting-started-connect-1.png b/public/screenshot-getting-started-connect-1.png
index c6bcf83..bf1a897 100644
Binary files a/public/screenshot-getting-started-connect-1.png and b/public/screenshot-getting-started-connect-1.png differ
diff --git a/public/screenshot-getting-started-first-call-1-dark.png b/public/screenshot-getting-started-first-call-1-dark.png
new file mode 100644
index 0000000..51bf9e5
Binary files /dev/null and b/public/screenshot-getting-started-first-call-1-dark.png differ
diff --git a/public/screenshot-getting-started-first-call-1.png b/public/screenshot-getting-started-first-call-1.png
index 572bc04..3d3addc 100644
Binary files a/public/screenshot-getting-started-first-call-1.png and b/public/screenshot-getting-started-first-call-1.png differ
diff --git a/public/screenshot-getting-started-first-call-2-dark.png b/public/screenshot-getting-started-first-call-2-dark.png
new file mode 100644
index 0000000..c530e44
Binary files /dev/null and b/public/screenshot-getting-started-first-call-2-dark.png differ
diff --git a/public/screenshot-getting-started-first-call-2.png b/public/screenshot-getting-started-first-call-2.png
index 340e843..74ef98d 100644
Binary files a/public/screenshot-getting-started-first-call-2.png and b/public/screenshot-getting-started-first-call-2.png differ
diff --git a/public/screenshot-getting-started-install-2-dark.png b/public/screenshot-getting-started-install-2-dark.png
new file mode 100644
index 0000000..0c68e7f
Binary files /dev/null and b/public/screenshot-getting-started-install-2-dark.png differ
diff --git a/public/screenshot-getting-started-install-2.png b/public/screenshot-getting-started-install-2.png
index 8abaa0a..9873c5d 100644
Binary files a/public/screenshot-getting-started-install-2.png and b/public/screenshot-getting-started-install-2.png differ
diff --git a/public/screenshot-mobile-channels-dark.png b/public/screenshot-mobile-channels-dark.png
new file mode 100644
index 0000000..0e755d0
Binary files /dev/null and b/public/screenshot-mobile-channels-dark.png differ
diff --git a/public/screenshot-mobile-chat-dark.png b/public/screenshot-mobile-chat-dark.png
new file mode 100644
index 0000000..79de88d
Binary files /dev/null and b/public/screenshot-mobile-chat-dark.png differ
diff --git a/public/screenshot-mobile-chat.png b/public/screenshot-mobile-chat.png
index db2f2eb..40ea9fb 100644
Binary files a/public/screenshot-mobile-chat.png and b/public/screenshot-mobile-chat.png differ
diff --git a/public/screenshot-mobile-profile-dark.png b/public/screenshot-mobile-profile-dark.png
new file mode 100644
index 0000000..8ef95f1
Binary files /dev/null and b/public/screenshot-mobile-profile-dark.png differ
diff --git a/public/screenshot-mobile-profile.png b/public/screenshot-mobile-profile.png
index 2ac9c78..74a55d2 100644
Binary files a/public/screenshot-mobile-profile.png and b/public/screenshot-mobile-profile.png differ
diff --git a/public/screenshot-mobile-voice-dark.png b/public/screenshot-mobile-voice-dark.png
new file mode 100644
index 0000000..1d2bedd
Binary files /dev/null and b/public/screenshot-mobile-voice-dark.png differ
diff --git a/public/screenshot-server-features-link-previews-1-dark.png b/public/screenshot-server-features-link-previews-1-dark.png
new file mode 100644
index 0000000..6811122
Binary files /dev/null and b/public/screenshot-server-features-link-previews-1-dark.png differ
diff --git a/public/screenshot-server-features-link-previews-1.png b/public/screenshot-server-features-link-previews-1.png
index 18c96fc..82827b6 100644
Binary files a/public/screenshot-server-features-link-previews-1.png and b/public/screenshot-server-features-link-previews-1.png differ
diff --git a/public/screenshot-server-features-persistent-chat-1-dark.png b/public/screenshot-server-features-persistent-chat-1-dark.png
new file mode 100644
index 0000000..7d3690a
Binary files /dev/null and b/public/screenshot-server-features-persistent-chat-1-dark.png differ
diff --git a/public/screenshot-server-features-persistent-chat-1.png b/public/screenshot-server-features-persistent-chat-1.png
index ab3949b..68aada2 100644
Binary files a/public/screenshot-server-features-persistent-chat-1.png and b/public/screenshot-server-features-persistent-chat-1.png differ
diff --git a/public/screenshot-server-features-reactions-1-dark.png b/public/screenshot-server-features-reactions-1-dark.png
new file mode 100644
index 0000000..4ff2ea4
Binary files /dev/null and b/public/screenshot-server-features-reactions-1-dark.png differ
diff --git a/public/screenshot-server-features-reactions-1.png b/public/screenshot-server-features-reactions-1.png
index da2dba8..b28ad13 100644
Binary files a/public/screenshot-server-features-reactions-1.png and b/public/screenshot-server-features-reactions-1.png differ
diff --git a/public/screenshot-troubleshooting-debug-logging-1-dark.png b/public/screenshot-troubleshooting-debug-logging-1-dark.png
new file mode 100644
index 0000000..7446af0
Binary files /dev/null and b/public/screenshot-troubleshooting-debug-logging-1-dark.png differ
diff --git a/public/screenshot-troubleshooting-debug-logging-1.png b/public/screenshot-troubleshooting-debug-logging-1.png
index b12b871..ecf18df 100644
Binary files a/public/screenshot-troubleshooting-debug-logging-1.png and b/public/screenshot-troubleshooting-debug-logging-1.png differ
diff --git a/public/screenshot-users-audio-1-dark.png b/public/screenshot-users-audio-1-dark.png
new file mode 100644
index 0000000..c530e44
Binary files /dev/null and b/public/screenshot-users-audio-1-dark.png differ
diff --git a/public/screenshot-users-audio-1.png b/public/screenshot-users-audio-1.png
index 340e843..74ef98d 100644
Binary files a/public/screenshot-users-audio-1.png and b/public/screenshot-users-audio-1.png differ
diff --git a/public/screenshot-users-audio-2-dark.png b/public/screenshot-users-audio-2-dark.png
new file mode 100644
index 0000000..cf4206c
Binary files /dev/null and b/public/screenshot-users-audio-2-dark.png differ
diff --git a/public/screenshot-users-audio-2.png b/public/screenshot-users-audio-2.png
index a91efec..29b2c96 100644
Binary files a/public/screenshot-users-audio-2.png and b/public/screenshot-users-audio-2.png differ
diff --git a/public/screenshot-users-chat-background-dark.png b/public/screenshot-users-chat-background-dark.png
new file mode 100644
index 0000000..264b7c1
Binary files /dev/null and b/public/screenshot-users-chat-background-dark.png differ
diff --git a/public/screenshot-users-chat-background.png b/public/screenshot-users-chat-background.png
new file mode 100644
index 0000000..f63d87a
Binary files /dev/null and b/public/screenshot-users-chat-background.png differ
diff --git a/public/screenshot-users-chat-community-dark.png b/public/screenshot-users-chat-community-dark.png
new file mode 100644
index 0000000..51bf9e5
Binary files /dev/null and b/public/screenshot-users-chat-community-dark.png differ
diff --git a/public/screenshot-users-chat-community.png b/public/screenshot-users-chat-community.png
index 572bc04..3d3addc 100644
Binary files a/public/screenshot-users-chat-community.png and b/public/screenshot-users-chat-community.png differ
diff --git a/public/screenshot-users-file-sharing-1-dark.png b/public/screenshot-users-file-sharing-1-dark.png
new file mode 100644
index 0000000..7bfaebc
Binary files /dev/null and b/public/screenshot-users-file-sharing-1-dark.png differ
diff --git a/public/screenshot-users-file-sharing-1.png b/public/screenshot-users-file-sharing-1.png
index bbb747b..22e6165 100644
Binary files a/public/screenshot-users-file-sharing-1.png and b/public/screenshot-users-file-sharing-1.png differ
diff --git a/public/screenshot-users-file-sharing-2-dark.png b/public/screenshot-users-file-sharing-2-dark.png
new file mode 100644
index 0000000..2cb924c
Binary files /dev/null and b/public/screenshot-users-file-sharing-2-dark.png differ
diff --git a/public/screenshot-users-file-sharing-2.png b/public/screenshot-users-file-sharing-2.png
index c7de431..fb44641 100644
Binary files a/public/screenshot-users-file-sharing-2.png and b/public/screenshot-users-file-sharing-2.png differ
diff --git a/public/screenshot-users-live-doc-1-dark.png b/public/screenshot-users-live-doc-1-dark.png
new file mode 100644
index 0000000..5b7ef54
Binary files /dev/null and b/public/screenshot-users-live-doc-1-dark.png differ
diff --git a/public/screenshot-users-live-doc-1.png b/public/screenshot-users-live-doc-1.png
new file mode 100644
index 0000000..9d005de
Binary files /dev/null and b/public/screenshot-users-live-doc-1.png differ
diff --git a/public/screenshot-users-notifications-1-dark.png b/public/screenshot-users-notifications-1-dark.png
new file mode 100644
index 0000000..7cc0b4d
Binary files /dev/null and b/public/screenshot-users-notifications-1-dark.png differ
diff --git a/public/screenshot-users-notifications-1.png b/public/screenshot-users-notifications-1.png
index 010f727..dc43f15 100644
Binary files a/public/screenshot-users-notifications-1.png and b/public/screenshot-users-notifications-1.png differ
diff --git a/public/screenshot-users-personalization-1-dark.png b/public/screenshot-users-personalization-1-dark.png
new file mode 100644
index 0000000..a36ccc6
Binary files /dev/null and b/public/screenshot-users-personalization-1-dark.png differ
diff --git a/public/screenshot-users-personalization-1.png b/public/screenshot-users-personalization-1.png
new file mode 100644
index 0000000..482dfa5
Binary files /dev/null and b/public/screenshot-users-personalization-1.png differ
diff --git a/public/screenshot-users-personalization-2-dark.png b/public/screenshot-users-personalization-2-dark.png
new file mode 100644
index 0000000..da94cac
Binary files /dev/null and b/public/screenshot-users-personalization-2-dark.png differ
diff --git a/public/screenshot-users-personalization-2.png b/public/screenshot-users-personalization-2.png
index aca1ff7..e72826d 100644
Binary files a/public/screenshot-users-personalization-2.png and b/public/screenshot-users-personalization-2.png differ
diff --git a/public/screenshot-users-personalization-3-dark.png b/public/screenshot-users-personalization-3-dark.png
new file mode 100644
index 0000000..036950e
Binary files /dev/null and b/public/screenshot-users-personalization-3-dark.png differ
diff --git a/public/screenshot-users-personalization-3.png b/public/screenshot-users-personalization-3.png
index 05bc326..af07e3a 100644
Binary files a/public/screenshot-users-personalization-3.png and b/public/screenshot-users-personalization-3.png differ
diff --git a/public/screenshot-users-privacy-1-dark.png b/public/screenshot-users-privacy-1-dark.png
new file mode 100644
index 0000000..3399a3c
Binary files /dev/null and b/public/screenshot-users-privacy-1-dark.png differ
diff --git a/public/screenshot-users-privacy-1.png b/public/screenshot-users-privacy-1.png
index 1c31c42..dc1d61f 100644
Binary files a/public/screenshot-users-privacy-1.png and b/public/screenshot-users-privacy-1.png differ
diff --git a/public/screenshot-users-profile-1-dark.png b/public/screenshot-users-profile-1-dark.png
new file mode 100644
index 0000000..3376061
Binary files /dev/null and b/public/screenshot-users-profile-1-dark.png differ
diff --git a/public/screenshot-users-profile-1.png b/public/screenshot-users-profile-1.png
index b85773d..2b76309 100644
Binary files a/public/screenshot-users-profile-1.png and b/public/screenshot-users-profile-1.png differ
diff --git a/public/screenshot-users-profile-2-dark.png b/public/screenshot-users-profile-2-dark.png
new file mode 100644
index 0000000..62411c0
Binary files /dev/null and b/public/screenshot-users-profile-2-dark.png differ
diff --git a/public/screenshot-users-profile-2.png b/public/screenshot-users-profile-2.png
index c5159d3..09053b9 100644
Binary files a/public/screenshot-users-profile-2.png and b/public/screenshot-users-profile-2.png differ
diff --git a/public/screenshot-users-profile-3-dark.png b/public/screenshot-users-profile-3-dark.png
new file mode 100644
index 0000000..3a38b4e
Binary files /dev/null and b/public/screenshot-users-profile-3-dark.png differ
diff --git a/public/screenshot-users-profile-3.png b/public/screenshot-users-profile-3.png
index 0ce1250..c20f398 100644
Binary files a/public/screenshot-users-profile-3.png and b/public/screenshot-users-profile-3.png differ
diff --git a/public/screenshot-users-screen-sharing-1-dark.png b/public/screenshot-users-screen-sharing-1-dark.png
new file mode 100644
index 0000000..72c2019
Binary files /dev/null and b/public/screenshot-users-screen-sharing-1-dark.png differ
diff --git a/public/screenshot-users-screen-sharing-1.png b/public/screenshot-users-screen-sharing-1.png
index 72116fc..b38a7aa 100644
Binary files a/public/screenshot-users-screen-sharing-1.png and b/public/screenshot-users-screen-sharing-1.png differ
diff --git a/public/shortcuts-dark.png b/public/shortcuts-dark.png
new file mode 100644
index 0000000..173d3d4
Binary files /dev/null and b/public/shortcuts-dark.png differ
diff --git a/public/shortcuts.png b/public/shortcuts.png
index 9d7fbc5..913ef63 100644
Binary files a/public/shortcuts.png and b/public/shortcuts.png differ
diff --git a/src/content/docs/admin/acl.mdx b/src/content/docs/admin/acl.mdx
index 1ef07a3..c83d57e 100644
--- a/src/content/docs/admin/acl.mdx
+++ b/src/content/docs/admin/acl.mdx
@@ -15,7 +15,7 @@ ACLs are powerful, but easy to over-engineer. Most servers do fine
with mostly-roles plus a handful of per-channel ACL tweaks.
-
+
## Opening the ACL editor
diff --git a/src/content/docs/admin/bans.mdx b/src/content/docs/admin/bans.mdx
index 1cf7492..09b191e 100644
--- a/src/content/docs/admin/bans.mdx
+++ b/src/content/docs/admin/bans.mdx
@@ -15,7 +15,7 @@ The **Ban list** is a server-wide block list of:
Banned identities cannot connect. The list survives restarts.
-
+
## Ban from the user list
diff --git a/src/content/docs/admin/channels.mdx b/src/content/docs/admin/channels.mdx
index aaf8ba7..b93221f 100644
--- a/src/content/docs/admin/channels.mdx
+++ b/src/content/docs/admin/channels.mdx
@@ -11,7 +11,7 @@ Channels are the rooms in your server. Users sit in one channel at a
time for voice; chat is per channel.
-
+
## Create a channel
diff --git a/src/content/docs/admin/emotes.mdx b/src/content/docs/admin/emotes.mdx
index 1cdbe5b..4655ade 100644
--- a/src/content/docs/admin/emotes.mdx
+++ b/src/content/docs/admin/emotes.mdx
@@ -15,7 +15,7 @@ This feature requires the [file server](/server/features/file-server/)
to be enabled and the **Manage emotes** permission.
-
+
## Upload an emote
diff --git a/src/content/docs/admin/groups.mdx b/src/content/docs/admin/groups.mdx
index 99a680a..1566d79 100644
--- a/src/content/docs/admin/groups.mdx
+++ b/src/content/docs/admin/groups.mdx
@@ -13,7 +13,7 @@ should use instead. Groups are still useful for **per-channel
membership lists** that should not be promoted to server-wide roles.
-
+
## Groups vs roles
diff --git a/src/content/docs/admin/marketplace.mdx b/src/content/docs/admin/marketplace.mdx
index 91a8341..e6fee0e 100644
--- a/src/content/docs/admin/marketplace.mdx
+++ b/src/content/docs/admin/marketplace.mdx
@@ -5,7 +5,7 @@ description: Browse plugins and check server support before installing them.
Open **Settings, Marketplace** to browse the catalogue exposed to your client. Availability depends on the catalogue, network access, and the connected server’s plugin capabilities.
-
+
## Check compatibility
diff --git a/src/content/docs/admin/onboarding.mdx b/src/content/docs/admin/onboarding.mdx
index 5444e88..1705821 100644
--- a/src/content/docs/admin/onboarding.mdx
+++ b/src/content/docs/admin/onboarding.mdx
@@ -20,7 +20,7 @@ If you have used Discord's "Community" onboarding, this is the same
idea.
-
+
## What you can configure
diff --git a/src/content/docs/admin/roles.mdx b/src/content/docs/admin/roles.mdx
index b3f5ea1..9467830 100644
--- a/src/content/docs/admin/roles.mdx
+++ b/src/content/docs/admin/roles.mdx
@@ -13,7 +13,7 @@ everywhere on the server. Roles are the bread-and-butter of
administration.
-
+
## Built-in roles
diff --git a/src/content/docs/admin/users.mdx b/src/content/docs/admin/users.mdx
index 3b4ed6c..e623aea 100644
--- a/src/content/docs/admin/users.mdx
+++ b/src/content/docs/admin/users.mdx
@@ -18,7 +18,7 @@ specific username on your server. Registered users can:
This page covers the **Registered users** tab in the admin panel.
-
+
## Register a user
diff --git a/src/content/docs/getting-started/android.mdx b/src/content/docs/getting-started/android.mdx
index 9cf5f9b..7119dc9 100644
--- a/src/content/docs/getting-started/android.mdx
+++ b/src/content/docs/getting-started/android.mdx
@@ -16,7 +16,7 @@ small adjustments for touch.
-
+
The screenshots show the current phone layout with a sample community.
@@ -59,7 +59,7 @@ notifications. Open **Settings, Battery, Fancy Mumble** and pick
The **Channels**, **Friends**, and **Settings** tabs sit at the bottom of the navigation screen. Select a channel to open its conversation; use **Back** to return to the channel list. The server-strip control shows or hides saved servers.
-
+
Chat gives the conversation the whole screen. Its composer stays at the bottom, and an active voice call adds a compact call bar above it. File-sharing controls depend on the connected server's capabilities.
@@ -67,13 +67,13 @@ Chat gives the conversation the whole screen. Its composer stays at the bottom,
Tap **In voice** on the call bar to expand the call screen. It shows the channel's participants and their audio states. Use the large microphone and headphones controls to mute or deafen, **Disconnect** to leave voice, and the down arrow to return to chat.
-
+
## Profiles and message actions
Tap a member's name or avatar to inspect their profile and available actions. Profiles can include their own avatar, banner, status, pronouns, and bio. Long-press a message for its available actions, such as reply, reaction, or copy; moderation actions depend on your permissions.
-
+
## Battery and data
diff --git a/src/content/docs/getting-started/connect.mdx b/src/content/docs/getting-started/connect.mdx
index 07e8106..96b7604 100644
--- a/src/content/docs/getting-started/connect.mdx
+++ b/src/content/docs/getting-started/connect.mdx
@@ -10,7 +10,7 @@ Ask the server owner for its host name, port, and any password. The default Mumb
3. Save the entry, select it in the server list, and choose **Connect**.
4. Complete any server password or account prompt. The app can remember passwords in the operating system's credential store.
-
+
The saved entry belongs to the identity you chose. Use your server owner's address; sample addresses in documentation are examples.
diff --git a/src/content/docs/getting-started/first-call.mdx b/src/content/docs/getting-started/first-call.mdx
index fd8c0ad..8554258 100644
--- a/src/content/docs/getting-started/first-call.mdx
+++ b/src/content/docs/getting-started/first-call.mdx
@@ -5,7 +5,7 @@ description: Join a channel, enable voice, and choose an activation mode.
After connecting, select a channel in the sidebar and use its **Join** action. Viewing a channel's chat and joining its voice room are separate actions.
-
+
## Enable voice
@@ -15,7 +15,7 @@ Use the microphone control in your voice dock. If it says **Enable voice**, the
The **Activation mode** cards offer **Voice activation**, **Continuous**, and **Push to talk**. Voice activation transmits while you speak; Continuous transmits continuously; Push to talk transmits while your chosen shortcut is held.
-
+
## Calibrate and listen
diff --git a/src/content/docs/getting-started/install.mdx b/src/content/docs/getting-started/install.mdx
index 61e4dc8..21c735c 100644
--- a/src/content/docs/getting-started/install.mdx
+++ b/src/content/docs/getting-started/install.mdx
@@ -11,7 +11,7 @@ import { Icon } from 'astro-icon/components';
Fancy Mumble runs on Windows, Linux, and Android. Pick your platform
below.
-
+
A sample community after connecting. Your first launch guides you through setup; then you can add your community''s server.
@@ -116,7 +116,7 @@ name, interface mode, and theme. Choose **Get started** to open the server
list, which is empty until you add a server.
-
+
If you do not see this screen, check
[Common issues](/troubleshooting/common-issues/).
diff --git a/src/content/docs/index.mdx b/src/content/docs/index.mdx
index a195926..49a9f8f 100644
--- a/src/content/docs/index.mdx
+++ b/src/content/docs/index.mdx
@@ -5,7 +5,7 @@ template: splash
hero:
tagline: A modern, feature-rich voice chat for gaming, podcasts, communities, and study groups.
image:
- html: ''
+ html: ''
actions:
- text: Get started in 5 minutes
link: /getting-started/install/
diff --git a/src/content/docs/server/features/link-previews.mdx b/src/content/docs/server/features/link-previews.mdx
index 293e4ff..e64d447 100644
--- a/src/content/docs/server/features/link-previews.mdx
+++ b/src/content/docs/server/features/link-previews.mdx
@@ -25,4 +25,4 @@ These limits bound page fetches, redirects, parallel work, and thumbnail size. S
The destination site sees a request from your server. Outbound DNS, firewall, and proxy rules can prevent a preview from loading. Check the link-preview service logs, then test a public page with Open Graph metadata. A page without suitable metadata may produce only a text link.
-
+
diff --git a/src/content/docs/server/features/persistent-chat.mdx b/src/content/docs/server/features/persistent-chat.mdx
index 7d64b5f..e3576db 100644
--- a/src/content/docs/server/features/persistent-chat.mdx
+++ b/src/content/docs/server/features/persistent-chat.mdx
@@ -21,4 +21,4 @@ Send a message, disconnect, reconnect with the same identity, and confirm that h
Moving an existing deployment has separate history limitations. Read [Migrating to Starling](/server/migrating-to-starling/) before importing its database.
-
+
diff --git a/src/content/docs/server/features/reactions.mdx b/src/content/docs/server/features/reactions.mdx
index 2a3ba40..84af337 100644
--- a/src/content/docs/server/features/reactions.mdx
+++ b/src/content/docs/server/features/reactions.mdx
@@ -12,7 +12,7 @@ Starling handles reactions and polls through its **social service**. The same se
The service is included in the default Starling stack. For a custom deployment, check that `social` is running and healthy. See [feature availability](/server/features/) and the [Starling service inventory](https://github.com/Fancy-Mumble/starling/blob/main/docs/SERVICES.md).
-
+
## Reactions
diff --git a/src/content/docs/troubleshooting/audio.mdx b/src/content/docs/troubleshooting/audio.mdx
index c4d82a1..22576b3 100644
--- a/src/content/docs/troubleshooting/audio.mdx
+++ b/src/content/docs/troubleshooting/audio.mdx
@@ -1,162 +1,72 @@
---
title: Audio problems
-description: No sound, no mic, choppy audio, echo, robot voice. A symptom-driven checklist.
-sidebar:
- order: 2
+description: Locate a voice failure by testing capture, processing, activation, output, and transport separately.
---
-import { Steps, Aside, Card, CardGrid } from '@astrojs/starlight/components';
+Use a quiet test channel and one other member. Change one setting at a time and repeat the same sentence. Start in **More, Settings, Voice** on desktop, or **Settings, Voice** on mobile.
-Most audio problems come from one of:
+## 1. Does the client receive your microphone?
-- The wrong **device** is selected.
-- The **activation mode** is wrong.
-- Your **firewall** is dropping UDP voice packets.
-- The **codec settings** do not match your network capacity.
+
-Walk through the section that matches your symptom.
+1. Turn voice on if the page offers **Turn voice on**. A connected text session does not by itself mean the audio engine is running.
+2. Select the microphone by name in **Input device**. System default can change when a headset is connected or a Bluetooth device changes profile.
+3. Speak while watching the voice-gate meter. Check that **Microphone volume** is not zero.
-## "Nobody can hear me"
+| Observation | What to test next |
+| --- | --- |
+| No level movement | Check microphone permission and the input device in the OS. Record with another app using the same device. If that also fails, resolve device/permission access first. |
+| The OS recorder works, but Fancy Mumble's meter does not | Re-select the input. On Windows, disable **Exclusive microphone mode** and close other apps holding the device. Turn voice off and on after the change. Capture the resulting device error in the client log. |
+| Level responds to speech | Continue to the sample recorder. Increasing gain will not fix a transmission or channel-permission problem. |
-
+On Windows, check **Settings, Privacy & security, Microphone** and access for desktop apps. On Android, check the app's **Microphone** permission. On Linux, check the recording stream's selected source in your PipeWire/PulseAudio mixer; an output monitor records the desktop instead of your microphone.
-1. Look at the **mute** and **deafen** icons at the bottom left of the
- window. Make sure neither is on.
+## 2. Is the processed signal usable?
-2. **Settings, Voice, Input device**. Confirm the correct microphone
- is selected. *System default* is fine on most setups.
+
-3. **Microphone Volume** slider: 100% is the safe default. Above
- that the app digitally amplifies; very high values can clip.
+Use **Hear yourself, Record sample**, speak for a few seconds, stop, and play it back. This tests the configured processing locally; it does not establish that another member receives your voice.
-4. Click **Calibrate** below the threshold slider. Speak. The fill
- bar should move. If it does not, the **operating system** is not
- delivering audio. Check OS-level mic settings.
+| Sample result | Next check |
+| --- | --- |
+| No playback, and other members are also inaudible | Select **Output device**, raise **Speaker volume** from zero, and check the OS per-app volume. Test another app through the same headphones. |
+| Loud cracks or distortion | Lower the microphone's OS input level and compare with **Auto gain** off. If the OS recorder is already distorted, changing the chat bitrate cannot repair the source. |
+| Words become metallic or disappear | Compare the same sentence with noise suppression **Off**, then with one algorithm enabled. Keep the option that preserves speech; do not combine this test with a gain or network change. |
+| Clear sample | Continue to activation and permissions. |
-5. If the fill bar moves but does not cross the threshold line,
- either:
- - Lower the threshold.
- - Turn on **Auto sensitivity**.
- - Increase the microphone volume.
+Noise suppression and the activation gate do different jobs: suppression processes sound; the gate decides when transmission is allowed. Continuous activation does not mean processing is disabled.
-6. If you are in **Push to Talk** mode, confirm the PTT key is set.
- Click the recorder and press your key.
+## 3. Does activation allow transmission?
-7. Try **Continuous** mode (no gate). If you can be heard in
- Continuous, the gate is too aggressive.
+Keep the microphone unmuted and headphones undeafened. Check the channel is the one you joined for voice, rather than only the conversation you are viewing.
-
+1. Temporarily select **Continuous** in the test channel and ask your partner to listen.
+2. If Continuous works but **Voice activation** does not, use **Auto calibrate**, press **Calibrate**, and speak naturally for about five seconds.
+3. For **Manual calibrate**, the Open marker must be crossed to begin transmitting. The lower Close marker and hold keep the gate open between syllables. A close threshold nearer the opening threshold makes it easier to close; raising it is not a general fix for cut-off speech.
+4. If Continuous works but **Push to talk** does not, check the assigned shortcut and whether it is detected with the client both focused and in the background. Do not use mute as the push-to-talk switch.
+5. Restore your usual activation mode after the test.
-## "I cannot hear anyone"
+If the local sample is clear and Continuous still cannot be heard, ask an administrator to check **Speak** permission and suppression in that channel. Try a channel where a known working member can speak. Record whether your own speaking indicator appears and whether the other member sees it.
-
-1. **Deafen** icon at the bottom left of the window: make sure it is off.
-2. **Settings, Voice, Output device**. Confirm the right speakers
- or headphones are selected.
-3. **Speaker Volume**: above 0. At 100% you hear at normal level.
-4. Are other apps audible? If no, the OS volume mixer is muting the
- app.
-5. On Windows: check the per-app volume in the OS mixer.
-
+## 4. Is voice transport the failing part?
-## "Audio is choppy or stuttering"
+Use **Force TCP audio** in the Transmission section as a comparison. Repeat the same test with it off and on; allow the client time to apply the change.
-The voice path is dropping packets.
+| Result | Interpretation and action |
+| --- | --- |
+| Voice works only with Force TCP audio | UDP reachability or the UDP voice path needs investigation. Report the server address, port, and test result to its owner. |
+| Voice fails over both paths, but local recording works | Check channel permissions, mute/suppression, and both clients' logs before changing codec settings. |
+| Only one listener fails | Check that listener's output device, local user mute/volume, and connection. |
+| All members become choppy together | Compare server voice-service logs and host load at the recorded time. |
-
-1. Settings, Voice, Network. Turn on **Force TCP**. This sends voice
- over the already-established connection and avoids UDP drops.
-2. Lower the **bitrate** to 32 kbps under Compression.
-3. Increase **Audio per packet** to 40 or 60 ms. Bigger packets per
- second, fewer of them.
-4. Switch to a wired Ethernet connection if you are on Wi-Fi.
-5. If you are on a busy Wi-Fi (apartment building, coffee shop),
- try a different channel from your router admin page.
-
+For the maintained Starling Compose deployment, normal Mumble voice needs **64738/UDP**, while control needs **64738/TCP**. A successful TCP port test does not test UDP. The owner should check the published UDP mapping and both host and cloud firewalls; see [Connection problems](/troubleshooting/connection/).
-If the problem persists, look at **Audio statistics** in the panel
-(Expert mode). Sustained >2% packet loss means the underlying
-connection is the issue, not the app.
+For stutter, make a controlled comparison using lower **Quality** (for example 32 kb/s) or a different **Audio per packet** value. A 40 ms packet bundles more audio into fewer packets than 20 ms and adds packetization delay; it is not a packet-loss repair. Note which change actually helped, then restore settings that did not.
-## "My voice sounds robotic or distorted"
+## Echo and feedback
-- The bitrate is too low for the activity (you are using extra-low
- bitrate for music). Bump bitrate.
-- Auto-gain is over-amplifying because the mic is too quiet. Lower
- the **Max Amplification** in Audio Processing.
-- The mic is clipping at the hardware level. Lower the OS-level mic
- level (not the app's).
+Mute your microphone during an echo and ask whether the echo stops. If it does, test with headphones and disable any loopback/desktop-monitor input. If it continues, isolate other participants one at a time. This identifies whose capture path contains the returned audio instead of asking everyone to change noise suppression.
-## "I hear an echo"
+## Evidence to attach
-You are picking up your own speakers in your mic.
-
-- Use **headphones**. Most echo problems go away.
-- Lower the speaker volume.
-- Some headsets have an "echo cancellation" toggle in their utility.
- Turn it on.
-- Make sure the mic is not pointed at the speakers.
-
-## "Voice cuts at the start of sentences"
-
-The gate is closing too quickly between syllables.
-
-- Settings, Voice, Expert, **Hold Frames**. Raise it. 10 to 20 is a
- good range.
-- **Gate Close Ratio**: try a higher value (closer to 1).
-
-## "Voice cuts in the middle of speech"
-
-The denoiser is being too aggressive.
-
-- Try a different denoiser algorithm. RNNoise is the friendliest
- default. DeepFilterNet is cleaner but may chop fricatives in
- rare cases.
-- Lower the **attenuation limit** in the algorithm's advanced
- controls.
-
-## "Background noise leaks through"
-
-- Switch to **DeepFilterNet** denoiser. Heavier but cleaner.
-- Raise the VAD threshold slightly.
-- Make sure **Voice Activation** mode is on. **Continuous** mode does
- not denoise.
-
-## "Mic test works but nobody hears me"
-
-The mic works on the OS side but the app is not transmitting.
-
-- **Activation mode**: confirm it is not stuck in PTT without a key.
-- **Whisper key** is held by accident, so audio is going to a
- whisper target. Check whisper keys in Shortcuts.
-- The server has **denied Speak** to your role in this channel. Try
- another channel.
-
-## "My friend hears themselves through me"
-
-You are unmuted in a noisy room and the speakers are picking up the
-remote audio. Mute when you are not talking, or use headphones.
-
-## "Cannot pick a specific audio device"
-
-- The device is offline or being exclusive-used by another app.
-- The OS does not expose it to apps without permission. On Windows,
- grant microphone permission to the app under Privacy settings.
-- On Linux PipeWire, the device may need to be made the default in
- `pavucontrol`.
-
-## Legacy backend
-
-If audio is wonky on Linux specifically, try **Settings, Voice,
-Expert, Legacy Audio Backend**. Takes effect on the next voice
-toggle.
-
-## Still broken?
-
-[Open a bug report](/troubleshooting/reporting-bugs/) with:
-
-- Your platform.
-- Output of the Audio statistics panel (Expert mode).
-- Whether the issue happens with another headset or another
- microphone.
-- Debug logs (see [Debug logging](/troubleshooting/debug-logging/)).
+Include input/output device names, activation mode, sample-recorder result, Continuous result, UDP-versus-TCP result, affected channel and listeners, and a timestamp with timezone. Attach a screenshot of Voice settings and [client logs](/troubleshooting/debug-logging/). This lets maintainers distinguish capture, processing, permission, and transport failures.
diff --git a/src/content/docs/troubleshooting/common-issues.mdx b/src/content/docs/troubleshooting/common-issues.mdx
index 7236e07..87048da 100644
--- a/src/content/docs/troubleshooting/common-issues.mdx
+++ b/src/content/docs/troubleshooting/common-issues.mdx
@@ -1,72 +1,33 @@
---
-title: Common issues
-description: First-line checks for the problems we see most often.
-sidebar:
- order: 1
+title: Find the failing part
+description: Choose a diagnostic path using what works and what fails.
---
-import { Aside, Card, CardGrid } from '@astrojs/starlight/components';
+Start with an observable result. Keep a working comparison—a second channel, listener, device, or network—so each change has a measurable outcome.
-Most problems fall into one of four buckets. Pick the closest match
-and follow the link for the deep dive.
+
-
-
- No sound out, no sound in, mic cuts, robot voice, echo. Start at
- [Audio problems](/troubleshooting/audio/).
-
-
- Connection refuses, times out, drops, or asks for a password
- when you do not have one. Start at
- [Connection problems](/troubleshooting/connection/).
-
-
- Black thumbnail, never appears, only some viewers see it. Start
- at [Screen-share problems](/troubleshooting/screen-share/).
-
-
- Send debug logs to a developer with the steps in
- [Debug logging](/troubleshooting/debug-logging/).
-
-
+| What fails | First comparison | Detailed guide |
+| --- | --- | --- |
+| Cannot connect | DNS and TCP listener test before changing credentials | [Connection problems](/troubleshooting/connection/) |
+| Chat works; nobody hears you | Local sample recorder, then Continuous activation, then TCP/UDP comparison | [Audio problems](/troubleshooting/audio/) |
+| You cannot hear members | Local playback and the selected output device | [Audio problems](/troubleshooting/audio/#2-is-the-processed-signal-usable) |
+| Share is blank | Sender preview versus one and then two viewers | [Screen-share problems](/troubleshooting/screen-share/) |
+| A Fancy feature is absent | Server capability and required plugin/service status | [Feature availability](/server/features/) |
+| Failure needs developer investigation | Short reproduction and synchronized logs | [Debug logging](/troubleshooting/debug-logging/) |
-## Quick sanity checks
+## File upload or download fails
-Before diving into a specific page, try these:
+If the attachment button says the server has no file sharing, ask the owner to check the advertised files service and your permissions. A URL that points to localhost can work on the server itself and fail for every remote client.
-### The app
+
-- **Restart the app**. Many transient bugs go away.
-- **Update the app** to the latest version. Get it from
- [fancy-mumble.com](https://fancy-mumble.com/) or the
- [GitHub releases page](https://github.com/Fancy-Mumble/FancyMumble/releases).
-- **Try a different network**. Tether to your phone for a quick A/B.
+For an upload error, record the filename type, size, visibility, expiry choice, and exact error. Compare a small image with the failing file. For a download error, check whether the attachment is expired, requires a password, or is restricted to the conversation. Ask the owner to correlate the request with files-service logs; never publish the private download URL or password in a bug report.
-### The server
+## Settings or profile do not appear to apply
-- **Check the server is up**: `ping your-host` or
- `nc -zv your-host 64738`.
-- **Check the Starling logs**: `docker compose logs -f gateway`.
-- **Restart the server** if you can afford a moment of downtime.
+Separate local appearance from shared profile data. **Personalize** changes your window; **Profile** changes the card other members see. Confirm the active certificate identity and server, then ask another Fancy Mumble user to reopen your card. A standard Mumble client will not render every Fancy profile field.
-### Your account
+## Crash, hang, or regression
-- **Try a different identity**. Settings, Identities, new identity,
- reconnect.
-- **Try as SuperUser** (server admin only) to rule out a permission
- issue.
-
-## When you cannot find a solution
-
-- **Search existing issues** in the
- [client repo](https://github.com/Fancy-Mumble/FancyMumble/issues)
- or
- [Starling repo](https://github.com/Fancy-Mumble/starling/issues).
-- **Open a new issue** with the information from
- [Reporting bugs](/troubleshooting/reporting-bugs/).
-
-
+Record the last action, time with timezone, platform, and exact build. Check whether the same steps work on another device or an earlier build without replacing your current identity/data. Capture the error and [export logs](/troubleshooting/debug-logging/). Keep a copy of relevant data before trying a reset; resets can remove the state needed to reproduce the bug.
diff --git a/src/content/docs/troubleshooting/connection.mdx b/src/content/docs/troubleshooting/connection.mdx
index 8f24cc6..e3cf2a3 100644
--- a/src/content/docs/troubleshooting/connection.mdx
+++ b/src/content/docs/troubleshooting/connection.mdx
@@ -1,39 +1,65 @@
---
title: Connection problems
-description: Check the client address, Starling listener, credentials, and certificate.
+description: Separate DNS, control-port, authentication, certificate, and voice failures.
---
-## Connection refused or timed out
+First record the exact error and whether it occurs before connecting, during login, or after chat is already working. A voice failure after successful login follows a different path from a failed control connection.
-Check the server address and port. Starling's default Mumble port is **64738**. On the server, check the gateway and both TCP and UDP firewall rules:
+## Check the saved address and identity
+
+
+
+Confirm the host and port with the owner. Starling's maintained deployment uses **64738/TCP** for control and **64738/UDP** for voice. A web address that opens the administration site is not necessarily the Mumble listener. Select the same certificate identity previously registered on that server.
+
+## DNS, timeout, or connection refused
+
+On Windows PowerShell, substitute the owner's host name:
+
+~~~powershell
+Resolve-DnsName voice.example.org
+Test-NetConnection voice.example.org -Port 64738
+~~~
+
+On Linux or macOS:
~~~sh
-docker compose ps
-docker compose logs gateway
+nslookup voice.example.org
+nc -vz voice.example.org 64738
~~~
-A TCP port probe can show whether the control listener is reachable:
+| Result | Next action |
+| --- | --- |
+| Name does not resolve | Correct the name or ask the owner to fix DNS. Record whether IPv4, IPv6, or both records are returned. |
+| TCP test fails | Ask the owner to check the listener, published port, routing, and firewall. A refusal often means nothing is accepting the connection; a timeout does not identify which network device dropped it. |
+| TCP succeeds but login fails | Continue with credentials, identity, and the displayed certificate/login error. A TCP success does not prove the application handshake succeeded. |
+| Chat works but voice does not | Use the UDP/TCP comparison in [Audio problems](/troubleshooting/audio/#4-is-voice-transport-the-failing-part). |
+
+The server owner can check the Compose deployment with:
~~~sh
-nc -zv your-server.example.org 64738
+docker compose ps
+docker compose logs --since=10m gateway voice
+docker compose config
~~~
-If TCP works but voice does not, check **64738/UDP**. Force TCP in the client's voice network settings as a diagnostic fallback.
+Check that services are running and the intended TCP and UDP ports are published. If the port is customized, use the same number in the client, firewall, and container mapping. Keep internal gRPC listeners private. See [Ports and networking](/server/network/).
+
+## Password or account rejected
-## Password or identity rejected
+Do not repeatedly guess passwords. Ask the owner whether the prompt is a server password, registered-user password, or SuperUser login. A registered account can be tied to a client certificate; changing the username alone does not restore that identity. Compare the identity selected in the connection entry with **Settings, Identities**.
-Check the username and password with the server owner. A registered account may also be tied to a certificate, so verify the selected client identity. For a fresh Starling server, the SuperUser password was printed once at first boot; see [SuperUser and first login](/admin/superuser/).
+For a new Starling instance, use [SuperUser and first login](/admin/superuser/). For a migrated instance, verify the imported account and target instance rather than registering a replacement over it.
-## Certificate changed
+## Certificate fingerprint changed
-Starling keeps its self-signed TLS certificate in the data directory. If that directory or Docker volume was replaced, clients see a changed certificate fingerprint. Confirm the new fingerprint with the server owner before accepting it. Preserve the data directory during upgrades.
+Record the host, port, and displayed fingerprint and verify it with the owner. A replaced TLS certificate or a lost data volume can legitimately cause a change, but the dialog cannot establish that by itself. The owner should compare the running gateway certificate with its backup. Preserve the TLS files during upgrades.
-## Public listing is missing
+## Connected, then disconnected
-Public directory registration is off until the registry fields are configured in Starling's instances.settings. A password-protected server is not listed. See the [Starling example TOML](https://github.com/Fancy-Mumble/starling/blob/main/starling.example.toml).
+Record how long the session lasted and whether it happens while idle, during voice, or during uploads. Compare the client log and gateway log at the same timestamp. Check whether every member disconnected or only this device. Do not reset identities or delete application data to diagnose a recurring disconnect.
-## The server exits at startup
+## Server fails before it can accept clients
-Read the gateway or affected service logs. Starling rejects unknown TOML keys. Compare your file with its [configuration reference](https://github.com/Fancy-Mumble/starling/blob/main/examples/reference.toml).
+Run **docker compose logs** for the failing service and read the first startup error. Unknown TOML keys, missing TLS files, storage permissions, and unavailable internal endpoints require different fixes. Compare the configuration with your Starling release's TOML reference. Do not expose more ports to fix a configuration parse error.
-If the problem persists, include the client and server versions and relevant logs in a [bug report](/troubleshooting/reporting-bugs/).
+Attach the displayed error, resolved IPs, TCP test result, client/server versions, timestamp, and relevant logs to a [bug report](/troubleshooting/reporting-bugs/). Remove passwords and tokens from exported Compose configuration before sharing it.
diff --git a/src/content/docs/troubleshooting/debug-logging.mdx b/src/content/docs/troubleshooting/debug-logging.mdx
index 1f2c269..4b06143 100644
--- a/src/content/docs/troubleshooting/debug-logging.mdx
+++ b/src/content/docs/troubleshooting/debug-logging.mdx
@@ -1,208 +1,47 @@
---
-title: Debug logging
-description: Enable verbose logging in the app and server, find the log file, and send it to a developer.
-sidebar:
- order: 5
+title: Collect useful logs
+description: Enable file logging, reproduce one issue, export the archive, and correlate Starling service logs.
---
-import { Steps, Aside, Tabs, TabItem, Card, CardGrid } from '@astrojs/starlight/components';
-import { Icon } from 'astro-icon/components';
+Logs are most useful when paired with a short reproduction and a timestamp. Record what you expected, what actually happened, and the exact client/server versions before collecting them.
-When you report a bug, the developer will almost always ask for
-**debug logs**. This page tells you how to enable them, where to
-find them, and how to share them safely.
-
-## Why debug logs?
-
-A normal log line says "something happened". A debug log line says
-**why** it happened and **what data was involved**. For an audio
-glitch, the difference is between:
-
-```text
-info: voice frame dropped
-```
-
-and
-
-```text
-debug: voice frame dropped: jitter buffer late by 47ms (threshold 30ms), last 3 frames late
-```
-
-## App: enable debug logging
-
-
+## Enable client file logging
1. Open **Settings, Advanced**.
+2. Enable **Expert mode**, then **Developer mode**. Logging controls appear in the developer section.
+3. Set **Log level** to **Debug** and enable file logging. A level change alone does not create a file while file logging is off.
+4. Reproduce the failure once and note the time and timezone.
+5. Use the **Log files** actions to open the directory or export the archive. Restore your usual level afterwards.
-2. Find the **Log level** dropdown (Expert mode required).
-
-3. Pick:
- - `info` for normal operation (default).
- - `debug` for the issue you are reporting.
- - `trace` for the most detail. Massive log files, use sparingly.
-
-4. **Reproduce the problem** while debug logging is on. Try to make
- the minimum reproduction so the log stays short.
-
-5. Switch back to `info` afterwards. Debug logging is expensive on
- disk and CPU.
-
-
-
-
-
-
-## App: where is the log file?
-
-The location depends on your operating system.
-
-
-
-
-
- Windows
-
-
- ```text
- %APPDATA%\com.fancy-mumble.app\logs\fancy-mumble.log
- ```
-
- In Explorer, paste `%APPDATA%\com.fancy-mumble.app\logs` into the
- address bar.
-
-
-
-
- The app cannot easily expose the log file. Use **Settings,
- Advanced, Export logs** to get a zip that you can save or share.
-
-
-
-The folder also contains rotated archives:
-
-- `fancy-mumble.log` is the live file.
-- `fancy-mumble.log.1`, `.2`, ... are previous sessions.
-
-## Server: enable verbose logging
-
-Starling services use Rust tracing. Set `RUST_LOG=info` for normal operation or `RUST_LOG=debug` while investigating a problem, then restart the affected service. Apply the variable to the service you are diagnosing in your Compose environment. Return to the normal level after collecting the relevant logs.
-
-## Server: where to read the log
-
-```bash
-# Live:
-docker compose logs -f gateway
-
-# Last 1000 lines:
-docker compose logs --tail=1000 gateway > server.log
-```
-
-For long-running diagnostics, redirect to a file:
-
-```bash
-docker compose logs -f gateway > server.log 2>&1 &
-# ... reproduce the issue ...
-kill %1
-```
-
-## Redacting before you share
-
-Before posting a log on GitHub or in chat, **strip personally
-identifying data**:
-
-- Your **public IP** (search and replace with `1.2.3.4`).
-- **Tokens** in the form `Authorization: Bearer ...`.
-- **Push credentials** (rare in logs, but check).
-- **Other users' usernames** if your community values privacy.
-
-A quick one-liner:
-
-```bash
-sed -E -e 's/[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+/1.2.3.4/g' \
- -e 's/Authorization: [^[:space:]]*/Authorization: [REDACTED]/g' \
- fancy-mumble.log > fancy-mumble.redacted.log
-```
-
-## What to include in a bug report
-
-
-
-1. **Steps to reproduce**, minimum reproduction.
-2. **Expected** vs **observed** behavior.
-3. The **app version** and **server version**.
-4. **Operating system** and version.
-5. **Network setup** (home, office, mobile, VPN).
-6. **The debug log** for the reproduction window, redacted.
-
-
+
-## A round trip example
+Use **Trace** only when a maintainer needs it for a particular problem; it can produce substantially more output. Terminal logging is a separate sink and is not required for exporting saved file logs.
-You: "audio cuts mid-sentence".
+## File names and export format
-Developer: "can you enable debug logging and reproduce with a 10-
-second sample?"
+The current desktop logger writes date-stamped files named **fancy-mumble.YYYY-MM-DD.log** into the OS application log directory. Use **View log files** to find the actual path for your installation rather than assuming a hard-coded user folder.
-You:
+Older files can be compressed to **.log.zst**. **Export saved logs** creates a Zstandard-compressed **.log.zst** archive, not a ZIP file. Keep the filename extension when attaching it. A missing directory before file logging is enabled is expected: the logger creates it when needed.
-1. Settings, Advanced, Log level, debug.
-2. Reconnect to the server.
-3. Talk for 10 seconds with a friend in the call, including the
- moment the cut happens.
-4. Disconnect.
-5. Grab the log file, redact.
-6. Attach to the issue.
+If export fails, record the displayed error and the destination path's accessibility. Preserve existing logs; deleting them removes the failure evidence.
-Developer: "the audio packet `seq=4231` was dropped because the
-jitter buffer was full. Increase `jitterBufferSize` in your config
-to 200." Issue closed.
+## Correlate server logs
-That round trip would take an extra five messages without debug
-logs.
+For the maintained Starling Compose deployment, collect the service relevant to the symptom:
-## Real-time tracing (advanced)
+~~~sh
+docker compose ps
+docker compose logs --since=10m gateway voice > voice-incident.log
+docker compose logs --since=10m files > files-incident.log
+docker compose logs --since=10m screenshare > share-incident.log
+~~~
-Both client and server can stream events to a TCP listener for live
-diagnosis. Set:
+Use only the relevant command for your issue. Service names may differ in a customized Compose file. Include service exit/restart information from **docker compose ps**, and capture the first startup error for a service that never becomes healthy.
-```yaml
-environment:
- MUMBLE_TRACE_TCP: "192.0.2.5:4444"
-```
+Starling uses Rust tracing. Set **RUST_LOG=debug** on the affected service and restart it when normal logs do not explain the failure. Return to normal logging after the reproduction. Do not apply legacy plugin INI log-level keys to Starling.
-A `nc -l 4444` on the listener side captures everything. Useful for
-sessions where you cannot reproduce locally.
+## Review before attaching
-## Next step
+Check for passwords, session tokens, private file URLs, personal messages, public IPs, and usernames you do not want to publish. Redact sensitive values consistently so related events can still be matched. Do not attach certificate private keys or entire data directories.
-You are ready to file a bug report. Head to
-[Reporting bugs](/troubleshooting/reporting-bugs/) for the checklist.
+In the report, identify the start/end times of the reproduction and attach the screenshot of the affected controls alongside the logs. See [Reporting bugs](/troubleshooting/reporting-bugs/) for an evidence template.
diff --git a/src/content/docs/troubleshooting/reporting-bugs.mdx b/src/content/docs/troubleshooting/reporting-bugs.mdx
index 09b7f2a..48c7749 100644
--- a/src/content/docs/troubleshooting/reporting-bugs.mdx
+++ b/src/content/docs/troubleshooting/reporting-bugs.mdx
@@ -1,137 +1,51 @@
---
title: Reporting bugs
-description: A checklist for filing a bug report that gets fixed.
-sidebar:
- order: 6
+description: Submit a reproducible failure with settings, comparisons, screenshots, and matching logs.
---
-import { Steps, Aside, Card, CardGrid } from '@astrojs/starlight/components';
+| Problem | Repository |
+| --- | --- |
+| Client UI, device capture, playback, or crash | [Fancy Mumble client issues](https://github.com/Fancy-Mumble/FancyMumble/issues) |
+| Starling service, storage, configuration, or deployment | [Starling issues](https://github.com/Fancy-Mumble/starling/issues) |
+| Incorrect or missing documentation | [Docs issues](https://github.com/Fancy-Mumble/docs/issues) |
-A good bug report saves everyone time. Use this checklist before
-hitting **Submit**.
+## Capture the controls that matter
-## Which repo?
+For an audio issue, show the selected devices, activation mode, and processing/transmission choices. For a connection issue, show the exact error and the address/port fields with private values redacted. For a share issue, show the sender preview and viewer stats. A screenshot of the whole desktop often hides the important control at an unreadable size.
-| You are reporting | Where to file |
-|-------------------|---------------|
-| The app crashes, misrenders, or behaves wrong | [FancyMumble, app](https://github.com/Fancy-Mumble/FancyMumble/issues) |
-| Starling crashes, rejects a valid config, or its Compose deployment fails | [Fancy-Mumble/starling](https://github.com/Fancy-Mumble/starling/issues) |
-| The docs (this site) | [Fancy-Mumble/docs](https://github.com/Fancy-Mumble/docs/issues) |
+
-When in doubt, file on the app repo. A maintainer will move it.
+## Copy this evidence template
-## The good report
+~~~text
+Client version / build:
+Server version and deployment:
+OS version; relevant audio/video device and driver:
+Time of reproduction, including timezone:
-
+Steps (starting from the current state):
+1.
+2.
-```markdown
-**Summary**: one-line description.
+Expected result:
+Actual result and exact error:
+How often it happens:
-**Steps to reproduce**:
-1. Open the app.
-2. ...
-3. ...
+Working comparison:
+One change that was tested:
+Result before / after that change:
-**Expected**: what should have happened.
-**Observed**: what actually happened.
+Audio: local sample result; Continuous result; UDP versus TCP result.
+Share: sender preview; affected viewers; delivery mode; stats.
+Connection: resolved address; TCP probe; login/certificate error.
-**Versions**:
-- App: x.y.z (from Help, About).
-- Server: x.y.z (from server log on startup).
-- OS: Windows 11 / Ubuntu 24.04 / Android 15.
+Attachments: relevant screenshots and logs for the same time window.
+~~~
-**Network**: home Wi-Fi / corporate / mobile.
+Use the applicable evidence lines and remove the rest. Include exact version strings rather than “latest.” Describe a working comparison even when it is on the same device—for example another channel, another capture source, or the same call using TCP.
-**Logs**: attached (redacted), generated with log level = debug.
+## Obtain logs
-**Screenshots**: attached if visual.
-```
+Follow [Collect useful logs](/troubleshooting/debug-logging/) to enable file output and export the current **.log.zst** archive. Turn on logging before reproducing the issue. For a server problem, attach the failing service's logs and restart/exit status. Keep the reproduction short enough to identify in those logs.
-
-
-## What makes a report easy to fix
-
-
-
- Strip down to the smallest steps that show the problem. "Connect,
- join channel, click X" beats "I have used the app for three
- weeks and yesterday Y stopped working".
-
-
- Two unrelated bugs need two issues. They get fixed independently
- and shipped in different releases.
-
-
- "Latest" is not a version. Help, About, copy the exact string.
- Maintainers reproduce against a specific build.
-
-
- Always attach debug logs. See
- [Debug logging](/troubleshooting/debug-logging/).
-
-
-
-## What makes a report hard to fix
-
-- "It does not work" with no further detail.
-- A 1000-line screenshot of the bug screen with no log.
-- Multiple unrelated issues in one report.
-- A wall of text describing how you feel about the bug. Save that for
- the comment thread.
-
-## Security issues
-
-**Do not** file security issues as public GitHub issues.
-
-Instead, email the maintainers privately or use the GitHub "Security
-advisories" feature on the repo. Both are linked from the repo's
-**Security** tab.
-
-## Feature requests
-
-Open as a regular issue, but use the **enhancement** label. Include:
-
-- The problem you are trying to solve.
-- The expected behavior.
-- Optional: a sketch of how it could work.
-
-Maintainers prefer "problem-shaped" requests (here is a pain) over
-"solution-shaped" ones (please add this exact button).
-
-## Voting and following
-
-You can:
-
-- **Subscribe** to an issue to get notified about updates.
-- Add a **thumbs-up** reaction to "vote" for an issue. Comments like
- "+1" are discouraged, use the reaction.
-
-## Pull requests
-
-If you can fix it yourself, even better:
-
-
-1. Fork the repo.
-2. Create a branch.
-3. Open a draft PR early to discuss approach.
-4. Link the issue with `Fixes #123`.
-5. Add a test if you can.
-
-
-Read the `CONTRIBUTING.md` in the repo first for code style rules.
-
-## Triage timeline
-
-Maintainers triage new issues within a few days. If your issue gets
-no reply after a week:
-
-- Add more context (logs, repro, video).
-- Tag the issue in the project's discussion channel.
-
-Persistence with patience is the right balance.
-
-## Thank you
-
-Bug reports are the only way the maintainers know something is
-broken. Every well-shaped issue makes the project better. Thanks
-for taking the time.
+Review attachments for credentials, private URLs, certificate keys, and other members' messages before making them public. Report separate failures in separate issues unless the reproduction shows they share the same cause.
diff --git a/src/content/docs/troubleshooting/screen-share.mdx b/src/content/docs/troubleshooting/screen-share.mdx
index 82256f9..07c1c12 100644
--- a/src/content/docs/troubleshooting/screen-share.mdx
+++ b/src/content/docs/troubleshooting/screen-share.mdx
@@ -1,11 +1,43 @@
---
title: Screen-share problems
-description: Check client capture permissions and Starling's media relay address.
+description: Distinguish source capture, media transport, and viewer rendering failures.
---
-If the share does not start, first check the sender's operating-system capture permission and whether another app can capture the same window. On Linux, confirm the desktop portal is available for your session. Try sharing a different window to separate a capture failure from a transport failure.
+Test with one sender and one viewer. Record whether the sender's local preview contains the expected window before changing server settings.
-If the sender sees a preview but viewers see a black frame or no stream, check the Starling screenshare service logs. The relay needs a public_url with a literal IP and UDP port reachable by viewers; the corresponding UDP listener must be open in the host and cloud firewalls. The [Starling example TOML](https://github.com/Fancy-Mumble/starling/blob/main/starling.example.toml) shows the setting. A private address or localhost will fail for remote viewers.
+
+## No source, permission error, or wrong window
-For diagnosis, record the client and server versions, whether the sender's local preview works, whether all viewers fail, and the relevant logs. See [Reporting bugs](/troubleshooting/reporting-bugs/).
+Open **Change source** in the share menu and choose the intended screen or window again. Check the sender's OS capture permission. On a Wayland desktop, confirm that the screen-capture portal opens and that a source was accepted; selecting a window in another application does not grant this application's portal request.
+
+Compare sharing a simple application window with sharing the whole desktop. If one source fails and the other works, report the application and capture type. Protected video can intentionally appear black; it is not a relay configuration test.
+
+## Sender sees the picture; viewer does not
+
+Ask a second viewer to try the same share. Open **Stats for Nerds** from the share menu and record the available transport and stream counters, plus whether they change. Capture the visible error rather than describing every blank view as a capture failure.
+
+| Comparison | Where to investigate |
+| --- | --- |
+| No sender preview | Sender capture permission, source selection, or capture backend. |
+| Preview works; all remote viewers fail | Advertised delivery mode, server media endpoint, and network reachability. |
+| One viewer fails; others work | That viewer's network, decoding/rendering backend, and logs. |
+| Same-LAN viewers work; off-network viewers fail | Private/loopback advertised addresses, NAT, and firewall rules. |
+| Picture arrives but is cropped | Compare **Fit**, **Fill**, and **1:1**. These are display modes, not transport repairs. |
+
+For a Starling relay, the owner should inspect:
+
+~~~sh
+docker compose ps screenshare
+docker compose logs --since=10m screenshare
+~~~
+
+Check the screenshare service's advertised **public_url** and UDP listener against the actual public IP, published port, and host/cloud firewall. A localhost or private address cannot be reached by arbitrary remote members. Screen-share media uses its own UDP listener; opening only the Mumble voice port does not establish media reachability. See [Media relay](/server/features/webrtc-sfu/) and [Ports and networking](/server/network/).
+
+If the client advertises peer-to-peer delivery instead, investigate reachability between sender and viewer. Do not treat relay settings as active merely because a relay exists on the server.
+
+## Freezes, high delay, or poor quality
+
+Compare a smaller capture source or lower **Stream Quality** while keeping the same viewer and network. Record whether only playback freezes or the sender preview also stops. Include the available stats and hardware/driver information. A successful low-resolution test suggests a capacity or encoding/decoding issue; it does not prove which machine is responsible.
+
+Before [reporting](/troubleshooting/reporting-bugs/), include sender/receiver OS and versions, source type, delivery mode, local-preview result, same-LAN/off-network result, number of affected viewers, stats screenshot, and matching client/server log timestamps.
diff --git a/src/content/docs/users/audio.mdx b/src/content/docs/users/audio.mdx
index 224d2f5..36f9a26 100644
--- a/src/content/docs/users/audio.mdx
+++ b/src/content/docs/users/audio.mdx
@@ -5,7 +5,7 @@ description: Devices, activation, calibration, processing, and transmission sett
Open **More, Settings, Voice** from the voice dock. This page reads and changes the audio engine's settings. If the engine is unavailable, the page reports that instead of offering controls that cannot work.
-
+
## Devices and volume
@@ -25,7 +25,7 @@ Use **Hear yourself** to record a short sample through the current filters and l
**Auto gain** adjusts microphone level for consistent speech. Noise suppression offers the algorithms included in your build, including RNNoise, DeepFilterNet, OMLSA + IMCRA, and spectral subtraction where available. Choose a setting that keeps speech clear on your hardware; compare it with noise suppression off using the sample recorder.
-
+
## Transmission
diff --git a/src/content/docs/users/chat.mdx b/src/content/docs/users/chat.mdx
index 7b25aa3..01f8bf8 100644
--- a/src/content/docs/users/chat.mdx
+++ b/src/content/docs/users/chat.mdx
@@ -15,7 +15,7 @@ walks every feature you will use day to day.
This capture of the current client shows five sample members with different avatars and a community conversation. The interactive sample scene below demonstrates their banners, statuses, and bios.
-
+
The [sample profiles](/users/profile/#try-a-sample-profile) include downloadable avatars and a distinct banner for each person. [Open the illustration at full size](/screenshot-users-chat-community.png), or [try the interactive community scene](/examples/community-scene.html) to select members and see their profiles.
diff --git a/src/content/docs/users/file-sharing.mdx b/src/content/docs/users/file-sharing.mdx
index 16d6452..753c91f 100644
--- a/src/content/docs/users/file-sharing.mdx
+++ b/src/content/docs/users/file-sharing.mdx
@@ -5,7 +5,7 @@ description: Stage files in chat and choose visibility, image quality, and expir
Share files from the composer when your server provides file storage. These screenshots use sample members and a flower arrangement.
-
+
## Share files
@@ -14,7 +14,7 @@ Share files from the composer when your server provides file storage. These scre
3. Expand the share options. Choose visibility, compressed or full image quality, and an expiry where the server supports it.
4. Add a message if you want, then **Send**. The options apply to the whole batch of attachments.
-
+
## Visibility
diff --git a/src/content/docs/users/live-doc.mdx b/src/content/docs/users/live-doc.mdx
index 2ea6487..3d1a123 100644
--- a/src/content/docs/users/live-doc.mdx
+++ b/src/content/docs/users/live-doc.mdx
@@ -19,6 +19,10 @@ This feature needs a compatible live-document plugin. Verify its advertised capa
+
+
+This local example shows the document canvas and sample content; a shared session requires the server plugin described above.
+
## Open a document
1. Select a channel in the sidebar.
diff --git a/src/content/docs/users/notifications.mdx b/src/content/docs/users/notifications.mdx
index b9da28a..9e4d33f 100644
--- a/src/content/docs/users/notifications.mdx
+++ b/src/content/docs/users/notifications.mdx
@@ -12,7 +12,7 @@ Open **Settings, Notifications** to control which events trigger a
sound and how loud each one plays.
-
+
## Master toggle
diff --git a/src/content/docs/users/personalization.mdx b/src/content/docs/users/personalization.mdx
index cffe5d8..113c2f7 100644
--- a/src/content/docs/users/personalization.mdx
+++ b/src/content/docs/users/personalization.mdx
@@ -3,7 +3,6 @@ title: Personalization & themes
description: Themes, light and dark appearance, message layout, and chat backgrounds.
---
-import ChatBackgroundExample from '../../../components/ChatBackgroundExample.astro';
Open **Settings, Personalize** to change the appearance of your client. These choices affect your own window; edit **Settings, Profile** for the styling other members see.
@@ -11,21 +10,19 @@ Open **Settings, Personalize** to change the appearance of your client. These ch
Choose a theme from the preview tiles. Each theme has a light and dark scheme. **Appearance** can follow your system or use a fixed **Light** or **Dark** scheme.
-
+
## Messages and text
Choose **Bubbles**, **Flat**, or **Compact** message style. **Text size** offers Small, Medium, and Large. **Compact mode** hides avatars and tightens spacing; **Always show message actions** keeps the action controls visible without hovering.
-
+
## Chat background
Choose an image or video behind the conversation. The client keeps your last five backgrounds so you can switch without choosing the file again. Adjust **Blur**, **Opacity**, and **Dim**, and move the focus point to keep the subject visible when the chat pane crops the image.
-
-
-
+
[Download the sample background](/examples/sample-chat-background.png) to try these controls. Start with low opacity or stronger dimming so text remains readable. Video backgrounds may take time to process after changing blur or dimming.
diff --git a/src/content/docs/users/privacy.mdx b/src/content/docs/users/privacy.mdx
index fe516b5..7496d09 100644
--- a/src/content/docs/users/privacy.mdx
+++ b/src/content/docs/users/privacy.mdx
@@ -27,7 +27,7 @@ You can have multiple identities. For example one for a gaming
server, one for a work group, one for an anonymous community.
-
+
### Create a new identity
@@ -98,6 +98,8 @@ What the server **does not** see:
## Privacy settings
+
+
Open **Settings, Privacy** to control what data the app sends and
what it renders for you.
diff --git a/src/content/docs/users/profile.mdx b/src/content/docs/users/profile.mdx
index 24947d1..b77138c 100644
--- a/src/content/docs/users/profile.mdx
+++ b/src/content/docs/users/profile.mdx
@@ -25,7 +25,7 @@ Use the **Avatar** and **Banner** download links under any profile to try a matc
The [example community conversation](/users/chat/#example-community-conversation) shows several members using different avatars, names, statuses, and bios together.
-
+
## What you can change
@@ -90,7 +90,7 @@ Choose **Edit** under Avatar, select an image, and confirm its crop in the image
-
+
## Step by step: pick a banner
@@ -149,7 +149,7 @@ users, vanilla Mumble shows your plain username.
-
+
## Nameplates, frames, decorations, effects
diff --git a/src/content/docs/users/screen-sharing.mdx b/src/content/docs/users/screen-sharing.mdx
index 113e415..dd0c658 100644
--- a/src/content/docs/users/screen-sharing.mdx
+++ b/src/content/docs/users/screen-sharing.mdx
@@ -16,7 +16,7 @@ You can also **draw on top of any stream** with the built-in whiteboard,
which is great for "look at this" moments.
-
+
## Start sharing your screen
diff --git a/src/content/docs/users/shortcuts.mdx b/src/content/docs/users/shortcuts.mdx
index 08bbf00..89837cb 100644
--- a/src/content/docs/users/shortcuts.mdx
+++ b/src/content/docs/users/shortcuts.mdx
@@ -10,7 +10,7 @@ import { Icon } from 'astro-icon/components';
Open **Settings, Shortcuts** to bind keys.
-
+
## Global vs in-app
diff --git a/src/content/docs/welcome/tour.mdx b/src/content/docs/welcome/tour.mdx
index 2131007..d1f485d 100644
--- a/src/content/docs/welcome/tour.mdx
+++ b/src/content/docs/welcome/tour.mdx
@@ -5,7 +5,7 @@ description: Find channels, chat, voice controls, profiles, and settings.
The connected client has a server rail, a channel sidebar, and a conversation pane. This capture uses sample members and messages.
-
+
## Servers and channels
diff --git a/src/styles/custom.css b/src/styles/custom.css
index 59e8d91..e85be52 100644
--- a/src/styles/custom.css
+++ b/src/styles/custom.css
@@ -317,3 +317,9 @@ div.header {
flex-shrink: 0;
color: var(--sl-color-accent-high);
}
+
+/* Follow the documentation theme, including its system preference. */
+.theme-screenshot { display: block; }
+.theme-screenshot .screenshot-dark { display: none; }
+:root[data-theme="dark"] .theme-screenshot .screenshot-light { display: none; }
+:root[data-theme="dark"] .theme-screenshot .screenshot-dark { display: block; }