:root{--bg:#f6f7f9;--card:#fff;--ink:#1c2330;--mut:#68738a;--line:#e4e7ee;--acc:#2f6df6;--ok:#1d9a6c;--bad:#d64545;--chip:#eef1f7}
@media (prefers-color-scheme:dark){:root{--bg:#12151c;--card:#1a1f2a;--ink:#e8ebf2;--mut:#93a0b8;--line:#2a3140;--chip:#232a38}}
*{box-sizing:border-box}body{margin:0;font:14px/1.45 -apple-system,'Segoe UI',Roboto,sans-serif;background:var(--bg);color:var(--ink)}
header{padding:18px 24px 10px;display:flex;align-items:baseline;gap:16px;flex-wrap:wrap}
h1{font-size:19px;margin:0}
#syncInfo{color:var(--mut);font-size:12.5px}
/* Логин в шапке и «Выход» (сброс Bearer-токена в auth_gate.dart, не переход
   по ссылке). Правый край держит `margin-left:auto` у `.me-login`, а не у
   «Выхода»: логин рисуется ВСЕГДА, в том числе пустым, поэтому прижим на нём
   не пропадает — иначе «Выход» прыгал бы к середине, пока логин не приехал.
   Переносу на узких экранах это не мешает (header уже flex-wrap).
   Приглушённый цвет — та же ненавязчивость, что у #syncInfo рядом. */
.me-login{margin-left:auto;color:var(--mut);font-size:12.5px}
.logout-link{margin-left:12px;color:var(--mut);font-size:12.5px;text-decoration:none;cursor:pointer}
.logout-link:hover{color:var(--ink);text-decoration:underline}
/* Экран входа (login_page.dart) — центрированная карточка формы, как у
   остальных пустых/переходных состояний приложения, но отдельная от них: до
   входа никакого другого содержимого (шапки, вкладок) на странице ещё нет. */
.login-page{min-height:100vh;display:flex;align-items:center;justify-content:center;padding:24px}
.login-form{width:100%;max-width:320px;background:var(--card);border:1px solid var(--line);border-radius:12px;padding:24px;display:flex;flex-direction:column;gap:14px}
.login-form h1{font-size:18px;margin:0 0 4px}
.login-field{display:flex;flex-direction:column;gap:6px;font-size:13px;color:var(--mut)}
.login-field input{padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:var(--bg);color:var(--ink);font:inherit}
.login-form button{padding:9px;border:0;border-radius:8px;background:var(--acc);color:#fff;font:inherit;font-weight:600;cursor:pointer}
.login-form button:disabled{opacity:.6;cursor:default}
.login-error{color:var(--bad);font-size:12.5px}
/* flex-wrap: с шестью вкладками (добавилась «Задачи») ряд у admin шире узкого
   экрана — на 500px он ~557px и без переноса обрезался бы (правка координатора
   18.09.2026). */
nav{display:flex;gap:4px;padding:0 24px;flex-wrap:wrap}
nav button{padding:8px 16px;border:1px solid var(--line);border-bottom:none;border-radius:10px 10px 0 0;background:var(--bg);color:var(--mut);font:inherit;cursor:pointer}
nav button.active{background:var(--card);color:var(--ink);font-weight:600}
.filters{display:flex;flex-wrap:wrap;gap:8px;padding:12px 24px;position:sticky;top:0;background:var(--bg);z-index:5;border-bottom:1px solid var(--line)}
.filters input,.filters select{padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit}
.filters input[type=date]{width:150px}
/* Галочка «только с разбором ИИ». Общее правило выше даёт полям рамку и
   отступы — чекбоксу они не нужны, он от них раздувается и теряет вид
   флажка. */
.filter-check{display:inline-flex;align-items:center;gap:6px;white-space:nowrap;color:var(--mut);font-size:13px;cursor:pointer;padding:0 4px}
.filter-check input[type=checkbox]{padding:0;width:15px;height:15px;border-radius:3px;accent-color:var(--acc);cursor:pointer}
/* Выбор объектов (object_picker.dart, спека 2026-09-17-objects-design, п. 6).
   Каждый класс ниже обязан иметь правило: класс без правила рисуется
   браузерным умолчанием — так уже уехала на прод кнопка разбора (14.09).
   Кнопка «Объекты: …» повторяет поле .filters select рядом: это такой же
   контрол панели, а не действие. Шорткат font с inherit не писать —
   `font:13px inherit` невалиден и отбрасывается целиком. */
.obj-toggle{padding:7px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;cursor:pointer}
.obj-toggle[aria-expanded=true]{border-color:var(--acc)}
/* Панель галочек — в потоке, последней строкой липкой полосы фильтров
   (order + flex-basis:100% действуют только на прямых детей .filters — поэтому
   ObjectPicker отдаёт фрагмент, а не обёртку). Не выпадающий слой поверх ленты:
   у правого края на узком экране он уехал бы за край. Высота ограничена и в vh:
   липкая полоса с открытой панелью не должна стать выше низкого окна. */
.obj-panel{order:1;flex-basis:100%;max-height:min(240px,35vh);overflow:auto;display:flex;flex-direction:column;align-items:flex-start;gap:4px;padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card)}
/* Длинное название объекта переносится внутри панели, а не распирает её
   вбок: общее правило .filter-check держит галочку одной строкой. */
.obj-panel .filter-check{white-space:normal;align-items:flex-start}
.obj-panel .filter-check input[type=checkbox]{flex:none;margin-top:2px}
.obj-panel .filter-check input[type=checkbox]:disabled{cursor:default}
/* Поиск по галочкам — на ширину панели, но не шире разумного на широком экране. */
.obj-panel input[type=search]{width:100%;max-width:320px}
/* «Отметить все» — пунктирный чип, как «+ комментарий»: подсказка-действие
   над списком, а не главная кнопка. */
.obj-all{padding:3px 8px;border:1px dashed var(--line);border-radius:20px;background:transparent;color:var(--mut);font:inherit;font-size:12px;cursor:pointer}
.obj-all:hover{color:var(--ink);border-color:var(--mut)}
.obj-all:disabled{opacity:.6;cursor:default}
/* Оговорки и подсказки панели — приглушённо и мелко, как .manual-note. */
.obj-note{color:var(--mut);font-size:12px}
/* «Звонок не прочитать» — приглушённее обычного раскрытия: это объяснение
   отсутствия, а не содержимое, и оно стоит у подавляющего большинства
   звонков, потому что ИИ разбирает лишь выборку, а другого источника текста
   на этом развёртывании нет (см. transcript_reason.dart). */
.muted-details>summary{color:var(--mut)}
/* «+ комментарий» — вид пунктирной подсказки, как у «+ тег» рядом: это одна
   и та же операция «добавить пометку», и выглядеть они должны одинаково. */
.row2 button.comment-add{padding:3px 8px;border:1px dashed var(--line);border-radius:20px;background:transparent;color:var(--mut);font:12px inherit;cursor:pointer}
.row2 button.comment-add:hover{color:var(--ink);border-color:var(--mut)}
/* «Разобрать звонок» — тот же чип, что «+ тег»/«+ комментарий» рядом, но
   сплошной рамкой: это не пометка, а действие, которое тратит деньги. Стоит
   в ряду действий, а не отдельной строкой — иначе браузерная кнопка по
   умолчанию рвала бы вёрстку карточки (замечание владельца 14.09.2026). */
.row2 button.analyze-now{margin-left:auto;padding:3px 10px;border:1px solid var(--line);border-radius:20px;background:var(--chip);color:var(--ink);font:12px inherit;cursor:pointer}
.row2 button.analyze-now:hover{border-color:var(--acc);color:var(--acc)}
.row2 button.analyze-now:disabled{opacity:.6;cursor:default}
/* Ход и исход ручного разбора — приглушённой строкой под рядом действий. */
.manual-note{margin:6px 0 0;font-size:12.5px;color:var(--mut)}
.manual-note.bad{color:var(--bad)}
/* Переключатель сводной таблицы на «Анализе». Стоит над таблицей, чтобы до
   него не пришлось прокручивать те самые экраны, ради которых он заведён. */
.agg-toggle{margin:0 24px 10px;padding:6px 12px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;font-size:13px;cursor:pointer}
.agg-toggle:hover{border-color:var(--mut)}
/* «найти такие звонки» — со следующей строки, а не в конец предложения:
   замечание бывает длинным, и ссылка, приклеенная к его хвосту, теряется. */
.remark-link{display:block;margin-top:4px;padding:0;border:0;background:none;color:var(--acc);font:12px inherit;text-align:left;cursor:pointer}
.remark-link:hover{text-decoration:underline}
#stats{padding:8px 24px;color:var(--mut);font-size:12.5px}
.feed{padding:0 24px 40px;display:flex;flex-direction:column;gap:10px;max-width:1200px}
.call{background:var(--card);border:1px solid var(--line);border-left:4px solid var(--line);border-radius:12px;padding:12px 16px}
/* цвет левой полосы карточки по статусу (#8) */
.call.st-listened{border-left-color:#1d9a6c}
.call.st-new{border-left-color:#9aa4b8}
.call.st-attention{border-left-color:#d64545}
/* Статус, которого нет в текущем списке: исторические пометки упразднённого
   «ОК» из meta.json. Отдельный цвет, чтобы такой звонок не выглядел как
   непрослушанный — см. unknownStatusClass в domain/call_status.dart. */
.call.st-unknown{border-left-color:#b08a2e}
.dayhead{font-size:13px;font-weight:700;color:var(--mut);margin:16px 0 2px}
.dayhead:first-child{margin-top:2px}
.dayhead .wd{font-weight:400}
.row1{display:flex;flex-wrap:wrap;gap:6px 14px;align-items:baseline}
.dt{color:var(--mut);font-variant-numeric:tabular-nums}.obj{font-weight:600}
/* Название объекта Alloka рядом с меткой клиента (спека объектов, п. 1) —
   обычным начертанием: жирная метка клиента остаётся главной. Длинное
   название переносится, а не распирает первую строку карточки. */
.objname{font-weight:400;overflow-wrap:anywhere}
.phone{font-variant-numeric:tabular-nums}
.badge{font-size:11.5px;padding:2px 8px;border-radius:20px;background:var(--chip)}
.badge.ok{color:var(--ok)}.badge.bad{color:var(--bad)}
.dur{color:var(--mut)}
.summary{color:var(--mut);margin:6px 0 0;font-size:13px;max-width:80ch}
.row2{display:flex;flex-wrap:wrap;gap:10px;align-items:center;margin-top:8px}
.row2 select,.row2 input{padding:5px 8px;border:1px solid var(--line);border-radius:7px;background:var(--bg);color:var(--ink);font:13px inherit}
.row2 input.comment{flex:1;min-width:180px}
.tag{background:var(--chip);border-radius:20px;padding:2px 9px;font-size:12px}
/* тег-чип в карточке кликабелен (фильтр ленты, #6); крестик удаления — своя зона клика */
.tags-wrap .tag{display:inline-flex;align-items:center;gap:5px;cursor:pointer}
.tags-wrap .tag-x{cursor:pointer;color:var(--mut);font-style:normal}
.tags-wrap .tag-x:hover{color:var(--bad)}
.tags-wrap input.tag-add{width:84px;padding:3px 8px;border:1px dashed var(--line);border-radius:20px;background:transparent;color:var(--ink);font:12px inherit}
#fTagActive{cursor:pointer;white-space:nowrap}
/* свой лёгкий плеер (#2): играем только по клику, длительность известна сразу с сервера */
.player{display:flex;align-items:center;gap:8px}
.playBtn{width:28px;height:28px;border-radius:50%;border:1px solid var(--line);background:var(--card);color:var(--ink);font:13px inherit;cursor:pointer;flex:none}
.playBtn:disabled{cursor:default;opacity:.6}
.bar{width:140px;height:6px;border-radius:4px;background:var(--chip);cursor:pointer;position:relative}
.fill{height:100%;border-radius:4px;background:var(--acc);width:0}
.player .time{color:var(--mut);font-variant-numeric:tabular-nums;font-size:12.5px}
.player.player-error .time{color:var(--bad)}
.score-badge{color:#fff;font-weight:700;font-size:12px;padding:2px 9px;border-radius:20px;min-width:22px;text-align:center}
.gist{font-weight:600}
.empty{color:var(--mut);padding:30px 24px}
table{border-collapse:collapse;margin:16px 24px;background:var(--card);border:1px solid var(--line);border-radius:12px;overflow:hidden}
th,td{padding:10px 16px;text-align:left;border-bottom:1px solid var(--line);font-variant-numeric:tabular-nums}
th{background:var(--chip);font-size:12.5px;color:var(--mut)}
tr:last-child td{border-bottom:none}
/* Строка прогресса стояла без стилей вовсе и потому прижималась к краю окна,
   тогда как соседний #syncErrors и таблица ниже отступают на 24px. */
#syncProgress{margin:12px 24px 0;color:var(--mut);font-size:12.5px}
#syncProgress:empty{margin:0}
#syncErrors{margin:0 24px;color:var(--bad);font-size:12.5px;white-space:pre-line}
/* отступ как у остальных блоков вкладки — раньше блок сидел вплотную к краю (#7) */
/* Замечание модели — свободный текст; в узкой колонке он растянул бы строку
   таблицы, поэтому ограничиваем ширину и приглушаем, как вспомогательный. */
.agg-comment{max-width:38ch;color:var(--mut);font-variant-numeric:normal}
/* «Общий совет» — свободный текст сводки клиента; та же ширина, что у
   agg-comment, чтобы длинный совет не растягивал строку таблицы. Не приглушён:
   это ключевая колонка, а не вспомогательная. */
.agg-summary{max-width:44ch;color:var(--ink);font-variant-numeric:normal}
/* Блоки советов над таблицами «Статистики» (#statsAdvice) и «Анализа»
   (#analysisAttention) — отступ 24px по краям, как у остального содержимого
   вкладки. Без него блок прижимался к краю окна (фидбек Михаила 21.08) — та же
   болезнь, что была у #syncProgress выше. */
#statsAdvice,#analysisAttention{padding:6px 24px 10px}
/* Пустой блок советов — настоящий `div` без детей (так требует ловушка
   «Биллинга» 18.09), поэтому его отступы надо гасить явно. Оба блока: у
   «Анализа» пустой `div` появился позже, и без второго селектора он давал
   16px пустоты между сводкой и переключателем таблицы. */
#statsAdvice:empty,#analysisAttention:empty{display:none}
/* Секция вкладки «Статистика»: заголовок, пояснение, таблица. Отступы
   повторяют `table{margin:16px 24px}`, чтобы заголовок встал над таблицей, а
   не рядом с ней. Пустая секция (нечего показывать) ничего не занимает. */
.stats-section h3{margin:16px 24px 0;font-size:14px}
.stats-section p{margin:2px 24px 0}
.stats-section table{margin-top:8px}
.stats-section:empty{display:none}
/* Класс `.muted` стоит в разметке с самого переноса фронта, но правила у него
   не было нигде. Оба места, где он применён, — пояснение под «Требуют
   внимания» на «Статистике» и такое же на «Анализе» — выезжали на парном
   правиле по id (`#statsAdvice p,#analysisAttention p` ниже), поэтому
   сломанным ничего и не выглядело. Правило теперь есть, значениями один в
   один с тем id-правилом (оно специфичнее и продолжает выигрывать): класс
   перестал быть ловушкой «новый класс без правила в styles.css», а выглядит
   всё по-прежнему. */
.muted{color:var(--mut);font-size:12.5px}
.advice-group{margin-bottom:8px}
#statsAdvice h3,#analysisAttention h3{font-size:14px;margin:10px 0 2px}
#statsAdvice p,#analysisAttention p{margin:0 0 6px;color:var(--mut);font-size:12.5px}
#statsAdvice ul,#analysisAttention ul{margin:0;padding-left:20px}
#statsAdvice li,#analysisAttention li{margin:2px 0}
#analysisSummary{padding:10px 24px 4px}
#analysisSummary p{margin:0 0 10px;max-width:80ch}
.foot-note{color:var(--mut);font-size:12px;margin:-8px 24px 16px;max-width:80ch}
/* выбор недели на отчётных вкладках и выбор месяца на «Биллинге»
   (billing_page.dart) — один вид на оба; отступ по краям — как у таблиц ниже */
#weekPicker,#monthPicker{display:flex;align-items:center;gap:8px;margin:12px 24px 0}
#weekPicker button,#monthPicker button{padding:4px 10px;border:1px solid var(--line);background:var(--card);border-radius:8px;cursor:pointer}
#weekPicker button.active{background:var(--chip);font-weight:600}
/* Погашенная стрелка «вперёд» на текущей неделе или текущем месяце: дальше
   данных нет, и кнопка должна выглядеть недоступной, а не молча не срабатывать. */
#weekPicker button:disabled,#monthPicker button:disabled{opacity:.4;cursor:default}
/* Подпись постоянной ширины: без неё стрелки прыгали бы при смене «3 — 9 авг»
   на «27 июл — 2 авг» или «май 2026» на «сентябрь 2026». */
#weekLabel,#monthLabel{min-width:200px;text-align:center;font-variant-numeric:tabular-nums}
/* Вкладка «Чаты» (chats_page.dart) — реплики диалога Carrot внутри карточки
   `.call`. Своя колонка с отступом, а не `.summary`: реплик в диалоге может
   быть много, и им нужен читаемый интервал строк, а не приглушённый цвет
   вспомогательного текста. */
.chat-messages{display:flex;flex-direction:column;gap:2px;margin:8px 0 0}
.chat-line{margin:0;font-size:13px;line-height:1.5}
.chat-line b{font-weight:600}
/* Вкладка «Задачи» (tasks_page.dart, спека 2026-09-16-tasks-tab-design). Каждый
   класс ниже обязан иметь правило: без него строка рисовалась бы браузерными
   умолчаниями — дефект 14.09.2026, из-за которого кнопка разбора стала серой
   браузерной кнопкой. Отступ контейнера — 24px, как у ленты и таблиц. */
#tasks{padding:0 24px 40px;max-width:1200px}
/* Пустое состояние внутри вкладки: свои 24px по краям уже даёт #tasks, иначе
   отступ удвоился бы относительно соседних строк. */
#tasks .empty{padding:30px 0}
/* Над списком: «Только невыполненные» и счётчик — одной строкой, с переносом
   на узком экране. Сама галочка берёт вид .filter-check панели фильтров. */
.task-toolbar{display:flex;align-items:center;gap:14px;flex-wrap:wrap;margin:12px 0 10px}
/* Список задач — колонка карточек с тем же зазором, что у ленты. */
.task-list{display:flex;flex-direction:column;gap:8px}
/* Строка задачи — карточка без левой полосы статуса: у задачи нет статуса
   контроля, есть только галочка. */
.task{background:var(--card);border:1px solid var(--line);border-radius:12px;padding:10px 16px}
/* Первая строка: чекбокс, текст, чип. Всё прижато к верху: у длинного
   обещания в несколько строк чекбокс и чип остаются у первой строки, а не
   уезжают в середину абзаца. Чекбокс не растягивается. */
.task-head{display:flex;align-items:flex-start;gap:10px;flex-wrap:wrap}
.task-head input[type=checkbox]{width:16px;height:16px;margin:2px 0 0;accent-color:var(--acc);cursor:pointer;flex:none}
/* Текст обещания занимает остаток строки; чип уходит вправо и переносится,
   а не сжимает текст до нечитаемого. */
.task-text{flex:1;min-width:220px}
/* Выполненная задача зачёркнута и приглушена — просьба владельца: «зачёркивать
   по мере выполнения». */
.task.task-done .task-text{text-decoration:line-through;color:var(--mut)}
/* Чип «кто обещал» — вид .tag (фон и скругление оттуда), но без переноса
   внутри и приглушённым текстом: это происхождение, а не пометка. */
.task-who{white-space:nowrap;color:var(--mut)}
/* Вторая строка — клиент, дата звонка, кто и когда отметил; сдвиг на ширину
   чекбокса, чтобы колонка текста читалась ровно. */
.task-meta{display:flex;flex-wrap:wrap;gap:6px 14px;margin:4px 0 0 26px;font-size:12.5px}
/* Раскрытие «Звонок» — под текстом, с тем же сдвигом. */
.task>details.summary{margin-left:26px}
/* «Показать ещё» — спокойная кнопка в стиле переключателя «Анализа», не
   браузерная по умолчанию. */
.task-more{margin:12px 0 0;padding:6px 14px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;font-size:13px;cursor:pointer}
.task-more:hover{border-color:var(--mut)}
.task-more:disabled{opacity:.6;cursor:default}
/* Оговорка про выборку под списком (решение владельца 2026-09-17) — одно
   предложение одной строкой, приглушённо и мелко, как .foot-note, но без её
   отрицательного отступа (над ней не таблица, а список) и без ограничения
   ширины: фраза короткая и на обычном экране встаёт в строку целиком,
   переносится только на узком. */
.task-caveat{margin:14px 0 0;color:var(--mut);font-size:12px}
/* Вкладка «Биллинг» (billing_page.dart, спека 2026-09-17-billing-tab-design).
   Каждый селектор ниже обязан иметь правило: без него элемент рисуется
   браузерными умолчаниями, а тесты этого не видят. Таблицы берут общее
   оформление table/th/td; строка-пояснение под таблицей — существующий
   .foot-note, как под таблицей «Анализа». */
/* Блок тарифа (billing_page.dart, _tariffBlock): название, расход, дата
   возобновления, переключатель и «Пополнить баланс». Отступ 24px по краям. */
#billingTariff{margin:14px 24px 0;padding:12px 14px;border:1px solid var(--line);border-radius:8px;max-width:640px}
#billingTariff .tariff-title{font-size:15px;font-weight:600}
#billingTariff .tariff-usage,#billingTariff .tariff-renewal{margin-top:4px;font-variant-numeric:tabular-nums}
#billingTariff .tariff-renewal{color:var(--mut)}
#billingTariff .tariff-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:10px}
/* Переключатель и отмена — настоящие кнопки проекта, не браузерные: без правила
   они рисовались системной серой кнопкой системным шрифтом, и это сидело бы
   рядом со стилизованными стрелками месяца (#monthPicker button, выше) на той
   же вкладке. Оформление — как у .task-more, ближайшей кнопки того же вида.
   Правило `button.link` ниже относится только к «Пополнить баланс». */
#billingTariff #tariffSwitch,#billingTariff #tariffCancel{padding:6px 14px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;font-size:13px;cursor:pointer}
#billingTariff #tariffSwitch:disabled,#billingTariff #tariffCancel:disabled{opacity:.6;cursor:default}
#billingTariff button.link{background:none;border:0;padding:0;color:inherit;text-decoration:underline;cursor:pointer;font:inherit}
#billingTariff .foot-note{margin:8px 0 0}
#billingTariff .tariff-error{margin-top:8px}
/* Карточка доли разбора (решение Миши 12.10) — рамка и отступы как у блока
   тарифа: обе карточки стоят одна под другой и обязаны выглядеть родными.
   Бегунок и кнопки — свои правила: без них браузер рисует системный ползунок и
   системную серую кнопку рядом со стилизованными стрелками месяца. */
#billingShare{margin:14px 24px 0;padding:12px 14px;border:1px solid var(--line);border-radius:8px;max-width:640px}
#billingShare .share-title{font-size:15px;font-weight:600}
#billingShare #shareSlider{display:block;width:100%;max-width:420px;margin:10px 0 2px;accent-color:var(--acc);cursor:pointer}
#billingShare #shareSlider:disabled{opacity:.6;cursor:default}
#billingShare .share-fact,#billingShare .share-scale{margin-top:4px;font-variant-numeric:tabular-nums}
#billingShare .share-scale{color:var(--mut)}
#billingShare .share-actions{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-top:10px}
#billingShare #shareApply,#billingShare #shareCancel{padding:6px 14px;border:1px solid var(--line);border-radius:8px;background:var(--card);color:var(--ink);font:inherit;font-size:13px;cursor:pointer}
#billingShare #shareApply:disabled,#billingShare #shareCancel:disabled{opacity:.6;cursor:default}
#billingShare .foot-note{margin:8px 0 0}
#billingShare .share-error{margin-top:8px}
/* Итог месяца — главное число вкладки: крупнее и плотнее приглушённых строк,
   отступ 24px по краям — как у остального содержимого. */
#billingTotal{margin:14px 24px 0;font-size:15px;font-weight:600;font-variant-numeric:tabular-nums}
/* Раздел плательщика у admin: заголовок «agency — 12 · 240 ₽» и его таблица.
   Заголовок — по краю таблицы (24px), таблица подтянута к своему заголовку. */
.billing-payer{margin-top:18px}
.billing-payer h3{margin:0 24px;font-size:14px;font-variant-numeric:tabular-nums}
.billing-payer table{margin-top:8px}
/* Разборы и суммы — вправо: разряды встают один под другим, и сумму на сотне
   строк сверяют взглядом. Только в пределах вкладки — общие таблицы не трогаем. */
#viewBilling th.num,#viewBilling td.num{text-align:right}
/* Страница условий сервиса (`web/web/terms.html`, отдельный HTML без Jaspr, но
   с этим же styles.css): служебная, читается редко — нужна читаемая колонка, а
   не украшения. Ширина ~68 знаков в строке, отступы от края на узком экране
   (padding), шрифт крупнее 14px интерфейса, потому что это сплошной текст. */
.terms-page{max-width:680px;margin:0 auto;padding:32px 24px 48px;font-size:15px;line-height:1.6}
.terms-page h1{font-size:22px;margin:0 0 6px}
.terms-page p{margin:0 0 14px}
/* Номер редакции — справка под заголовком, не часть текста условий. */
.terms-version{color:var(--mut);font-size:12.5px}
/* Регистрация (спека 2026-09-16), N1: пометки звонка без права правки —
   текстом, а не полями. Без этих правил статус выглядел бы голым словом. */
.row2 .status-ro{padding:5px 8px;border:1px solid var(--line);border-radius:7px;color:var(--mut);font-size:13px}
.row2 .comment-ro{flex:1;min-width:180px;color:var(--ink);font-size:13px}
.task-head input[type=checkbox]:disabled{cursor:not-allowed;opacity:.6}
/* Регистрация (спека 2026-09-16, §9.5): форма шире формы входа — в ней
   список объектов; «Зарегистрироваться»/«Ко входу» — ссылкой, а не второй
   синей кнопкой (общее правило .login-form button красит все кнопки). */
.login-form.register-form{max-width:420px}
.login-form button.login-switch{background:transparent;color:var(--acc);font-weight:400;padding:0}
.key-objects{display:flex;flex-direction:column;align-items:flex-start;gap:4px;max-height:min(260px,40vh);overflow:auto;padding:8px 10px;border:1px solid var(--line);border-radius:8px;background:var(--card)}
.key-objects .filter-check{white-space:normal;align-items:flex-start}
.key-objects .filter-check input[type=checkbox]{flex:none;margin-top:2px}
.key-objects-hint{color:var(--bad)}
.register-terms{white-space:normal}
.register-terms a{color:var(--acc)}

/* «Настройки импорта» → «Ключи Alloka» (спека регистрации §9). Без этих
   правил строки ключей слипаются, а кнопки-ссылки выглядят браузерными. */
#settings h2{font-size:16px;margin:18px 0 4px}
#settings h3{font-size:14px;margin:12px 0 2px;color:var(--mut)}
.key-row{display:flex;flex-direction:column;gap:6px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--card)}
.key-head,.key-actions,.key-edit{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
/* Правка — одной строкой кнопок; список объектов и поля — на всю строку. */
.key-edit>.key-objects,.key-edit>input,.key-edit>p{flex:1 1 100%;max-width:560px}
.key-label{font-weight:600}
.key-note{color:var(--mut);font-size:12.5px}
.key-edit input[type=text],.key-edit input[type=password]{padding:6px 9px;border:1px solid var(--line);border-radius:7px;background:var(--bg);color:var(--ink);font:inherit}
.keys-section button,.carrot-section button{padding:5px 12px;border:1px solid var(--line);border-radius:7px;background:var(--chip);color:var(--ink);font-family:inherit;font-size:13px;cursor:pointer}
.keys-section button.key-link{padding:0;border:0;background:transparent;color:var(--acc)}
.keys-section button:disabled{opacity:.6;cursor:default}

/* «Заявки» (спека регистрации §8): ждущая старше 14 дней — подсвечена. */
#registrations h2{font-size:16px;margin:14px 0 4px}
.reg-list{display:flex;flex-direction:column;gap:10px}
.reg-row{display:flex;flex-direction:column;gap:6px;padding:10px 12px;border:1px solid var(--line);border-radius:10px;background:var(--card)}
.reg-row.reg-line{flex-direction:row;flex-wrap:wrap;align-items:center;gap:10px}
.reg-row.reg-stale{border-color:var(--bad)}
.reg-age-stale{color:var(--bad);font-weight:600}
.reg-row .key-edit{flex-direction:row;align-items:center;font-size:13px;color:var(--mut)}
.reg-row .key-edit input{padding:5px 8px;border:1px solid var(--line);border-radius:7px;background:var(--bg);color:var(--ink);font:inherit}
#registrations button{padding:5px 12px;border:1px solid var(--line);border-radius:7px;background:var(--chip);color:var(--ink);font-family:inherit;font-size:13px;cursor:pointer}
#registrations button.key-link{padding:0;border:0;background:transparent;color:var(--acc)}
#registrations button:disabled{opacity:.6;cursor:default}
.reg-decided{margin-top:12px}
.reg-decided summary{cursor:pointer;color:var(--mut);font-size:13px}
.reg-decided .reg-row{margin-top:6px}
/* Раздел «Рекомендации» (изменение recommendations-section). Отступы по краям
   24px — как у остального содержимого вкладки; блоки подразделов повторяют
   #statsAdvice, чтобы два списка советов в сервисе выглядели одинаково. */
.recs-section{padding:6px 24px 10px}
/* Пустой подраздел — настоящий `div` без детей (ловушка «Биллинга» 18.09:
   пустой вложенный фрагмент оставляет узлы в DOM), поэтому его гасим правилом,
   а не отсутствием элемента. */
.recs-section:empty{display:none}
.recs-section h3{font-size:14px;margin:10px 0 2px}
.recs-section ul{margin:0;padding-left:20px}
#recsEmpty{padding:10px 24px;color:var(--mut);font-size:12.5px;max-width:80ch}
.recs-item{margin:6px 0;max-width:90ch;line-height:1.45}
/* Лайк подчёркивает, дизлайк зачёркивает — ровно как просил заказчик; строка
   остаётся на месте до следующей загрузки, переезд в «Задачи» делает сервер. */
.recs-liked .recs-text{text-decoration:underline;text-decoration-color:var(--ok, #2e7d32)}
/* Приглушается ТЕКСТ строки, а не вся строка: `opacity` на `li` действует на
   всё поддерево как на группу, и кнопка «Вернуть» внутри него собственным
   `opacity:1` уже не восстанавливается — а видна она нужна именно здесь. */
.recs-disliked .recs-client,.recs-disliked .recs-text,.recs-disliked .recs-channels{opacity:.55}
.recs-disliked .recs-text{text-decoration:line-through}
.recs-client{font-weight:600}
.recs-text{color:var(--ink)}
.recs-actions{display:inline-flex;gap:6px;margin-left:8px;vertical-align:baseline}
/* Кнопки: класс без правила в styles.css даёт браузерную кнопку — отдельная
   ловушка проекта. Форма повторяет .agg-toggle, размер меньше: это действие на
   строке, а не переключатель раздела. */
.recs-like,.recs-dislike,.recs-restore{padding:2px 8px;border:1px solid var(--line);border-radius:6px;background:var(--card);color:var(--ink);font:inherit;font-size:12px;cursor:pointer}
.recs-like:hover,.recs-dislike:hover,.recs-restore:hover{border-color:var(--mut)}
.recs-like[disabled],.recs-dislike[disabled],.recs-restore[disabled]{cursor:default;opacity:.5}
/* «Вернуть» — единственное действие на отклонённой строке: обводка заметнее,
   чтобы кнопка читалась рядом с приглушённым текстом. */
.recs-disliked .recs-restore{border-color:var(--mut)}
#recsNote{padding:0 24px 8px;color:var(--mut);font-size:12.5px;max-width:80ch}
/* Вкладка «Учётки» (admin). Классы без правил дали бы браузерные кнопки —
   отдельная ловушка проекта, см. соседний блок про .recs-like. */
#accountsBody{padding:6px 24px 10px}
#accountsEmpty{color:var(--mut);font-size:12.5px}
.accounts-message{color:var(--mut);font-size:12.5px;margin:4px 0 8px}

.accounts-login{font-weight:600}
.accounts-tariff{margin-right:8px}
.accounts-actions{display:inline-flex;gap:6px;vertical-align:baseline}
.accounts-switch{padding:2px 8px;border:1px solid var(--line);border-radius:6px;background:var(--card);color:var(--ink);font:inherit;font-size:12px;cursor:pointer}
.accounts-switch:hover{border-color:var(--mut)}
/* Выключена кнопка только на время запроса — чтобы двойное нажатие не
   отправило два тарифа. Действующий тариф называет подпись слева. */
.accounts-switch[disabled]{cursor:default;opacity:.45}

/* Персональная скидка (пункт 5 списка Миши 16.10). Цена стоит отдельной
   строкой НАД бегунком: это ответ на вопрос «почём», а бегунок — средство. */
.accounts-price{font-variant-numeric:tabular-nums;white-space:nowrap}
/* Хватает на бегунок (140), число и кнопку; шире — и колонка тарифа
   начинает ломать свою кнопку на три строки. */
.accounts-price-cell{min-width:240px}
.accounts-discount-row{display:flex;align-items:center;gap:6px;margin-top:4px}
/* Бегунок ощутимо шире, чем помещалось бы «лишь бы влезло»: на диапазоне
   0–90 каждый пиксель — это процент, а процент — деньги. При 84 px клик по
   дорожке промахивался на несколько процентов (находка ревью Jaspr 18.10).
   Акцент и курсор — как у бегунка доли в «Биллинге», иначе новый ползунок
   рисуется системным цветом и заметно чужероден в тёмной схеме. */
.accounts-discount{width:140px;flex:0 0 auto;accent-color:var(--acc);cursor:pointer}
.accounts-discount[disabled]{cursor:default;opacity:.45}
.accounts-discount-value{color:var(--mut);font-size:12px;min-width:34px;font-variant-numeric:tabular-nums}
.accounts-discount-apply{padding:2px 8px;border:1px solid var(--line);border-radius:6px;background:var(--card);color:var(--ink);font:inherit;font-size:12px;cursor:pointer}
.accounts-discount-apply:hover{border-color:var(--mut)}
/* Выключена, пока бегунок не сдвинут: применять то же самое значило бы
   записать лишнее решение в стор учёток. Гасим кнопку, а не строку — на
   родителе `opacity` образует группу, и ребёнку её уже не отменить
   (найдено на «Рекомендациях» 16.10). */
.accounts-discount-apply[disabled]{cursor:default;opacity:.45}

/* Подразделы задач бизнеса и контента (изменение recommendations-section).
   Пустой подраздел — настоящий `div` без детей, гасим правилом. */
.biz-section{padding:6px 24px 10px}
.biz-section:empty{display:none}
.biz-section h3{font-size:14px;margin:10px 0 2px}
.biz-section ul{margin:0;padding-left:0;list-style:none}
.biz-item{margin:6px 0;max-width:90ch;line-height:1.45}
/* Не flex: на узком экране он сжимал колонку с меткой клиента, и «Клиент 5»
   ломался пополам. Обычный поток строки — как в разделе «Рекомендации». */
.biz-check{cursor:pointer}
.biz-client{font-weight:600;white-space:nowrap}
.biz-text{color:var(--ink)}
.biz-done{text-decoration:line-through;color:var(--mut)}
/* Заголовок списка задач сотрудников — появляется вместе с подразделами. */
.biz-head{font-size:14px;margin:10px 24px 2px}
/* Разбивка темы по каналам и строка периода — вспомогательные, приглушены. */
.recs-channels{color:var(--mut);font-size:12.5px}
#recsPeriod{padding:0 24px 6px;color:var(--mut);font-size:12.5px}
/* Раздел «Рейтинг запросов» (спека 2026-10-19). Отступы и приглушённые подписи
   повторяют «Рекомендации»: два раздела на одном движке не должны выглядеть
   по-разному без причины. Нумерацию строк даёт сам `ol` — она и есть «1., 2.,
   3.» из постановки Миши 12.10. Класс без правила здесь означал бы браузерный
   список без отступов (правило проекта: вёрстку смотреть глазами). */
.rating-key{padding:6px 24px 10px}
.rating-key h3{font-size:14px;margin:10px 0 2px}
.rating-key ol{margin:0;padding-left:22px}
.rating-key p{margin:4px 0}
.rating-item{margin:6px 0;max-width:90ch;line-height:1.45}
.rating-text{color:var(--ink)}
.rating-channels{color:var(--mut);font-size:12.5px}
#ratingEmpty{padding:10px 24px;color:var(--mut);font-size:12.5px;max-width:80ch}
#ratingPeriod{padding:0 24px 6px;color:var(--mut);font-size:12.5px}
/* Свёрнутый остаток. Без своего правила строка уехала бы к левому краю: класс
   `muted` даёт цвет и размер, но не отступы, а на стенде её не видно вовсе —
   ключей там ровно пять, столько же, сколько потолок показа. Поймало ревью,
   не глаза. */
#ratingHidden{padding:6px 24px 10px;color:var(--mut);font-size:12.5px;max-width:80ch}
