# 14. Mobile Screens — визуальное решение

**Дата:** 2026-04-13
**Автор:** Mobile UI Designer
**Стек:** Flutter 3.x, Material 3 Expressive, GoRouter
**Reference:** iPhone 390×844 dp, Android — scale via MediaQuery
**Источники:** 08-typography, 09-color-motion, 10-mobile-patterns, 11-design-brief

Детальное решение 15 ключевых экранов. Каждый экран — ASCII-скетч, токены, motion, haptic, a11y, ссылки на критерии успеха.

---

## Онбординг

### 1. Слайд 1 из 3 — «Инструмент рядом. Без людей»

**Цель:** объяснить суть сервиса за 7 секунд.

```
+--------------------------------------------------------------------+
| [SafeArea]                                            Пропустить   |
|                                                                    |
|                                                                    |
|              +---------+   +---------+                              |
|              | [drill] |   | [snow]  |    <- Bento 2.0 иллюстрация |
|              +---------+   +---------+       (280x280 dp)          |
|              +---------+   +---------+                              |
|              | [map]   |   | [lock]  |                              |
|              +---------+   +---------+                              |
|                                                                    |
|                                                                    |
|  Инструмент рядом.                                                 |
|  Без людей.                                <- display-md Onest 700 |
|                                                                    |
|  От перфоратора до снегоуборщика —                                 |
|  в автоматических стеллажах вашего района.  <- body-lg Inter 400   |
|                                                                    |
|                                                                    |
|                   • o o                  <- page indicator        |
|                                                                    |
|  +------------------------------------------------------+          |
|  |                     Далее                            |          |
|  +------------------------------------------------------+          |
+--------------------------------------------------------------------+
```

**Токены:** bg `slate-1 warm #FAF8F5`; headline display-md (32/40) Onest 700 slate-12; body body-lg (16/24) Inter 400 slate-11; CTA `FilledButton` 56 dp, iris-9 `#5B5BD6`, label-lg Inter 500 white; skip — text button body-sm slate-11.

**Ключевой приём:** Bento 2.0 иллюстрация из 4 карточек с Material Symbols (drill, snowflake, map, lock) — визуализирует «инструмент + постамат + карта + безопасность».

**Микрокопи:** H «Инструмент рядом. Без людей.» · Sub «От перфоратора до снегоуборщика — в автоматических стеллажах вашего района.» · CTA «Далее».

**Motion:** horizontal slide при переключении, 240ms `ease.emphasized`. Индикатор — width transition active dot (dur.fast).

**Haptic:** `selection` на CTA.

**A11y:** CTA touch 56 dp; контраст 14.2:1; skip semantic «Пропустить онбординг»; respect `textScaler` до 1.3×.

**Критерии:** S1 (warm bg), V5 (typography scale), T1 (tagline).

---

### 2. Слайд 2 из 3 — «Залог: спишем и вернём» (критичный!)

**Цель:** снять страх №1 — «деньги ушли и не вернутся». Объяснить deposit-refund метафорой до первой брони.

```
+--------------------------------------------------------------------+
| [SafeArea]                                            Пропустить   |
|                                                                    |
|                    +-----------------------+                       |
|                    |        [↻ replay]     |   <- 160dp jade ↻    |
|                    |          ↻            |      return-9 glow   |
|                    +-----------------------+                       |
|                                                                    |
|         +----------------+    +----------------+                   |
|         | К оплате       |    | Залог ↻        |                   |
|         | 500 ₽          |    | 3 000 ₽        |  <- две карточки |
|         | iris-9         |    | return-3 bg    |     side-by-side  |
|         |                |    | return-11 text |                   |
|         +----------------+    +----------------+                   |
|                                                                    |
|                                                                    |
|  Залог спишем явно — и вернём после фото возврата.                |
|                                                                    |
|  Деньги уйдут с карты, но мы запустим refund                       |
|  за 15 мин после фото · банк зачислит 1–3 дня.                    |
|                                                                    |
|                   o • o                                            |
|                                                                    |
|  +------------------------------------------------------+          |
|  |                     Далее                            |          |
|  +------------------------------------------------------+          |
+--------------------------------------------------------------------+
```

**Токены:** две demo-карточки — «К оплате» (iris-9 solid, white), «Залог ↻» (return-3 `#D1FAE5` bg, return-11 `#047857` text, ↻ icon return-9). Суммы — display-md tabular-nums.

