diff --git a/docs/work-items/ET-007/01-brd.md b/docs/work-items/ET-007/01-brd.md
new file mode 100644
index 0000000..235da43
--- /dev/null
+++ b/docs/work-items/ET-007/01-brd.md
@@ -0,0 +1,98 @@
+---
+type: brd
+work_item_id: ET-007
+title: "BRD: Спутниковая карта (Схема / Спутник)"
+version: 1
+status: draft
+created_at: 2026-05-31
+updated_at: 2026-05-31
+authors:
+ - "agent:analyst"
+---
+
+# BRD — ET-007: Спутниковая карта (Схема / Спутник)
+
+## 1. Цель
+
+Дать пользователю возможность одним кликом переключать подложку карты
+между «Схемой» (текущая OSM-схема) и «Спутник» (растровые снимки
+поверхности Земли). Спутниковая подложка помогает увидеть реальный
+рельеф и поверхность маршрута — лес/поле/брод/каменистый участок — до
+выезда.
+
+## 2. Контекст
+
+- Сейчас в приложении используется единственная подложка — OSM-растр,
+ стилизованный для «Схемы» в двух темах (`style.json`,
+ `style-dark.json`). Спутникового слоя нет.
+- В фазе PH-5 Redesign уже была введена тёмная/светлая тема — но
+ «тема» относится к стилизации (контрасты, насыщенность), а не к
+ природе подложки.
+- Эндуро-маршруты часто проходят вне дорог OSM (бездорожье, броды,
+ лесные участки). Спутник критичен для разведки.
+- Все клиентские модули (`app.js`, `units.js`, `gpx.js`) уже умеют
+ переживать `map.setStyle()` через `rebuildMapOverlays()` — это
+ опорная точка для будущей реализации.
+
+## 3. Scope
+
+### In scope
+
+| # | Функция |
+| ----- | ------------------------------------------------------------------------------------ |
+| F-01 | Переключатель «Схема / Спутник» в UI (segmented control) |
+| F-02 | Спутниковая подложка как новый raster-источник (бесплатный, без API-ключа) |
+| F-03 | В режиме «Спутник» — скрыта OSM-схема, показаны спутниковые тайлы |
+| F-04 | Все надстройки (грунтовки, тропы, POI, hillshade, TRI, маршрут, GPX) поверх спутника |
+| F-05 | Сохранение выбора в `localStorage` (ключ `map-base-layer`) |
+| F-06 | Восстановление выбора при загрузке страницы и при смене темы |
+| F-07 | Корректное отображение атрибуции спутниковых тайлов |
+| F-08 | Сохранение всех пользовательских слоёв (роутинг, GPX, recon) при переключении |
+
+### Out of scope
+
+- Кэширование спутниковых тайлов (offline / PWA — это PH-9).
+- Динамический выбор провайдера спутниковых тайлов в UI.
+- Гибридный режим «Спутник + подписи дорог OSM поверх».
+- Самостоятельный хостинг спутниковых тайлов (юридические/трафик-риски).
+- Изменение базовой карты для расчёта маршрутов (роутинг по-прежнему OSRM).
+- Авто-переключение Схема/Спутник в зависимости от зума.
+
+## 4. Метрики успеха
+
+| Метрика | Критерий |
+| ------------------------ | ------------------------------------------------------------------------------------- |
+| Время переключения | ≤ 500 мс от клика до первой видимой спутниковой плитки |
+| Сохранение состояния | Выбор подложки сохраняется после reload, смены темы, смены слоёв terrain |
+| Совместимость со слоями | Грунтовки, тропы, POI, маршрут OSRM, GPX-треки, hillshade, TRI видны и поверх спутника |
+| Совместимость с темой | Переключение тёмной/светлой темы не сбрасывает режим «Спутник» |
+| Атрибуция | На карте видна корректная атрибуция провайдера спутника |
+| Не ломает существующее | Все режимы (роутинг, разведка, красивый маршрут, GPX, линейка) работают как прежде |
+
+## 5. Риски
+
+| Риск | Вероятность | Влияние | Митигация |
+| ------------------------------------------------------------------------------------------------- | ----------- | ------- | -------------------------------------------------------------------------------------------------------------------------- |
+| Провайдер спутниковых тайлов закроет доступ / введёт лимит / потребует API-ключ | Средняя | Высокое | Зафиксировать конкретного провайдера в ADR; предусмотреть точку расширения для альтернативного провайдера (несколько URL) |
+| Спутниковая подложка медленно грузится → пользователь видит «дыры» | Высокая | Среднее | Использовать background-цвет (тёмно-серый) под спутником; OSM-схема остаётся как fallback в случае ошибки загрузки тайлов |
+| Цвет грунтовок и троп плохо виден на спутниковой подложке | Высокая | Среднее | TRZ: на режиме «Спутник» включается обводка (halo) у линий грунтовок и троп — по аналогии с подписями POI |
+| Hillshade поверх спутника даёт некрасивое наложение (двойное затенение рельефа) | Средняя | Низкое | По умолчанию hillshade отключается при включении спутника — поведение фиксируется в TRZ |
+| Юридические ограничения на использование стороннего провайдера спутниковых тайлов | Низкая | Высокое | В ADR указать выбранного провайдера с лицензией, разрешающей использование без API-ключа (Esri World Imagery, ArcGIS) |
+| Регресс UI на мобильных устройствах из-за нового переключателя | Низкая | Среднее | UI-тест-кейсы (04b) для desktop и mobile viewport |
+| Конфликт с уже сохранёнными localStorage-значениями старых версий | Низкая | Низкое | Использовать новый ключ `map-base-layer`, default = `schematic` |
+
+## 6. Зависимости
+
+- Только фронтенд — backend изменений не требуется.
+- MapLibre GL JS 4.7.0 (уже подключен).
+- Внешний провайдер спутниковых тайлов (выбор и фиксация — в ADR).
+- Сетевое подключение клиента к серверу провайдера.
+
+## 7. Связь с roadmap
+
+- Фаза PH-5 Redesign — тёмная тема и mobile UI уже сделаны; ET-007
+ встраивается в эту же панель «Рельеф / Слои» (одна точка управления
+ визуальными слоями карты).
+- Фаза PH-9 PWA — кэширование спутниковых тайлов оффлайн — будет
+ планироваться отдельно, ET-007 закладывает архитектурную основу
+ (источник тайлов, точка переключения).
diff --git a/docs/work-items/ET-007/02-trz.md b/docs/work-items/ET-007/02-trz.md
new file mode 100644
index 0000000..ea6eb40
--- /dev/null
+++ b/docs/work-items/ET-007/02-trz.md
@@ -0,0 +1,385 @@
+---
+type: trz
+work_item_id: ET-007
+title: "ТЗ: Спутниковая карта (Схема / Спутник)"
+version: 1
+status: draft
+created_at: 2026-05-31
+updated_at: 2026-05-31
+authors:
+ - "agent:analyst"
+---
+
+# ТЗ — ET-007: Спутниковая карта (Схема / Спутник)
+
+## 1. Функциональные требования
+
+### REQ-F-01: Переключатель «Схема / Спутник»
+
+- В попап-панели слоёв (`#terrain-popup`, открывается кнопкой
+ `#terrain-toggle`) добавляется новая секция в самом верху панели —
+ «Подложка».
+- Реализация — segmented-control (`.seg-control` / `.seg-btn`) с двумя
+ кнопками:
+ - «Схема» (`data-base="schematic"`, ID `base-btn-schematic`) —
+ активна по умолчанию.
+ - «Спутник» (`data-base="satellite"`, ID `base-btn-satellite`).
+- Активная кнопка визуально выделяется (`.active` — оранжевый фон, по
+ аналогии с переключателем единиц измерения, ET-005).
+- Обработчик: `onBaseLayerToggle(base)` в `src/web/app.js`.
+- Под переключателем — горизонтальная линия-разделитель (`
`),
+ как уже сделано между секциями попапа.
+
+### REQ-F-02: Спутниковый растровый источник
+
+- Используется растровый тайл-сервер Esri World Imagery (см. ADR в
+ `docs/work-items/ET-007/06-adr/`):
+ - URL-шаблон: `https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}`.
+ - `tileSize: 256`, `minzoom: 0`, `maxzoom: 19`.
+ - Атрибуция: «Source: Esri, Maxar, Earthstar Geographics, and the GIS User Community».
+- Источник добавляется на карту лениво: при первом включении режима
+ «Спутник», а не на старте приложения.
+- ID источника: `satellite-raster`.
+- ID слоя: `satellite-base`.
+
+### REQ-F-03: Поведение в режиме «Спутник»
+
+- При включении «Спутник»:
+ - Если ещё не добавлен — добавить source `satellite-raster` и layer
+ `satellite-base` сразу после слоя `background` (т.е. ниже всех
+ остальных слоёв).
+ - Слой `osm-base` (существующий) скрывается (`visibility: none`).
+ - Слой `background` остаётся (показывает «дыры» если тайлы ещё не
+ загрузились) — цвет фона `#2a2a2a` для тёмной темы и `#1a1a1a` для
+ светлой темы в режиме «Спутник» (чтобы белый фон не «бликовал» под
+ тёмными снимками).
+- При возврате на «Схема»:
+ - `osm-base` снова видим (`visibility: visible`).
+ - `satellite-base` скрывается (`visibility: none`), но не удаляется
+ из стиля (быстрое повторное переключение).
+
+### REQ-F-04: Совместимость со слоями приложения
+
+Все клиентские слои должны корректно отображаться поверх спутника:
+
+| Слой | Z-order над спутником | Доп. правила в режиме «Спутник» |
+| ----------------------------- | --------------------- | ------------------------------------------------------------------------------ |
+| Hillshade (`terrain-hillshade`) | поверх спутника | Включается/выключается чекбоксом как раньше; по умолчанию НЕ авто-выключается |
+| TRI (`terrain-tri`) | поверх спутника | Аналогично hillshade |
+| Trails (grade1..5) | поверх terrain | Линия получает halo (line-gap-width + полупрозрачная обводка) для контраста |
+| Paths/bridleway | поверх trails | Аналогично — halo для контраста |
+| POI circles | поверх trails | Обводка `circle-stroke-color: #ffffff`, толщина 2 px |
+| POI labels | поверх POI | `text-halo-color: #000000`, `text-halo-width: 2px` для читаемости на спутнике |
+| Route / Scenic / Link / Ruler | поверх POI | Без изменений |
+| GPX-треки и waypoints | поверх Route | Без изменений (ET-006 уже совместим) |
+
+Реализация:
+- Для halo у линий грунтовок/троп добавить отдельные «underlay»-слои с
+ более широкой полупрозрачной белой линией; включать их через
+ `visibility` только в режиме «Спутник».
+- Стили POI на спутнике задаются динамически через `setPaintProperty`
+ при переключении режима.
+
+### REQ-F-05: Сохранение состояния (localStorage)
+
+- Ключ: `map-base-layer`.
+- Значения: `"schematic"` (default) | `"satellite"`.
+- При `onBaseLayerToggle()` — запись.
+- При старте приложения — чтение и применение через
+ `restoreBaseLayerState()` (по аналогии с `restoreTerrainState()`).
+
+### REQ-F-06: Восстановление после смены стиля карты
+
+- При вызове `map.setStyle()` (переключение тёмной/светлой темы, см.
+ `switchMapStyle()` в `app.js`) спутниковый source/layer удаляются
+ вместе со стилем.
+- В функции `rebuildMapOverlays()` добавляется вызов
+ `restoreBaseLayerState()` — это пересоздаёт source/layer спутника и
+ выставляет видимость по сохранённому состоянию.
+- Порядок вызовов в `rebuildMapOverlays()`: `restoreBaseLayerState()`
+ вызывается **до** `restoreTerrainState()` — чтобы hillshade/TRI
+ оказались выше спутника, но ниже trails (тот же подход, что и для
+ schematic-режима).
+
+### REQ-F-07: Атрибуция
+
+- При создании source `satellite-raster` передаётся свойство
+ `attribution: "Source: Esri, Maxar, Earthstar Geographics, and the GIS User Community"`.
+- MapLibre автоматически отображает атрибуцию в правом нижнем углу
+ карты, когда соответствующий source активен.
+- Атрибуция OSM остаётся видимой в обоих режимах (vector-источник
+ `trails-tiles` всегда активен).
+
+### REQ-F-08: Fallback при ошибке загрузки тайлов
+
+- Если спутниковые тайлы не загружаются (network error / 4xx / 5xx),
+ MapLibre сам показывает прозрачную плитку — под ней видим `background`.
+- Логика fallback на схему не предусмотрена (пользователь сам
+ переключит, если нужно).
+
+## 2. Нефункциональные требования
+
+### REQ-NF-01: Производительность
+
+- Время переключения «Схема → Спутник» (до первой видимой спутниковой
+ плитки): ≤ 500 мс при скорости сети ≥ 5 Мбит/с.
+- Переключение обратно «Спутник → Схема» — мгновенное (источник
+ остаётся в стиле, меняется только visibility).
+- В момент переключения не должно быть «прыжков» камеры — `center`,
+ `zoom`, `bearing`, `pitch` сохраняются.
+
+### REQ-NF-02: Совместимость
+
+- Браузеры: Chrome 90+, Firefox 90+, Safari 15+.
+- Мобильные: iOS Safari 15+, Chrome для Android.
+- MapLibre GL JS 4.7.0 (уже подключен).
+
+### REQ-NF-03: UX
+
+- Текущая активная подложка визуально видна в UI всегда (в попапе
+ слоёв).
+- Переключение происходит без перезагрузки страницы и без потери
+ пользовательского состояния (маршрута, GPX, точек разведки).
+
+### REQ-NF-04: Хранение
+
+- localStorage ключ `map-base-layer`, размер ≤ 16 байт.
+- Никаких других данных приложение для этой фичи не хранит.
+
+### REQ-NF-05: Безопасность
+
+- Запросы к Esri World Imagery идут по HTTPS.
+- Никаких персональных данных пользователя в URL запросов не
+ передаётся.
+- Атрибуция выводится в соответствии с лицензией провайдера (см. ADR).
+
+## 3. UI-спецификация
+
+### 3.1 Изменения в `#terrain-popup`
+
+Сейчас:
+```
+┌────────────────────────────┐
+│ Эндуро │
+│ ☐ Тени рельефа │
+│ ☐ Перепады │
+│ ─────── │
+│ ☑ Грунтовки │
+│ ☑ Тропы │
+│ ─────── │
+│ ☑ POI │
+│ ─────── │
+│ Единицы [км][мили] │
+└────────────────────────────┘
+```
+
+После:
+```
+┌────────────────────────────┐
+│ Подложка [Схема][Спутник] │ ← новая секция
+│ ─────── │
+│ Эндуро │
+│ ☐ Тени рельефа │
+│ ☐ Перепады │
+│ ─────── │
+│ ☑ Грунтовки │
+│ ☑ Тропы │
+│ ─────── │
+│ ☑ POI │
+│ ─────── │
+│ Единицы [км][мили] │
+└────────────────────────────┘
+```
+
+### 3.2 Разметка HTML
+
+В `src/web/index.html`, в начале `#terrain-popup` (сразу после
+`
Эндуро
` ИЛИ выше него — по
+выбору разработчика; рекомендуется в самом верху для большей
+заметности):
+
+```html
+
+
+ Подложка
+
+
+
+
+
+
+```
+
+### 3.3 CSS
+
+В `src/web/app.css` — добавить стили (по аналогии с `.terrain-unit-row`):
+
+```css
+.terrain-base-row {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 4px 0;
+}
+.terrain-base-label {
+ font-size: 12px;
+ color: var(--text2);
+ flex-shrink: 0;
+}
+.terrain-base-row .seg-control {
+ flex: 1;
+ margin-bottom: 0;
+}
+.base-seg .seg-btn {
+ font-size: 12px;
+}
+```
+
+### 3.4 Поведение на мобильных устройствах
+
+- Попап `#terrain-popup` уже адаптирован под мобильные (ET-005). Новая
+ строка не должна нарушать ширину попапа.
+- Высота кнопок `.seg-btn` остаётся 34px (как у переключателя единиц).
+
+## 4. Данные
+
+### 4.1 Спутниковый источник (MapLibre source spec)
+
+```js
+{
+ type: 'raster',
+ tiles: [
+ 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
+ ],
+ tileSize: 256,
+ minzoom: 0,
+ maxzoom: 19,
+ attribution: 'Source: Esri, Maxar, Earthstar Geographics, and the GIS User Community'
+}
+```
+
+### 4.2 Спутниковый слой (MapLibre layer spec)
+
+```js
+{
+ id: 'satellite-base',
+ type: 'raster',
+ source: 'satellite-raster',
+ paint: {
+ 'raster-opacity': 1.0,
+ 'raster-resampling': 'linear'
+ },
+ layout: { visibility: 'none' } // включается при переключении
+}
+```
+
+Вставляется в стиль сразу после слоя `background`.
+
+### 4.3 localStorage
+
+| Ключ | Значения | Default |
+| ----------------- | ------------------------------ | ------------- |
+| `map-base-layer` | `"schematic"` \| `"satellite"` | `"schematic"` |
+
+## 5. Алгоритмы
+
+### 5.1 `onBaseLayerToggle(base)`
+
+```
+1. Если base === текущий — return.
+2. Сохранить в localStorage('map-base-layer', base).
+3. Применить applyBaseLayer(base).
+4. syncBaseLayerUI(base).
+```
+
+### 5.2 `applyBaseLayer(base)`
+
+```
+1. map = window._map; если нет — return.
+2. Если base === 'satellite':
+ 2.1. Если source 'satellite-raster' отсутствует — addSource (см. 4.1).
+ 2.2. Если layer 'satellite-base' отсутствует — addLayer (см. 4.2),
+ вставлять beforeId = id первого слоя trails-* или terrain-*
+ (первый из существующих) — чтобы спутник оказался под terrain
+ и trails.
+ 2.3. setLayoutProperty('satellite-base', 'visibility', 'visible').
+ 2.4. setLayoutProperty('osm-base', 'visibility', 'none').
+ 2.5. Применить «спутниковые» правки к слоям trails/path/poi:
+ - усилить halo у line-слоёв (через setPaintProperty);
+ - сделать POI text-halo чёрным.
+ 2.6. Сменить background-color на тёмно-серый (#2a2a2a).
+3. Иначе (base === 'schematic'):
+ 3.1. setLayoutProperty('osm-base', 'visibility', 'visible').
+ 3.2. setLayoutProperty('satellite-base', 'visibility', 'none')
+ (если слой существует).
+ 3.3. Вернуть halo trails / POI к дефолтным значениям из текущего стиля.
+ 3.4. Background-color — из исходного стиля (не трогать,
+ он восстанавливается при setStyle).
+```
+
+### 5.3 `restoreBaseLayerState()`
+
+```
+1. base = localStorage.getItem('map-base-layer') || 'schematic'.
+2. syncBaseLayerUI(base).
+3. applyBaseLayer(base).
+```
+
+### 5.4 `syncBaseLayerUI(base)`
+
+```
+1. schematicBtn.classList.toggle('active', base === 'schematic').
+2. satelliteBtn.classList.toggle('active', base === 'satellite').
+```
+
+### 5.5 Интеграция с `rebuildMapOverlays()` (`app.js`)
+
+В существующей функции (см. `app.js`, ~строка 127) добавить вызов
+**первым**:
+
+```js
+function rebuildMapOverlays() {
+ // ET-007: восстановить выбранную подложку первой —
+ // чтобы terrain/trails/POI применили свои overlays поверх неё
+ if (typeof restoreBaseLayerState === 'function') {
+ restoreBaseLayerState();
+ }
+ // ── далее без изменений ──
+ restoreTerrainState();
+ restoreTrailsState();
+ // ...
+}
+```
+
+## 6. Файловая структура изменений
+
+```
+src/web/
+├── index.html # + блок переключателя в #terrain-popup
+├── app.css # + стили .terrain-base-row, .base-seg
+├── app.js # + onBaseLayerToggle, applyBaseLayer,
+ # restoreBaseLayerState, syncBaseLayerUI,
+ # правка rebuildMapOverlays
+```
+
+Backend изменений нет.
+
+## 7. Взаимодействие с существующими режимами
+
+- Все режимы тулбара (Маршрут, Связка, Красивый, Разведка, Линейка,
+ Поиск, Метка, GPX) работают независимо от выбранной подложки.
+- Переключение подложки **не сбрасывает** состояние режимов: маршруты,
+ GPX-треки, точки разведки, линейка, метки — остаются.
+- Переключение темы (тёмная/светлая) **не сбрасывает** выбор подложки.
+- При вызове `map.setStyle()` (тема, восстановление стиля)
+ спутниковый слой пересоздаётся в `rebuildMapOverlays()`.
+
+## 8. Открытые вопросы для ADR
+
+- Выбор провайдера спутниковых тайлов (Esri / Mapbox / Bing / OpenAerialMap).
+- Решение по halo для POI/trails на спутнике: статические правки в
+ `style.json` через `visibility` или динамические `setPaintProperty`.
+- Поведение hillshade при включении спутника: оставить как есть (по
+ выбору пользователя) — зафиксировано в REQ-F-04 как «оставить».
diff --git a/docs/work-items/ET-007/03-acceptance-criteria.md b/docs/work-items/ET-007/03-acceptance-criteria.md
new file mode 100644
index 0000000..cece277
--- /dev/null
+++ b/docs/work-items/ET-007/03-acceptance-criteria.md
@@ -0,0 +1,207 @@
+---
+type: acceptance-criteria
+work_item_id: ET-007
+title: "AC: Спутниковая карта (Схема / Спутник)"
+version: 1
+status: draft
+created_at: 2026-05-31
+updated_at: 2026-05-31
+authors:
+ - "agent:analyst"
+---
+
+# Acceptance Criteria — ET-007: Спутниковая карта (Схема / Спутник)
+
+## AC-01: UI переключателя
+
+```gherkin
+Feature: Переключатель подложки в попапе слоёв
+
+ Scenario: Открытие попапа показывает переключатель
+ Given пользователь находится на карте
+ When пользователь нажимает кнопку «Рельеф» (#terrain-toggle)
+ Then открывается попап #terrain-popup
+ And в попапе виден segmented-control «Подложка» с кнопками «Схема» и «Спутник»
+ And одна из кнопок имеет класс .active
+
+ Scenario: Default — Схема
+ Given localStorage пуст (или ключ 'map-base-layer' не задан)
+ When пользователь открывает попап слоёв
+ Then активна кнопка «Схема» (#base-btn-schematic)
+ And не активна кнопка «Спутник» (#base-btn-satellite)
+```
+
+## AC-02: Переключение на «Спутник»
+
+```gherkin
+Feature: Переключение Схема → Спутник
+
+ Scenario: Базовое переключение
+ Given активна подложка «Схема»
+ When пользователь нажимает «Спутник» в попапе слоёв
+ Then кнопка «Спутник» получает класс .active
+ And кнопка «Схема» теряет класс .active
+ And на карте слой osm-base скрыт (visibility=none)
+ And на карте появляется слой satellite-base (visibility=visible)
+ And положение карты (center, zoom, bearing, pitch) не изменилось
+
+ Scenario: Атрибуция Esri отображается
+ Given пользователь включил режим «Спутник»
+ Then в нижнем правом углу карты видна атрибуция «Source: Esri, Maxar, Earthstar Geographics, and the GIS User Community»
+```
+
+## AC-03: Переключение на «Схема»
+
+```gherkin
+Feature: Переключение Спутник → Схема
+
+ Scenario: Возврат на схему
+ Given активна подложка «Спутник»
+ When пользователь нажимает «Схема» в попапе слоёв
+ Then кнопка «Схема» получает класс .active
+ And слой osm-base снова виден (visibility=visible)
+ And слой satellite-base скрыт (visibility=none), но source остаётся в стиле
+ And положение карты не изменилось
+```
+
+## AC-04: Совместимость со слоями приложения
+
+```gherkin
+Feature: Слои поверх спутника
+
+ Scenario: Грунтовки и тропы видны на спутнике
+ Given активна подложка «Спутник»
+ And в попапе включены «Грунтовки» и «Тропы»
+ Then на карте видны линии грунтовок и троп поверх спутника
+ And линии имеют визуально различимую обводку (halo) для контраста
+
+ Scenario: POI видны на спутнике
+ Given активна подложка «Спутник»
+ And в попапе включён «POI»
+ Then на карте видны маркеры POI поверх спутника
+ And подписи POI читаемы (имеют тёмный halo)
+
+ Scenario: Hillshade поверх спутника
+ Given активна подложка «Спутник»
+ When пользователь включает «Тени рельефа»
+ Then на карте видны и спутник, и hillshade (hillshade поверх спутника)
+
+ Scenario: Маршрут OSRM поверх спутника
+ Given пользователь построил маршрут через OSRM
+ When пользователь переключает подложку на «Спутник»
+ Then маршрут остаётся виден поверх спутника
+ And статистика маршрута сохранена
+
+ Scenario: GPX-треки поверх спутника
+ Given пользователь загрузил GPX-трек
+ When пользователь переключает подложку на «Спутник»
+ Then GPX-линии и waypoints остаются видны поверх спутника
+```
+
+## AC-05: Сохранение в localStorage
+
+```gherkin
+Feature: Persistence выбора подложки
+
+ Scenario: Сохранение при переключении
+ Given активна подложка «Схема»
+ When пользователь нажимает «Спутник»
+ Then localStorage['map-base-layer'] === 'satellite'
+
+ Scenario: Восстановление после reload
+ Given localStorage['map-base-layer'] === 'satellite'
+ When пользователь перезагружает страницу
+ Then после загрузки карты активна подложка «Спутник»
+ And кнопка «Спутник» имеет класс .active
+```
+
+## AC-06: Восстановление при смене темы
+
+```gherkin
+Feature: Подложка переживает смену темы
+
+ Scenario: Переключение тёмной/светлой темы в режиме «Спутник»
+ Given активна подложка «Спутник»
+ When пользователь переключает тему (тёмная ↔ светлая)
+ Then после завершения map.setStyle() спутниковый слой восстановлен
+ And подложка «Спутник» остаётся активной
+ And все слои поверх (trails, POI, маршрут, GPX) восстановлены
+
+ Scenario: Переключение слоёв terrain в режиме «Спутник»
+ Given активна подложка «Спутник»
+ When пользователь включает или выключает «Тени рельефа» / «Перепады»
+ Then подложка «Спутник» остаётся активной
+```
+
+## AC-07: Совместимость с режимами тулбара
+
+```gherkin
+Feature: Подложка не мешает другим режимам
+
+ Scenario: Режим «Маршрут» на спутнике
+ Given активна подложка «Спутник»
+ When пользователь активирует режим «Маршрут»
+ And тапает 2 точки на карте
+ Then маршрут строится корректно
+ And линия маршрута видна на спутнике
+
+ Scenario: Режим «Разведка» на спутнике
+ Given активна подложка «Спутник»
+ When пользователь активирует режим «Разведка» и тапает на карту
+ Then круг радиуса разведки видим
+ And статистика разведки отображается
+
+ Scenario: Линейка на спутнике
+ Given активна подложка «Спутник»
+ When пользователь активирует «Линейка» и расставляет точки
+ Then линия линейки видна
+ And расстояние отображается
+
+ Scenario: Поиск на спутнике
+ Given активна подложка «Спутник»
+ When пользователь нажимает «Поиск» и вводит запрос
+ Then результаты поиска отображаются
+ And карта корректно центрируется на найденной точке
+```
+
+## AC-08: Производительность
+
+```gherkin
+Feature: Скорость переключения
+
+ Scenario: Переключение Схема → Спутник
+ Given активна подложка «Схема» и сеть ≥ 5 Мбит/с
+ When пользователь нажимает «Спутник»
+ Then первая спутниковая плитка отображается в течение ≤ 500 мс
+
+ Scenario: Переключение Спутник → Схема
+ Given активна подложка «Спутник» (тайлы уже подгружены)
+ When пользователь нажимает «Схема»
+ Then смена визуально мгновенная (≤ 100 мс)
+```
+
+## AC-09: Mobile UI
+
+```gherkin
+Feature: Переключатель на мобильных устройствах
+
+ Scenario: Попап слоёв на мобильном
+ Given пользователь открыл приложение на мобильном устройстве (виртуальный viewport 375×812)
+ When пользователь открывает попап слоёв
+ Then переключатель «Подложка» виден полностью
+ And обе кнопки нажимаемы (touch target ≥ 34px)
+ And не перекрывает другие элементы попапа
+```
+
+## AC-10: Не ломает существующий функционал
+
+```gherkin
+Feature: Регресс-проверка
+
+ Scenario: Все режимы работают как в режиме «Схема», так и в «Спутник»
+ Given пользователь использует приложение
+ Then режимы Маршрут, Связка, Красивый, Разведка, Линейка, Поиск, Метка, GPX
+ работают одинаково в обеих подложках
+ And переключение единиц измерения (км/мили) работает в обеих подложках
+ And переключение темы работает в обеих подложках
+```
diff --git a/docs/work-items/ET-007/04-test-plan.yaml b/docs/work-items/ET-007/04-test-plan.yaml
new file mode 100644
index 0000000..a5ef729
--- /dev/null
+++ b/docs/work-items/ET-007/04-test-plan.yaml
@@ -0,0 +1,231 @@
+---
+type: test-plan
+work_item_id: ET-007
+title: "Test Plan: Спутниковая карта (Схема / Спутник)"
+version: 1
+status: draft
+created_at: 2026-05-31
+updated_at: 2026-05-31
+authors:
+ - "agent:analyst"
+
+test_suites:
+
+ - name: unit-base-layer-state
+ type: unit
+ description: "Чтение/запись/восстановление выбора подложки"
+ cases:
+ - id: U-01
+ name: "Default — Схема, если localStorage пуст"
+ input: "localStorage без ключа 'map-base-layer'"
+ expected: "restoreBaseLayerState() выставляет base='schematic'"
+
+ - id: U-02
+ name: "Чтение значения 'satellite' из localStorage"
+ input: "localStorage['map-base-layer'] = 'satellite'"
+ expected: "restoreBaseLayerState() выставляет base='satellite'"
+
+ - id: U-03
+ name: "Запись значения при переключении"
+ input: "onBaseLayerToggle('satellite')"
+ expected: "localStorage['map-base-layer'] === 'satellite'"
+
+ - id: U-04
+ name: "Игнор некорректного значения в localStorage"
+ input: "localStorage['map-base-layer'] = 'unknown'"
+ expected: "restoreBaseLayerState() fallback на 'schematic'"
+
+ - id: U-05
+ name: "Toggle на уже активный режим — no-op"
+ input: "active=schematic; onBaseLayerToggle('schematic')"
+ expected: "Никаких изменений в стиле, localStorage не записывается повторно"
+
+ - name: unit-ui-sync
+ type: unit
+ description: "Синхронизация .active у кнопок переключателя"
+ cases:
+ - id: U-10
+ name: "syncBaseLayerUI('satellite')"
+ input: "DOM с #base-btn-schematic.active и #base-btn-satellite без класса"
+ expected: "После: #base-btn-satellite.active=true, #base-btn-schematic.active=false"
+
+ - id: U-11
+ name: "syncBaseLayerUI('schematic')"
+ input: "DOM с #base-btn-satellite.active"
+ expected: "После: #base-btn-schematic.active=true, #base-btn-satellite.active=false"
+
+ - name: integration-maplibre-layers
+ type: integration
+ description: "Взаимодействие с MapLibre source/layer"
+ cases:
+ - id: I-01
+ name: "Добавление спутникового source при первом включении"
+ input: "applyBaseLayer('satellite') впервые"
+ expected: "map.getSource('satellite-raster') !== undefined; URL содержит arcgisonline.com"
+
+ - id: I-02
+ name: "Добавление спутникового layer при первом включении"
+ input: "applyBaseLayer('satellite') впервые"
+ expected: "map.getLayer('satellite-base') !== undefined; type='raster'"
+
+ - id: I-03
+ name: "Visibility OSM-base после переключения на спутник"
+ input: "applyBaseLayer('satellite')"
+ expected: "map.getLayoutProperty('osm-base', 'visibility') === 'none'"
+
+ - id: I-04
+ name: "Visibility satellite-base после переключения на схему"
+ input: "applyBaseLayer('satellite') → applyBaseLayer('schematic')"
+ expected: "satellite-base.visibility==='none', osm-base.visibility==='visible'"
+
+ - id: I-05
+ name: "Z-order: satellite ниже terrain и trails"
+ input: "applyBaseLayer('satellite'); включены hillshade и trails"
+ expected: "Layer index(satellite-base) < index(terrain-hillshade) < index(trails-track)"
+
+ - id: I-06
+ name: "Position карты сохраняется при переключении"
+ input: "center=[37.6,55.75], zoom=10; applyBaseLayer('satellite')"
+ expected: "После: getCenter() == [37.6,55.75], getZoom() == 10"
+
+ - id: I-07
+ name: "Атрибуция Esri зарегистрирована"
+ input: "applyBaseLayer('satellite')"
+ expected: "source 'satellite-raster' содержит attribution с упоминанием Esri"
+
+ - name: integration-style-switch
+ type: integration
+ description: "Поведение при map.setStyle (смена темы)"
+ cases:
+ - id: I-10
+ name: "Спутник восстанавливается после setStyle (тёмная → светлая)"
+ input: "active='satellite'; вызывается switchMapStyle()"
+ expected: "После idle: layer 'satellite-base' существует; visibility='visible'; osm-base.visibility='none'"
+
+ - id: I-11
+ name: "Сохранённое состояние читается из localStorage в rebuildMapOverlays"
+ input: "localStorage='satellite'; rebuildMapOverlays() вручную"
+ expected: "applyBaseLayer вызван с 'satellite'"
+
+ - id: I-12
+ name: "Восстановление выполняется до restoreTerrainState"
+ input: "rebuildMapOverlays() с заглушками-shpions"
+ expected: "Порядок вызовов: restoreBaseLayerState → restoreTerrainState"
+
+ - name: integration-other-layers
+ type: integration
+ description: "Совместимость со всеми клиентскими слоями"
+ cases:
+ - id: I-20
+ name: "Маршрут OSRM не теряется при переключении"
+ input: "Построен маршрут; applyBaseLayer('satellite')"
+ expected: "Layer маршрута существует, координаты не изменились"
+
+ - id: I-21
+ name: "GPX-трек не теряется при переключении"
+ input: "Загружен GPX; applyBaseLayer('satellite')"
+ expected: "Layer gpx-* существует, source.data не изменён"
+
+ - id: I-22
+ name: "Recon-круг не теряется при переключении"
+ input: "Активен recon; applyBaseLayer('satellite')"
+ expected: "Recon-круг отображается на карте"
+
+ - id: I-23
+ name: "Hillshade поверх спутника"
+ input: "applyBaseLayer('satellite'); включить hillshade"
+ expected: "Оба слоя видимы; hillshade выше satellite-base в стиле"
+
+ - id: I-24
+ name: "POI halo чёрный на спутнике"
+ input: "applyBaseLayer('satellite')"
+ expected: "map.getPaintProperty('poi-labels','text-halo-color') === '#000000' (или эквивалент)"
+
+ - id: I-25
+ name: "POI halo дефолтный на схеме"
+ input: "applyBaseLayer('schematic') после спутника"
+ expected: "POI labels вернули halo цвет схемы (#ffffff)"
+
+ - name: e2e-base-layer-workflow
+ type: e2e
+ description: "Полный пользовательский сценарий"
+ cases:
+ - id: E-01
+ name: "Открыть попап → включить спутник → сохранилось"
+ steps:
+ - "Открыть приложение (default — Схема)"
+ - "Нажать кнопку «Рельеф» в правой панели"
+ - "Убедиться: переключатель «Подложка» виден"
+ - "Нажать «Спутник»"
+ - "Убедиться: спутниковые тайлы загрузились"
+ - "Убедиться: атрибуция Esri видна"
+ - "Перезагрузить страницу"
+ - "Убедиться: после загрузки активен «Спутник»"
+
+ - id: E-02
+ name: "Переключение туда-обратно без потери маршрута"
+ steps:
+ - "Построить маршрут через OSRM (2 точки)"
+ - "Переключить на «Спутник»"
+ - "Убедиться: маршрут виден на спутнике, статистика сохранена"
+ - "Переключить на «Схема»"
+ - "Убедиться: маршрут виден на схеме, статистика та же"
+
+ - id: E-03
+ name: "Спутник + загрузка GPX"
+ steps:
+ - "Переключить на «Спутник»"
+ - "Загрузить GPX-файл"
+ - "Убедиться: трек отрисован поверх спутника"
+ - "Убедиться: цвет трека различим"
+
+ - id: E-04
+ name: "Спутник + смена темы"
+ steps:
+ - "Переключить на «Спутник»"
+ - "Переключить тёмную тему на светлую"
+ - "Дождаться idle"
+ - "Убедиться: подложка осталась «Спутник»"
+ - "Убедиться: все остальные слои восстановились"
+
+ - id: E-05
+ name: "Спутник + переключение единиц измерения"
+ steps:
+ - "Переключить на «Спутник»"
+ - "Открыть попап слоёв и переключить «мили»"
+ - "Убедиться: единицы переключились, подложка не сбросилась"
+
+ - id: E-06
+ name: "Спутник + hillshade"
+ steps:
+ - "Переключить на «Спутник»"
+ - "Включить «Тени рельефа»"
+ - "Убедиться: видны спутник и тени одновременно"
+
+ - id: E-07
+ name: "Линейка на спутнике"
+ steps:
+ - "Переключить на «Спутник»"
+ - "Активировать линейку"
+ - "Поставить 3 точки на карте"
+ - "Убедиться: линия линейки видна на спутнике"
+ - "Убедиться: расстояния отображаются"
+
+ - name: e2e-error-handling
+ type: e2e
+ description: "Поведение при сетевых ошибках"
+ cases:
+ - id: E-10
+ name: "Спутниковые тайлы недоступны (offline)"
+ steps:
+ - "Включить «Спутник»"
+ - "Симулировать offline (DevTools throttling: Offline)"
+ - "Сдвинуть карту в новую область"
+ - "Убедиться: приложение не падает; видим фон background"
+ - "Восстановить сеть → тайлы догружаются"
+
+test_data:
+ - name: "test-track-simple.gpx"
+ description: "1 трек, 10 точек — для проверки совместимости с GPX"
+ - name: "Тестовый OSRM-маршрут"
+ description: "2 waypoint в районе [37.6,55.75] → [37.7,55.8]"
diff --git a/docs/work-items/ET-007/04b-ui-test-cases.md b/docs/work-items/ET-007/04b-ui-test-cases.md
new file mode 100644
index 0000000..497f857
--- /dev/null
+++ b/docs/work-items/ET-007/04b-ui-test-cases.md
@@ -0,0 +1,274 @@
+---
+type: ui-test-cases
+work_item_id: ET-007
+title: "UI Test Cases: Спутниковая карта (Схема / Спутник)"
+version: 1
+status: draft
+created_at: 2026-05-31
+updated_at: 2026-05-31
+authors:
+ - "agent:analyst"
+---
+
+# UI Test Cases — ET-007: Спутниковая карта (Схема / Спутник)
+
+Базовый URL: `https://openclaw.mva154.duckdns.org/enduro/`
+
+Все тесты проверяют появление и поведение переключателя «Подложка» в
+попапе слоёв, а также корректное отображение спутниковой подложки
+поверх существующих UI-элементов.
+
+---
+
+### TC-UI-01 — Переключатель «Подложка» виден в попапе
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. screenshot: "01-popup-with-base-toggle"
+6. check-visual: "В открывшемся попапе #terrain-popup видна строка «Подложка» с двумя кнопками: «Схема» (активна, оранжевый фон) и «Спутник» (неактивна)"
+
+---
+
+### TC-UI-02 — Активация «Спутник» меняет подложку
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. screenshot: "02-satellite-active"
+8. check-visual: "Карта показывает спутниковые снимки (зелёные/коричневые поля, реальный рельеф). В попапе кнопка «Спутник» подсвечена оранжевым, «Схема» — нет"
+
+---
+
+### TC-UI-03 — Атрибуция Esri видна
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. click: "#terrain-toggle"
+8. wait: 500
+9. screenshot: "03-attribution-esri"
+10. check-visual: "В правом нижнем углу карты видна атрибуция со словом «Esri» (или иконка info, при клике на которую разворачивается полный текст)"
+
+---
+
+### TC-UI-04 — Возврат на «Схема»
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. click: "#base-btn-schematic"
+8. wait: 2000
+9. screenshot: "04-schematic-restored"
+10. check-visual: "Карта снова показывает схему OSM (бежевый/серый фон, дороги). В попапе кнопка «Схема» подсвечена оранжевым"
+
+---
+
+### TC-UI-05 — Грунтовки и тропы видны на спутнике
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. screenshot: "05-trails-on-satellite"
+8. check-visual: "На спутниковой подложке отчётливо видны линии грунтовок (золотые/красные) и троп (красные пунктирные). Линии имеют светлую обводку (halo) для контраста с тёмным спутником"
+
+---
+
+### TC-UI-06 — POI и подписи на спутнике читаемы
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. screenshot: "06-poi-on-satellite"
+8. check-visual: "POI-маркеры (цветные кружки) видны на спутнике. Подписи POI имеют тёмный halo, читаемы на любом фоне"
+
+---
+
+### TC-UI-07 — Спутник переживает смену темы
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. click: "#btn-theme"
+8. wait: 3000
+9. screenshot: "07-satellite-after-theme-switch"
+10. check-visual: "После переключения темы карта по-прежнему показывает спутниковую подложку (а не схему)"
+
+---
+
+### TC-UI-08 — Hillshade поверх спутника
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. click: "#terrain-hillshade-cb"
+8. wait: 3000
+9. screenshot: "08-hillshade-on-satellite"
+10. check-visual: "Виден спутник + затенение рельефа поверх (тёмные тени по склонам, рельеф «выпуклый»). Слои не перекрывают друг друга полностью"
+
+---
+
+### TC-UI-09 — Маршрут OSRM на спутнике
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#tb-route"
+4. wait: 1000
+5. click: "#map"
+6. wait: 2000
+7. scroll: 100
+8. click: "#map"
+9. wait: 5000
+10. click: "#terrain-toggle"
+11. wait: 500
+12. click: "#base-btn-satellite"
+13. wait: 5000
+14. screenshot: "09-route-on-satellite"
+15. check-visual: "Маршрут (синяя/оранжевая линия) виден поверх спутниковой подложки, конечные точки маршрута отмечены маркерами"
+
+---
+
+### TC-UI-10 — Переключатель на мобильном
+
+- тип: ui
+- viewport: mobile
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. screenshot: "10-popup-mobile"
+6. check-visual: "На мобильном viewport попап #terrain-popup помещается на экране целиком. Переключатель «Подложка» виден, обе кнопки нажимаемы, не перекрывают другие элементы попапа"
+
+---
+
+### TC-UI-11 — Активация «Спутник» на мобильном
+
+- тип: ui
+- viewport: mobile
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. screenshot: "11-satellite-mobile"
+8. check-visual: "Спутниковая подложка отображается на мобильном устройстве. Тулбар внизу и попап работают корректно, переключатель «Спутник» подсвечен"
+
+---
+
+### TC-UI-12 — Persistence: спутник после перезагрузки
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. navigate: https://openclaw.mva154.duckdns.org/enduro/
+8. wait: 5000
+9. screenshot: "12-satellite-after-reload"
+10. check-visual: "После перезагрузки карта сразу открывается со спутниковой подложкой (не со схемой). Активный режим — «Спутник»"
+
+---
+
+### TC-UI-13 — GPX-панель + Спутник
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. click: "#tb-gpx"
+8. wait: 1000
+9. screenshot: "13-gpx-sheet-on-satellite"
+10. check-visual: "Открылась панель #sheet-gpx с пустым состоянием поверх спутниковой карты. Панель и подложка визуально не конфликтуют"
+
+---
+
+### TC-UI-14 — Совместимость с переключателем единиц
+
+- тип: ui
+- viewport: desktop
+
+шаги:
+1. navigate: https://openclaw.mva154.duckdns.org/enduro/
+2. wait: 5000
+3. click: "#terrain-toggle"
+4. wait: 500
+5. click: "#base-btn-satellite"
+6. wait: 5000
+7. click: "#unit-btn-mi"
+8. wait: 1000
+9. screenshot: "14-satellite-with-miles"
+10. check-visual: "Подложка остаётся «Спутник», единицы переключены на мили (кнопка «мили» подсвечена). Оба переключателя видны и работают независимо"