# Navigation

## App Flow

The app follows this general flow:

```
Launch → Scanner Screen → [Connect via BLE/USB/TCP] → Channels Screen
```

After connecting, the three main screens (Contacts, Channels, Map) are accessible via a persistent bottom navigation bar called the **QuickSwitchBar**.

## Quick Switch Bar

The QuickSwitchBar is a Material 3 `NavigationBar` with a frosted-glass visual treatment (blur backdrop, transparent theme, rounded corners). It appears at the bottom of all three main screens.

| Index | Icon | Label | Screen |
|---|---|---|---|
| 0 | People | Contacts | ContactsScreen |
| 1 | Tag | Channels | ChannelsScreen |
| 2 | Map | Map | MapScreen |

Tapping a tab replaces the current screen with a subtle fade + slight horizontal nudge transition (220ms forward, 200ms reverse). The back button is suppressed on all three main screens — navigation between them is flat, not stacked. All icons use outline variants (`people_outline`, `tag`, `map_outlined`) following Material 3 conventions.

## Disconnection

- The disconnect button (available in the overflow menu of each main screen) shows a confirmation dialog before disconnecting
- If the device disconnects unexpectedly, the app automatically navigates back to the Scanner screen (fires after the current frame completes via a post-frame callback)
- This auto-navigation behavior (`DisconnectNavigationMixin`) is shared across all main screens

## Theme and Locale

- **Theme mode** is user-configurable in App Settings (System / Light / Dark) — not locked to system
- **Language** can be overridden to one of 18 supported languages, or follow the system locale
- On web, if a non-Chromium browser is detected, the app shows a `ChromeRequiredScreen` instead of the Scanner (Web Bluetooth requires Chromium)

## Full Navigation Graph

```
ScannerScreen (root, always on stack)
  ├─ [BLE connect] → push → ChannelsScreen
  ├─ [TCP icon button] → push → TcpScreen
  │     └─ [TCP connected] → pushReplacement → ChannelsScreen
  └─ [USB icon button] → push → UsbScreen
        └─ [USB connected] → pushReplacement → ChannelsScreen

ContactsScreen (selected=0)
  ├─ [quick-switch 1] → pushReplacement → ChannelsScreen
  ├─ [quick-switch 2] → pushReplacement → MapScreen
  ├─ [tap contact] → push → ChatScreen
  ├─ [overflow > Settings] → push → SettingsScreen
  └─ [overflow > Discovered] → push → DiscoveryScreen

ChannelsScreen (selected=1)
  ├─ [quick-switch 0] → pushReplacement → ContactsScreen
  ├─ [quick-switch 2] → pushReplacement → MapScreen
  ├─ [tap channel] → push → ChannelChatScreen
  └─ [overflow > Settings] → push → SettingsScreen

MapScreen (selected=2)
  ├─ [quick-switch 0] → pushReplacement → ContactsScreen
  ├─ [quick-switch 1] → pushReplacement → ChannelsScreen
  ├─ [radar menu item] → enters in-map path trace mode (push → PathTraceMapScreen after path is built)
  ├─ [terrain menu item] → push → LineOfSightMapScreen
  └─ [long-press] → share marker sheet

Settings (push from any main screen)
  └─ [App Settings] → push → AppSettingsScreen
        └─ [Offline Map Cache] → push → MapCacheScreen
```

Any disconnection from any screen triggers `popUntil(route.isFirst)`, returning to the Scanner.
