diff --git a/README.md b/README.md
index 6c095aa..131a56b 100644
--- a/README.md
+++ b/README.md
@@ -89,6 +89,14 @@ Install desktop apps like Moonlight or VLC, and set each Android app's resolutio
**⚡ One-click tools**
SSH, SFTP, Steam Link, remote desktop, volume, sleep, restart and shut down.
+
+
+
+
+
+**💾 Backup and recovery**
+Copy game saves, settings and Android app data to your computer, and restore them after a factory reset. Sign-in files and keys are never copied. A Return to Game Mode button helps when the headset is stuck in Desktop Mode. Not tested on a headset yet. [How it works](docs/backup-and-recovery.md).
+
diff --git a/docs/backup-and-recovery.md b/docs/backup-and-recovery.md
new file mode 100644
index 0000000..1007819
--- /dev/null
+++ b/docs/backup-and-recovery.md
@@ -0,0 +1,159 @@
+# Backup and recovery
+
+**Tools → Backup & recovery** copies what a factory reset would lose from the
+Steam Frame to your computer, puts it back afterwards, and gets the headset out
+of Desktop Mode. It runs from Frame Control on a computer, not from the iPhone
+app or the Frame itself.
+
+**Not tested on a headset yet.** Everything here is covered by unit tests and
+the fake Frame (see [Verification](#verification)); the save locations and the
+Desktop Mode switch are taken from Valve's tools and from Proton's layout, not
+from a backup and restore on a real Frame.
+
+## Back up
+
+Choose **Game saves**, **Steam and desktop settings** and **Android app data**
+(all three by default), then **Back up now**. **See what's included** lists each
+part and its size first. Backing up only reads the headset.
+
+Each backup is a folder named after the time it started:
+
+```
+~/Documents/Frame Control Backups/2026-10-23-142530/
+ manifest.json
+ saves/saves-1234.tar.gz one per game
+ saves/saves-linux.tar.gz
+ settings/settings-steam.tar.gz
+ settings/settings-system.tar.gz
+ android/org.example.game.tar.gz one per Android app
+```
+
+`manifest.json` records the headset's name, SteamOS version and BUILD_ID, every
+file with its size and SHA-256, and each archive's SHA-256. It also lists what
+was skipped and why. A backup is written under a hidden `.…partial` name and
+renamed when complete, so a cut-off backup never shows up as one.
+
+### What's saved
+
+| Part | From the headset (`~` is `/home/steamos`) | Restored? |
+|---|---|---|
+| Windows game saves | `~/.local/share/Steam/steamapps/compatdata//pfx/drive_c/users/steamuser/` → `AppData/Roaming`, `AppData/Local`, `AppData/LocalLow`, `Documents`, `Saved Games`. Wine's own folders in them (`Temp`, `Microsoft`, `D3DSCache`, `CrashDumps`) are left out. Sideloaded Windows games (non-Steam shortcuts) have prefixes here too | Yes |
+| Linux game saves | `~/.config/unity3d`, `~/.local/share/godot/app_userdata`: where Unity and Godot games save by default | Yes |
+| Steam controller layouts | `userdata//241100/remote/controller_config`, `steamapps/common/Steam Controller Configs//config` | Yes |
+| Steam library settings | `userdata//config/localconfig.vdf`, `shortcuts.vdf`, `grid/` (custom artwork) | Kept for reference |
+| Desktop settings | `~/.config/kdeglobals`, `kwinrc`, `kxkbrc` (keyboard layout), `konsolerc`, `dolphinrc` | Yes |
+| SteamVR settings | `~/.config/openvr/config/steamvr.vrsettings` | Kept for reference |
+| Android app data | Each Frame Control Android app's private data, through the existing `backup-data` helper ([sidequest.md](sidequest.md#private-app-data-backups)) | Yes |
+
+"Kept for reference" files are in the backup but not put back automatically:
+Steam and SteamVR rewrite them while they run, and an old `shortcuts.vdf` would
+point at apps that aren't installed after a reset. Open the backup folder to
+copy one by hand if you need it.
+
+### What's never copied
+
+- **Steam sign-in:** `steam.token`, `config/config.vdf`, `loginusers.vdf`,
+ `registry.vdf` and `ssfn*` files.
+- **Keys and passwords:** `~/.ssh`, `~/.gnupg`, keyrings and KWallet, any
+ `*.token`, `*.key` or `*.pem` file, Tailscale state and proxy settings
+ (`secrets.env`). These are refused by name wherever they turn up, including
+ inside a game's folder, and a restore refuses them too.
+- Games, Proton and the Steam runtimes: reinstall them from Steam.
+- Steam Cloud's own folders (`userdata//`), shader caches and
+ screenshots (**Tools → Capture & Live** saves those to Pictures).
+- Android apps themselves, their OBB files and shared storage (`/sdcard`).
+- Symbolic links (never followed), and single files over 2 GiB.
+
+Backups aren't encrypted. Game folders can still hold a launcher's login, and
+Android app data can hold an app's, so keep backups private.
+
+Android apps that are open are skipped (the helper needs the app closed); close
+them and back up again.
+
+## Restore after a factory reset
+
+1. Set up the headset again: Developer Mode, **Set Up Connection**, sign in to
+ Steam with the same account.
+2. Reinstall your games, and **start each once** so Proton creates its folders.
+3. Reinstall your Android apps from Frame Control.
+4. **Tools → Backup & recovery → Restore…** on a backup. Frame Control checks
+ each part against the headset and says what it would do: how many files it
+ replaces and how many are new.
+5. Tick the parts to restore and **Restore selected**. It asks before replacing
+ anything.
+
+Parts that can't go back yet are skipped, not failed, with the reason:
+
+| Reason | What to do |
+|---|---|
+| Install the game first | Install it from Steam, then restore |
+| Start the game once | Proton hasn't made its folders yet; start the game, quit, restore |
+| Sign in to Steam first | Controller layouts go under your account's folder |
+| Install the app first / close the app first | Android app data needs the app installed and closed |
+| The backup file doesn't match its checksum | The archive changed since it was made |
+
+A restore writes only the files in the parts you chose, and only inside that
+part's folders: it never deletes a file, and a save archive can't write outside
+its game. Before replacing a file it copies the current one to
+`~/.local/share/frame-control/restore-previous/