# Визуальный язык Клиент оформлен по образцу Snowball (сервис учёта инвестиций): графитово-фиолетовые поверхности, один яркий голубой акцент, плоские скруглённые карточки без рамки, заливные поля ввода, навигация вкладками сверху. Раньше был другой язык (сине-индиго, боковой сайдбар по референсу Grimmory) — он заменён целиком, кроме доменных экранов, которые сохранили свою раскладку и просто подхватили новые токены. Одна тема на обе яркости: форма карточек, акцент и поведение навигации одинаковы, различаются только тона поверхностей. Приложение живёт на вебе, Linux, Windows и Android, и тема переключается в Настройках (`themeModeProvider`) — светлая версия не должна выглядеть недоделанной. ## Токены: `core/theme/app_theme.dart` `AppTheme.light()` / `AppTheme.dark()` строятся одной функцией `_build(Brightness)`. - **Акцент** — `AppTheme.seed = 0xFF14AFFF` (тот же, что `ChartColors.slot1Blue`, главный ряд графиков). В светлой теме `primary` чуть темнее (`0xFF0A98E6`) ради контраста на белом. - **Тёмные поверхности** заданы явно поверх `ColorScheme.fromSeed`, потому что тонировка Material 3 даёт синий, а не графитово-фиолетовый: `surface` `#25252F` (фон страницы) → `surfaceContainerLowest` `#1F1F28` (верхняя панель) → `surfaceContainer` `#2F2F3C` (карточки) → `surfaceContainerHigh` `#3A3A49` (поля ввода, вторичные кнопки) → `surfaceContainerHighest` `#474757` (активная «таблетка» навигации). - **Плюс и минус** — `ChartColors.gain` (мятный `#3DDC97`) и `ChartColors.loss` (коралловый `#F26B6B`); `signColor` (`portfolio/labels.dart`) возвращает именно их. Категориальные цвета графиков (`slot1…slot5`) не менялись. - **`cardTheme`** — радиус 12, `elevation: 0`; в тёмной теме без рамки, в светлой с тонкой `outlineVariant`. Глобальный токен: меняет вид `Card` везде. - **`inputDecorationTheme`** — заливка `surfaceContainerHigh`, без обводки, радиус 8, акцентная рамка в фокусе. Действует на все формы и диалоги без правки экранов. - Кнопки (радиус 8), `tabBarTheme`, `dialogTheme`, `popupMenuTheme`, `chipTheme` — из тех же токенов. Все цвета берутся из `ColorScheme` или `ChartColors`; хардкод вне них — только градиент логотипа. ## Навигация: верхняя панель `features/shell/top_nav.dart` (`TopNav`) показывается от 600 px и шире; уже 600 — нижний `NavigationBar` с «Ещё» (как раньше). Список направлений — `nav_destinations.dart`. - **Слева** знак сервиса (`core/widgets/service_mark.dart`, тот же рисунок, что `web/favicon.svg`: диск с градиентом от акцента к фиолетовому и три растущих столбца; тап ведёт на Обзор) и четыре основные вкладки-«таблетки»: Обзор, Аналитика, Портфель, Счета (порядок как в Snowball). Экраны «Операции» (События, Импорт, Потоки, Категории, Операции, Правила) собраны в выпадающем меню «Операции ▾»; на нём же подписано имя открытого экрана. - **Справа** «Добавить» (событие, брокерский счёт, портфель, отчёт брокера), значок Здоровья со счётчиком замечаний (`dataQualityProvider`), Настройки, аватар с меню (email, «Выйти»). - До 900 px «Добавить» сжимается до иконки. - Контент центрируется и не шире 1440 px. `NavSidebar` и `NavigationRail` удалены. Наблюдение за `dataQualityProvider` и `meProvider` остаётся в `TopNav`, значит эти запросы уходят при каждом заходе, а не только на трёх экранах; для одного пользователя это не проблема, но стоит знать при правке `core/cache/*`. ## Экраны - **Обзор** — сверху сетка карточек «Портфели»: по одной на `all`, портфель и счёт (`home/scope_cards.dart`). В карточке: стоимость, прибыль (₽ и %), за день, доходность (XIRR с начала), пассивный доход (% и ₽ в год). Один запрос `GET /analytics/overview`; тап открывает Портфель в этом скоупе. Ниже прежние блоки (капитал, месяц, запас хода, графики). - **Аналитика** — общая полоса вкладок под верхней панелью (`shell/analytics_tabs.dart`): Общее, Дивиденды, Ребалансировка, Цели, Налоги, Портфели. Каждая вкладка — свой маршрут (`/analytics`, `/income`, …), остаются ссылаемыми. «Общее» (`AnalyticsHubPage`) — четыре плитки (Стоимость, Прибыль, Доходность, Пассивный доход; `portfolio/overview_tiles.dart`), график стоимости, доходность, бенчмарки. На телефоне вместо полосы остаётся список разделов. - **Портфель** — таблица активов (`portfolio/holdings_table.dart`) с вкладками-пресетами колонок (Мои активы, Общее, Дивиденды, Прибыль, Облигации), поиском и двухстрочными ячейками (сумма и, ниже, цена за штуку или доля). Колонки растягиваются на карточку, при нехватке места таблица прокручивается вбок. Неизвестная величина — «—», а не «0 ₽»; нулевые дивиденды тоже «—». `HoldingsTab` принимает `HoldingsSections` (`all`, `table`, `overview`), чтобы Портфель и «Аналитика → Общее» брали одни и те же провайдеры и не могли разойтись в числах. - **Счета** — один компактный список (`accounts/accounts_page.dart`): поиск, чипы статуса с числами (Все / Активные / Отключённые / Архивные) и типа (ликвидные, сбережения, инвестиции, долги). В строке — источник (ZenMoney, T-Invest, отчёты), тип-«таблетка» с меню, баланс или стоимость, переключатели «В капитал» и «Активен». Отключённые и архивные приглушены и идут в конце. Чекбоксы включают панель массовых действий (отключить, включить, сменить тип, учёт в капитале) — по одному запросу на счёт и один пересчёт метрик на всю пачку (`accounts/actions.dart`). До 880 px строка двухстрочная. - **Настройки** — карточка с вкладками сверху (Аккаунт, Отображение, Сервер) и меню разделов слева; до 720 px меню превращается в ряд чипов. ## Что не менялось Экраны Счета, События, Импорт, Потоки, Категории, Операции, Правила, Здоровье, Цели, Налоги, Ребалансировка, карточка инструмента сохранили раскладку и подхватили токены (карточки, поля, кнопки, вкладки). Переделывать их по образцу Snowball можно тем же способом: экран за экраном. ## Иконки активов `AssetIcon` (`core/widgets/asset_icon.dart`) — круг с логотипом эмитента; стоит в колонке «Актив» таблицы и в шапке карточки инструмента. Логотип берётся из брендовых данных T-Invest: синк раскладывает `brand.logo_name` и `brand.logo_base_color` по `instrument.logo_name` / `logo_color` (сначала по `tinvest_uid`, потом по ISIN — так подхватываются и бумаги из отчётов Сбера и ВТБ; заполненное не перезаписывается). API отдаёт готовый `logo_url` (`branding.logo_url`, публичный CDN `invest-brands.cdn-tinkoff.ru`, 160 px, без ключа, с `access-control-allow-origin: *`) и `logo_color`. Нет логотипа, он ещё грузится или не загрузился — круг цвета бренда (нейтральный, если цвета нет) с иконкой класса актива (`assetClassIcon`), так что подписи по типу остаются запасным вариантом. ## Подсказки к терминам Рядом с терминами и аббревиатурами (XIRR, TWR, НКД, ЛДВ, «Запас хода», «Пассивный доход» и т. д.) стоит приглушённый значок «?»: на вебе и десктопе подсказка появляется по наведению, на телефоне по тапу (`core/widgets/help_tip.dart`, `HelpTip`). - **`TermLabel(text)`** — подпись, которая сама ищет объяснение в словаре (`core/glossary.dart`, `glossaryHint`) по тексту подписи (без учёта регистра и «ё»). Нет записи — обычный `Text`, поэтому его безопасно ставить под любую подпись. Параметр `hint` перекрывает словарь там, где одно слово значит разное (например, «Прибыль» в налогах). - `StatTile` и `SectionCard` уже рисуют подписи через `TermLabel`, поэтому Обзор, доходы, цели и налоги получили подсказки без правки экранов; заголовки таблиц (Портфель, Налоги), карточки на Обзоре, плитки Аналитики, детали события и карточка инструмента — тоже. - **Новый термин** — добавить строку в `_entries` словаря; определения сверяйте с кодом аналитики (`analytics/*.py`), а не с общими представлениями: например, запас хода считается от «обычного» расхода за три последних полных месяца и не включает инвестиции.