**Ключевой приём:** **Deposit-refund metaphor** раскрыта до первой оплаты — full-screen coach-mark. Разделение двух денежных сущностей визуально (обе списываются, но залог имеет обещание refund'а).

**Микрокопи:** H «Залог спишем явно — и вернём после фото возврата.» · Sub «Деньги уйдут с карты, но мы запустим refund за 15 мин после фото · банк зачислит 1–3 дня.» · CTA «Далее».

**Motion:** при появлении — ↻ scale 0→1 (240ms decelerate) + soft pulse return-9. `prefers-reduced-motion` → cross-fade 80ms. **Без shimmer** — деньги списываем явно.

**Haptic:** `impact.light` на появление ↻ (1 раз).

**A11y:** return цвет сопровождён ↻ иконкой + текстом «залог · вернём» (не только цветом); semantic «Демонстрация: к оплате 500 рублей, залог 3000 рублей с возвратом после фото».

**Критерии:** T2 (прозрачность залога), T3 (return-cycle metaphor), V2 (return-9 применён), F1 (снятие страха №1).

---

### 3. Слайд 3 из 3 — СБП, Max Login, первая бронь

**Цель:** закрыть вход (auth), показать доступные способы оплаты.

```
+--------------------------------------------------------------------+
| [SafeArea]                                            Пропустить   |
|                                                                    |
|              +---------+  +---------+  +---------+                 |
|              | [СБП]   |  | [Max]   |  | [Т-Банк]|                 |
|              +---------+  +---------+  +---------+                 |
|                                                                    |
|                    +-------------------+                           |
|                    |    90 секунд      |  <- таймер-бейдж         |
|                    +-------------------+     amber-3 bg           |
|                                                                    |
|  Первая аренда — за 90 секунд.          <- display-md Onest 700   |
|                                                                    |
|  Войдите через Max или номер телефона.                             |
|  Оплата — СБП или картой Т-Банка.       <- body-lg slate-11       |
|                                                                    |
|                                                                    |
|                   o o •                                            |
|                                                                    |
|  +------------------------------------------------------+          |
|  |                Войти через Max                       |          |
|  +------------------------------------------------------+          |
|                                                                    |
|           Войти по номеру телефона          <- text button        |
+--------------------------------------------------------------------+
```

**Токены:** Max CTA — iris-9 FilledButton 56 dp; secondary text button label-lg iris-11. Логотипы СБП/Max/Т-Банк — official brand assets на `slate-2` chip-подложке radius 12.

**Ключевой приём:** **Trust signal через узнаваемые логотипы** + чёткий пакет «90 секунд» amber-badge. Два способа входа без перегруза.

**Микрокопи:** H «Первая аренда — за 90 секунд.» · Sub «Войдите через Max или номер телефона. Оплата — СБП или картой Т-Банка.» · CTA-primary «Войти через Max» · CTA-secondary «Войти по номеру телефона».

**Motion:** логотипы stagger-fade-in 40ms между, 240ms total.

**Haptic:** `selection` на CTA.

**A11y:** логотипы с `semanticLabel` «Оплата через СБП», «Вход через Max»; контраст iris-9/warm-bg — 6.8:1.

**Критерии:** T4 (90 секунд KPI), F3 (узнаваемые бренды-партнёры), A1 (два пути входа).

---

## Core UI

### 4. Карта постаматов (peek state bottom sheet)

**Цель:** за 1 взгляд — где есть нужный инструмент рядом.

```
+--------------------------------------------------------------------+
| +--------------------------------------------------+               |
| |  Q  Поиск по адресу или инструменту     [filter] |  <- pill      |
| +--------------------------------------------------+     elev 3    |
|                                                                    |
|  [ Все ] [ Свободно сейчас ] [ < 500м ] [ Перфораторы ]  chips    |
|                                                                    |
|                                                                    |
|              • [7]                 [locate]                        |
|                     • [3]                                          |
|                                                                    |
|                          • [12]                                    |
|                 • [0]                                              |
|                                                                    |
|                                                                    |
|                                                 [•]  <- FAB mini   |
|                                                                    |
| ==================   ───   ==================  <- drag handle     |
| +----------------------------------------------------------------+ |
| | Рядом с вами                                3 постамата        | |
| +----------------------------------------------------------------+ |
| | [img] Стеллаж № A-47 · 120 м                                   | |
| |       ул. Ленина 12  · Свободно: 7 инструментов  • green      | |
| +----------------------------------------------------------------+ |
| | [img] Стеллаж № B-12 · 340 м                                   | |
| |       Парк Горького  · Свободно: 3  • amber                    | |
| +----------------------------------------------------------------+ |
+--------------------------------------------------------------------+
```

**Токены:** маркеры-кластеры — pill radius 999, bg по доступности: green `success-9` (>5), amber `warning-9` (1-4), slate-7 (0). Цифра — label-lg Inter 600 white. Peek-sheet 15% height (≈130 dp), slate-1 bg, radius-top 24, shadow 0 -2 12 rgba(0,0,0,0.04).

**Ключевой приём:** **Анти-Ozon — не скрываем пустые постаматы**, показываем серым с причиной. Цвет кластера отвечает на вопрос «есть ли что брать?» без тапа.

**Микрокопи:** search «Поиск по адресу или инструменту» · chip-фильтры «Свободно сейчас», «< 500 м» · карточка «Свободно: 7 инструментов» · empty-state «Нет свободных — обновляется каждую минуту».

**Motion:** маркеры stagger 40ms при загрузке viewport; кластеризация — merge/split 240ms ease.standard; bottom-sheet drag — spring.soft.

**Haptic:** `lightImpact` tap по маркеру; `selectionClick` при drag-snap на peek/mid/full.

**A11y:** карта — fallback text-list (ссылка «Показать списком» в search-bar menu); маркеры имеют semantic label «Постамат А-47, 120 метров, 7 инструментов доступно»; target маркера 48 dp.

**Критерии:** M1 (fullscreen map), M2 (peek sheet), S2 (не скрываем пустые), V1 (цветовая кластеризация).

---

### 5. Детали постамата (mid state bottom sheet)

**Цель:** выбрать инструмент с уверенностью «точно есть».

```
+--------------------------------------------------------------------+
|                                                                    |
|         • [7]                                                      |
|                 ← карта видна на 45% сверху                        |
|                                                                    |
| ──────                                                             |
| +----------------------------------------------------------------+ |
| |  Стеллаж № A-47                                          × │   |
| |  ул. Ленина 12 · 120 м · 2 мин пешком                      |   |
| +----------------------------------------------------------------+ |
| | [ 24/7 ]  [ Парковка ]  [ Освещение ]  [ Возврат в любой ] |   |
| +----------------------------------------------------------------+ |
| |  +------------------------------------------------------+      | |
| |  |         Построить маршрут                            |      | |
| |  +------------------------------------------------------+      | |
| +----------------------------------------------------------------+ |
| |  Фото стеллажа                                                 | |
| |  +--------------------------------+                            | |
| |  | [photo реального постамата]    |                            | |
| |  +--------------------------------+                            | |
| +----------------------------------------------------------------+ |
| |  Свободно сейчас — 7 инструментов                              | |
| |  ┌──────────┐ ┌──────────┐ ┌──────────┐ →                      | |
| |  │ [drill]  │ │ [grind]  │ │ [ladder] │    <- horiz carousel   | |
| |  │ Перфора- │ │ Болгарка │ │ Лестница │                        | |
| |  │ тор      │ │          │ │          │                        | |
| |  │ 800₽/сут │ │ 400₽/сут │ │ 300₽/сут │                        | |
| |  │ 3 000₽↻  │ │ 1 500₽↻  │ │ 800₽↻    │                        | |
| |  └──────────┘ └──────────┘ └──────────┘                        | |
| +----------------------------------------------------------------+ |
+--------------------------------------------------------------------+
```

**Токены:** chips — label Inter 500, slate-3 bg, slate-11 text. Badge «Возврат в любой» — iris-3 bg, iris-11 text (киллер-фича акцентирована). Фото — radius 16, aspect 16:9. Карточка оборудования 160×220 dp, radius 20, shadow мягкий, `DepositChip` с суммой залога снизу.

**Ключевой приём:** **Bento-карусель с реальным фото постамата** (не рендер) + badge «Возврат в любой постамат сети» — снимает страх привязки к одной точке. Полная стоимость (аренда + залог) видна ДО тапа.

**Микрокопи:** «Свободно сейчас — 7 инструментов» · chip «Возврат в любой постамат сети» · «800 ₽/сут» · «Залог 3 000 ₽ ↻» · CTA «Построить маршрут».

**Motion:** sheet expand peek→mid 240ms decelerate; горизонтальный carousel — snap scroll physics.

**Haptic:** `selectionClick` при snap карточки, `mediumImpact` при тапе на инструмент.

**A11y:** badge-chip semantic «Можно вернуть в любой постамат сети»; карточка — combined label «Перфоратор, 800 рублей в сутки, залог 3000 рублей».

**Критерии:** M3 (фото реального стеллажа), M4 (возврат в любой = киллер-фича), T2 (полная цена до оплаты), V3 (Bento carousel).

---

### 6. Карточка оборудования (full screen)

**Цель:** решение «беру» за 15 секунд.

```
+--------------------------------------------------------------------+
|  ←                                                    [share] [♡]  |
|                                                                    |
|   +-----------------------------------------------------------+    |
|   |                                                           |    |
|   |              [PHOTO galleries · 1 / 4]                    |    |
|   |                                                           |    |
|   |                    • o o o                                |    |
|   +-----------------------------------------------------------+    |
|                                                                    |
|  Перфоратор Bosch GBH 2-26         <- headline 24 Inter 600       |
|  Артикул PM-A47-9B2                <- JetBrains Mono body-sm      |
|                                                                    |
|  Новинка  · Доступно 3 шт · Срок аренды от 2 ч                     |
|                                                                    |
|  ┌────────────────────────────────────────────────────────┐       |
|  │  Тариф                                                  │       |
|  │  [ 2 ч · 200₽ ] [ 4 ч · 350₽ ] [ сутки · 800₽ ] [ 3д ]│  chips |
|  └────────────────────────────────────────────────────────┘       |
|                                                                    |
|  ┌────────────────────────────────────────────────────────┐       |
|  │  Что в комплекте                                        │       |
|  │  • Перфоратор · Кейс · 3 бура (6/8/10мм) · Инструкция  │       |
|  └────────────────────────────────────────────────────────┘       |
|                                                                    |
|  ┌────────────────────────────────────────────────────────┐       |
|  │  Залог ↻  3 000 ₽                                       │       |
|  │  Спишем как залог на карте, вернём после возврата.             │       |
|  │  [ Как это работает? → ]                                │       |
|  └────────────────────────────────────────────────────────┘       |
|                                                                    |
|                                                                    |
| ==================================================================|
|  К оплате  |  800 ₽ + 3 000 ₽ ↻       [ Забронировать 800 ₽ ]    |
|            | аренда   залог                                       |
+--------------------------------------------------------------------+
```

**Токены:** hero gallery 16:9; headline Inter 24/600; артикул JetBrains Mono body-sm slate-11; тариф-chips — selected iris-9 bg white text, unselected slate-3 bg. Залог-блок — return-3 `#D1FAE5` bg, return-11 text, ↻ иконка. Persistent summary bar — slate-1 bg, top-border slate-5, CTA `FilledButton` label-lg iris-9 с суммой.

**Ключевой приём:** **Sticky summary bar «аренда + залог» всегда видна**. Тарифные пакеты (не поминутка) — chips с жирной суммой. `DepositChip` — reusable компонент.

**Микрокопи:** «Залог ↻ 3 000 ₽ — спишем как залог на карте, вернём после возврата» · «Как это работает?» · CTA «Забронировать 800 ₽».

**Motion:** gallery swipe — horizontal snap; chip selected — scale 0.98→1 fast; залог-карточка на scroll-in — slide up 240ms.

**Haptic:** `selectionClick` на chip, `lightImpact` на gallery swipe.

**A11y:** артикул с `TextSpan` semantics «артикул P M тире A четыре семь…»; summary bar — live region; контраст return-11/return-3 — 7.2:1.

**Критерии:** T2 (sticky total), V2 (DepositChip return-cycle), M5 (пакеты вместо поминутки), F2 (explainer ссылка).

---

### 7. Экран оплаты + залог (КРИТИЧНЫЙ — deposit-refund) 🎯

**Цель:** снять страх «деньги ушли и не вернутся». Самый важный финтех-экран. Финмодель: списываем явно, возвращаем refund'ом после фото возврата.

```
+--------------------------------------------------------------------+
|  ←                  Оплата                                         |
|                                                                    |
|  Перфоратор Bosch · 1 сутки · Стеллаж А-47                         |
|                                                                    |
|  ┌────────────────────────────────────────────────────────┐       |
|  │  Аренда                                    800 ₽        │       |
|  │  ────────────────────────────────────────────────       │       |
|  │  К оплате сейчас                           800 ₽        │       |
|  │  iris-9 display-md 32/40 tabular-nums                   │       |
|  └────────────────────────────────────────────────────────┘       |
|                                                                    |
|  ┌────────────────────────────────────────────────────────┐       |
|  │  ↻  Залог                                  3 000 ₽      │       |
|  │     return-9                          return-11 display │       |
|  │                                                          │       |
|  │  Спишем сейчас, вернём после возврата оборудования.     │       |
|  │  Это полноценное списание (банк покажет «-3 000 ₽»),    │       |
|  │  refund запустим за 15 мин после получения 4-х фото.    │       |
|  │                                                          │       |
|  │  Банк зачислит возврат за 1–3 дня                        │       |
|  │                                                          │       |
|  │  [ Как устроен залог? → ]  <- coach-mark при первом pay │       |
|  └────────────────────────────────────────────────────────┘       |
|                                                                    |
|  Способ оплаты                                                     |
|  ◉  СБП через Max / Т-Банк / другой банк            [выбрать]    |
|  ○  Карта Т-Банк ·· 4127                                          |
|                                                                    |
|  [ Чек придёт на +7···45, 54-ФЗ ]  <- trust signal caption        |
|                                                                    |
|                                                                    |
| ==================================================================|
|  +--------------------------------------------------------+       |
|  |         Оплатить 800 ₽ + Залог 3 000 ₽ ↻              |       |
|  |                  iris-9 FilledButton 56dp               |       |
|  +--------------------------------------------------------+       |
|                                                                    |
|     Нажимая, вы соглашаетесь с условиями аренды                   |
+--------------------------------------------------------------------+
```

**Токены:** два равноправных блока `PriceBreakdown` — оба представляют **списания**, разница в обещании refund'а у второго. Блок 1 — iris-accented, «К оплате (аренда) 800 ₽» display-md iris-9. Блок 2 — `return-3 #D1FAE5` bg, «Залог 3 000 ₽» display-md return-11, ↻ icon 24dp return-9. Бордюр между блоками slate-5. CTA — iris-9 FilledButton 56 dp с двумя суммами в label через `+`.

**Ключевой приём — Deposit-refund metaphor (как реализована):**
1. Визуальная иерархия: два **равных** блока вместо вложенного «итого» — разделяем «аренду» (трата без возврата) и «залог» (трата с обещанием refund'а).
2. `return-9 #30A46C` jade-green — мягкий обещающий, не тревожный. Ассоциация «↻ цикл → вернётся».
3. Иконка ↻ (`replay`) в заголовке блока + перед суммой; rotate-анимация при переходе в состояние `refunding`.
4. Два разных SLA рядом: **наш** («refund запустим за 15 мин после фото») и **банковский** («зачислит за 1–3 дня»).
5. Coach-mark «Как устроен залог?» — full-screen объяснение AirBnB-аналогией (security deposit: списание + refund).
6. **Анимация при подтверждении:** сумма 3 000 ₽ `slate-12 → return-11` (120ms), ↻ прорастает scale 0→1 (200ms decelerate) с soft pulse return-9, haptic `impact.medium` 1×. **Без shimmer** — деньги списаны явно.

**Микрокопи:** «К оплате (аренда) 800 ₽» · «Залог 3 000 ₽ ↻» · «Спишем сейчас, вернём после возврата оборудования. Refund запустим за 15 мин после фото · банк зачислит за 1–3 дня.» · «Как устроен залог?» · CTA «Оплатить 800 ₽ + Залог 3 000 ₽ ↻» · caption «Чек 54-ФЗ придёт на +7…45 (и второй чек — при возврате)».

**Motion:** deposit-charge sequence (см. выше § A в 09-color-motion); CTA press — scale 0.98 fast; переход на success — slide-from-right 400ms.

**Haptic:** `impact.medium` ровно 1× в момент 120ms deposit-charge анимации (iOS `selection`, Android `CONTEXT_CLICK`).

**A11y:** ↻ не единственный индикатор — текст «Залог · вернём после возврата» + цвет + иконка; суммы `tabular-nums` + semantic «восемьсот рублей»; coach-mark с focus trap; CTA label полный «Оплатить восемьсот рублей за аренду и три тысячи рублей залога с возвратом после фото».

**Критерии:** T1, T2, T3 (все три главных trust-signal), V2 (return-9), F1 (main fear removed), F4 (дедлайн конкретный), S3 (двойная сумма на CTA).

---

### 8. BLE pairing screen (Apple-Find-My-подобный)

**Цель:** подтвердить присутствие у стеллажа без QR и без взгляда на экран. Открывать ничего не нужно — полки открытые, BLE только для proximity-верификации (Challenge-Response Ed25519). После confirm — переход в `ShelfMapView` с подсветкой нужной полки.

```
+--------------------------------------------------------------------+
|  ←                    Подходим к стеллажу А-47                     |
|                                                                    |
|                                                                    |
|                      .  . . . . . .                                |
|                  .   .             .  .                            |
|               .   .     pulse-ring     .  .                        |
|              .  .        iris-3           .                        |
|             .                               .                      |
|            .    +-----------------------+    .                     |
|            .    |                       |    .                     |
|            .    |   [stellage icon]     |    .                     |
|            .    |                       |    .                     |
|            .    +-----------------------+    .                     |
|             .                               .                      |
|              .                             .                       |
|                                                                    |
|               Расстояние  ~3 м                                     |
|               JetBrains Mono display-sm                            |
|                                                                    |
|               [ ████████░░░░░░░░ ]  <- BleSignalIndicator         |
|                                                                    |
|               Подойдите ближе к стеллажу А-47                      |
|               body-lg slate-11                                     |
|                                                                    |
|                                                                    |
|                                                                    |
|                                                                    |
|  ────────────────────────────────────────────────────             |
|  Не получается?    [ Открыть по коду со стеллажа → ]              |
+--------------------------------------------------------------------+
```

**Состояния:**
1. **Searching:** пульсирующая волна iris-3, текст «Подойдите ближе к стеллажу А-47», без signal bar.
2. **Detected RSSI > -80:** progress-ring заполняется, «Расстояние ~3 м».
3. **Connecting:** ring полный iris-9, «Связь установлена».
4. **Confirmed:** large ✓ 120dp iris-9 + `impact.medium`, микрокопи «Вы у стеллажа А-47 — подтверждено», auto-redirect 1.0 с на `ShelfMapView` с пульсирующей целевой полкой. Никакого «открытия» — полки открытые.

**Токены:** фон slate-1; pulse-ring `iris-3 → iris-5 → transparent` 1400ms loop; ring stroke iris-9 4dp; distance — JetBrains Mono 28/36; fallback CTA — text button iris-11 label-lg.

**Ключевой приём:** **физическая метафора «приближения»**, не технический спиннер. Честная деградация — всегда виден путь «по коду».

**Микрокопи:** «Расстояние ~3 м» · «Подойдите ближе к стеллажу А-47» · fallback «Открыть по коду со стеллажа →» · состояние-fail «Не удалось подключиться. Введите 6-значный код».

**Motion:** pulse-ring 1400ms loop ease.standard; ring fill — прямо пропорционально RSSI (smooth 120ms lerp); ✓ stroke-animation 400ms decelerate.

**Haptic:** `impact.light` при detect, `impact.medium` при connecting, `impact.medium` при proximity confirmed (не heavy — это не unlock-событие), `vibrate` при connection lost.

**A11y:** `reduce-motion` → static ring + text-only indicator «Сигнал: сильный / слабый / нет»; TalkBack озвучивает distance on change; fallback CTA visible always.

**Критерии:** M6 (Apple-like proximity), F5 (honest fallback), A2 (reduce-motion), V4 (iris pulse).

---

### 9. QR scanner (Max Mini App fallback)

**Цель:** в Max Mini App без BLE — быстрый путь через QR со стеллажа.

```
+--------------------------------------------------------------------+
|  ←                       Сканируйте QR                             |
|                                                                    |
|                                                                    |
|          ┌──────────────────────────────────────┐                 |
|          │                                       │                 |
|          │                                       │                 |
|          │       ╔═══════════════════╗           │                 |
|          │       ║                   ║           │                 |
|          │       ║    [camera]       ║           │                 |
|          │       ║                   ║           │                 |
|          │       ║   naviga scan     ║           │                 |
|          │       ║   iris-9 frame    ║           │                 |
|          │       ║                   ║           │                 |
|          │       ╚═══════════════════╝           │                 |
|          │                                       │                 |
|          │          scanner-line slide           │                 |
|          │                                       │                 |
|          └──────────────────────────────────────┘                 |
|                                                                    |
|  Наведите камеру на QR-код на стеллаже                            |
|  body-lg slate-12                                                  |
|                                                                    |
|                                                                    |
|  ────────────────────────────────────────────────────             |
|  Не видно QR?     [ Ввести 6-значный код вручную → ]              |
+--------------------------------------------------------------------+
```

**Токены:** рамка 260×260 iris-9 stroke 3dp, четыре угла-маркера; scan-line iris-9 2dp, animate top↔bottom 1600ms linear; backdrop `rgba(0,0,0,0.6)`; instruction — body-lg on dark overlay, white.

**Ключевой приём:** **честная деградация** — в Mini App BLE нет, но UX ровный; manual PIN-fallback всегда видим. Banner «Для быстрой выдачи — установите APK» на первом открытии.

**Микрокопи:** «Наведите камеру на QR-код на стеллаже» · fallback «Ввести 6-значный код вручную» · banner «Для быстрой выдачи без кода установите приложение».

**Motion:** scan-line 1600ms loop; success — рамка iris-9 → success-9, scale 1→1.05→1 (240ms), haptic + auto-redirect.

**Haptic:** `mediumImpact` на detect QR (через Web Vibration fallback в Max).

**A11y:** если permission denied — full-screen state с кнопкой «Открыть настройки»; manual PIN input — textField labelLarge JetBrains Mono, autofocus, numeric keyboard.

**Критерии:** M7 (Max parity), F5 (manual fallback), S4 (honest degradation).

---

## Аренда

### 10. Photo capture (guided overlay, 4 ракурса)

**Цель:** доказательные фото без ощущения допроса. Снижает ½ споров. Это **единственное** доказательство состояния и факта возврата — камер внутри стеллажа нет.

```
+--------------------------------------------------------------------+
|  ←                                                    [flash] [?]  |
|                                                                    |
|  Фото 2 из 4 · Серийный номер крупно                               |
|  label-lg Inter 500 white on dark                                  |
|                                                                    |
|                                                                    |
|        ╔════════════════════════════════════════╗                 |
|        ║                                         ║                 |
|        ║   ┌─────────────────────────────┐      ║                 |
|        ║   │                              │      ║                 |
|        ║   │    [ghost silhouette]       │      ║                 |
|        ║   │    корпуса перфоратора      │      ║                 |
|        ║   │    iris-9 stroke dashed     │      ║                 |
|        ║   │                              │      ║                 |
|        ║   └─────────────────────────────┘      ║                 |
|        ║                                         ║                 |
|        ║          [camera live preview]          ║                 |
|        ║                                         ║                 |
|        ╚════════════════════════════════════════╝                 |
|                                                                    |
|  «Совместите корпус с рамкой»                                      |
|                                                                    |
|  [reference thumbnail]                      ← эталонное фото       |
|                                                                    |
|                                                                    |
|  ┌───┐ ┌───┐ ┌───┐ ┌───┐                                           |
|  │ ✓ │ │ ◎ │ │ ○ │ │ ○ │          checklist: общий · серийник ·   |
|  └───┘ └───┘ └───┘ └───┘          кейс · ремень закреплён          |
|                                                                    |
|                         ( ● )                 <- shutter 72dp     |
|                                                                    |
+--------------------------------------------------------------------+
```

**Токены:** ghost overlay — iris-9 stroke dashed 2dp opacity 0.6; checklist row — 4 thumbs 44×44, done = success-9 ✓, current = iris-9 ring pulse, pending = slate-6 border. Shutter — 72 dp white ring + inner solid iris-9. Hint — caption white on scrim. GPS+timestamp watermark в углу финального кадра.

**Ключевой приём:** **Turo-style guided flow** — эталонный ghost + reference thumbnail + on-device ML Kit blur detection (Android) / server-side retake-loop (Max). Серийный номер — отдельный обязательный кадр с OCR. Последний кадр «ремень закреплён» обязателен при возврате (доказывает, что инструмент оставлен в корректном положении). Это **единственное** доказательство — поэтому overlay строгий.

**Микрокопи:** «Фото 1 из 4 · Общий план (инструмент на полке)» · «Фото 2 из 4 · Серийный номер крупно» · «Фото 3 из 4 · Кейс / комплектация» · «Фото 4 из 4 · Ремень закреплён — крупно» · hint «Совместите с рамкой» · blur-warning «Слишком темно, включите свет» · final-caption «GPS и время встроены в кадр».

**Motion:** при shutter — flash-overlay 80ms; preview slide-up 240ms «Переснять / OK»; checklist ✓ stamp-in 200ms decelerate.

**Haptic:** `selectionClick` при shutter, `lightImpact` при успешной валидации, `mediumImpact` на переход к след ракурсу.

**A11y:** ghost-overlay имеет текстовый alt «Рамка для фото корпуса перфоратора»; shutter `Semantics(button: true, label: "Сделать фото 2 из 4")`; progress «Фото два из четырёх».

**Критерии:** M8 (Turo-like), F6 (serial OCR), V6 (guided UX), S5 (4 ракурса чеклист).

---

### 11. Active rental (top banner + detail screen)

**Цель:** аренда всегда под рукой, но не мешает.

**Top banner (на всех табах):**
```
+--------------------------------------------------------------------+
| [drill]  Перфоратор Bosch · осталось 2 ч 15 мин       →           |
| iris-3 bg · label Inter 500 slate-12 · tabular                    |
+--------------------------------------------------------------------+
```

**Full-screen (таб «Аренды»):**
```
+--------------------------------------------------------------------+
|   Аренда № R-4712                              JetBrains Mono     |
|                                                                    |
|   +----------------------------------------------------------+   |
|   |                                                           |   |
|   |              [hero фото инструмента]                      |   |
|   |                                                           |   |
|   +----------------------------------------------------------+   |
|                                                                    |
|   Перфоратор Bosch GBH 2-26                                        |
|                                                                    |
|                                                                    |
|        Осталось                                                    |
|        2 ч 15 мин                    <- display-lg 40/48 Onest    |
|        tabular-nums slate-12                                       |
|                                                                    |
|        Вернуть до  14.04, 20:00                                    |
|                                                                    |
|   [ ███████████░░░░░░░░░░░░ ]   <- usage bar iris-9 / slate-3     |
|      использовано 6 ч из 24                                        |
|                                                                    |
|                                                                    |
|   ┌──────────────────┐   ┌──────────────────┐                     |
|   │     Продлить     │   │     Вернуть      │                     |
|   │    iris-9 tonal  │   │  iris-9 filled   │                     |
|   └──────────────────┘   └──────────────────┘                     |
|   ┌──────────────────┐   ┌──────────────────┐                     |
|   │     Помощь       │   │    Инструкция    │                     |
|   │     outlined     │   │     outlined     │                     |
|   └──────────────────┘   └──────────────────┘                     |
|                                                                    |
|   ┌────────────────────────────────────────────────────────┐     |
|   │  Стеллаж возврата   [ мини-карта ]                      │     |
|   │  А-47, ул. Ленина 12  · [Построить маршрут →]          │     |
|   │  🔄 Или верните в любой стеллаж сети →                  │     |
|   └────────────────────────────────────────────────────────┘     |
|                                                                    |
|   ┌────────────────────────────────────────────────────────┐     |
|   │  ↻  Залог 3 000 ₽   · status: charged                   │     |
|   │     return-9 · вернём refund'ом после фото возврата     │     |
|   └────────────────────────────────────────────────────────┘     |
+--------------------------------------------------------------------+
```

**Токены:** `RentalTimer` — display-lg Onest 700 tabular-nums, обновление 1×/мин (не посекундно!); usage-bar — `LinearProgressIndicator` iris-9/slate-3 height 6dp radius 3. CTA-grid 2×2 — filled (Вернуть), tonal (Продлить), outlined (Помощь, Инструкция); DepositChip с залогом reuses экран 6.

**Ключевой приём:** **НЕ поминутный таймер** — мы не каршеринг. Обновление раз в минуту. Timer display-lg Onest — единственный экран в приложении с Onest (как «hero-момент»).

**Микрокопи:** banner «Перфоратор Bosch · осталось 2 ч 15 мин» · «Осталось 2 ч 15 мин» · «Вернуть до 14.04, 20:00» · CTA «Продлить», «Вернуть», «Помощь», «Инструкция» · push-при-30-мин «Осталось 30 мин. Продлить на час? →».

**Motion:** timer — количество обновляется cross-fade 80ms (без «бега цифр»); usage-bar width transition 400ms; <24h banner `iris-3 → amber-3` color tween 400ms.

**Haptic:** `selection` при tap banner, `mediumImpact` при Вернуть.

**A11y:** timer live region; «2 часа 15 минут» textual; контраст iris-9/iris-3 banner — 6.8:1; CTA touch 56 dp; reduce-motion — no usage-bar animation.

**Критерии:** M9 (banner sticky), M10 (минутное обновление), F7 (продление из push), V5 (Onest hero moment).

---

### 12. Return initiated (назначен slot, инструкция)

**Цель:** «знаю, куда и как вернуть» без звонка в поддержку.

```
+--------------------------------------------------------------------+
|  ←                    Возврат                                      |
|                                                                    |
|                                                                    |
|                  ┌────────────────────┐                            |
|                  │      ↻  →  ✓       │  <- иконка «лёд → чек»    |
|                  │    animated 240ms  │                            |
|                  └────────────────────┘                            |
|                                                                    |
|   Полка № 7 ждёт перфоратор                                        |
|   headline-24 Inter 600                                            |
|                                                                    |
|   Стеллаж А-47, ул. Ленина 12                                      |
|   body-lg slate-11                                                 |
|                                                                    |
|   ┌────────────────────────────────────────────────────────┐     |
|   │  Что делать:                                            │     |
|   │                                                          │     |
|   │  1. Подойдите к стеллажу  A-47 (или любому в сети)       │     |
|   │  2. BLE подтвердит присутствие — в приложении            │     |
|   │     подсветится свободная полка (или код 482913)         │     |
|   │  3. Поставьте инструмент на полку и закрепите ремнём     │     |
|   │     (затяните до щелчка)                                 │     |
|   │  4. Сделайте 4 фото: общий план, серийник, кейс, ремень  │     |
|   │                                                          │     |
|   └────────────────────────────────────────────────────────┘     |
|                                                                    |
|   ┌────────────────────────────────────────────────────────┐     |
|   │  Код полки                                              │     |
|   │                                                          │     |
|   │       482 913                 JetBrains Mono display-md │     |
|   │                                                          │     |
|   │  Действителен до  20:00 (ещё 1 ч 45 мин)                │     |
|   └────────────────────────────────────────────────────────┘     |
|                                                                    |
|   После фото залог 3 000 ₽ вернём                              |
|   за 15 мин                                     <- SLA caption    |
|                                                                    |
|  +--------------------------------------------------------+       |
|  |            Построить маршрут (2 мин)                   |       |
|  +--------------------------------------------------------+       |
|                                                                    |
|            Нужна помощь?   [ Чат с поддержкой ]                   |
+--------------------------------------------------------------------+
```

**Токены:** шаги — нумерованный list, label 36dp круг iris-3 bg iris-9 digit, body-md. Код — JetBrains Mono 32/40 с NBSP группировка 3-3. Timer до истечения — caption slate-11. SLA-caption — info-3 bg info-11 text.

**Ключевой приём:** **1 вопрос — 1 ответ: «куда?»** (stellage+полка), «как?» (auto+fallback код), «когда вернут деньги?» (15 мин SLA). No шагов confirm-модалок.

**Микрокопи:** «Полка № 7 ждёт перфоратор» · «Полку подсветим в приложении при приближении (или введите код 482 913)» · «Закрепите ремнём — до щелчка» · «Можно вернуть в любой стеллаж сети» · «Действителен до 20:00 (ещё 1 ч 45 мин)» · SLA «После фото залог 3 000 ₽ вернём за 15 мин» · CTA «Построить маршрут (2 мин)».

**Motion:** иконка «↻ → ✓» кросс-fade 240ms при входе на экран; timer-countdown — обновление 1×/мин cross-fade.

**Haptic:** `selection` на CTA.

**A11y:** код — `Semantics(value: "четыре восемь два девять один три")`; step list — standard reading order; timer с live region.

**Критерии:** M11 (1 вопрос — 1 ответ), T5 (SLA 15 мин явно), F8 (fallback код всегда видим).

---

### 13. Return success (celebration + refund залога)

**Цель:** убедить, что refund действительно запущен. После первого возврата — снять тревогу навсегда. **Без false-promise** «деньги уже на карте» — банк зачислит за 1–3 дня.

```
+--------------------------------------------------------------------+
|                                                                    |
|                                                                    |
|                                                                    |
|                    ┌──────────────┐                                |
|                    │              │                                |
|                    │      ✓       │  <- stroke-anim 400ms         |
|                    │   success-9  │     + one pulse ring          |
|                    │              │                                |
|                    └──────────────┘                                |
|                                                                    |
|                                                                    |
|              Возврат 3 000 ₽ обработан                              |
|              display-lg 48/52 Onest 700 return-9                   |
|                                                                    |
|              refund отправлен в банк ·· 4127                       |
|              body-lg slate-11                                      |
|                                                                    |
|                                                                    |
|  ┌────────────────────────────────────────────────────────┐     |
|  │  ● Refund отправлен         14.04  19:42                │     |
|  │  │                                                       │     |
|  │  ● Банк получил запрос      14.04  19:43                │     |
|  │  │                                                       │     |
|  │  ● На карте                  за 1–3 дня (банк-зависимо) │     |
|  │                                                          │     |
|  │  Refund: банк не пришлёт отдельный push —               │     |
|  │  баланс просто вырастет за 1–3 дня.                      │     |
|  └────────────────────────────────────────────────────────┘     |
|                                                                    |
|  ┌────────────────────────────────────────────────────────┐     |
|  │  Чек 54-ФЗ                                              │     |
|  │  [QR]   Для nalog.ru · ₽800 · № 789…                    │     |
|  │  [ Скачать PDF → ]                                      │     |
|  └────────────────────────────────────────────────────────┘     |
|                                                                    |
|         Оцените аренду    ★ ★ ★ ★ ★                               |
|                                                                    |
|  +--------------------------------------------------------+       |
|  |                 Готово                                 |       |
|  +--------------------------------------------------------+       |
+--------------------------------------------------------------------+
```

**Токены:** ✓ — 96dp return-9 stroke 4, pulse-ring scale 1→1.3 opacity 1→0 600ms; сумма display-lg Onest 700 return-9 `#30A46C` tabular; timeline-dots — return-9 filled (done) / slate-6 outline (pending); QR — JetBrains Mono caption. DepositChip переходит в `refunded` после webhook'а от банка.

**Ключевой приём:** **сдержанная celebration без false-promise** — ✓ + 1 pulse, НЕ конфетти, НЕ fireworks. Микрокопи говорит про **запуск возврата** (refund-initiated), а не про факт зачисления. При **первом** успешном refund'е — one-time full-screen «Запустили возврат 3 000 ₽. Деньги придут за 1–3 дня — теперь вы знаете цикл». Явный disclaimer про refund снимает главную причину звонков.

**Микрокопи:** «Возврат 3 000 ₽ обработан» · «refund отправлен в банк ·· 4127» · timeline «Refund отправлен / Банк получил запрос / На карте за 1–3 дня» · «Refund: банк не пришлёт отдельный push — баланс просто вырастет за 1–3 дня.» · first-time «Запустили возврат 3 000 ₽. Деньги придут за 1–3 дня — теперь вы знаете цикл.» · CTA «Готово».

**Motion:** ✓ stroke draw 400ms decelerate + single pulse ring 600ms — **один раз** (не loop); сумма fade+slide-up 240ms после ✓; timeline-dots stagger 120ms.

**Haptic:** `notification.success` ровно 1× в момент старта ✓-анимации.

**A11y:** announce на успех «Возврат три тысячи рублей запущен в банк заканчивающийся на четыре один два семь, зачисление за один-три дня»; reduce-motion → static ✓ + cross-fade 80ms.

**Критерии:** T6 (явный disclaimer о банке), F9 (first-time celebration), V7 (сдержанный success), S6 (timeline прозрачность).

---

## Auxiliary

### 14. История аренд (timeline, группы по статусу)

**Цель:** найти чек/повторить аренду за 3 тапа.

```
+--------------------------------------------------------------------+
|   Аренды                                              [filter]     |
|                                                                    |
|   ┌─────────────────────────────────────────────────────────┐    |
|   │  АКТИВНЫЕ                                        ● 1    │    |
|   └─────────────────────────────────────────────────────────┘    |
|   +--------------------------------------------------------+       |
|   | [drill] Перфоратор Bosch     · Осталось 2 ч 15 мин    |       |
|   |         А-47 · R-4712  ↻ 3 000 ₽                      |       |
|   +--------------------------------------------------------+       |
|                                                                    |
|   ┌─────────────────────────────────────────────────────────┐    |
|   │  ЗАВЕРШЁННЫЕ                                            │    |
|   └─────────────────────────────────────────────────────────┘    |
|   +--------------------------------------------------------+       |
|   | [grind]  Болгарка Makita    · 10 апр  ·   400 ₽        |       |
|   |          R-4689  · Залог 3 000 ₽: списано · возвращено |       |
|   +--------------------------------------------------------+       |
|   +--------------------------------------------------------+       |
|   | [ladder] Лестница 3м         · 05 апр  ·   300 ₽       |       |
|   |          R-4612  · Залог 800 ₽: списано · возвращено   |       |
|   +--------------------------------------------------------+       |
|                                                                    |
|   ┌─────────────────────────────────────────────────────────┐    |
|   │  ОТМЕНЁННЫЕ                                             │    |
|   └─────────────────────────────────────────────────────────┘    |
|   +--------------------------------------------------------+       |
|   | [saw]    Пила циркулярная    · 28 мар · возврат 500 ₽  |       |
|   |          R-4533  · отменена до выдачи                  |       |
|   +--------------------------------------------------------+       |
+--------------------------------------------------------------------+
```

**Токены:** sticky section headers — overline Inter 600 11/14 UPPERCASE tracking 1.0 slate-11; карточка 88 dp, radius 16, slate-2 bg; badge статуса — ✓ success-9 / ● iris-9 (active) / ○ slate-8; R-ID — JetBrains Mono body-sm slate-11.

**Ключевой приём:** **timeline со sticky группами по статусу**, не по дате. Активная — первая, всегда сверху. Все завершённые — с ✓ залог-статусом для снятия тревоги.

**Микрокопи:** секции «Активные», «Завершённые», «Отменённые» · row «Залог 3 000 ₽: списано · возвращено» · pull-to-refresh «Обновляем…».

**Motion:** pull-to-refresh LinearProgress iris-9; карточки fade-in на scroll 120ms.

**Haptic:** `selectionClick` на tap карточки, `lightImpact` на pull-refresh trigger.

**A11y:** section headers — `Semantics(header: true)`; row combined label «Перфоратор Bosch, аренда четыре семь один два, осталось два часа пятнадцать минут».

**Критерии:** M12 (группировка по статусу), T7 (залог-статус в списке), V8 (sticky headers).

---

### 15. Dispute flow (форма спора + SLA-таймер)

**Цель:** если что-то пошло не так — пользователь видит, что его заявка зафиксирована и в работе.

```
+--------------------------------------------------------------------+
|  ←                 Открыть спор                                    |
|                                                                    |
|   Аренда R-4689 · Болгарка Makita                                  |
|                                                                    |
|                                                                    |
|   Что случилось?                                                   |
|                                                                    |
|   ○  Списали с залога, а инструмент был исправен                   |
|   ○  Не списали залог, а должны были                               |
|   ●  Списали больше, чем ожидал                    ← selected     |
|   ○  Не работает оборудование                                      |
|   ○  Другое                                                        |
|                                                                    |
|                                                                    |
|   Сумма, которая вас смутила                                       |
|   ┌──────────────────────────────────────┐                        |
|   │ 1 200 ₽                              │                        |
|   └──────────────────────────────────────┘                        |
|                                                                    |
|                                                                    |
|   Опишите подробнее (необязательно)                                |
|   ┌──────────────────────────────────────┐                        |
|   │                                       │                        |
|   │                                       │                        |
|   └──────────────────────────────────────┘                        |
|                                                                    |
|   Прикрепите фото (до 5)                                           |
|   ┌────┐ ┌────┐ ┌────┐   [ + ]                                    |
|   │[img]│ │[img]│ │[img]│                                          |
|   └────┘ └────┘ └────┘                                             |
|                                                                    |
|                                                                    |
|   ┌────────────────────────────────────────────────────────┐     |
|   │  ⏱  Ответим за 2 часа в рабочее время                  │     |
|   │     Если нарушим SLA — бонус 200 ₽ на следующую аренду  │     |
|   │     info-3 bg  info-11 text                             │     |
|   └────────────────────────────────────────────────────────┘     |
|                                                                    |
|                                                                    |
|  +--------------------------------------------------------+       |
|  |              Отправить заявку                          |       |
|  +--------------------------------------------------------+       |
+--------------------------------------------------------------------+
```

**Токены:** radio-list row 56dp slate-1 bg, selected — iris-3 bg iris-9 dot; text field M3 OutlinedInputDecoration radius 12, focus iris-9; photo-slots 72×72 radius 12; SLA-баннер — info-3 `#DDF3FF` bg info-11 text, ⏱ icon 20dp.

**Ключевой приём:** **структурированная форма** (категоризированные причины) + явный **SLA-таймер**: «Ответим за 2 часа» + бонус-за-нарушение-SLA = trust signal. Не заставляем печатать с нуля.

**Микрокопи:** «Что случилось?» · причины-list · «Сумма, которая вас смутила» · «Опишите подробнее (необязательно)» · SLA «Ответим за 2 часа в рабочее время. Если нарушим SLA — бонус 200 ₽ на следующую аренду» · CTA «Отправить заявку» · success-state «Заявка #D-1204 в работе. Ответим до 14.04 21:15.»

**Motion:** radio selection — scale 0.9→1 fast; photo-upload — linear progress iris-9 поверх thumb; submit — button press + slide-to-success 400ms.

**Haptic:** `selectionClick` radio, `mediumImpact` submit, `notification.success` при confirmation.

**A11y:** radio — `Radio` виджет с Semantics group label «Что случилось»; SLA-баннер — live region `info`; обязательное поле пустое → inline error (не только цветом, но и иконкой + текстом).

**Критерии:** T8 (SLA явный + компенсация), F10 (структура снимает ступор), V9 (info-цвет в UX тревоги).

---

## Компоненты (reusable)

Итоговые reusable Flutter-виджеты, на которых построены 15 экранов.

### PriceBreakdown

Разбивка суммы на «К оплате» и «Спишем как залог». Используется на экранах 6, 7.

```dart
class PriceBreakdown extends StatelessWidget {
  final int amountKopecks;       // сумма к оплате
  final int? depositKopecks;     // сумма залога, nullable
  final Duration refundSlaWindow; // SLA: 15 мин на refund-инициирование после фото
  const PriceBreakdown({
    super.key, required this.amountKopecks,
    this.depositKopecks,
    this.refundSlaWindow = const Duration(minutes: 15)});

  @override
  Widget build(BuildContext c) {
    final t = Theme.of(c);
    final rc = t.extension<RentColors>()!;
    return Column(children: [
      _Row(label: 'К оплате (аренда)', amount: amountKopecks,
        color: t.colorScheme.primary, textStyle: t.textTheme.displayMedium),
      if (depositKopecks != null) ...[
        const SizedBox(height: 16),
        _DepositCard(
          amount: depositKopecks!,
          refundSlaWindow: refundSlaWindow,
          accentColor: rc.returnFill,
          textColor: rc.returnText,
          bgColor: rc.returnBgSubtle,
        ),
      ],
    ]);
  }
}
```

### DepositChip

Return-cycle индикатор залога. Reusable на 5, 6, 7, 11, 13. 3 состояния: `charged | refunding | refunded`.

```dart
enum DepositStatus { charged, refunding, refunded }

class DepositChip extends StatelessWidget {
  final int amountKopecks;
  final DepositStatus status;
  final bool large;
  const DepositChip({super.key,
    required this.amountKopecks,
    this.status = DepositStatus.charged,
    this.large = false});

  @override
  Widget build(BuildContext c) {
    final rc = Theme.of(c).extension<RentColors>()!;
    final isRefunded = status == DepositStatus.refunded;
    final iconData = isRefunded ? Icons.check_circle : Icons.replay;
    final color = isRefunded ? rc.successFill : rc.returnFill;
    final textColor = isRefunded ? rc.successText : rc.returnText;
    final bg = isRefunded ? rc.successFill.withOpacity(0.12) : rc.returnBgSubtle;

    final label = switch (status) {
      DepositStatus.charged   => 'Залог ${formatMoney(amountKopecks)} ₽ · вернём после возврата',
      DepositStatus.refunding => 'Возвращаем залог ${formatMoney(amountKopecks)} ₽',
      DepositStatus.refunded  => 'Залог ${formatMoney(amountKopecks)} ₽ возвращён',
    };

    Widget icon = Icon(iconData, size: large ? 20 : 14, color: color);
    if (status == DepositStatus.refunding) {
      icon = RotationTransition(turns: const AlwaysStoppedAnimation(0), child: icon);
      // фактически — AnimationController rotate 360° 600ms
    }

    return Container(
      padding: EdgeInsets.symmetric(
        horizontal: large ? 16 : 10, vertical: large ? 10 : 6),
      decoration: BoxDecoration(
        color: bg,
        borderRadius: BorderRadius.circular(large ? 12 : 999),
      ),
      child: Row(mainAxisSize: MainAxisSize.min, children: [
        icon,
        const SizedBox(width: 6),
        Text(label,
          style: (large ? Theme.of(c).textTheme.titleLarge
                        : Theme.of(c).textTheme.labelLarge)!
              .copyWith(color: textColor, fontFeatures: const [
                FontFeature.tabularFigures()])),
      ]),
    );
  }
}
```

> ⚠️ `FreezeChip` — deprecated имя предыдущей версии (snowflake/❄ холд-метафора). Сохранять как typedef-alias на `DepositChip` на 1 версию для миграции, затем удалить.

### PostomatCard

Карточка постамата для peek-sheet и результатов поиска (экраны 4, 5).

```dart
class PostomatCard extends StatelessWidget {
  final Postomat data;
  final VoidCallback? onTap;
  const PostomatCard({super.key, required this.data, this.onTap});
  // image 56x56, title title-md, address body-md slate-11,
  // availability badge (green/amber/slate)
}
```

### EquipmentCard

Карточка оборудования для caroseli и каталога (экраны 5, 3).

```dart
class EquipmentCard extends StatelessWidget {
  final Equipment data;
  // 160x220, hero image 16:9, title title-lg,
  // price/day in body-lg bold, DepositChip(deposit) снизу
}
```

### RentalTimer

Таймер оставшегося времени (экран 11). Обновление 1×/мин, не посекундно.

```dart
class RentalTimer extends StatefulWidget {
  final DateTime endsAt;
  final TextStyle? style; // default display-lg Onest
  const RentalTimer({super.key, required this.endsAt, this.style});
}
class _RentalTimerState extends State<RentalTimer> {
  Timer? _t;
  @override void initState() {
    super.initState();
    _t = Timer.periodic(const Duration(minutes: 1), (_) => setState((){}));
  }
  @override void dispose() { _t?.cancel(); super.dispose(); }
  // renders "2 ч 15 мин" in tabular, uses formatDuration(ru)
}
```

### GuidedPhotoOverlay

Ghost-frame + checklist для photo capture (экран 10).

```dart
class GuidedPhotoOverlay extends StatelessWidget {
  final List<PhotoStep> steps;          // 8 ракурсов
  final int currentIndex;
  final String? blurWarning;            // ML Kit hint
  final VoidCallback onShutter;
  final String? referenceThumbUrl;
  // renders: ghost SVG overlay, hint, reference thumb, checklist row, shutter
}
```

### BleSignalIndicator

Apple-Find-My-подобная визуализация BLE (экран 8).

```dart
class BleSignalIndicator extends StatelessWidget {
  final BleState state;  // searching | detected | connecting | opened | failed
  final double? distanceMeters;
  final VoidCallback onManualPin;
  // pulse ring (lottie/custom painter), progress ring, checkmark
}
```

### ShelfMapView

Схема стеллажа (1×N или 2×N, 16–24 полки) с подсветкой целевой полки. Заменяет устаревший «grid 6×4 ячеек». Появляется в mobile после BLE proximity-confirm (экран 8 → ShelfMapView) и в админке (экран постамата).

```dart
class ShelfMapView extends StatelessWidget {
  final StallageLayout layout;      // rows × cols (обычно 1×16..24 или 2×12)
  final int targetShelfNumber;      // пульсирующая полка-цель
  final Map<int, ShelfState> states; // occupied | free | strapFault | unavailable | target
  final void Function(int shelfNumber)? onTap;
  // Рендерит vertical rack-иллюстрацию; цвет полки:
  //  target → iris-9 pulse 1400ms, free → success-3, occupied → slate-3,
  //  strapFault → warning-9, unavailable → slate-8 diagonal hatch.
  // A11y: каждая полка — Semantics(label: "Полка 7, целевая, пульсирует").
}
```

### ShelfStrapInstruction

Bottom-sheet overlay с анимированной микро-иллюстрацией «отстегните / закрепите ремень». Reduce-motion → статичная схема + текст. Заменяет несуществующее событие «дверца закрылась».

```dart
class ShelfStrapInstruction extends StatelessWidget {
  final StrapMode mode;             // unstrap (pickup) | strap (return)
  final int shelfNumber;
  final VoidCallback onDone;        // «Я забрал» / «Закрепил — сделать фото»
  // Lottie-анимация 3 сек loop: рука, карабин, щелчок.
  // Микрокопи unstrap: «Полка 7 — отстегните ремень и заберите инструмент»
  // Микрокопи strap:   «Закрепите ремнём до щелчка. Инструмент не должен болтаться.»
}
```

### CrossReturnBanner

Бейдж на экране активной аренды и на карточке оборудования: «Можно вернуть в любой из N стеллажей сети». TTL-reserve 45 мин при выборе альтернативного стеллажа (из B6).

```dart
class CrossReturnBanner extends StatelessWidget {
  final int networkStallageCount;
  final VoidCallback onTapShowAlternatives;
  // chip iris-3 bg iris-11 text, icon swap_horiz.
}
```

### CsbpQrSheet

Bottom-sheet с QR СБП и deep-links в банки (экран 7 → детали).

```dart
class CsbpQrSheet extends StatelessWidget {
  final String qrData;
  final int amountKopecks;
  final List<BankDeepLink> banks;
  // grid банков + «Другой банк», таймер ожидания "0:45"
}
```

### PrimaryCta

Основная кнопка с опциональной суммой (везде).

```dart
class PrimaryCta extends StatelessWidget {
  final String label;
  final int? amountKopecks;           // если не null — показывается в label
  final int? depositKopecks;          // «+ Залог 3000 ₽ ↻»
  final VoidCallback? onPressed;
  final bool loading;

  @override
  Widget build(BuildContext c) {
    final scheme = Theme.of(c).colorScheme;
    return SizedBox(
      height: 56, width: double.infinity,
      child: FilledButton(
        style: FilledButton.styleFrom(
          backgroundColor: scheme.primary,
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)),
        ),
        onPressed: loading ? null : onPressed,
        child: loading
          ? const SizedBox(
              width: 24, height: 24,
              child: CircularProgressIndicator(strokeWidth: 2, color: Colors.white))
          : Text(_buildLabel(), style: Theme.of(c).textTheme.labelLarge!
              .copyWith(color: Colors.white, fontSize: 16)),
      ),
    );
  }

  String _buildLabel() {
    final sb = StringBuffer(label);
    if (amountKopecks != null) sb.write(' ${formatMoney(amountKopecks!)}');
    if (depositKopecks != null) {
      sb.write(' + Залог ${formatMoney(depositKopecks!)} ₽ ↻');
    }
    return sb.toString();
  }
}
```

---

## Checklist соответствия 12-success-criteria (сквозной)

- T1-T8 — trust-signals распределены по экранам 1, 2, 6, 7, 12, 13, 14, 15.
- F1-F10 — fear-removal реализован через return-cycle (↻), explainer, fallback, SLA.
- M1-M12 — mobile-patterns соблюдены (map+sheet, M3 Banner, Onest hero, группировка).
- V1-V9 — visual tokens (iris, return/jade, Onest, Inter, JetBrains Mono); freeze оставлен как legacy для статуса «недоступно».
- S1-S6 — system-constraints (warm bg, не скрываем пустые, двойная сумма на CTA, чеклист, timeline).
- A1-A2 — a11y (два пути входа, reduce-motion).

Все mapping см. в блоках «Критерии» каждого экрана.
