# ТРЗ — ET-014: Z-index конфликт terrain-popup vs sheet-gps-filters

**Work Item:** ET-014
**Связан с BRD:** 01-brd.md
**Тип задачи:** Bug-fix (UI / стили / DOM-stacking)

---

## 1. Анализ текущего состояния

### 1.1 DOM-структура (как есть)

- `#terrain-popup` (`src/web/index.html:43`) — `position: fixed`, `z-index: 500`
  (`src/web/app.css:785-795`). Открывается по клику на кнопку «Рельеф»
  (`#terrain-toggle` в `#map-controls-r`). Содержит чекбоксы слоёв,
  переключатели подложки и единиц, а также кнопку-ссылку
  `#public-tracks-filters-btn` с текстом «Фильтры…».
- `#sheet-gps-filters` (`src/web/index.html:478`) — класс `.bottom-sheet`,
  `position: fixed`, `z-index: 400` (`src/web/app.css:183-196`). Открывается
  через `togglePublicTracksFiltersSheet()` в `src/web/gps_tracks.js:737`,
  который вызывает `openSheet('sheet-gps-filters')`.
- `#sheet-backdrop` (`src/web/index.html:19`) — `z-index: 390`
  (`src/web/app.css:222-228`). На mobile перекрывает экран при открытом
  sheet'е; на desktop скрыт (`#sheet-backdrop { display: none; }` в
  media-query, `src/web/app.css:543`).

### 1.2 Стек z-index в проекте (для ориентира)

| Элемент           | z-index | Файл/строка             |
|-------------------|---------|-------------------------|
| `#map`            | 0       | app.css:68              |
| `#no-data-warning`| 200     | app.css:410             |
| `#sheet-backdrop` | 390     | app.css:225             |
| `.bottom-sheet`   | 400     | app.css:188             |
| `#map-controls-r` | 400     | app.css:129             |
| `.terrain-popup`  | **500** | app.css:787             |
| `#marker-dialog`  | 500     | app.css:399             |
| `#search-panel`   | 600     | app.css:1101            |
| `#ruler-info`     | 600     | app.css:1122            |

### 1.3 Корень проблемы

1. `togglePublicTracksFiltersSheet()` открывает sheet (z=400), но **не
   закрывает** `#terrain-popup` (z=500). Popup остаётся на экране и
   визуально/event-but перекрывает sheet.
2. Клик по ссылке «Фильтры…» внутри popup не триггерит
   `closeTerrainOnOutside` (popup.contains(target) === true), поэтому popup
   не закрывается сам.
3. Backdrop sheet'а (z=390) тоже ниже popup'а (z=500), поэтому даже на
   mobile нет визуальной индикации, что popup стал «фоном».

## 2. Требования к решению

### 2.1 Функциональные (REQ-F)

| ID         | Требование |
|------------|------------|
| REQ-F-01   | При открытии `#sheet-gps-filters` из «Фильтры…» панель `#terrain-popup` НЕ должна перекрывать sheet ни визуально, ни для событий ввода. |
| REQ-F-02   | Когда `#sheet-gps-filters` открыт, состояние кнопки `#terrain-toggle` (класс `.active`) должно быть консистентно с состоянием popup: если popup скрывается / закрывается на время открытия фильтров — кнопка не должна оставаться визуально «прижатой». |
| REQ-F-03   | После закрытия `#sheet-gps-filters` (через `✕`, свайп вниз, клик по backdrop на mobile, либо `closeAllSheets()`) пользователь возвращается к карте. Возврат панели слоёв — на усмотрение архитектора (см. §3 «Варианты решения»). В любом случае не должно оставаться «фантомных» оверлеев / неактивных DOM в видимой области. |
| REQ-F-04   | Решение должно работать единообразно при инициации фильтров повторно (открыли → закрыли → открыли снова). |
| REQ-F-05   | Поведение `#terrain-popup` для всех других сценариев (открыть/закрыть кнопкой, кликнуть вне popup'а, переключить чекбокс/подложку/единицы) **не должно регрессировать**. |
| REQ-F-06   | Поведение остальных bottom-sheets (`#sheet-route`, `#sheet-recon`, `#sheet-scenic`, `#sheet-link`, `#sheet-gpx`) **не должно регрессировать**. |
| REQ-F-07   | Решение должно одинаково корректно работать в светлой и тёмной теме. |

### 2.2 Нефункциональные (REQ-NF)

| ID          | Требование |
|-------------|------------|
| REQ-NF-01   | Изменения локализованы во фронте (`src/web/`). Backend (`src/api/`) не затрагивается. |
| REQ-NF-02   | Нет регрессий по производительности (никаких новых тяжёлых обработчиков resize/scroll). |
| REQ-NF-03   | Если решение меняет z-index — оно не должно ломать стекинг `#marker-dialog` (z=500), `#search-panel` (z=600), `#ruler-info` (z=600). |
| REQ-NF-04   | Решение совместимо с PWA-режимом (PH-9, в работе): в standalone display и при наличии safe-area-inset. |
| REQ-NF-05   | Решение работает на mobile viewport 360–414 px (Chrome Android), desktop ≥1024 px (Chrome desktop). |

## 3. Варианты решения (на усмотрение архитектора)

> Аналитик не выбирает архитектуру. Перечисляю опции, которые могут быть
> рассмотрены реализатором/архитектором:

- **Вариант A — закрывать `#terrain-popup` при открытии sheet-gps-filters.**
  В `togglePublicTracksFiltersSheet()` перед `openSheet(...)` явно скрыть
  popup (как делает `closeTerrainOnOutside`) и снять `.active` с
  `#terrain-toggle`. Backdrop sheet'а корректно затемнит фон на mobile.
- **Вариант B — поднять z-index sheet'ов выше terrain-popup.** Например,
  `.bottom-sheet { z-index: 510; }` и `#sheet-backdrop { z-index: 505; }`.
  Тогда sheet физически окажется поверх popup'а. Требует проверки на не-
  конфликт с marker-dialog (z=500) и не-перекрытие toolbar / search-panel.
- **Вариант C — точечно поднять z-index только `#sheet-gps-filters` и его
  backdrop.** Узкий хак: `#sheet-gps-filters { z-index: 510; }`. Менее
  системно, но минимальные риски регрессии для других sheet'ов.

Решение фиксируется архитектором в ADR работы (`06-adr/`).

## 4. Acceptance hooks

См. полные критерии в `03-acceptance-criteria.md`.

Краткая выжимка:
- Открытие фильтров → панель полностью видна, кликабельна (mobile и
  desktop).
- Панель слоёв не перекрывает фильтры (визуально и для событий).
- Закрытие фильтров → возврат к карте без артефактов.
- Остальные оверлеи (marker-dialog, search-panel, ruler-info, остальные
  sheets) — без регрессий.

## 5. Тесты

См. `04-test-plan.yaml` (функциональные тесты) и
`04b-ui-test-cases.md` (Playwright UI тест-кейсы).

## 6. Артефакты для модификации (ожидание аналитика)

- `src/web/app.css` — стили stacking-context (если выбран вариант B/C).
- `src/web/gps_tracks.js` — логика `togglePublicTracksFiltersSheet()`
  (если выбран вариант A).
- Возможно `src/web/app.js` — если в `openSheet` / `closeAllSheets`
  требуется хук «при открытии sheet закрыть popup» как универсальное
  решение для будущих кейсов.

Это рекомендация, конкретный набор файлов определит архитектор.
