+
# MeshCore Solo Companion Firmware
A fork of the official [MeshCore](https://github.com/meshcore-dev/MeshCore) companion radio firmware with a full standalone on-device UI — messages, contacts, GPS navigation and tools without a phone.
@@ -27,7 +29,7 @@ Discussion: [MeshCore Discord](https://discord.gg/sdhYArU2jr) — [Solo firmware
Firmware files are on the [releases page](https://github.com/MarekZegare4/MeshCore-Solo/releases). Every binary serves the companion app over both BLE and USB serial.
-Heltec V3/V4 need [a keyboard or joystick wired up](./docs/solo_features/external_keyboard.md#wiring-heltec-v3--v4); ProMicro needs a CardKB; the T-Echo Lite needs the KeyShield. The rest work out of the box.
+Heltec V3/V4 need [a keyboard or joystick wired up](./docs/solo/hardware.md#wiring-on-the-heltec-v3--v4); ProMicro needs a CardKB; the T-Echo Lite needs the KeyShield. The rest work out of the box.
---
@@ -47,7 +49,7 @@ Heltec V3/V4 need [a keyboard or joystick wired up](./docs/solo_features/externa
## Documentation
-[docs/solo_features](./docs/solo_features/README.md) — features, screens, external keyboards, build flags and developer guides.
+[Documentation](./docs/solo/README.md) — getting started, messages, navigation, tools, settings, hardware and developer guides.
**Solo Tools** — [a web app](https://marekzegare4.github.io/Solo-tools/) (Chromium, Web Serial) that takes screenshots and exports the GPS trail as GPX over USB; the same as local scripts in [tools/](./tools/README.md).
@@ -60,7 +62,7 @@ pio run -e -t upload # build and flash ov
FIRMWARE_VERSION=v1.0.0 bash build.sh build-firmware # release artifacts into out/
```
-Environments are the `*_solo_dual` (OLED / e-ink) and `*_solo_lvgl` (touch) entries in `solo//platformio.ini`. Optional hardware (CardKB, joystick, GPIO, buzzer…) is enabled with [build flags](./docs/solo_features/build_flags.md). Releasing: [RELEASE.md](./RELEASE.md).
+Environments are the `*_solo_dual` (OLED / e-ink) and `*_solo_lvgl` (touch) entries in `solo//platformio.ini`. Optional hardware (CardKB, joystick, GPIO, buzzer…) is enabled with [build flags](./docs/solo/developer/build-flags.md). Releasing: [RELEASE.md](./RELEASE.md).
This README is protected from upstream merges via `.gitattributes`; after cloning run once `git config merge.ours.driver true`.
diff --git a/docs/solo/README.md b/docs/solo/README.md
new file mode 100644
index 00000000..4e5d02ae
--- /dev/null
+++ b/docs/solo/README.md
@@ -0,0 +1,70 @@
+
+
+# MeshCore Solo
+
+Solo is a MeshCore companion firmware that works on its own: messages, contacts,
+GPS navigation and tools right on the device, no phone needed. The phone app
+still connects as with the stock firmware, over Bluetooth or USB.
+
+**Try it in your browser: [solo.marekzegarek.com](https://solo.marekzegarek.com)**
+
+## What it does
+
+- **Messages without a phone**: channels, direct messages and rooms, with
+ quick replies, live placeholders (`{loc}`, `{time}`, sensor readings) and
+ keyboards for Latin, Cyrillic, Greek and European diacritics.
+- **GPS navigation**: trail recording with GPX export, waypoints, a compass,
+ navigate to any node, waypoint or shared location, live location sharing
+ and a geofence alert (Locator).
+- **Nearby nodes**: who's around, signal and distance, ping, and remote
+ admin of your repeaters and rooms.
+- **Tools**: clock with alarm, timer and stopwatch, a remote bot that answers
+ commands over the mesh, repeater mode, a ringtone editor, diagnostics.
+- **Screen lock** with an optional PIN.
+- **On the Wio Tracker L2**: an offline map, message history on the SD card,
+ the SD card as a USB drive, updates over WiFi.
+
+## Devices
+
+The firmware is the same everywhere; how you drive it depends on the device.
+These docs mark the differences with notes like this:
+
+> [!NOTE]
+> **Wio Tracker L2:** what's different on the touch screen.
+
+| Group | Devices | Controls |
+| ----- | ------- | -------- |
+| **Joystick** | Wio Tracker L1 (OLED / e-ink), GAT562 30S, GAT562 Watch13, Heltec V3/V4 with a joystick | Four directions, Enter, Back |
+| **Keyboard** | M5Stack Cardputer ADV, T-Echo Lite + KeyShield, any board with a CardKB | Keys; arrows or their Fn combinations for the directions |
+| **Touch** | Wio Tracker L2 | Taps, swipes and holds; two side buttons |
+
+| OLED / e-ink | | Wio Tracker L2 |
+| :---: | :---: | :---: |
+|  |  |  |
+
+The joystick and keyboard devices share one interface, sized for small OLED
+and e-ink screens. The Wio Tracker L2 has its own, built for a 320 × 240
+colour touch screen, with extras its hardware allows: an offline map, message
+history on the SD card and updates over WiFi.
+
+## Pages
+
+- [Getting started](./getting-started.md): controls, the home screen, the phone app, updates
+- [Messages](./messages.md): channels, direct messages, rooms, typing
+- [Contacts](./contacts.md): nearby nodes, favourites, remote admin
+- [Navigation](./navigation.md): GPS, trail, waypoints, compass, sharing your location, the map
+- [Tools](./tools.md): clock tools, bot, repeater, ringtones, diagnostics
+- [Settings](./settings.md): what is where
+- [Screen lock](./lock.md): locking, auto-lock, PIN
+- [Hardware](./hardware.md): external keyboards and joysticks, e-ink, SD card, WiFi
+
+For developers: [UI Core](./developer/ui-core.md), [UI framework](./developer/ui-framework.md), [build flags](./developer/build-flags.md).
+
+## Contributors
+
+Big thanks to the people who contributed to Solo:
+[vanous](https://github.com/vanous), [marczykm](https://github.com/marczykm),
+[tchellow](https://github.com/tchellow) and [3urobeat](https://github.com/3urobeat).
+
+Built on [MeshCore](https://github.com/meshcore-dev/MeshCore) and the work of
+its [community](https://github.com/meshcore-dev/MeshCore/graphs/contributors).
diff --git a/docs/solo/contacts.md b/docs/solo/contacts.md
new file mode 100644
index 00000000..8a8dbd74
--- /dev/null
+++ b/docs/solo/contacts.md
@@ -0,0 +1,69 @@
+# Contacts
+
+## Nearby nodes
+
+**Tools › Nodes** lists the nodes the device has heard: their type, how long
+ago, and, when they have a position, distance and bearing. **Left / Right**
+filters by type (All, Fav, Companions, Repeaters, Rooms, Sensors); the sort,
+by distance or by last heard, is in the options. A ★ marks a favourite, a ♦
+someone sharing their position live.
+
+**Enter** shows a node's details. **Hold Enter**, in the list or the details,
+for what you can do with it:
+
+| Option | Does |
+| ------ | ---- |
+| Navigate | Distance and bearing to the node; follows it if it shares its position live |
+| Ping | Sends a ping and shows the round trip time and SNR |
+| Save waypoint, Set as target | Its position as a waypoint, or as the [Locator](./navigation.md#locator) target |
+| Fav, Pin to dial | Favourite, or a place on the Favourites page |
+| Admin | Remote admin, for a repeater or room (below) |
+| Discover scan | Asks the repeaters, rooms and sensors in direct range to answer, with their signal |
+
+> [!NOTE]
+> **Wio Tracker L2:** the **Nodes** app. Filter chips at the top, the sort in
+> the header, and a map button that shows every node with a position. A
+> node's card has buttons for the same actions, plus **Add** for a node that
+> isn't a contact yet and **Delete**.
+
+## Favourites
+
+The **Favourites** home page holds six slots for the conversations you open
+most: a contact, a room or a channel, each with its unread count. **Enter** on
+an empty slot picks one from Messages; **hold Enter** on a filled slot to
+replace or remove it. **Pin to dial** in any contact, channel or node menu
+does the same.
+
+A pinned slot is not the same as a favourite. **Fav** is the star shared with
+the phone app: it sorts contacts to the top and drives the "favourites only"
+filters in Settings › Contacts.
+
+> [!NOTE]
+> **Wio Tracker L2:** the first home page. Tap a slot to open it, hold it to
+> change it.
+
+## Cleaning up
+
+Settings › Contacts › **Expire** (7, 30 or 90 days) sets when a contact you
+haven't heard from counts as inactive, and **Prune now** removes those after
+showing how many it will delete. Favourites are always kept, and nothing is
+removed without **Prune now**.
+
+## Remote admin
+
+**Tools › Admin** manages a repeater or room server you are an admin on, the
+same way the phone app does. Pick the node, type its admin password (saved for
+next time), then choose a field:
+
+- **System**: name, owner info, admin password.
+- **Radio**: frequency, bandwidth, spreading factor, coding rate, TX power.
+- **Routing**: repeat on/off, advert intervals, max hops.
+- **Actions**: send an advert, sync its clock, reboot, start OTA, or any
+ [CLI command](../cli_commands.md).
+
+Name and owner info are read from the node first, so you edit the current
+value. Reboot and OTA ask before sending.
+
+> [!WARNING]
+> Admin commands change the remote node. Check the node and the value before
+> sending.
diff --git a/docs/solo_features/build_flags.md b/docs/solo/developer/build-flags.md
similarity index 95%
rename from docs/solo_features/build_flags.md
rename to docs/solo/developer/build-flags.md
index 474127b4..cf56d231 100644
--- a/docs/solo_features/build_flags.md
+++ b/docs/solo/developer/build-flags.md
@@ -1,6 +1,6 @@
## Build Flags
-[Go back](../../README.md)
+[Go back](../README.md)
Reference for the `-D` build flags a Solo build understands beyond the
per-board defaults already set in `solo//platformio.ini`. Add any of
@@ -11,7 +11,7 @@ isn't there costs nothing and can't brick a build; the exceptions (pin
conflicts, wrong polarity) are called out per flag.
None of this needs touching to get a board running — see the
-[environment table](../../README.md#building-from-source) for the flag-free
+[environment list](../../../README.md#building) for the flag-free
default build for each supported board.
---
@@ -48,11 +48,11 @@ existing `solo//platformio.ini` for what's already claimed).
| Flag | Adds |
| --- | --- |
-| `ENV_PIN_SDA` / `ENV_PIN_SCL` | CardKB (M5Stack I2C keyboard, addr `0x5F`) on a second I2C bus (resolves to `Wire1`). Probed at boot — harmless with nothing plugged in. See [External Keyboard & Joystick](./external_keyboard.md). |
+| `ENV_PIN_SDA` / `ENV_PIN_SCL` | CardKB (M5Stack I2C keyboard, addr `0x5F`) on a second I2C bus (resolves to `Wire1`). Probed at boot — harmless with nothing plugged in. See [External Keyboard & Joystick](../hardware.md#external-keyboard-and-joystick). |
| `CARDKB_I2C=` | Same CardKB support, naming the bus directly — for a board with no free pins for a second bus, set `CARDKB_I2C=Wire` to share the primary bus (already used by the display/RTC) instead of defining `ENV_PIN_SDA`/`ENV_PIN_SCL`. Takes precedence if both are somehow set. |
-| `UI_HAS_JOYSTICK=1` + `UI_HAS_JOYSTICK_UPDOWN=1` (optional) + `JOYSTICK_UP` / `JOYSTICK_DOWN` / `JOYSTICK_LEFT` / `JOYSTICK_RIGHT` + `PIN_USER_BTN` + `PIN_BACK_BTN` | A wired joystick (four direction contacts + a press contact for Enter). Replaces single-button navigation entirely once enabled. See [External Keyboard & Joystick](./external_keyboard.md). |
-| `PIN_GPIO1` .. `PIN_GPIO4` | Up to four general-purpose pins, each independently switchable between Off / Input / Output (GPIO1/GPIO2 also get an Analog step, if wired to an ADC-capable pin) from Tools › GPIO, and via the `!gpio1`..`!gpio4` bot commands. Not restricted to any particular board — works anywhere the pins are actually free. See [Tools Screen › GPIO](./tools_screen/tools_screen.md#gpio). |
-| `PIN_HALL_SENSOR` + `HALL_ACTIVE_HIGH=1` (optional) | A Hall-effect or reed sensor for a magnetic flip cover: closing locks and blanks the screen instantly, opening unlocks and wakes it, no combo either way. `HALL_ACTIVE_HIGH` is only for a module wired to pull the pin high (rather than low) when the magnet is near. See [Screen Lock › Magnetic cover](./screen_lock/screen_lock.md#magnetic-cover-hall-sensor). |
+| `UI_HAS_JOYSTICK=1` + `UI_HAS_JOYSTICK_UPDOWN=1` (optional) + `JOYSTICK_UP` / `JOYSTICK_DOWN` / `JOYSTICK_LEFT` / `JOYSTICK_RIGHT` + `PIN_USER_BTN` + `PIN_BACK_BTN` | A wired joystick (four direction contacts + a press contact for Enter). Replaces single-button navigation entirely once enabled. See [External Keyboard & Joystick](../hardware.md#external-keyboard-and-joystick). |
+| `PIN_GPIO1` .. `PIN_GPIO4` | Up to four general-purpose pins, each independently switchable between Off / Input / Output (GPIO1/GPIO2 also get an Analog step, if wired to an ADC-capable pin) from Tools › GPIO, and via the `!gpio1`..`!gpio4` bot commands. Not restricted to any particular board — works anywhere the pins are actually free. See [Tools › GPIO](../tools.md#gpio). |
+| `PIN_HALL_SENSOR` + `HALL_ACTIVE_HIGH=1` (optional) | A Hall-effect or reed sensor for a magnetic flip cover: closing locks and blanks the screen instantly, opening unlocks and wakes it, no combo either way. `HALL_ACTIVE_HIGH` is only for a module wired to pull the pin high (rather than low) when the magnet is near. See [Screen lock › Magnetic cover](../lock.md#magnetic-cover). |
| `PIN_GPS_SWITCH` | A physical on/off switch for GPS power, read alongside the software GPS toggle — the Tools screen shows `gps off(hw)` / `gps off(sw)` when the two disagree, instead of silently trusting one over the other. |
---
diff --git a/docs/developer/ui-core.md b/docs/solo/developer/ui-core.md
similarity index 100%
rename from docs/developer/ui-core.md
rename to docs/solo/developer/ui-core.md
diff --git a/docs/developer/ui-framework.md b/docs/solo/developer/ui-framework.md
similarity index 99%
rename from docs/developer/ui-framework.md
rename to docs/solo/developer/ui-framework.md
index 1ede0aa7..93f6c33a 100644
--- a/docs/developer/ui-framework.md
+++ b/docs/solo/developer/ui-framework.md
@@ -1,10 +1,10 @@
# Solo UI framework — a guide for adding features
-[Go back](../../README.md)
+[Go back](../README.md)
This is a developer guide to the reusable building blocks behind the
`companion_radio` **solo** firmware UI (the `ui-new` screens). It is not a
-user manual — for what each screen *does*, see [solo_features](../solo_features/).
+user manual — for what each screen *does*, see the [documentation](../README.md).
The goal here is so that adding a new screen or feature means *wiring together
existing helpers*, not reinventing list scrolling, text wrapping, or persistence.
diff --git a/docs/solo/getting-started.md b/docs/solo/getting-started.md
new file mode 100644
index 00000000..0bfb1ce1
--- /dev/null
+++ b/docs/solo/getting-started.md
@@ -0,0 +1,66 @@
+# Getting started
+
+## Controls
+
+On joystick devices:
+
+| Input | Does |
+| ----- | ---- |
+| **Up / Down** | Move through a list |
+| **Left / Right** | Switch home pages; change the value of a setting |
+| **Enter** | Open, select, confirm |
+| **Hold Enter** | Options for the selected item (a message, contact, channel…) |
+| **Back** | One step back; from a screen, back to the home screen |
+
+Lists wrap around at both ends. Any key wakes a dark screen without acting on it.
+
+Keyboard devices use the same controls, from the arrow keys (or their Fn
+combinations), Enter and Esc. [Hardware](./hardware.md) has the key maps.
+
+> [!NOTE]
+> **Wio Tracker L2:** tap to open, hold for options, swipe sideways between
+> pages. The top button turns the screen off and on. The side button goes
+> back to the home screen; hold it and let go to mute or unmute the sound.
+> Holding the side button while pressing the top one takes a screenshot.
+
+## Home screen
+
+The home screen is a row of pages. On joystick devices, **Left / Right** steps
+through them and **Enter** opens the one shown:
+
+Clock, Recent, Radio, Bluetooth, Advert, GPS, Sensors, Tools, Shutdown,
+Settings, Messages, Favourites, Map.
+
+Settings › Home Pages sets their order and hides the ones you don't use;
+Settings and Messages are always shown.
+
+> [!NOTE]
+> **Wio Tracker L2:** pages you swipe between: favourite chats, the clock
+> (where it starts), a minimap, then the apps, six to a page. Hold an app to
+> arrange or hide them.
+
+## Connecting the phone app
+
+Every build serves the MeshCore app over **Bluetooth and USB**, one at a time:
+while Bluetooth is connected, USB is ignored. To use USB, disconnect Bluetooth
+first or turn it off on the device.
+
+The Bluetooth pairing PIN is shown on the Bluetooth home page until the phone
+is paired.
+
+> [!NOTE]
+> **Wio Tracker L2:** the PIN is under Settings › Bluetooth.
+
+Everything you do on the device and in the app stays in sync: contacts,
+channels and messages are the same data.
+
+## Updating
+
+Download the new file from the [releases page](https://github.com/MarekZegare4/MeshCore-Solo/releases)
+and flash it the way you did the first time (see the [main README](../../README.md#flashing)).
+Settings, contacts and messages are kept.
+
+> [!NOTE]
+> **Wio Tracker L2:** Settings › Firmware update checks GitHub for a newer
+> release and installs it over WiFi. Set up a network under Settings › WiFi
+> first.
diff --git a/docs/solo/hardware.md b/docs/solo/hardware.md
new file mode 100644
index 00000000..9e75e2c7
--- /dev/null
+++ b/docs/solo/hardware.md
@@ -0,0 +1,99 @@
+# Hardware
+
+## External keyboard and joystick
+
+Two optional add-ons, detected at boot; a build with them enabled works the
+same with nothing plugged in.
+
+| Device | CardKB | Wired joystick |
+| ------ | :----: | :------------: |
+| Wio Tracker L1 (OLED / e-ink) | Grove connector | built in |
+| GAT562 30S Mesh Kit | — | built in |
+| Heltec V3 / V4 | soldered (below) | soldered (below) |
+| ProMicro | on the main I2C bus (required: it has no buttons) | — |
+| Cardputer ADV, T-Echo Lite + KeyShield | built-in keyboard instead | — |
+
+### CardKB
+
+An M5Stack CardKB types straight into any text field. It sends plain
+characters, so the keyboard alphabet settings don't apply to it.
+
+| Key | Does |
+| --- | ---- |
+| Arrows, Enter, Esc | Same as the joystick, Enter and Back |
+| Backspace | Deletes before the cursor |
+| **Fn+Enter** | Submits the field |
+| **Fn+letter** | Accents for that letter (Fn+A → á à ä…) |
+| **Tab** | Hold Enter (options menus) |
+| **Fn+Esc** | Locks / unlocks the screen |
+
+Settings › Keyboard › **Ext. KB**: **Full** keeps the on-screen grid, so the
+CardKB and the joystick can be mixed; **Compact** hides it, the arrows move the
+text cursor and Enter submits. Compact needs no joystick at all.
+
+### Wired joystick
+
+Four direction contacts and a press contact (Enter), each shorted to ground
+when pressed; the firmware enables the pull-ups, so no resistors are needed.
+The board's own button becomes Back. Settings › Display › **Joystick
+rotation** turns the directions for a stick mounted sideways.
+
+### Wiring on the Heltec V3 / V4
+
+Neither board has a joystick or a keyboard connector, so both are soldered to
+free pins. V3 and V4 use the same pins (confirmed on a V4).
+
+| Function | GPIO |
+| -------- | :--: |
+| CardKB SDA / SCL | 3 / 4 (second I2C bus, not the display's) |
+| Joystick up / down / left / right | 23 / 6 / 47 / 48 |
+| Joystick press (Enter) | 33 |
+| Back | 0 (the PRG button, nothing to wire) |
+
+The pins are set in [`solo/heltec_v3/platformio.ini`](../../solo/heltec_v3/platformio.ini)
+and [`solo/heltec_v4/platformio.ini`](../../solo/heltec_v4/platformio.ini).
+For a CardKB-only build, comment out the joystick block there and use
+Ext. KB = Compact.
+
+### Built-in keyboards
+
+The Cardputer ADV has a QWERTY keyboard, the T-Echo Lite a T9 keypad on its
+KeyShield add-on (without it the board has no usable input). Their keymaps
+are in each board's driver under `variants/`; they don't follow the CardKB's
+Fn shortcuts.
+
+## E-ink
+
+The e-ink Wio Tracker L1 (250 × 122) has a few settings of its own in
+Settings › Display:
+
+- **Rotation**: landscape or portrait, applied at once; every screen reflows.
+- **Joystick rotation**, independent of the display's.
+- **Full refresh**: how many partial updates between full ones, against
+ ghosting.
+
+Clock seconds are hidden by default, and live timers refresh coarsely, to
+spare the panel.
+
+## Wio Tracker L2
+
+- **Buttons**: the top one turns the screen off and on; the side one goes
+ home, and held and let go mutes the sound. Side + top takes a screenshot.
+ Holding the side button in the first seconds after power-on starts the CLI
+ rescue on USB serial.
+- **SD card**: holds the message history, maps, GPX trails and live map tiles.
+ Settings › Storage shows what takes the space, how many messages each
+ conversation keeps, and deletes the history.
+- **USB drive**: plugged into a computer, the device asks whether to only
+ charge or to lend the computer the SD card. While lent, the device can't use
+ the card; eject it on the computer and the device restarts. With a screen
+ PIN set, it doesn't ask until the screen is unlocked.
+- **WiFi**: used only for map downloads, live tiles and updates, and off the
+ rest of the time. Settings › WiFi saves several networks and joins the
+ strongest; the WiFi switch in Settings forbids it entirely.
+
+## Build flags
+
+Extra hardware (a buzzer, a vibration motor, a Hall sensor for a magnetic
+cover, GPIO, an external PA) is enabled with build flags in your own
+`solo//platformio.ini`; see [Build flags](./developer/build-flags.md).
diff --git a/docs/solo/img/hero.png b/docs/solo/img/hero.png
new file mode 100644
index 00000000..ddbed432
Binary files /dev/null and b/docs/solo/img/hero.png differ
diff --git a/docs/solo/img/l2-home.png b/docs/solo/img/l2-home.png
new file mode 100644
index 00000000..0ef9be6f
Binary files /dev/null and b/docs/solo/img/l2-home.png differ
diff --git a/docs/solo/img/oled-clock.png b/docs/solo/img/oled-clock.png
new file mode 100644
index 00000000..22c9a776
Binary files /dev/null and b/docs/solo/img/oled-clock.png differ
diff --git a/docs/solo/img/oled-messages.png b/docs/solo/img/oled-messages.png
new file mode 100644
index 00000000..1cc31673
Binary files /dev/null and b/docs/solo/img/oled-messages.png differ
diff --git a/docs/solo/lock.md b/docs/solo/lock.md
new file mode 100644
index 00000000..13cbe9e5
--- /dev/null
+++ b/docs/solo/lock.md
@@ -0,0 +1,45 @@
+# Screen lock
+
+The lock keeps pocket presses from doing anything. It locks the screen only:
+messages still arrive, alarms still ring and the phone app still connects.
+
+## Locking and unlocking
+
+**Hold Back and press Enter three times** within 3 seconds; the same locks
+and unlocks. A hint on the lock screen counts the presses. With a CardKB,
+**Fn+Esc** does it in one press.
+
+**Settings › Display › Lock screen** locks the device whenever the screen
+turns off by itself.
+
+The lock screen shows the time, the date and the first two of the Clock
+page's fields, but not the device's name.
+
+> [!NOTE]
+> **Wio Tracker L2:** with **Lock screen** on (Settings › Display), waking
+> the screen shows a clock card with **slide to unlock**. Settings › Display
+> › **Tap to wake** decides whether a tap wakes it or only the top button.
+
+## PIN
+
+**Settings › Display › Lock PIN** adds a PIN to unlocking, asked also right
+after power-up.
+
+- Enter on the row opens a number pad. Type the PIN (at least 4 characters),
+ confirm, then type it again. The pad's keyboard key switches to letters.
+- A wrong PIN shows how many tries are left; after 5 in a row, entry pauses
+ for 30 seconds.
+- Enter on the row again removes the PIN.
+
+The PIN is stored as a salted hash, never as the PIN itself.
+
+> [!NOTE]
+> **Wio Tracker L2:** **Settings › Display › Screen PIN**, digits only. With a PIN, the lock card comes up every time the screen wakes, and
+> the SD card isn't offered as a USB drive until it's unlocked.
+
+## Magnetic cover
+
+A Hall or reed sensor wired to a free pin (`PIN_HALL_SENSOR`, see
+[Build flags](./developer/build-flags.md)) locks and blanks the screen when a
+magnetic cover closes and unlocks it when it opens (asking for the PIN, if
+one is set).
diff --git a/docs/solo/messages.md b/docs/solo/messages.md
new file mode 100644
index 00000000..363b47a3
--- /dev/null
+++ b/docs/solo/messages.md
@@ -0,0 +1,117 @@
+# Messages
+
+Messages holds three lists: **Channels**, **Direct** messages and **Rooms**.
+Unread counts show on each conversation, on the list and on the home screen.
+
+> [!NOTE]
+> **Wio Tracker L2:** one screen with all three as sections; tap a section
+> title to fold it. **New** in the header starts a conversation with any
+> contact.
+
+## Reading
+
+Open a conversation to see its history as chat bubbles: yours on the right,
+received ones on the left, newest at the bottom. Each bubble shows the sender,
+its age and a small hop count: on a received message, how many repeaters it
+came through; on your own, how many repeaters were heard passing it on.
+
+**Enter** on a message opens it full screen; **Left / Right** there pages to the
+older and newer one.
+
+**Hold Enter** on a message for its options:
+
+- **Reply**: starts a message addressed to the sender (`@[name]`).
+- **Navigate**, **Save waypoint**, **Set as target**: when the message
+ contains a location (see [Navigation](./navigation.md)).
+- **Path** on a received message: the repeaters it came through.
+ **Relayed by** on your own channel post: the repeaters heard repeating it.
+
+> [!NOTE]
+> **Wio Tracker L2:** hold a bubble. The card shows when it was sent, the hop
+> count, the path as a diagram, and **Reply** / **Set target**.
+
+### How much is kept
+
+The device keeps the newest 48 channel messages and 32 direct messages, all
+conversations together. When a busy conversation pushes out messages you
+haven't read, its unread count gets a **+** (for example `48+`).
+
+> [!NOTE]
+> **Wio Tracker L2:** 256 channel and 128 direct messages in memory, and with
+> an SD card every conversation is also saved to the card (100 to 2000
+> messages each, Settings › Storage). The history survives a reboot and
+> scrolls back through everything on the card.
+
+## Writing
+
+Open a conversation and choose **[+ send]** (or Enter at the bottom of the
+history). Pick a quick message or **Custom message** for the keyboard.
+
+- **Quick messages**: ten of your own, edited in Settings › Messages.
+- **Placeholders** fill in live data when the message is sent:
+ `{loc}` (your GPS position), `{time}`, `{batt}`, and the readings of any
+ sensor the device has: `{temp}`, `{hum}`, `{pres}`, `{alt}`, `{lux}`,
+ `{dist}`, `{co2}`.
+
+> [!NOTE]
+> **Wio Tracker L2:** the compose bar sits under the conversation; its **+**
+> opens quick messages and placeholders. Quick messages are edited in
+> Settings › Messages & contacts.
+
+### The keyboard
+
+The on-screen keyboard is a letter grid (or a phone-style T9 keypad, Settings ›
+Keyboard › Layout). Up from the top row moves the cursor through the text.
+
+Accented letters don't need a language setting: **hold Enter** on the base
+letter and pick from its variants, for example `a` → `á à â ä å ą…`, `z` →
+`ź ż ž`. This covers Polish, Czech, German, French, Spanish, Nordic and the
+other European languages written in Latin.
+
+Settings › Keyboard picks two scripts, **Main** and **Additional**, from Latin,
+Cyrillic and Greek; the keyboard's **#@/abc** key cycles between them and
+symbols. Cyrillic includes the Ukrainian, Belarusian and Serbian letters
+(under the key they sit on). Received messages in any of these scripts display
+correctly whatever the keyboard is set to.
+
+> [!NOTE]
+> **Wio Tracker L2:** a phone-style keyboard. Hold a key for its accents; the
+> globe key switches between the two alphabets.
+
+## Channels
+
+**Hold Enter** on a channel for its options:
+
+| Option | Does |
+| ------ | ---- |
+| Mark all read | Clears its unread count |
+| Notif, Melody | Its own notification and sound, instead of the global ones |
+| Fav | Marks it as a favourite (shared with the app) |
+| Scope | The region its messages are tagged with (`*` = none); the list is in Settings › Radio › Scope |
+| Pin to dial | Puts it on the Favourites page |
+| Edit, Delete | Renames it or changes its secret; removes it |
+
+**+ Add channel** at the end of the list adds:
+
+- **Public**: the default public channel, if you deleted it.
+- **Hashtag**: a topic such as `#hiking`. Anyone who types the same topic
+ joins the same channel.
+- **Private**: a name and a secret, typed as a passphrase or as the 32-digit
+ hex key (the format of channel QR codes).
+
+> [!NOTE]
+> **Wio Tracker L2:** hold a channel, or tap ⚙ in an open channel, for its
+> options.
+
+## Direct messages
+
+**Hold Enter** on a contact: Mark as read, Notif, Melody, Fav, Pin to dial.
+**Fav** is the star shared with the app and sorts favourites to the top;
+**Pin to dial** only puts the contact on the Favourites page.
+
+## Rooms
+
+Opening a room logs in first. You type the password once (empty if the room
+has none); it's saved on the device, including passwords set from the app,
+so the next time it logs in without asking. A wrong password is forgotten and
+you're asked again. **Hold Enter** on a room offers **Login…** and **Logout**.
diff --git a/docs/solo/navigation.md b/docs/solo/navigation.md
new file mode 100644
index 00000000..e9e97447
--- /dev/null
+++ b/docs/solo/navigation.md
@@ -0,0 +1,125 @@
+# Navigation
+
+Everything here works from the device's own GPS; no magnetometer or extra
+hardware is needed. Distances and speeds follow Settings › System › Units
+(metric or imperial).
+
+## Trail
+
+**Tools › Trail** records your route in the background while you use the rest
+of the device (a blinking **G** in the status bar). Straight stretches are
+stored as their two ends, so the 512 points cover a long route. **Left / Right**
+switches between the **Summary** (distance, time, speed or pace), the **Map**
+(your route, waypoints, people sharing their position, the target) and the
+point **List**.
+
+**Hold Enter** for the trail menu: start / stop, mark a waypoint, the waypoint
+list, **Track back** (retrace the route to where it started), share your
+position, the trail file, and the trail settings:
+
+- **Min dist**: how far apart points are recorded.
+- **Auto-pause**: pauses the trail after you stop for 1–5 minutes and resumes
+ when you move, so breaks don't count.
+- **Mark avg**: averages the GPS for 5–30 seconds when marking a waypoint.
+- **Auto-save**: saves the trail when the device powers off, including a
+ low-battery shutdown.
+
+The trail lives in memory: save it (Trail file › Save) or turn on Auto-save
+to keep it through a reboot.
+
+### GPX export
+
+Connect USB, open [Solo Tools](https://marekzegare4.github.io/Solo-tools/) in
+Chrome or Edge and click **Connect device**, then on the device choose
+**Trail file › Export**. The GPX includes your waypoints. Without a browser,
+`uv run tools/trail_export.py` does the same. Disconnect the phone app first if
+it's connected over USB.
+
+> [!NOTE]
+> **Wio Tracker L2:** the trail holds 4096 points and is drawn on the map.
+> Its controls (start / stop, save, load, track back, reset) are in the map's
+> **Map tools**, the settings in Settings › Map. **GPX** writes the trail to
+> the SD card; take it off with the card as a USB drive
+> ([Hardware](./hardware.md)).
+
+## Waypoints
+
+A waypoint is a saved spot (the car, a camp, water) with a short label, up to
+16 of them, kept through reboots. Add one with **Mark here** at your position,
+or **+ Add by coords** to type coordinates. The list starts with **Trail
+start**, so you can always go back to where the trail began.
+
+**Hold Enter** on a waypoint: Rename, Delete, **Send** (as a message to a
+contact or channel) and **Set as target**.
+
+> [!NOTE]
+> **Wio Tracker L2:** up to 64 waypoints. The pin button on the map opens the
+> list; hold a spot on the map to make it a waypoint or the target.
+
+## Navigating to something
+
+**Navigate** on a waypoint, a node in Nearby or a location in a message opens
+the navigation view: the distance, the bearing **To** the target and your own
+heading (**Hdg**), with the time to arrival once you're getting closer. Turn
+until the two bearings match. The heading comes from your movement, so it
+shows `--` while you stand still.
+
+**Tools › Compass** shows the same heading as a scrolling tape with the
+degrees and direction.
+
+> [!NOTE]
+> **Wio Tracker L2:** the target is drawn on the map with a line to it, and a
+> bar with distance, bearing, heading and time to arrival. The Compass app is
+> a turning dial.
+
+## Sharing locations
+
+- **Once**: **Share my pos** in the trail menu sends your position to a
+ contact or channel you pick.
+- **A waypoint**: **Send** in the waypoint menu.
+- **Live**: **Tools › Live Share** sends your position while you move, to one
+ contact or channel, for 1 to 12 hours. It only sends after you've moved
+ (50–500 m) and never more often than you set; an optional heartbeat repeats
+ it while you stand still.
+
+With **Track loc** on in Live Share, other people's shares show on the map
+and in Nearby, with live distance and bearing.
+
+Locations travel as ordinary text (`[LOC]lat,lon`, or `[WAY]lat,lon label`
+for a waypoint), readable in the phone app and on other firmware. On the
+receiving side, **hold Enter** on the message to navigate to it, save it or
+set it as the target.
+
+## Locator
+
+**Tools › Locator** alerts you when you cross a circle around a target:
+arriving at a waypoint, leaving it, or a person coming near or moving away.
+
+- **Target**: a waypoint (a fixed place) or a contact (follows their live
+ share, else their last known position).
+- **Radius**: 50 m to 1 km.
+- **Mode**: alert on arriving, leaving, or both.
+- **Beeper**: ticks faster as you get closer, even when the sound is muted.
+
+**Set as target** in Nearby, the waypoint list or a message sets the target
+in one step. The target shows as a flag on the map.
+
+## Map
+
+The **Map** home page shows your position, the trail, waypoints, people
+sharing their position and the target. **Enter** opens the trail map;
+**hold Enter** shares your position.
+
+> [!NOTE]
+> **Wio Tracker L2:** a real map with offline tiles on the SD card. Drag to
+> pan, +/− to zoom, the crosshair follows your GPS again.
+>
+> - **Download**: frame an area on the map and download its tiles over WiFi.
+> Downloaded areas can be renamed, refreshed or deleted.
+> - **Live tiles**: with WiFi on, tiles for where you look are fetched and
+> cached, up to the size set in Settings › Storage.
+> - **Vector regions**: whole regions as packs made with
+> `tools/maps/osm_vector.py`, copied to the card.
+>
+> The minimap on the home screen shows your surroundings at a glance; tap it
+> for the full map. The **Nodes** map shows every node with a position.
diff --git a/docs/solo/settings.md b/docs/solo/settings.md
new file mode 100644
index 00000000..7a310838
--- /dev/null
+++ b/docs/solo/settings.md
@@ -0,0 +1,40 @@
+# Settings
+
+Settings are saved as you change them and kept through reboots and updates.
+On joystick devices they're folding sections: **Enter** on a section opens
+it, **Left / Right** changes a value, **Back** leaves. Only the rows your
+board supports are shown.
+
+| Section | What's there |
+| ------- | ------------ |
+| **Display** | Brightness, auto-off, lock screen and [PIN](./lock.md), battery as icon / % / volts, clock format and seconds, wake on message; on e-ink also rotation and full refresh |
+| **Sound** | Buzzer on / off / auto (quiet while the app is connected), volume, quiet hours, the melody for messages, channels and adverts |
+| **Home Pages** | Order of the home pages, and which are shown |
+| **Radio** | TX power, preset, frequency, SF / BW / CR, saved presets, Auto pwr, the scope list |
+| **System** | Device name, time zone, low-battery shutdown, GPS power saving, units, reboot |
+| **Keyboard** | ABC or T9 layout, the two scripts, CardKB mode |
+| **Contacts** | Show all or favourites only (DMs, channels, rooms), favourites on top, contact expiry and prune |
+| **Messages** | Automatic resend of direct messages, the ten quick messages |
+
+A few notes:
+
+- **Auto pwr** lowers the TX power on strong links and raises it back on weak
+ ones; the power set above is the ceiling.
+- **Scope** is a list of named regions (plus `*`, no region). Messages are
+ tagged with a scope so repeaters can tell communities on the same frequency
+ apart. The default one is used for direct messages and repeating, and each
+ channel picks its own (see [Messages](./messages.md#channels)). Anyone who
+ types the same name gets the same scope; it isn't encryption.
+- **Low battery** shuts the device down at the voltage you choose, which is
+ also 0 % on the battery indicator.
+
+> [!NOTE]
+> **Wio Tracker L2:** one list of pages:
+>
+> - **Device**: Display (including the lock and **Tap to wake**), Home apps,
+> Power (battery, GPS), Sound (with the melody editor), Keyboard, Messages
+> & contacts.
+> - **Connections**: Radio, Bluetooth, WiFi, GPS.
+> - **Map & data**: Map (trail, live sharing and arrival alert options),
+> Storage.
+> - **System**: Name, Time, Firmware update, About; Reboot and Power off.
diff --git a/docs/solo/tools.md b/docs/solo/tools.md
new file mode 100644
index 00000000..75122853
--- /dev/null
+++ b/docs/solo/tools.md
@@ -0,0 +1,114 @@
+# Tools
+
+On joystick devices, the tools are in **Tools**, grouped into Location, Comms
+and System. The navigation tools are on the [Navigation](./navigation.md)
+page, Nodes and Admin on [Contacts](./contacts.md).
+
+> [!NOTE]
+> **Wio Tracker L2:** the tools are apps on the home screen: Messages, Nodes,
+> Settings, Compass, Clock, GPS, Bot, Repeater, Admin, Diagnostics. The trail,
+> live sharing and the locator are on the map (its tools button) and in
+> Settings › Map.
+
+## Clock
+
+The **Clock** home page shows the time, the date and up to three fields you
+choose (hold Enter): battery, temperature, humidity, pressure, altitude
+(barometric or GPS), light, CO₂, GPS position, satellites, contacts, unread
+messages. The time comes from GPS or the phone app; the time zone is in
+Settings.
+
+**Enter** on the clock opens the clock tools:
+
+- **Alarm**: a time, repeating daily, on weekdays, at weekends or once. It
+ rings with the screen off or locked, but not after a shutdown.
+- **Timer**: a countdown that rings when it reaches zero, whatever screen
+ you're on.
+- **Stopwatch**.
+
+Any key silences the ringing; it stops by itself after a minute.
+
+## Remote bot
+
+**Tools › Bot** answers messages for you. It watches your direct messages, one
+channel and one room, each switched on separately:
+
+- **Trigger and reply**: when a message contains the trigger (several can be
+ separated by commas, `*` matches any message), the bot sends the reply. The
+ reply can use placeholders, plus `{name}` (the sender) and `{hops}`.
+- **Commands**: messages starting with `!` get live data back:
+
+ | Command | Reply |
+ | ------- | ----- |
+ | `!ping` | `pong` |
+ | `!batt`, `!temp`, `!time`, `!loc` | battery, temperature, time, position |
+ | `!hops` | how many hops the command took |
+ | `!status` | battery, position and time |
+ | `!help` | the list of commands |
+
+ Several in one message get one reply: `!batt !time` → `4.10V | 14:30`.
+- **Actions** (off by default) let the command change the device: `!buzz`
+ (sounds the buzzer to find it), `!gps on` / `!gps off`, `!gps fix` (turns
+ the GPS on, waits for a good fix and sends it), `!advert`.
+
+**DM allow = Fav** limits the DM bot to your favourites, and **quiet hours**
+stop trigger replies at night (commands still answer). Replies are rate
+limited so two bots can't answer each other forever. The room bot uses the
+room's saved login.
+
+## Auto-advert
+
+**Tools › Auto-advert** sends an advert with your position every 30 seconds
+to 1 hour, so others see you in their Nearby list. With it on at both ends
+and Settings › Sound › **AD sound** set, each device beeps when it hears the
+other: a hands-free "still in range".
+
+## Repeater
+
+**Tools › Repeater** makes the device relay other people's packets while it
+keeps working as a companion. By default it relays on a separate repeater
+profile (the community's repeater frequency) and switches back when you turn
+it off; **Network = Current** relays on your own frequency instead.
+
+Optional filters keep a mobile repeater from adding noise: skip adverts, a
+maximum hop count, **Yield** (let fixed repeaters go first), a minimum SNR,
+drop duplicates already relayed by someone else, and relay only your
+**scopes**. Diagnostics shows how much it forwards.
+
+## Ringtones
+
+**Tools › Ringtone** composes two melodies of up to 32 notes (pitch, octave,
+length, tempo). Use them for notifications in Settings › Sound, or for a
+single contact or channel from its options.
+
+> [!NOTE]
+> **Wio Tracker L2:** the melody editor is under Settings › Sound.
+
+## Diagnostics
+
+**Tools › Diagnostics** shows live counters (packets received and sent by
+type, forwarded, errors), memory, the radio's noise floor and the last
+packet's signal; a **System** tab with the firmware and radio settings; and a
+**Font** tab with a sample of every script the font covers. Hold Enter on the
+live tab to reset the counters.
+
+> [!NOTE]
+> **Wio Tracker L2:** the Diagnostics app, with a **Noise** tab that
+> measures the noise floor over time.
+
+## GPIO
+
+*Wio Tracker L1 only.* **Tools › GPIO** sets four spare pins as input,
+output or (GPIO1–2) analog input, shows their level and switches outputs. The
+bot's `!gpio1`…`!gpio4` commands read and set the same pins.
+
+## GPS and sensors
+
+The **GPS** home page shows the fix and satellites; **Sensors** shows the
+readings of the sensors the board has. **GPS pwr** in Settings › System turns
+the GPS off between fixes to save battery; anything that needs your position
+(the trail, live share, the locator) keeps it on.
+
+> [!NOTE]
+> **Wio Tracker L2:** the **GPS** app draws a sky plot of the satellites and
+> each one's signal strength.
diff --git a/docs/solo_features/README.md b/docs/solo_features/README.md
deleted file mode 100644
index cc9785a7..00000000
--- a/docs/solo_features/README.md
+++ /dev/null
@@ -1,70 +0,0 @@
-# MeshCore Solo — documentation
-
-## Documents
-
-| Document | Description |
-| -------------------------------------------------------------------------- | --------------------------------------------------------------------- |
-| [Messages Screen](./message_screen/message_screen.md) | Sending messages, context menus, reply, navigate to / save shared locations, Notif/Melody overrides |
-| [Favourites Dial](./favourites_dial/favourites_dial.md) | Pinned contacts grid, unread badges, pin/unpin |
-| [Clock Screen](./clock_screen/clock_screen.md) | Clock page, date, configurable data fields, alarm / timer / stopwatch |
-| [Settings Screen](./settings_screen/settings_screen.md) | All settings sections with values and interactions |
-| [Screen Lock](./screen_lock/screen_lock.md) | Lock/unlock sequence, lock screen, auto-lock |
-| [Tools Screen](./tools_screen/tools_screen.md) | GPS trail & waypoints, compass, navigation, nearby nodes, ringtone editor, remote bot, auto-advert, live location sharing, locator, diagnostics, repeater, remote admin |
-| [External Keyboard & Joystick](./external_keyboard.md) | CardKB shortcuts, Full vs Compact mode, wired joystick, Heltec V3/V4 wiring |
-| [Build Flags](./build_flags.md) | Every optional `-D` build flag a solo build understands — GPIO, Hall sensor, buzzer/vibration, GPS switch, display/battery tuning |
-| [Solo UI framework](../developer/ui-framework.md) | **Developer guide** — the reusable building blocks (screens, lists, popups, mini-icons, geo/persistence helpers) and how to add a new feature |
-| [UI Core](../developer/ui-core.md) | **Developer guide** — the frontend-independent layer (models, settings schema, events) shared by the OLED/e-ink UI and the LVGL touch UI |
-
-## Upstream MeshCore
-
-| Document | Description |
-| -------------------------------------------------- | ------------------------------------------------ |
-| [FAQ](../faq.md) | Frequently asked questions |
-| [CLI Commands](../cli_commands.md) | Commands for repeaters, room servers and sensors |
-| [Terminal Chat CLI](../terminal_chat_cli.md) | Commands for the terminal chat client |
-| [Companion Protocol](../companion_protocol.md) | Serial/BLE frame protocol between device and app |
-| [Packet Format](../packet_format.md) | LoRa packet structure |
-| [QR Codes](../qr_codes.md) | Channel and contact QR code formats |
-
-## Features
-
-- Extended language support — one unified 6×9 font (Latin, Greek, Cyrillic) plus on-screen keyboard alphabets for Cyrillic, Greek, Polish, Czech, Slovak, German, French, Spanish, Portuguese and Nordic. Pick two in Settings › Keyboard (**Main**/**Additional**) and switch between them while typing
-
-- Enabled sensor screens with support for onboard sensors (temperature, humidity, pressure, luminosity, CO₂) and GPS data
-
-- **GPS navigation** — a full navigation suite that needs no extra hardware (details in the [Tools Screen](./tools_screen/tools_screen.md) docs):
-
- - **Waypoints** — mark a spot (car, camp, water…) with a short label, see it on the trail map, and get live bearing + distance back to it; the list always offers a one-tap backtrack to where your trail started
- - **GPS compass** — heading derived from course-over-ground (no magnetometer needed), shown as a clear scrolling heading tape with a large degrees + cardinal readout
- - **Navigate to anything** — a saved waypoint, a node straight from Nearby Nodes, or a location someone shares with you in a message
- - **Share & save locations** — send a waypoint to a contact or channel; on the other end, navigate to or save any shared location with one menu
- - **Live location sharing** — broadcast your position over the mesh as you move (movement-gated, to a channel or contact) and see others who share theirs as pins on the map and live distance/bearing in Nearby
- - **Locator** — arm a geofence around a waypoint or a person, get alerted on arrive/leave or near/far, with an optional homing beeper that speeds up as you close in. Set from the Locator screen, Nearby Nodes, or Waypoints; target shown as a flag on the map
- - **GPS trail** — background route recording with an auto-fit map (waypoints + live position), summary stats, auto-pause on stops, and [GPX export](../../README.md#documentation)
- - **Metric or imperial** — one global Units setting drives every distance and speed across the UI
-
-- [Messages Screen](./message_screen/message_screen.md) — view and send messages, open message details, reply with quick messages or custom text, navigate to / save locations shared in a message, per-channel notification and melody overrides, add/edit/delete channels on-device
-
-- [Favourites Dial](./favourites_dial/favourites_dial.md) — pin up to six contacts for quick access from the home screen
-
-- [Settings Screen](./settings_screen/settings_screen.md) — configure display, sound, home page order, radio and system settings
-
-- [Clock Screen](./clock_screen/clock_screen.md) — view time and date plus up to three configurable data fields, with built-in clock tools (one-shot alarm, countdown timer, stopwatch)
-
-- [Screen Lock](./screen_lock/screen_lock.md) — lock the device to prevent accidental keypresses, with a lock screen showing time and sensor data
-
-- [Tools Screen](./tools_screen/tools_screen.md) — GPS trail & waypoints, compass, nearby nodes (with ping & navigate), ringtone editor, remote bot, auto-advert, live location sharing, locator, diagnostics, repeater, remote admin
-
-- [External Keyboard & Joystick](./external_keyboard.md) — optional, auto-detected: **CardKB** for typing without the on-screen grid (Fn+Enter submits, Fn+letter picks an accent, Tab is Hold-Enter, Fn+Esc locks), plus a **wired joystick** for boards without one. Compact mode makes CardKB-only operation practical
-
-- **Auto pwr** (Settings › Radio) — Adaptive Power Control: trims actual TX power on strong links (from ACK SNR) and ramps back up to the configured ceiling on weak/lost links; the home screen shows the live power
-
-## E-ink Display (Wio Tracker L1)
-
-The e-ink variant targets the Wio Tracker L1 fitted with a 2.13″ GxEPD2 panel (250 × 122 px). Every screen is adapted for it:
-
-- **Adaptive layout** — every screen reflows correctly in both landscape (250 × 122) and portrait (122 × 250) orientations
-- **Display rotation** — configurable in Settings › Display; applied immediately and persisted across reboots
-- **Joystick rotation** — independent of display rotation; useful for custom enclosures
-- **Full refresh interval** — configurable in Settings › Display; reduces ghosting on long sessions
-- **Clock seconds suppressed by default** — seconds are hidden to reduce per-second panel refreshes and extend display lifetime; re-enable in Settings › Display
diff --git a/docs/solo_features/clock_screen/clock_screen.md b/docs/solo_features/clock_screen/clock_screen.md
deleted file mode 100644
index f4a46ad1..00000000
--- a/docs/solo_features/clock_screen/clock_screen.md
+++ /dev/null
@@ -1,93 +0,0 @@
-## Clock Screen
-
-[Go back](../../../README.md)
-
-### Overview
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-A full-screen clock page on the home screen. Shows the current time and date, with up to three configurable data fields below.
-
-Time is synchronized from GPS or via the companion app. Timezone offset is applied from **Settings › System**.
-
-If no time source is available, the screen shows _"! No time sync"_ with a hint to enable GPS or connect the app.
-
----
-
-### Time display
-
-- **Format** — 24 h or 12 h with AM/PM; configurable in **Settings › Display**
-- **Seconds** — shown by default on OLED; hidden on e-ink (always) and optionally on OLED via **Settings › Display › Clock seconds**; hiding reduces the refresh rate from 1 s to 60 s
-
----
-
-### Data fields
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Up to three data fields are shown below the date separator. Each field displays a label and a value on the same line.
-
-| Field | Label | Value |
-| ----------- | ----- | ------------------------------------------------------------------------- |
-| None | — | — |
-| Batt V | Batt | Battery voltage (e.g. `3.92V`) |
-| Batt % | Batt | Battery percentage using LiPo curve anchored at the low-battery threshold |
-| Temperature | Temp | °C from onboard sensor |
-| Humidity | Hum | % from onboard sensor |
-| Pressure | Pres | hPa from onboard sensor |
-| GPS | GPS | `lat lon` decimal degrees, or `no fix` |
-| Altitude (Baro) | Alt | metres/feet (per Settings › System › Units) from onboard barometric sensor (`--` without one) |
-| Luminosity | Lux | lux from onboard sensor |
-| CO₂ | CO2 | ppm from onboard sensor |
-| Contacts | Nodes | Total contacts in the mesh |
-| Messages | Msgs | Total unread message count. A trailing **+** (e.g. `48+`) means at least one channel or DM has filled its on-device history ring while unread — the real total is higher than shown, but that's everything still recoverable; the rest was evicted before ever being seen. |
-| Satellites | Sats | GPS satellite count (or `--` without GPS) |
-| Altitude (GPS) | AltG | metres/feet (per Settings › System › Units) from the GPS fix (or `no fix`) |
-
-Sensor fields show `--` when the sensor is not connected or has no data.
-
----
-
-### Configuring fields
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-
-
-**Hold Enter** (or press the **Context menu** key) on the Clock page to open the Dashboard Config screen, where each of the three field slots can be cycled with **LEFT/RIGHT**.
-
----
-
-### Clock tools — Alarm, Timer, Stopwatch
-
-**Press Enter** (short press) on the Clock page to open **Clock Tools**, a small menu with three time utilities. **Cancel** backs out one level (tool → menu → home). The same menu also has an entry under **Tools › System**, so it's reachable without the Clock page.
-
-#### Alarm
-
-A wake alarm with an optional repeat. Rows: **Hour**, **Minute**, **Repeat** and **Armed**. **Enter** on Hour or Minute opens the digit editor (LEFT/RIGHT moves between the tens/units, UP/DOWN changes the digit); **Enter** on Repeat cycles **OFF → Daily → Weekdays → Weekends → OFF**; **Enter** on Armed toggles ON/OFF. The configured time is shown next to the **Alarm** menu row when armed, and the setting persists across reboots.
-
-While armed, a bell icon shows in the Clock page's top-left corner and in the status bar on other home pages (hidden on the Clock page itself, hence its own indicator). Icon-only — the exact time is on the **Alarm** row in Clock Tools.
-
-The alarm fires at an absolute instant, so it survives clock re-syncs (mesh packets, companion app, GPS and the CLI can all jump the device clock). A jump past the alarm time still fires it, just late. With **Repeat** OFF (default) it disarms after firing once; with a pattern set, it re-arms for the next matching day.
-
-The alarm only fires while the device is **awake** (it keeps running with the display off or locked). It cannot wake the device from a full **Shutdown** (the CPU and RAM are powered down), and needs a valid time source — it stays pending until the clock is synced.
-
-#### Timer (countdown)
-
-A large **HH:MM:SS** readout with one digit underlined. **LEFT/RIGHT** moves the cursor one digit at a time, **Up/Down** changes the digit under it (minute/second tens cap at 5, hours at 23), and **Enter** starts the countdown. While running it shows **H:MM:SS** — **Enter** stops it, **Cancel** returns to the menu and leaves it counting. When it reaches zero the device rings, even if you have navigated to another screen.
-
-#### Stopwatch
-
-**Enter** starts/stops; **Up/Down** resets when stopped; **Cancel** returns to the menu and leaves it running.
-
-#### Ringing
-
-When the alarm or timer fires the device plays a melody (overriding mute) and shows an alert. **Any key** silences it; otherwise it stops on its own after a minute.
-
-> **E-ink note:** the live timer/stopwatch readouts would thrash a slow e-paper panel if redrawn every second, so on e-ink they refresh only coarsely (and immediately on any key press). The underlying timing is exact regardless, and the countdown's buzzer always fires on time.
diff --git a/docs/solo_features/clock_screen/fields_eink.png b/docs/solo_features/clock_screen/fields_eink.png
deleted file mode 100644
index 3a7a3d46..00000000
Binary files a/docs/solo_features/clock_screen/fields_eink.png and /dev/null differ
diff --git a/docs/solo_features/clock_screen/fields_oled.png b/docs/solo_features/clock_screen/fields_oled.png
deleted file mode 100644
index 7d1b4e73..00000000
Binary files a/docs/solo_features/clock_screen/fields_oled.png and /dev/null differ
diff --git a/docs/solo_features/clock_screen/overview_eink.png b/docs/solo_features/clock_screen/overview_eink.png
deleted file mode 100644
index 84ae6f66..00000000
Binary files a/docs/solo_features/clock_screen/overview_eink.png and /dev/null differ
diff --git a/docs/solo_features/clock_screen/overview_oled.png b/docs/solo_features/clock_screen/overview_oled.png
deleted file mode 100644
index 48c73dca..00000000
Binary files a/docs/solo_features/clock_screen/overview_oled.png and /dev/null differ
diff --git a/docs/solo_features/external_keyboard.md b/docs/solo_features/external_keyboard.md
deleted file mode 100644
index 12ffb90e..00000000
--- a/docs/solo_features/external_keyboard.md
+++ /dev/null
@@ -1,144 +0,0 @@
-## External Keyboard & Joystick
-
-[Go back](../../README.md)
-
-Two optional, auto-detected hardware add-ons — a build with them enabled runs
-the same with nothing plugged in. Two of the newer boards also ship with
-their own **built-in** keypad instead —
-see [Built-in keyboards](#built-in-keyboards-cardputer-adv-t-echo-lite--keyshield).
-
-- **CardKB** — an M5Stack I2C QWERTY keyboard (address `0x5F`), for typing
- messages, names and labels without walking the on-screen letter grid.
-- **Wired joystick** — four direction contacts plus a Back button, replacing the
- single-button navigation on boards that have no joystick of their own.
-
-### Support by device
-
-| Device | CardKB | Wired joystick |
-| ------ | :----: | :------------: |
-| Seeed Wio Tracker L1 (OLED) | ✅ Grove connector | onboard |
-| Seeed Wio Tracker L1 (E-ink) | ✅ Grove connector | onboard |
-| GAT562 30S Mesh Kit | — | onboard |
-| Heltec V3 *(experimental)* | ✅ solder to free GPIOs | ✅ solder to free GPIOs |
-| Heltec V4 *(experimental)* | ✅ solder to free GPIOs | ✅ solder to free GPIOs |
-| M5Stack Cardputer ADV *(experimental)* | — | built-in keyboard instead, see below |
-| LilyGO T-Echo Lite + KeyShield *(experimental)* | — | built-in keypad instead, see below |
-| ProMicro (nRF52840) *(experimental)* | ✅ shares the primary I2C bus (D8/D7) — no free pins for a second bus | — |
-
----
-
-## CardKB
-
-Plug it into the second I2C bus (the Grove connector on the Wio Tracker L1;
-see [Wiring](#wiring-heltec-v3--v4) for the Heltec boards). The firmware probes
-for it once at boot — nothing to enable in Settings.
-
-The same bus is scanned for environment sensors, so a CardKB and a sensor can
-share it.
-
-On a board with no free pins for a second bus (ProMicro), CardKB instead
-shares the primary bus already used by the display/RTC — set `CARDKB_I2C=Wire`
-as a build flag rather than `ENV_PIN_SDA`/`ENV_PIN_SCL`. See
-[Build Flags](./build_flags.md) for both forms.
-
-### Typing
-
-Printable characters insert straight at the cursor, bypassing the on-screen grid
-completely. The alphabet and T9/ABC settings do not apply — a real keyboard sends
-the right character already, so typing is always plain Latin ASCII regardless of
-what Settings › Keyboard is set to.
-
-| Key | Action |
-| --- | ------ |
-| letters / digits / symbols / space | insert at the cursor |
-| Backspace | delete the character before the cursor |
-| Esc | cancel / back |
-| Arrows | same as the joystick |
-| Enter | same as the centre button |
-| **Fn+Enter** | **submit the field** — no need to find the DONE cell |
-| **Fn+letter** | open the accent popup for that letter (e.g. Fn+A → á à ä ã…) |
-| **Tab** | the Hold-Enter equivalent, everywhere — context menus, shift-lock, clear-all |
-| **Fn+Esc** | lock / unlock the device (single press, works in both directions) |
-
-Fn+Esc rather than the adjacent Fn+Backspace on purpose: Fn and Backspace sit
-next to each other on CardKB's layout and would be far too easy to hit by
-accident. See [Screen Lock](./screen_lock/screen_lock.md) for the physical
-button equivalent.
-
-### Ext. KB — Full vs Compact
-
-**Settings › Keyboard › Ext. KB** picks how the on-screen keyboard behaves while
-a CardKB is doing the typing.
-
-| Mode | Behaviour |
-| ---- | --------- |
-| **Full** (default) | The letter grid stays on screen. Arrows and Enter drive the grid exactly as physical buttons do, so CardKB and the joystick can be used interchangeably. |
-| **Compact** | The grid, the special-row icons and the status line are all hidden — only the text being typed and two shortcut hints remain. Arrows move the **text cursor** directly, and plain Enter submits the field (same as Fn+Enter). |
-
-**Compact is designed to need no joystick at all** — the right choice when
-CardKB is the only input device, e.g. a Heltec V3/V4 with no joystick
-soldered on.
-
-Cursor mode and the accent / placeholder popups draw their own visible feedback,
-so they behave identically in both modes.
-
----
-
-## Wired joystick
-
-Four direction contacts plus a fifth "press" contact. Each contact simply
-shorts its pin to ground — the firmware enables the internal pull-ups, so no
-external resistors are needed.
-
-- The stick's own press contact drives the centre / Enter press — your thumb
- is already on the stick, so pressing it in is the natural "confirm" action.
-- The board's existing user button (PRG on the Heltec boards) becomes Back
- instead. Back is **not** optional: the UI uses it unconditionally once the
- joystick is enabled. Triple-clicking Back toggles the buzzer.
-- **Settings › Display › Joystick rotation** rotates the direction mapping at
- runtime (0–3), for a stick mounted sideways in a custom enclosure. It is
- independent of display rotation.
-
----
-
-## Wiring (Heltec V3 / V4)
-
-Neither board ships with a joystick or a keyboard header, so both are soldered to
-free GPIOs. V3 and V4 are pin-compatible per Heltec's documentation and the solo
-builds use the same assignment for both — **confirmed working on real V4
-hardware**; still worth checking against your own V3 module before soldering.
-
-| Function | GPIO | Notes |
-| -------- | ---- | ----- |
-| CardKB SDA | 3 | second I2C bus (`Wire1`) — *not* the OLED's 17/18 |
-| CardKB SCL | 4 | |
-| Joystick UP | 23 | |
-| Joystick DOWN | 6 | |
-| Joystick LEFT | 47 | |
-| Joystick RIGHT | 48 | |
-| Joystick press — Enter | 33 | the stick's own fifth contact; required when the joystick is enabled |
-| Back | 0 | the onboard PRG button — nothing to wire |
-
-Everything above lives in the `[env:Heltec_v3_companion_solo_dual]` /
-`[env:heltec_v4_companion_solo_dual]` blocks in
-[`solo/heltec_v3/platformio.ini`](../../solo/heltec_v3/platformio.ini)
-and [`solo/heltec_v4/platformio.ini`](../../solo/heltec_v4/platformio.ini),
-with comments explaining which pins are safe to reuse. To build a CardKB-only
-device, comment out the joystick block and set Ext. KB to Compact.
-
----
-
-## Built-in keyboards (Cardputer ADV, T-Echo Lite + KeyShield)
-
-*Experimental* — newly-added board support, not the CardKB/joystick add-ons
-above. Both keypads are TCA8418-based and share one polling path, entirely
-independent of the CardKB code — a board can have either, or neither.
-
-- **M5Stack Cardputer ADV** — built-in QWERTY, no CardKB or joystick needed.
-- **LilyGO T-Echo Lite + KeyShield** — the KeyShield add-on gives the T-Echo
- Lite a T9 keypad; without it the board has no usable input for the solo UI.
-
-Neither keypad follows CardKB's exact Fn-shortcut table (Fn+Enter,
-Fn+letter accent popups, Tab, Fn+Esc lock) — see each board's own
-keyboard driver under `variants/` and its solo `platformio.ini` under `solo/`
-for its current keymap.
diff --git a/docs/solo_features/favourites_dial/favourites_dial.md b/docs/solo_features/favourites_dial/favourites_dial.md
deleted file mode 100644
index 6774a5ba..00000000
--- a/docs/solo_features/favourites_dial/favourites_dial.md
+++ /dev/null
@@ -1,74 +0,0 @@
-## Favourites Dial
-
-[Go back](../../../README.md)
-
-### Overview
-
-| OLED | E-Ink |
-| :------------------------: | :------------------------: |
-|  |  |
-
-A dedicated home page showing a grid of up to 6 pinned conversations — chat contacts, room servers or channels — for quick access. The layout adapts to the display orientation:
-
-- **Portrait** (OLED, e-ink portrait) — 2 columns × 3 rows
-- **Landscape** (e-ink landscape) — 3 columns × 2 rows
-
----
-
-### Navigation
-
-Navigate tiles with **UP / DOWN / LEFT / RIGHT**. Pressing a directional key at the edge of the grid switches to the adjacent home page instead of wrapping.
-
-**Enter on a filled tile** — opens that conversation directly: a contact's DM, a channel's history, or a room server (running the room's login handshake first if it isn't logged in yet).
-
-**Enter on an empty tile (`+`)** — starts the picker to fill the slot.
-
-**Hold Enter on a filled tile** — opens **Unpin** / **Replace** for that slot.
-
-Channel tiles show their name with a leading `#`, so they read apart from contacts and rooms sharing the same grid.
-
----
-
-### Unread badge
-
-Filled tiles show an unread message count in the top-right corner — unread DMs for a contact or room, unread posts for a channel. The name is ellipsized to make room for the badge.
-
-If a pinned target disappears — a contact removed explicitly or auto-evicted to make room when the table is full, or a deleted channel — its slot is freed automatically and goes back to an empty `+` tile.
-
----
-
-### Pinning
-
-**From the Favourites Dial** — press **Enter** on an empty tile (`+`), or **Hold Enter** on a filled one and choose **Replace**. This opens the **Messages** screen in its normal Direct / Channels / Rooms browse; pick an entry and you land back on the dial with that slot filled. It's the same list you already use to open a conversation, rather than a second browser of its own.
-
-| OLED | E-Ink |
-| :------------------------: | :------------------------: |
-|  |  |
-
-
-
-**From the Messages lists** — **Hold Enter** on a contact, room or channel entry › **Pin to dial**, then choose a slot from the slot picker (Slot 1–6, showing the current occupant or "empty").
-
-**From Tools › Nodes** — **Hold Enter** on a node › **Pin to dial**. This one doesn't ask which slot; it takes the first free one (and says which), since that menu is already long.
-
-If the target is already pinned in another slot, it is moved to the new slot automatically.
-
----
-
-### Unpinning
-
-**From the Favourites Dial** — **Hold Enter** on the tile › **Unpin**.
-
-**From the Messages lists or Tools › Nodes** — **Hold Enter** › context menu › **Unpin (slot N)**.
-
----
-
-### Pinning is not the same as favouriting
-
-A pinned tile and a **Fav: ON** entry are two independent things. Pinning puts something on this page. Favouriting marks it with a ★ and sorts it to the top of every list it appears in, and is what the **Settings › Contacts** list filters read. Either can be used without the other.
-
----
-
-### Reordering the Favourites page
-
-The position of the Favourites Dial in the home page navigation sequence can be changed in **Settings › Home Pages** — press **LEFT / RIGHT** on the Favourites entry to move it earlier or later.
diff --git a/docs/solo_features/favourites_dial/overview_eink.png b/docs/solo_features/favourites_dial/overview_eink.png
deleted file mode 100644
index f0335d06..00000000
Binary files a/docs/solo_features/favourites_dial/overview_eink.png and /dev/null differ
diff --git a/docs/solo_features/favourites_dial/overview_oled.png b/docs/solo_features/favourites_dial/overview_oled.png
deleted file mode 100644
index a323aa55..00000000
Binary files a/docs/solo_features/favourites_dial/overview_oled.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/compose_eink.png b/docs/solo_features/message_screen/compose_eink.png
deleted file mode 100644
index a3b8b966..00000000
Binary files a/docs/solo_features/message_screen/compose_eink.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/compose_oled.png b/docs/solo_features/message_screen/compose_oled.png
deleted file mode 100644
index 02001879..00000000
Binary files a/docs/solo_features/message_screen/compose_oled.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/ctx_channel_eink.png b/docs/solo_features/message_screen/ctx_channel_eink.png
deleted file mode 100644
index 19bbf07b..00000000
Binary files a/docs/solo_features/message_screen/ctx_channel_eink.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/ctx_channel_oled.png b/docs/solo_features/message_screen/ctx_channel_oled.png
deleted file mode 100644
index bb70bff6..00000000
Binary files a/docs/solo_features/message_screen/ctx_channel_oled.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/ctx_contact_eink.png b/docs/solo_features/message_screen/ctx_contact_eink.png
deleted file mode 100644
index 37adf864..00000000
Binary files a/docs/solo_features/message_screen/ctx_contact_eink.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/ctx_contact_oled.png b/docs/solo_features/message_screen/ctx_contact_oled.png
deleted file mode 100644
index 478662d6..00000000
Binary files a/docs/solo_features/message_screen/ctx_contact_oled.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/fullscreen_eink.png b/docs/solo_features/message_screen/fullscreen_eink.png
deleted file mode 100644
index 9f62b3d1..00000000
Binary files a/docs/solo_features/message_screen/fullscreen_eink.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/fullscreen_menu_eink.png b/docs/solo_features/message_screen/fullscreen_menu_eink.png
deleted file mode 100644
index be72caf4..00000000
Binary files a/docs/solo_features/message_screen/fullscreen_menu_eink.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/fullscreen_menu_oled.png b/docs/solo_features/message_screen/fullscreen_menu_oled.png
deleted file mode 100644
index 3b396d18..00000000
Binary files a/docs/solo_features/message_screen/fullscreen_menu_oled.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/fullscreen_oled.png b/docs/solo_features/message_screen/fullscreen_oled.png
deleted file mode 100644
index 25b5630f..00000000
Binary files a/docs/solo_features/message_screen/fullscreen_oled.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/history_eink.png b/docs/solo_features/message_screen/history_eink.png
deleted file mode 100644
index 748a3bd5..00000000
Binary files a/docs/solo_features/message_screen/history_eink.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/history_oled.png b/docs/solo_features/message_screen/history_oled.png
deleted file mode 100644
index 2093cf3f..00000000
Binary files a/docs/solo_features/message_screen/history_oled.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/message_screen.md b/docs/solo_features/message_screen/message_screen.md
deleted file mode 100644
index 9fbad5d9..00000000
--- a/docs/solo_features/message_screen/message_screen.md
+++ /dev/null
@@ -1,184 +0,0 @@
-## Messages Screen
-
-[Go back](../../../README.md)
-
-### Overview
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-The Messages screen is split into three modes — **DMs**, **Channels**, and **Rooms** — selectable with UP/DOWN on the mode-select screen. Each mode shows the corresponding list of conversations with unread counters.
-
-DM and channel history are each kept in a fixed-size on-device ring (32 DM / 48 channel entries). A busy conversation that outpaces reading can fill its ring — new messages keep arriving, evicting the oldest ones, including unread ones that were never opened. When that's happened, the unread badge for that conversation (and the DM/Channels row on the mode-select screen, and the clock/lock screen's Msgs field) gets a trailing **+** — e.g. `48+` — meaning the count is honest for what's still on the device but understates how many actually came in; the rest are gone for good. Rooms aren't ring-limited the same way, so they never show a **+**.
-
----
-
-### Sending messages
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Press **Enter** on a contact or channel to open its history, then press **Enter** again (or select the **[+ send]** button, anchored at the right edge of the history) to compose a message. Choose between:
-
-- **Custom message** — opens the on-screen keyboard
-- **Q1–Q10** — quick reply templates editable in Settings › Messages
-
-While typing, **UP** from the top letter row enters cursor mode — LEFT/RIGHT move the insertion point, UP/DOWN jump to start/end (then to the grid on a second press), Enter/Cancel exit from anywhere — so you can edit mid-text, not just at the end. **Hold Enter** on a letter with accented variants (a, e, c, n, o, s, z…) opens a one-row accent popup instead — LEFT/RIGHT picks, Enter inserts, Cancel dismisses. Full key set (Shift, T9, Cyrillic/Greek) in the [UI framework guide](../../developer/ui-framework.md).
-
-The keyboard supports placeholders that insert live data at send time:
-
-| Placeholder | Value | Availability |
-| ----------- | -------------------- | --------------------------- |
-| `{time}` | current time (HH:MM) | always |
-| `{loc}` | GPS coordinates | always ("no GPS" if no fix) |
-| `{temp}` | temperature | sensor connected |
-| `{hum}` | humidity | sensor connected |
-| `{pres}` | barometric pressure | sensor connected |
-| `{alt}` | altitude | sensor connected |
-| `{lux}` | luminosity | sensor connected |
-| `{co2}` | CO₂ concentration | sensor connected |
-
-Sensor placeholders appear automatically in the placeholder picker when the corresponding sensor is active. `{time}` and `{loc}` are always shown.
-
----
-
-### Rooms — logging in
-
-Posting to a **room server** needs a login handshake — the device does this on its own, no phone app needed. First **Enter** on a room opens a password prompt automatically; type it and press **✓** (empty for no-password rooms). On success the chat opens automatically, no second Enter needed.
-
-- **Passwords are remembered across reboots.** After a successful login it's saved on the device, so picking that room again — even after a power cycle — logs back in silently.
-- **A wrong or changed password self-heals.** A failed login forgets the saved password, so the next **Enter** prompts for a new one.
-- **Re-login any time** with **Hold Enter** on the room → **Login…** — useful to switch passwords without waiting for a failure.
-- **Log out** with **Hold Enter** → **Logout** (only offered once logged in). Forgets the saved password, so the next open prompts for one again.
-- Passwords set from the **phone app** are saved on the device too, so it can post to that room standalone after a reboot.
-
-> The on-screen keyboard's default (Latin) page is ASCII only. Typing accented or non-Latin characters — Polish, Czech, Slovak, German, French, Spanish, Portuguese or Nordic diacritics, Cyrillic, or Greek — needs Settings › Keyboard › Alphabet set to the matching language first; the keyboard's **#@/abc** key then cycles Latin → that alphabet → Symbols → Latin. A password containing characters outside whatever's currently enabled can still be set from the phone app — the device stores and replays it byte-for-byte.
-
----
-
-### Message history
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Messages appear as chat bubbles sized to their content — **right**-anchored for outgoing, **left** for incoming — with sender name and a compact age indicator (`3m`, `2h`, `>1d`) in the top-right corner. List runs **newest at the bottom**; opening a history starts at the latest message, scrolling up goes further back. The list wraps at both ends like every other list: **UP** at the oldest message jumps to the newest, and **DOWN** past the newest lands on the compose row and then wraps to the oldest.
-
-A tiny digit icon on a bubble is its hop count: on your own messages, how many repeaters echoed them back; on a **received** DM or channel post, how many hops it took to reach you. A received message always shows a time — if its timestamp is unknown or reads slightly ahead of this device's clock (sender/receiver clock skew, or the clock isn't synced yet), the receipt time is shown instead. In a channel history the title carries the channel's scope in brackets (`name [scope]`) whenever it is set to anything but `*`.
-
-**Short Enter** on a message opens it in fullscreen. **Hold Enter** — on a history row or in fullscreen — opens the same options menu: Reply, plus **Navigate** / **Save waypoint** / **Set as target** when the message contains a location, and **Path** / **Relayed by** when hop data is available (see Fullscreen message view). You don't need to open the message first.
-
----
-
-### Fullscreen message view
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Navigate between messages like pages in a book — **LEFT** goes back to the older message, **RIGHT** forward to the newer one. The `<` / `>` markers along the bottom edge show which directions still have a message. Long messages scroll with **UP/DOWN**.
-
-If the message is a reply addressed to someone (`@[nick]`), a **To: nick** bar is shown below the sender name and the body is displayed without the address prefix.
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-**Hold Enter** in fullscreen opens the options menu. It always offers **Reply** for an incoming message, and when the message contains a **location** it adds three more:
-
-- **Navigate** — opens the bearing/distance view to those coordinates (the same two-bearing screen as Waypoints and Nearby; **Back** returns to the message).
-- **Save waypoint** — stores the location as a waypoint (visible on the trail map and in the Waypoints list).
-- **Set as target** — pins those coordinates as the active **Locator/Nav target** in one step, the same row Nodes and Waypoints offer (see Tools › Locator).
-
-A location is any `lat,lon` pair in the text — exactly what the `{loc}` placeholder inserts — so you can navigate to anything a contact shares. A `[WAY]lat,lon label` share also carries a name, used as the waypoint label. This works on DMs and channel messages, incoming or outgoing.
-
-When the entry has hop data recorded, the menu also adds one more row:
-
-- **Path (N hops)** — on a received message (DM or channel), lists every repeater the message actually travelled through to reach you, oldest hop first.
-- **Relayed by (N)** — on your own channel post instead, lists every distinct repeater heard rebroadcasting it back into the mesh (order isn't meaningful here — each one heard it independently, not as a chain).
-
-Selecting the row opens a read-only list of the resolved hops — each shown as the matching contact's name where one is known, or a short `?AABB`-style hex tag for an unrecognised repeater. Only repeaters within range of the message's actual travel — or, for **Relayed by**, within your own device's radio range — can ever be identified this way; a message with no recorded path (e.g. a zero-hop send, or one sent before any repeater relayed or echoed it) doesn't show this row at all.
-
----
-
-### Context menu — contact list
-
-**Hold Enter** on a contact entry opens a context menu:
-
-> Rows that show a value (`Notif:`, `Melody:`, `Fav:`) are changed in place — **LEFT/RIGHT** steps the value and **Enter** advances it, with the menu staying open. Only **Back** closes the menu. The same rule holds in every context menu on the device.
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-| Item | Action |
-| ---------------------------- | ------------------------------------------------------------------------------ |
-| Mark as read | Clears unread counter for this contact |
-| Notif: Default / OFF / ON | Per-contact notification override — **LEFT/RIGHT** or **Enter** to cycle |
-| Melody: Global / M1 / M2 | Per-contact melody override — **LEFT/RIGHT** or **Enter** to cycle |
-| Fav: ON / OFF | Mark this contact as a favourite — **LEFT/RIGHT** or **Enter** to toggle |
-| Pin to dial / Unpin (slot N) | Pin this contact to a Favourites Dial slot; if already pinned shows which slot |
-
-**Fav** and **Pin to dial** are separate. **Fav** is the starred flag shared with the companion app: it marks the row with a ★, sorts it above the rest of the list (unless **Settings › Contacts › Favs top** is off), and drives the `DMs = Fav` list filter. **Pin to dial** puts the contact on the [Favourites Dial](../favourites_dial/favourites_dial.md) page and changes nothing about the list.
-
-When **Pin to dial** is selected, a slot picker opens (Slot 1–6 showing current occupant name or "empty"). Choosing a slot that already holds another contact moves the new contact there.
-
-In the **Rooms** list the context menu instead offers:
-
-| Item | Action |
-| ------------- | ---------------------------------------------------------------------------- |
-| Login… | Opens the password prompt to (re-)log in to this room (see Rooms — logging in) |
-| Logout | Only shown once logged in. Forgets the saved password so the next open prompts for one again |
-| Fav: ON / OFF | Mark this room as a favourite — **LEFT/RIGHT** or **Enter** to toggle; drives the **Rooms = Fav** list filter |
-| Pin to dial / Unpin (slot N) | Pin this room to a [Favourites Dial](../favourites_dial/favourites_dial.md) slot |
-
----
-
-### Context menu — channel list
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-**Hold Enter** on a channel entry opens a context menu:
-
-| Item | Action |
-| ------------------------- | --------------------------------------------------------------------- |
-| Mark all read | Clears all unread for this channel |
-| Notif: Default / OFF / ON | Per-channel notification override — **LEFT/RIGHT** or **Enter** to cycle |
-| Melody: Global / M1 / M2 | Per-channel melody override — **LEFT/RIGHT** or **Enter** to cycle |
-| Fav: ON / OFF | Add or remove this channel from favourites — **LEFT/RIGHT** or **Enter** to toggle |
-| Scope: | **Enter** opens a picker over the shared scope list (Settings › Radio › Scope) — `*` sends this channel unscoped, any named scope tags its flood traffic with that region. Each channel keeps its own pick, matching the phone app's per-channel region picker. |
-| Pin to dial / Unpin (slot N) | Pin this channel to a [Favourites Dial](../favourites_dial/favourites_dial.md) slot |
-| Edit | Opens the Add/Edit form below, pre-filled with the channel's name |
-| Delete | Removes the channel — confirms first (defaults to Cancel) |
-
----
-
-### Adding / editing a channel
-
-Joining or creating a community channel no longer needs the phone app. The **Channels** list ends with **"+ Add channel"** — **Enter** picks a channel type; **Edit** from the context menu changes an existing channel's name/secret directly, skipping the type picker.
-
-**+ Add channel** first asks which type to create — the same three the phone app offers:
-
-- **Public** — instantly re-adds the well-known default public channel, no fields needed. Useful if it was deleted and you don't remember its key.
-- **Hashtag** — type a topic (e.g. `test`); name (`#test`) and secret (first 16 bytes of `sha256("#test")`) are both derived from it. A topic-based public chat — anyone typing the same topic elsewhere lands on the same channel, separate from the default Public one.
-- **Private** — the manual Name + Secret form:
-
- | Field | Notes |
- | ------ | ---------------------------------------------------------------------------------------------- |
- | Name | Up to 31 characters |
- | Secret | **LEFT/RIGHT** toggles between two entry modes; **Enter** opens the keyboard for whichever is selected |
-
- - **Passphrase** (default) — type any text; the device hashes it to the channel's 16-byte secret. Easiest to agree on verbally — same idea as a room password.
- - **Hex key** — the exact 32-hex-character secret (channel QR code format, see [QR Codes](../../qr_codes.md)), for joining with a secret you were given rather than a new passphrase. An all-zero secret (`00…0`) is rejected — reserved internally for an empty slot.
-
- Select **[Save]** to commit. The secret can't be redisplayed once saved (only the derived key is kept) — editing later means typing a new one, same as re-logging into a room.
-
----
-
-### Mark all read
-
-**Hold Enter** on the DM / Channels / Rooms mode-select screen to clear all unread counters for the highlighted category at once.
diff --git a/docs/solo_features/message_screen/overview_eink.png b/docs/solo_features/message_screen/overview_eink.png
deleted file mode 100644
index dcd029aa..00000000
Binary files a/docs/solo_features/message_screen/overview_eink.png and /dev/null differ
diff --git a/docs/solo_features/message_screen/overview_oled.png b/docs/solo_features/message_screen/overview_oled.png
deleted file mode 100644
index 4fd2353f..00000000
Binary files a/docs/solo_features/message_screen/overview_oled.png and /dev/null differ
diff --git a/docs/solo_features/screen_lock/overview_eink.png b/docs/solo_features/screen_lock/overview_eink.png
deleted file mode 100644
index ff5ec996..00000000
Binary files a/docs/solo_features/screen_lock/overview_eink.png and /dev/null differ
diff --git a/docs/solo_features/screen_lock/overview_oled.png b/docs/solo_features/screen_lock/overview_oled.png
deleted file mode 100644
index 3ae897a1..00000000
Binary files a/docs/solo_features/screen_lock/overview_oled.png and /dev/null differ
diff --git a/docs/solo_features/screen_lock/screen_eink.png b/docs/solo_features/screen_lock/screen_eink.png
deleted file mode 100644
index 227decc7..00000000
Binary files a/docs/solo_features/screen_lock/screen_eink.png and /dev/null differ
diff --git a/docs/solo_features/screen_lock/screen_lock.md b/docs/solo_features/screen_lock/screen_lock.md
deleted file mode 100644
index c6d1ec13..00000000
--- a/docs/solo_features/screen_lock/screen_lock.md
+++ /dev/null
@@ -1,85 +0,0 @@
-## Screen Lock
-
-[Go back](../../../README.md)
-
-### Overview
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Screen lock prevents accidental keypresses. While locked the display turns off and all input is ignored.
-
----
-
-### Locking and unlocking
-
-**Hold Back** and press **Enter** three times within 3 seconds. The sequence works in both directions — the same combination locks and unlocks.
-
-On boards with a CardKB attached, **Fn+Esc** does the same thing in one press. Esc rather than the adjacent Backspace — those two keys sit next to each other on CardKB's layout and would be too easy to hit by accident.
-
-If the display is off when the sequence begins, it turns on automatically so the hint is visible. Each press in the physical sequence extends the display-on timer by 5 seconds.
-
-The hint popup at the bottom of the lock screen guides through the physical sequence:
-
-| Step | Hint |
-| -------------- | ------------------------------------------------------------ |
-| Not started | _Hold Back + 3×Enter_ (_Back+3xEnter/Fn+Esc_ with CardKB attached) |
-| 1 press done | _Enter ×2 more…_ |
-| 2 presses done | _Enter ×1 more…_ |
-
-If no press is made for 3 seconds, the counter resets.
-
----
-
-### Lock screen
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-A brief press of any button wakes the display and shows the lock screen. It displays:
-
-- **Title bar** — battery and status icons, same as every other home page — but never the device name, so a locked device doesn't announce whose it is at a glance
-- **Time** — same format as the Clock page (24 h / 12 h from Settings), left-aligned
-- **Date** — day-of-week, day, month
-- **Two sensor values** — the first two Dashboard Config fields (same values configured for the Clock page); shown side by side if both are set
-
-The display turns off again automatically after 5 seconds of inactivity (or 2 seconds immediately after locking).
-
----
-
-### Auto-lock
-
-Enable **Auto-lock** in **Settings › Display** to lock the device automatically whenever the display turns off due to auto-off timeout.
-
----
-
-### Magnetic cover (Hall sensor)
-
-Optional, user-supplied hardware — no board in this repo has one built in. Wire a Hall-effect or reed sensor to any free GPIO, then set `PIN_HALL_SENSOR` (and `HALL_ACTIVE_HIGH=1`, if your module pulls the pin high rather than low when the magnet is present) as `build_flags` in your own env. No-op entirely unless `PIN_HALL_SENSOR` is defined.
-
-Fully autonomous, independent of Auto-lock and of any key combo:
-
-- **Magnet near (cover closed)** — locks and blanks the display immediately, no wake grace.
-- **Magnet away (cover opened)** — unlocks and wakes the display right away.
-
----
-
-### Lock PIN
-
-**Settings › Display › Lock PIN** asks for a PIN before the screen unlocks,
-also right after power-up, and when the magnet cover opens.
-
-- Enter on the row opens a number pad: type the PIN (at least 4 characters),
- confirm with ✓, then type it again. The pad's keyboard key switches to the
- normal keyboard for a PIN with letters.
-- Unlocking (Back + Enter three times, or opening the cover) shows the pad
- with the input masked. A wrong PIN says how many tries are left; after 5 in
- a row, entry pauses for 30 seconds.
-- Enter on the row again removes the PIN.
-
-The PIN is kept as a salted SHA-256 hash, never as the PIN itself. It locks
-the screen only: messages still arrive and the phone app still connects.
-On the Wio Tracker L2 it's **Settings › Display & power › Screen PIN**
-(digits only).
diff --git a/docs/solo_features/screen_lock/screen_oled.png b/docs/solo_features/screen_lock/screen_oled.png
deleted file mode 100644
index f92bdf01..00000000
Binary files a/docs/solo_features/screen_lock/screen_oled.png and /dev/null differ
diff --git a/docs/solo_features/settings_screen/homepages_eink.png b/docs/solo_features/settings_screen/homepages_eink.png
deleted file mode 100644
index e07cfd88..00000000
Binary files a/docs/solo_features/settings_screen/homepages_eink.png and /dev/null differ
diff --git a/docs/solo_features/settings_screen/homepages_oled.png b/docs/solo_features/settings_screen/homepages_oled.png
deleted file mode 100644
index f580b5fb..00000000
Binary files a/docs/solo_features/settings_screen/homepages_oled.png and /dev/null differ
diff --git a/docs/solo_features/settings_screen/overview_eink.png b/docs/solo_features/settings_screen/overview_eink.png
deleted file mode 100644
index 15c6fe58..00000000
Binary files a/docs/solo_features/settings_screen/overview_eink.png and /dev/null differ
diff --git a/docs/solo_features/settings_screen/overview_oled.png b/docs/solo_features/settings_screen/overview_oled.png
deleted file mode 100644
index 63b0de66..00000000
Binary files a/docs/solo_features/settings_screen/overview_oled.png and /dev/null differ
diff --git a/docs/solo_features/settings_screen/settings_screen.md b/docs/solo_features/settings_screen/settings_screen.md
deleted file mode 100644
index 33bac8b7..00000000
--- a/docs/solo_features/settings_screen/settings_screen.md
+++ /dev/null
@@ -1,142 +0,0 @@
-## Settings Screen
-
-[Go back](../../../README.md)
-
-### Overview
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-All settings are saved to flash and restored on next boot. Settings are organised into collapsible sections. Press **Enter** on a section header to expand or collapse it — all sections start collapsed for faster navigation. Press **LEFT/RIGHT** to change a value. **Enter** advances any row whose options wrap around — toggles, melodies, and option lists like Auto-off. Rows that ramp between fixed ends (Brightness, Volume, TX Pwr, Timezone, SF / BW / CR) are LEFT/RIGHT only, since there is nothing to wrap to.
-
-Press **Cancel/Back** to save and return to the home screen.
-
----
-
-### Display
-
-| Setting | Options | Notes |
-| ------------------------------------ | -------------------------------- | ----------------------------------------------------------------------------------------------------- |
-| Brightness | 1–5 | LEFT/RIGHT; preview applies immediately |
-| Auto-off | 5 s / 15 s / 30 s / 60 s / never | LEFT/RIGHT, or **Enter** to advance |
-| Auto-lock | ON / OFF | Locks device when display turns off |
-| Battery | icon / % / V | Display mode for the top-bar battery indicator |
-| Clock seconds | show / hide | Hiding reduces OLED refresh from 1 s to 60 s |
-| Clock format | 24 h / 12 h | 12 h appends AM/PM |
-| Display rotation _(e-ink only)_ | 0° / 90° / 180° / 270° | Applied immediately |
-| Joystick rotation _(e-ink only)_ | 0° / 90° / 180° / 270° | Rotates input mapping independently of display rotation; useful for custom enclosures |
-| Full refresh interval _(e-ink only)_ | OFF / 5 / 10 / 20 / 30 | Partial refreshes between full clears; reduces ghosting on long sessions |
-| Msg wake | ON / OFF | Whether an incoming message turns the display back on when it was off and no phone/app is connected (default ON — today's behaviour either way). |
-
----
-
-### Sound
-
-| Setting | Options | Notes |
-| -------------- | ------------------------------ | ------------------------------------------------------------ |
-| Buzzer | ON / OFF / Auto | Auto: silences while BLE connected, re-enables on disconnect |
-| Volume | 1–5 | LEFT/RIGHT; preview tone plays on each change |
-| DM Melody | built-in / Melody 1 / Melody 2 / None | Notification sound for incoming private messages. `None` disables the sound for this event. |
-| Channel Melody | built-in / Melody 1 / Melody 2 / None | Notification sound for incoming channel messages. `None` disables the sound for this event. |
-| AD sound | built-in / Melody 1 / Melody 2 / None | Sound played whenever an **advert** is received from *any* node — pairs with Auto-Advert as an audible "in range" heartbeat (see Tools › Auto-Advert). `None` disables the sound for this event. |
-| AD scope | All / Zero-hop | Filters the AD sound so it plays for every advert or only for local zero-hop adverts. |
-
-Melody 1 and Melody 2 are custom sequences editable in **Tools › Ringtone Editor**.
-
----
-
-### Home Pages
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Lists all available home screen pages. For each entry:
-
-- **LEFT / RIGHT** — move the page earlier or later in the navigation sequence
-- **Enter** — toggle the page ON / OFF
-
-**Settings** and **Messages** are always visible and cannot be disabled.
-
----
-
-### Radio
-
-| Setting | Options | Notes |
-| --------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
-| TX Pwr | 2–22 dBm | LEFT/RIGHT. With **Auto pwr** on this is the *ceiling* — the radio may transmit lower. On the **GAT562 30S** (external 30 dBm PA) the requested power maps through the PA's measured gain curve, so the stored value matches what is radiated; this row stays capped at 22, while the phone app / CLI can request up to 30 dBm — see [Build Flags › External PA](../build_flags.md#external-pa--tx-power-curve). |
-| Preset | named presets | LEFT/RIGHT cycles community RF presets (region frequency + bandwidth/SF/CR). **Enter** opens a popup to pick one, save the current settings as a named preset, or delete a saved one — deleting confirms first (defaults to Cancel). Applies frequency, bandwidth, SF and CR together. |
-| Freq | chip range | **Enter** opens a digit-by-digit editor: LEFT/RIGHT moves between decimal places, UP/DOWN steps that digit. Bounds come from the radio chip's own validated range, so a value the radio would reject can't be entered. |
-| SF | 5–12 | LEFT/RIGHT. Spreading factor. |
-| BW | 7.8–500 kHz | LEFT/RIGHT cycles the standard LoRa bandwidths. |
-| CR | 5–8 | LEFT/RIGHT. Coding rate (4/5–4/8). |
-| Auto pwr | ON / OFF | **Adaptive Power Control.** Lowers TX power on strong links, ramps back to the **TX Pwr** ceiling on weak/lost ones. Link quality from DM ACK SNR, or — for channels (no ACK) — a repeater's rebroadcast. Live power shown on the radio page/name bar. Default OFF. **Suppressed (`--`) while the repeater is on** — restored once it's switched off. |
-
-There is no "Pwr save" row: hardware RX duty-cycle receive was tried and disabled (`FEAT_RX_POWERSAVE 0` in `examples/companion_radio/Features.h`) — the SX126x's duty-cycle preamble detection needs the sender's actual preamble to exactly match what we configure, which a mixed-firmware mesh can't guarantee (silently drops every packet from a mismatched sender, no matter the signal strength).
-| Scope | list | Shows the list's **default** scope. **Enter** opens the **SCOPE** list: `*` (wildcard = unscoped, always first, can't be renamed or deleted) plus up to 8 named scopes of your own (e.g. `pl`). Typing a name derives a shared key the same way on every device, so any device that types the same name lands on the same scope automatically, no key exchange needed. **Enter** on a row opens **Set as default** / **Rename** / **Delete** (delete confirms first); **+ Add scope** at the bottom opens the keyboard. The **default** scope (marked `[default]`) governs **DMs** and the **repeater's own relay slot**; each **channel** carries its own pick — set from the channel's context menu (see [Message Screen](../message_screen/message_screen.md)) — and a channel left on `*` sends unscoped. Scopes tag flood traffic so repeaters can tell your community's messages apart from others sharing the same frequency; paired with **Tools › Repeater › Scope only** it's also what this device relays for in repeater mode. The default also syncs both ways with the phone app's default-scope setting. Not encryption — message content is unaffected either way. Upgrading from a build with the old single Scope field carries it over as the default entry and seeds every existing channel with it, so nothing changes on the air. |
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-
-
-The **repeater** mode and its flood filters live on their own screen — see **Tools › Repeater**, including how it uses **Scope** above.
-
----
-
-### System
-
-| Setting | Options | Notes |
-| ----------- | --------------------------------------------------- | -------------------------------------------------------------------------------------- |
-| Name | keyboard entry (up to 31 chars) | This device's node name, shown to others and in every advert. **Enter** opens the keyboard pre-filled with the current name; applied and saved on submit |
-| Timezone | −12 h … +14 h | UTC offset in whole hours |
-| Low battery | OFF / 3.0 V / 3.1 V / 3.2 V / 3.3 V / 3.4 V / 3.5 V | Auto-shutdown threshold; also sets the 0 % anchor for the battery percentage indicator |
-| GPS pwr _(if GPS detected)_ | OFF / 1 min / 5 min / 15 min / 30 min / 1 h | **Battery saver.** Cycles GPS off between fixes; each wake waits up to 60 s for a fix before sleeping again. Stays continuously on whenever something needs a live position — Trail recording, Live share, an armed Locator, Compass/Nearby, or an in-flight `!gps fix`. `OFF` (default) = always-on, as before. Status icon blinks while napping. |
-| Units | Metric / Imperial | Global unit system for every distance/speed shown in Tools (Nearby Nodes, Trail, navigate-to-point). Metric: m / km, km/h, min/km. Imperial: ft / mi, mph, min/mi |
-| Reboot | action (**Enter**) | Restarts this device. Pending setting changes are saved first. Last row, so it isn't the default-selected one |
-
----
-
-### Keyboard
-
-| Setting | Options | Notes |
-| -------- | ---------- | -------------------------------------------------------------------------------------------------- |
-| Layout | ABC / T9 | On-screen keyboard style. **ABC**: a-b-c…z grid, one key per letter. **T9**: phone-keypad multi-tap — each key labelled digit+letters (e.g. `2abc`); repeated **Enter** cycles the letters then the digit. Applies to whichever script page is active, not just Latin. |
-| Main | Latin / Cyrillic / Greek | Which script the keyboard opens on by default. **Latin** is the default; picking **Cyrillic** or **Greek** makes that the one you land on, with Latin moving to the Additional cycle instead. |
-| Additional | Latin / Cyrillic / Greek | The second script in the **#@/abc** key's cycle (Main → Additional → Symbols → Main). Setting it to the same script as Main drops the cycle to just that script plus Symbols. **Greek** covers the 24-letter alphabet plus final sigma (`ς`), not the tonos stress accents. Every script renders natively via one shared Unicode font — no separate toggle needed. |
-| Ext. KB | Full / Compact | Only shown on a build with CardKB support (`CARDKB_I2C` or `ENV_PIN_SDA`/`ENV_PIN_SCL` set). Picks how the on-screen keyboard behaves while a CardKB is doing the typing — see [External Keyboard & Joystick](../external_keyboard.md#ext-kb--full-vs-compact). |
-
-Applies to every on-screen text field (messages, waypoint labels, room passwords, preset names).
-
-European Latin-diacritic letters (Polish, Czech, Slovak, German, French, Spanish, Portuguese, Nordic, etc.) aren't separate alphabet pages — instead, **Hold Enter** on a plain Latin letter that has accented variants (`a c d e i l n o r s t u y z`) opens a one-row popup of its accents (e.g. holding `a` offers `á à â ã ä å ą`); **LEFT/RIGHT** picks, **Enter** inserts it, **Cancel** dismisses with no change. Holding a letter with no accented variants (e.g. `b`) does nothing. Works on whichever page is currently showing Latin, whether that's Main or Additional.
-
----
-
-### Contacts
-
-| Setting | Options | Notes |
-| -------- | --------- | ------------------------------------------- |
-| DMs | All / Fav | Show all chat contacts or only favourited ones |
-| Channels | All / Fav | Show all channels or only favourited ones |
-| Rooms | All / Fav | Show all room servers or only favourited ones |
-| Favs top | ON / OFF | Sort favourites to the top of every list (default ON) |
-| Expire | Off / 7d / 30d / 90d | Age after which a contact with no advert/update counts as inactive (default Off). Only used by **Prune now** — nothing is ever deleted automatically. |
-| Prune now | action (**Enter**) | Counts the contacts older than **Expire**, then asks `Remove N contacts?` (defaults to Cancel) before deleting anything. Shows `Expire is Off` / `No inactive contacts` instead when there is nothing to do. |
-
-Favourites are set per item in its context menu (**Hold Enter** › **Fav: ON / OFF**) — see [Message Screen](../message_screen/message_screen.md), and the same row exists in Tools › Nodes. A contact's or room's favourite flag is the same one the companion app shows as a starred contact, so it syncs both ways; a channel's is device-only.
-
-A favourite is marked with a ★ on its row wherever it is listed, and — unless **Favs top** is off — sorted above everything else. The three filters above are independent of that: they control what's *listed at all*, the sort only controls the order.
-
-**Pruning.** A contact is inactive when its last advert/update is older than **Expire**. **Favourites are never pruned**, and neither is a contact with no timestamp or one that reads ahead of the device's own clock (e.g. the clock isn't set yet) — the rule only ever errs on the side of keeping data.
-
----
-
-### Messages
-
-| Setting | Options | Notes |
-| ------- | -------------- | ---------------------------------------------------------------------------------------------- |
-| Resend | OFF / 1×–5× | Auto-resend an on-device direct message this many times when no delivery ACK is received (default 2×) |
-
-Up to 10 quick reply templates (Q1–Q10). Press **Enter** on a slot to open the keyboard editor. Supports the same placeholders as the main keyboard (`{time}`, `{loc}`, and sensor placeholders when connected).
diff --git a/docs/solo_features/tools_screen/autoreply_eink.png b/docs/solo_features/tools_screen/autoreply_eink.png
deleted file mode 100644
index 9499981e..00000000
Binary files a/docs/solo_features/tools_screen/autoreply_eink.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/autoreply_oled.png b/docs/solo_features/tools_screen/autoreply_oled.png
deleted file mode 100644
index 792a40ac..00000000
Binary files a/docs/solo_features/tools_screen/autoreply_oled.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/nearby_eink.png b/docs/solo_features/tools_screen/nearby_eink.png
deleted file mode 100644
index f1508d67..00000000
Binary files a/docs/solo_features/tools_screen/nearby_eink.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/nearby_oled.png b/docs/solo_features/tools_screen/nearby_oled.png
deleted file mode 100644
index f31a05cc..00000000
Binary files a/docs/solo_features/tools_screen/nearby_oled.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/nearby_ping_eink.png b/docs/solo_features/tools_screen/nearby_ping_eink.png
deleted file mode 100644
index 78fb3f6b..00000000
Binary files a/docs/solo_features/tools_screen/nearby_ping_eink.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/nearby_ping_oled.png b/docs/solo_features/tools_screen/nearby_ping_oled.png
deleted file mode 100644
index 3b5a8c55..00000000
Binary files a/docs/solo_features/tools_screen/nearby_ping_oled.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/nearby_scan_eink.png b/docs/solo_features/tools_screen/nearby_scan_eink.png
deleted file mode 100644
index 180cc782..00000000
Binary files a/docs/solo_features/tools_screen/nearby_scan_eink.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/nearby_scan_oled.png b/docs/solo_features/tools_screen/nearby_scan_oled.png
deleted file mode 100644
index 3cba2684..00000000
Binary files a/docs/solo_features/tools_screen/nearby_scan_oled.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/overview_eink.png b/docs/solo_features/tools_screen/overview_eink.png
deleted file mode 100644
index badff3b1..00000000
Binary files a/docs/solo_features/tools_screen/overview_eink.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/overview_oled.png b/docs/solo_features/tools_screen/overview_oled.png
deleted file mode 100644
index 5bb6d843..00000000
Binary files a/docs/solo_features/tools_screen/overview_oled.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/ringtone_eink.png b/docs/solo_features/tools_screen/ringtone_eink.png
deleted file mode 100644
index 731a3ed4..00000000
Binary files a/docs/solo_features/tools_screen/ringtone_eink.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/ringtone_oled.png b/docs/solo_features/tools_screen/ringtone_oled.png
deleted file mode 100644
index 5101aba3..00000000
Binary files a/docs/solo_features/tools_screen/ringtone_oled.png and /dev/null differ
diff --git a/docs/solo_features/tools_screen/tools_screen.md b/docs/solo_features/tools_screen/tools_screen.md
deleted file mode 100644
index 341b8888..00000000
--- a/docs/solo_features/tools_screen/tools_screen.md
+++ /dev/null
@@ -1,593 +0,0 @@
-## Tools Screen
-
-[Go back](../../../README.md)
-
-### Overview
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-The Tools screen is a hub for GPS trail recording, nearby node browsing, ringtone editing, the remote bot, auto-advert, live location sharing, locator, compass, clock tools (alarm / timer / stopwatch), device diagnostics, repeater mode, and remote admin. Tools are grouped into collapsible **Location** / **Comms** / **System** sections — the same fold-in-place model as Settings; Tools always opens folded back to the section list. Navigate with **UP/DOWN**, press **Enter** on a section header to expand or collapse it, or on a tool to open it.
-
----
-
-## Nearby Nodes
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Browse nodes that have recently advertised on the mesh. **Filter** (which nodes) and **sort** (in what order) are independent axes and combine freely.
-
-Filter by category with **LEFT/RIGHT**:
-
-| Filter | Shows |
-| ------ | ------------------------------ |
-| All | All known nodes |
-| Fav | Favourites only (★) |
-| Comp | Companion (chat) nodes |
-| Rpt | Repeaters |
-| Room | Room servers |
-| Snsr | Sensors |
-
-Select a node to see its coordinates, distance, bearing with cardinal direction, type, and last-heard time. A node that is **broadcasting its position** via Live Share is marked with a **♦ diamond** beside its name in the list (the same marker the map uses), and its detail shows `Sharing pos:` with the share age and whether it's DM-verified or channel-only. A **★ star** marks a favourite, which is also sorted to the top of the list unless **Settings › Contacts › Favs top** is off.
-
-**Hold Enter** opens the same **Options** menu everywhere (list and detail), in a fixed order — only the actions that apply appear:
-
-| Action | Available when |
-| ---------------------- | -------------------------------------------------------------------------------------- |
-| Navigate | selected node has GPS — for a node sharing live position, the view follows it as it moves and adds an ETA line |
-| Ping | a public key is known for the node |
-| Save waypoint | selected node has GPS |
-| Set as target | selected node has a position — pins it as the active **Locator/Nav target** right away (see **Locator**). A node with a known public key (a contact, a scan result, or someone sharing over DM) becomes a **person** target that keeps following them; a name-only row — someone sharing their position on a channel who isn't your contact — becomes a **place** target pinned where they were, since there's no identity to re-resolve |
-| Fav: ON / OFF | selected node is a saved contact — **LEFT/RIGHT** or **Enter** toggles it in place, as in the Messages menus; the same starred flag those lists use, shared with the companion app |
-| Pin to dial / Unpin (slot N) | selected node is a saved contact — puts it on the [Favourites Dial](../favourites_dial/favourites_dial.md), taking the first free slot |
-| Admin | selected node is a saved **repeater or room server** contact — opens **Tools › Admin** for it directly (see **Admin**) |
-| Sort: Dist/Recent | browsing stored nodes — **LEFT/RIGHT** or **Enter** flips distance ↔ last-heard in place |
-| Discover scan / Rescan | always (live `NODE_DISCOVER_REQ` scan) |
-
-Filtering stays on the list itself (**LEFT/RIGHT** cycles the type), so there is no separate Filter action in the menu. **Sort** is adjusted in place: highlight the **Sort** row and tap **LEFT/RIGHT** to flip the list (and its right-hand column) between **distance** and **last-heard** without closing the menu. The row appears only while browsing stored nodes (live-scan rows carry signal, not distance). Filter and sort are independent and **persist** across re-entry to the screen.
-
-Selecting **Ping** opens the Ping popup:
-
-| OLED | E-Ink |
-| :----------------------------: | :----------------------------: |
-|  |  |
-
-Use **Enter** on the popup’s `Ping` row to send a direct mesh ping to that node. The popup then shows the RTT and SNR values on the next lines, and can be used again immediately for another ping.
-
-> [!TIP]
-> Combined with **Auto-Advert** on the other device, Nearby Nodes becomes a passive location tracker — as long as the tracked device periodically broadcasts its GPS position, you can see its current distance and bearing without any manual interaction on either end.
-
----
-
-### Active Discovery (live scan)
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-**Options → Discover scan** sends a `NODE_DISCOVER_REQ`. Repeaters, sensors and room servers within zero-hop range respond immediately with name, type and signal data. This is not a separate screen — it is the **same list switched to a live-scan source**: the right-hand column shows **RSSI** instead of distance, and node detail shows the public key, signal data and contact status.
-
-Because it is the same list, all the same keys apply — **UP/DOWN** to navigate, **Enter** for detail, **Hold Enter** for the Options menu (where **Rescan** repeats the scan and **Ping** works exactly as on stored nodes).
-
-- **Cancel / Back** — return to the stored-nodes list
-
----
-
-## GPS Trail
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-Records your route in a RAM ring buffer (up to 512 points, sampled every 1 s). The track is **simplified as it's recorded** — a long straight stretch is kept as just its two endpoints while curves keep their detail (bounded to within the **Min dist** tolerance of the real path), so the buffer covers a far longer route than a flat point budget would suggest. Tracking runs in the background — a blinking **G** appears in the status bar. The trail survives display auto-off but is lost on reboot unless saved to flash first.
-
-> [!TIP]
-> The **Map** view is also reachable directly from the home carousel — the **Map** page shows a live mini-preview (your position, trail, and tracked contacts) with a **north marker** and a bottom-left **scale tick**. The status line below reads `Track:N` (tracked-node count) and, when you have a fix and at least one tracked contact, an **arrow + distance** to the **nearest** one (e.g. `Track:3 →120m`). If a **Locator/Nav target** is set it's drawn as a **flag marker** (see **Locator**). Press **Enter** to open the full Trail Map; **Hold Enter** shares your position (see **Live Share**); **Back** returns home.
-
-A GPS fix indicator also sits in the top status bar, alongside the trail/auto-advert/repeater icons — boxed (lit) once the receiver has a valid fix, a plain glyph while still searching. It only appears on boards with GPS hardware and while **GPS** is turned on in Settings; it's hidden the rest of the time rather than sitting there empty.
-
-Cycle views with **LEFT / RIGHT**:
-
-| View | Content |
-| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| **Summary** | Distance, elapsed time, avg speed or pace, point count, tracking status |
-| **Map** | Auto-fit dot-and-line plot with cos(lat) aspect correction; segment breaks marked; north arrow; square scale grid fitted to the map frame (toggle under **Hold Enter → Settings → Grid**, Map view only). Your **current GPS position**, all **waypoints**, and any **live-tracked contacts** (positions shared via Live Share) are always drawn — even with no trail recording — so the map is useful standalone. The active **Locator/Nav target**, if set, is drawn as a **flag** on top (folded into the frame so it's never off-screen). Point labels are auto-placed to avoid overlapping (a crowded cluster drops some labels rather than smearing them) |
-| **List** | Per-point rows showing local time (HH:MM) and delta distance from the previous point; segment-start rows show `start`; scroll with **UP/DOWN** |
-
-| OLED | E-Ink |
-| :-----------------------: | :-----------------------: |
-|  |  |
-
-**Hold Enter** opens the **action menu**. It is two-level — a short main menu, plus **Trail file…** and **Settings…** submenus. **Cancel/Back** in a submenu returns to the main menu.
-
-**Main menu:**
-
-| Item | Action |
-| --------------------- | --------------------------------------------------- |
-| Start / Stop tracking | Begin or end a recording session. If **GPS is off**, choosing Start asks **"GPS is off — Enable GPS & start"** so a session can't silently run with nothing to record |
-| Mark here | Drop a waypoint at the current GPS fix (see below) |
-| Waypoints… | Open the waypoint list / navigation / add-by-coords |
-| Track back | Retrace the recorded route back to its start (needs ≥2 points; see below) |
-| Share my pos | Send your current position as a one-shot `[LOC]` message — pick a contact or channel (see **Live Share**) |
-| Trail file… | Open the file submenu (below) |
-| Settings… | Open the settings submenu (below) |
-
-**Trail file…** (only the operations that apply right now appear):
-
-| Item | Action |
-| -------------- | ----------------------------------------------- |
-| Save trail | Write RAM ring to flash (`/trail`) |
-| Load trail | Restore flash trail into RAM |
-| Export (live) | Stream live RAM trail as GPX 1.1 over USB Serial |
-| Export (saved) | Stream saved flash trail as GPX 1.1 over USB Serial |
-| Reset trail | Clear RAM ring and elapsed time — confirms first (defaults to Cancel) since there's no way back short of a prior **Save trail** |
-
-**Settings…** (values cycle with **LEFT/RIGHT** or **Enter**; shown only where they apply):
-
-| Item | Available | Action |
-| ---------- | --------- | ------------------------------------------------------- |
-| Min dist | always | Sample gate, 4 levels — metric: 5/10/25/100 m, imperial: 15/30/75/300 ft |
-| Auto-pause | always | OFF / 1 / 2 / 5 min — auto-freeze the trail after a stop, resume on movement (see below) |
-| Mark avg | always | OFF / 5 / 10 / 30 s — GPS averaging for **Mark here** (see Waypoints below) |
-| Auto-save | always | OFF / ON — auto-write the live trail to flash on shutdown, so a **low-battery auto-shutdown** doesn't lose the route (see below) |
-| Readout | Summary view | Summary shows Speed or Pace (in the global unit system) |
-| Grid | Map view | Toggle scale grid on the map |
-
-(Trail file… appears only when a live or saved trail exists. Mark here needs a GPS fix; Waypoints is always available.)
-
-**Auto-pause** — when set, a recording trail automatically **pauses** after the device has stayed within ~15 m of one spot for the chosen delay: the elapsed timer and point sampling both freeze, and the map line breaks across the idle gap. It **resumes on its own** as soon as you move again. This keeps a stop (a break, a meal, parking) out of your distance and average-speed stats without you having to remember to stop and restart tracking. A paused trail is still "on" (the **G** marker keeps blinking) — the Summary **Status** row shows `paused`. The stop is detected with its own coarse movement gate, independent of **Min dist**, so GPS jitter while you're parked doesn't keep it awake.
-
-**Auto-save** — with this on (default off), the live trail is written to flash automatically when the device powers off, so a **low-battery auto-shutdown** no longer discards the whole route. It saves to the same `/trail` file as the manual **Trail file… → Save**, and only writes when the trail actually has points — an empty trail can't overwrite a previously saved one.
-
-### Track back
-
-**Hold Enter → Track back** retraces your recorded trail back to the start — useful in poor visibility or unfamiliar ground. It reuses the navigation view (distance + two absolute bearings; see *Waypoints › Navigating*), but walks the recorded breadcrumbs in reverse: snaps to the **nearest recorded point**, guides you to it, then advances to the next earlier point as you reach each one (within ~20 m). The header shows points remaining (`Back: 12 pt`), reading `Trail start` on the final leg; arriving shows `Back at start` and exits. **Cancel** leaves track-back at any time. Needs a trail with at least two points and a GPS fix; tracking doesn't need to still be running.
-
-### Waypoints
-
-A waypoint is a saved spot — your car, camp, a water source — that you can navigate back to later. Waypoints are **independent of the trail**: they live in their own flash file (`/waypoints`), survive a reboot, and are **not** cleared by *Reset trail*. Up to 16 can be stored — the Waypoints list header shows how many are in use (e.g. `WAYPOINTS 3/16`).
-
-**Dropping a waypoint** — **Hold Enter → Mark here**. This captures the current GPS fix and opens the on-screen keyboard for a short label (up to 11 characters — e.g. `CAR`, `CAMP`, `H2O`). Leaving it blank auto-names it `WP1`, `WP2`, … Marking works whether or not the trail is being recorded; it needs a GPS fix (otherwise it reports *No GPS fix*).
-
-**GPS averaging** — with **Settings → Mark avg** set (5 / 10 / 30 s), *Mark here* doesn't snapshot a single fix; it samples the GPS once a second for that window and stores the **mean** position, for a steadier mark than one instantaneous reading (handy for a precise spot — a cache, a car, a trailhead). A short screen shows the time left and the sample count while it runs; **Cancel** aborts. When the window closes it opens the label keyboard as usual. With **Mark avg = OFF** (the default) marking is instant.
-
-**Adding by coordinates** — open **Hold Enter → Waypoints** and select the **+ Add by coords** row (always the last entry in the list). This creates a waypoint without being there — no GPS fix required (handy for a meeting point or a spot read off a map). It opens a small form with three editable rows plus **Save**:
-
-| OLED | E-Ink |
-| :------------------------: | :------------------------: |
-|  |  |
-
-
-
-
-- **Lat** / **Lon** — **Enter** opens the digit-by-digit scroll editor (the same widget as the radio frequency field): **LEFT/RIGHT** move the cursor between decimal places, **UP/DOWN** change the digit under it, **Enter** confirms. With the editor closed, **LEFT/RIGHT** on the row toggles the hemisphere — N/S for latitude, E/W for longitude.
-- **Label** — **Enter** to type a name (blank → auto `WP`).
-- **Save** — validates the range and stores the waypoint. Missing or out-of-range values report a brief error.
-
-**On the map** — saved waypoints show as a hollow diamond with the label's first two characters beside it. Waypoints and your GPS position are drawn continuously, even with no trail recording, so the Map view doubles as a live "you + your marks" view. With **no trail**, it auto-fits to waypoints and position; **with a trail**, it frames the route instead, clamping any out-of-frame waypoint to the nearest edge so a distant mark can't blow up the scale.
-
-**Navigating** — **Hold Enter → Waypoints** opens the list (each row shows the label and live distance). The list always begins with a synthetic **Trail start** row whenever a trail exists, so you can backtrack to where you began without having marked it. Select a row and press **Enter** to open the navigation view:
-
-```
- CAMP ← target label
- 1.4 km ← distance to target
- To: 145° SE ← absolute bearing to the target
- Hdg: 090° E ← your current course over ground (-- when stationary)
-```
-
-| OLED | E-Ink |
-| :------------------------: | :------------------------: |
-|  |  |
-
-
-
-There is no magnetometer, so the screen shows two *absolute* bearings and you compare them: target at 145°, travelling at 90° → bear right. The **Hdg** line is derived from GPS movement (see Compass) and reads `--` until you move. A fourth line shows closing speed and **ETA** once you're actually approaching. **Back** leaves the view — it's the only key that does, on every navigate view.
-
-**Managing** — **Hold Enter** on a waypoint row offers **Rename** / **Delete** / **Send** / **Set as target** (the *Trail start* row is navigate-only). **Set as target** pins the waypoint as the active **Locator/Nav target** in one step (see **Locator**). Delete removes one at a time; there is no bulk clear.
-
-**Sharing** — **Send** hands the waypoint to the Messages screen: pick a contact or channel, and the message is pre-filled as `[WAY],