/* ─────────────────────────────────────────────────────────────────────────────
   Панель платформы. Оформление намеренно «редакторское»: острые углы, 1px-линии,
   крупные цифры. Никаких скруглённых плашек-карточек — панель для работы, а не
   для витрины.
   ───────────────────────────────────────────────────────────────────────────*/
:root{
  --bg:#0A0B0D; --panel:#101114; --panel-2:#15171A; --hover:#1B1E22;
  --line:rgba(255,255,255,.08); --line-strong:rgba(255,255,255,.16);
  /* --txt-3 был #6B7178: на фоне панели это 3,6:1 при норме 4,5 для мелкого
     текста — подписи, шапки таблиц и пояснения читались с трудом (сессия 339). */
  --txt:#E9EAEC; --txt-2:#9AA0A8; --txt-3:#80868E;
  --acc:#E24F26; --acc-soft:rgba(226,79,38,.14);
  /* Заливка под белым текстом: у фирменного #E24F26 с белым контраст 3,9 при
     норме 4,5 — кнопки, пузыри и метки читались хуже остального (сессия 339).
     Фирменный остаётся в линиях, значках и ссылках, где текста на нём нет. */
  --acc-fill:#C94420;
  --ok:#3BA55D; --ok-soft:rgba(59,165,93,.14);
  --warn:#D9A441; --warn-soft:rgba(217,164,65,.14);
  --danger:#E5484D; --danger-soft:rgba(229,72,77,.14);
  --mono:ui-monospace,SFMono-Regular,Menlo,monospace;
  /* Лёгкая заливка поверх фона: метки, цитаты, код. В тёмной теме это белый с
     малой прозрачностью, в светлой — чёрный; отдельный токен нужен, чтобы одна
     и та же плашка не превращалась в светлой теме в белое пятно на белом. */
  --tint:rgba(255,255,255,.05);
  --tint-2:rgba(255,255,255,.09);
  /* Затемнение под окном и тени. В светлой теме тень мягче: на белом фоне
     та же прозрачность выглядит грязным пятном. */
  --scrim:rgba(0,0,0,.62);
  --scrim-side:rgba(0,0,0,.5);
  --shadow:0 14px 34px rgba(0,0,0,.55);
  --shadow-soft:0 6px 18px rgba(0,0,0,.28);
  /* Поля и кнопки в одной строке должны совпадать по высоте — иначе строка
     «поиск + действие» выглядит собранной наспех. */
  /* Тонкая строка сверху на телефоне: значок меню и название раздела. На широком
     экране её нет — там меню видно всегда (сессия 226). */
  --mobile-bar:44px;
  --control-h:38px;
  --control-h-sm:30px;
  /* Ширина рабочей области. Раздел не растекается на весь монитор — строка
     таблицы в два метра читается хуже, а не лучше, — но и не жмётся к левому
     краю: свободное место делится поровну по обе стороны. На широких мониторах
     потолок поднимается ниже по файлу (сессия 262). */
  --content-max:1440px;
  /* Полоса, которую занимает плавающий значок меню на компьютере со свёрнутым
     меню: отступ 10 + кнопка 39 + зазор 7. Держим числом в одном месте — от неё
     отступает содержимое, чтобы значок ни на что не ложился. */
  --burger-rail:56px;
}
/* ── Светлая тема ────────────────────────────────────────────────────────────
   Те же токены другими значениями — правил ниже это не касается вовсе.
   Фирменный оранжевый один на обе темы, а вот «работает», «внимание» и
   «сломано» на белом пришлось притемнить: на тёмном фоне светлый зелёный
   читается, на белом — сливается и выглядит блёкло.
   Тень мягче и заливка темнее по той же причине: на белом та же прозрачность
   даёт грязное пятно вместо подсветки (сессия 262). */
:root[data-theme="light"]{
  --bg:#F6F6F4; --panel:#FFFFFF; --panel-2:#F1F1EE; --hover:#EBEBE7;
  --line:rgba(23,26,28,.12); --line-strong:rgba(23,26,28,.24);
  --txt:#16181A; --txt-2:#585F66; --txt-3:#676D74;
  --acc:#D9451F; --acc-soft:rgba(217,69,31,.12);
  --acc-fill:#BF3D1B;
  --ok:#1C7C43; --ok-soft:rgba(28,124,67,.13);
  --warn:#946108; --warn-soft:rgba(148,97,8,.13);
  --danger:#C22B2F; --danger-soft:rgba(194,43,47,.12);
  --tint:rgba(23,26,28,.05);
  --tint-2:rgba(23,26,28,.09);
  --scrim:rgba(23,26,28,.38);
  --scrim-side:rgba(23,26,28,.32);
  --shadow:0 12px 28px rgba(23,26,28,.16);
  --shadow-soft:0 4px 14px rgba(23,26,28,.10);
}
/* Браузер должен знать, какая тема сейчас: от этого зависят полосы прокрутки,
   выделение текста и рамка сфокусированного поля — их рисует он, не мы. */
:root{color-scheme:dark;}
:root[data-theme="light"]{color-scheme:light;}

*{box-sizing:border-box;}
html,body{height:100%;}
body{
  margin:0; background:var(--bg); color:var(--txt);
  font:14px/1.5 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--acc);}
h1,h2,h3{margin:0; font-weight:650; letter-spacing:-.01em;}
code{font-family:var(--mono); font-size:.92em;}

/* ── Каркас ─────────────────────────────────────────────────────────────── */
.shell{display:flex; min-height:100vh;}
.side{
  width:216px; flex:0 0 216px; border-right:1px solid var(--line);
  background:var(--panel); display:flex; flex-direction:column; position:sticky; top:0; height:100vh;
}
.brand{padding:14px 12px 13px 18px; border-bottom:1px solid var(--line);
  display:flex; align-items:center; gap:10px;}
.brand > div{min-width:0; flex:1;}
.brand b{display:block; font-size:15px; letter-spacing:-.02em;}
.brand span{display:block; font-size:12px; color:var(--txt-3); margin-top:2px;}
.nav{padding:10px 8px; flex:1; overflow-y:auto;}
.nav a{
  display:flex; align-items:center; gap:10px; padding:9px 10px; margin-bottom:1px;
  color:var(--txt-2); text-decoration:none; font-size:13.5px; border-left:2px solid transparent;
}
.nav a:hover{background:var(--hover); color:var(--txt);}
.nav a.on{background:var(--panel-2); color:var(--txt); border-left-color:var(--acc); font-weight:600;}
/* Подписи, надзаголовки и шапки таблиц — строчными: капс с разрядкой читается
   медленнее и по правилам интерфейсов не используется (сессия 339). */
.nav-group{font-size:11.5px; color:var(--txt-3);
  font-weight:600; padding:14px 12px 6px;}
.nav a.sub{padding-left:22px;}
.nav .ico{width:16px; text-align:center; color:var(--txt-3); font-size:13px;}
.nav a.on .ico{color:var(--acc);}
.nav .count{margin-left:auto; font-size:11px; color:var(--txt-3); font-variant-numeric:tabular-nums;}
.nav .count.alert{color:var(--danger);}
.side-foot{padding:12px 14px; border-top:1px solid var(--line); font-size:12px; color:var(--txt-3);}
.side-foot .sub{display:block; margin-top:3px; font-size:11px; color:var(--txt-3);}
/* Переключатель темы — там же, где выход: вещи, которые трогают раз в жизни,
   живут вместе и не занимают места в шапке раздела. */
.theme-switch{display:flex; margin-top:9px; border:1px solid var(--line-strong); border-radius:3px; overflow:hidden;}
.theme-switch button{
  flex:1; height:26px; padding:0; border:0; border-radius:0; background:transparent;
  color:var(--txt-2); font-size:11.5px; font-weight:400;
}
.theme-switch button:hover{background:var(--hover); color:var(--txt);}
.theme-switch button.on{background:var(--acc-fill); color:#fff; font-weight:600;}

.main{flex:1; min-width:0; display:flex; flex-direction:column; position:relative;}
/* Полосы над содержимым больше нет (сессия 226): она занимала 60 точек ради
   названия раздела, которое подсвечено в меню, и приписки «обновлено только что».
   Приписка переехала в подвал меню, значок меню — в его шапку. */
.spacer{margin-left:auto;}
/* `margin-inline:auto` — единственный способ центрировать элемент в колоночном
   флексе, когда у него задана ширина: `align-items` на определённый размер не
   действует, и свободное место целиком уходило вправо, а раздел стоял прижатым
   к левому краю (сессия 262). */
.content{padding:28px 28px 64px; max-width:var(--content-max); width:100%; margin-inline:auto;}
/* Рабочее место, а не документ: «Обращения» — внутренняя CRM, её читают и печатают
   в ней весь день. Раздел занимает экран целиком, поле ответа стоит у нижнего края,
   прокручиваются только список и переписка. До этого переписка обрывалась на 52vh,
   а под полем ввода оставалась мёртвая полоса в треть экрана (сессия 213). */
/* Раздел на весь экран. Полосы над ним больше нет — вычитать нечего (сессия 226). */
.content.full{max-width:none; padding:12px 12px; height:100vh;
  display:flex; flex-direction:column; overflow:hidden;}
/* Полка над разделом отделена от него линией самого раздела — второй воздушный
   зазор в двадцать точек только отнимал высоту у переписки (сессия 222). */
.content.full .section-head{flex:0 0 auto; margin-bottom:10px; gap:8px;}
.content.full .support{flex:1; min-height:0; height:auto;}

/* ── Типографика разделов ───────────────────────────────────────────────── */
.section-head{display:flex; align-items:center; gap:12px; margin-bottom:20px; flex-wrap:wrap; min-height:var(--control-h);}
/* Ряд шапки раздела — ОДНОЙ высоты. Фильтры были компактными (30), а поле поиска
   рядом — основным (38): ряд читался как собранный наспех, и Влад поймал это
   дважды. Компактными фильтры остаются только на телефоне, где они уезжают
   в свой собственный ряд, — см. медиазапрос ниже (сессия 226). */
/* `button.sm` объявлен ниже и весит столько же — поэтому класс назван и здесь:
   иначе «Архив» остаётся компактным рядом с полем поиска. */
.section-head > button.sm, .section-head > button,
.section-head > input, .section-head > select,
.section-head .filters > button{height:var(--control-h);}
.section-head h2{font-size:15px;}
.section-head .hint{font-size:12.5px; color:var(--txt-3);}
.eyebrow{
  font-size:12.5px; color:var(--txt-2); font-weight:650; margin:28px 0 10px;
}
/* Заголовок с кнопкой в одном ряду — кнопка не должна тянуть на себя внимание,
   поэтому она мелкая и стоит справа. */
.eyebrow-row{display:flex; align-items:center; justify-content:space-between; gap:10px;}
.eyebrow-row button{text-transform:none; letter-spacing:0; font-size:12px;}
.eyebrow:first-child{margin-top:0;}

/* ── Числа обзора: строка, разделённая линиями, а не плитки ─────────────── */
.figures{display:flex; border:1px solid var(--line); background:var(--panel); flex-wrap:wrap;}
.figure{flex:1 1 150px; padding:18px 20px; border-right:1px solid var(--line); min-width:0;}
.figure:last-child{border-right:0;}
.figure b{display:block; font-size:30px; font-weight:600; letter-spacing:-.03em; font-variant-numeric:tabular-nums; line-height:1.1;}
.figure span{display:block; font-size:12.5px; color:var(--txt-3); margin-top:6px;}
/* Переключатель месяца: стрелки вплотную к названию — это один орган управления,
   а не три кнопки подряд. Ширина названия фиксирована, иначе стрелки прыгают
   при переходе с «мая» на «сентябрь». */
.month-nav{display:flex; align-items:center; gap:6px;}
.month-nav b{font-size:13px; font-weight:600; min-width:11ch; text-align:center;}
.month-nav button{min-width:var(--control-h-sm);}

.stage-pick{width:100%; height:var(--control-h-sm); font-size:12px;}
/* Мелкое поле внутри строки таблицы или фактов: роль пользователя, дата обещания.
   Класс, а не inline-стиль, — иначе мобильное правило про 16px не перебить. */
.mini-pick{width:auto; height:var(--control-h-sm); font-size:12px;}
/* Те же размеры, когда под классом лежит свой список или своё поле даты: высота
   компактного ряда живёт в одной переменной, и у своих контролов тоже. */
.stage-pick.cs{height:auto;}
.mini-pick.cs{height:auto; width:auto; min-width:140px; max-width:220px;}
.stage-pick .cs-btn, .mini-pick .cs-btn{height:var(--control-h-sm); font-size:12px;}
.mini-pick.cdate .cdate-text, .mini-pick.cdate .cdate-btn{height:var(--control-h-sm); font-size:12px;}
.mini-pick.cdate{width:auto; max-width:150px;}
.mini-pick.cdate .cdate-btn{width:var(--control-h-sm);}
/* Расчётная стадия — приглушённая: человек должен видеть, что её никто не выбирал. */
.stage-pick.auto .cs-btn{color:var(--txt-3); border-style:dashed;}
/* Поле «чего ждём» — под селектом стадии, той же ширины: это уточнение к стадии,
   а не самостоятельное поле. */
.stage-note{width:100%; height:var(--control-h-sm); font-size:11.5px; margin-top:4px;}
.figure.warn b{color:var(--warn);} .figure.bad b{color:var(--danger);} .figure.good b{color:var(--ok);}

/* ── Список «требует внимания» ──────────────────────────────────────────── */
.issues{border:1px solid var(--line); background:var(--panel);}
.issue{display:flex; gap:12px; padding:12px 16px; border-bottom:1px solid var(--line); align-items:baseline;}
.issue:last-child{border-bottom:0;}
.issue .dot{width:7px; height:7px; flex:0 0 7px; margin-top:6px;}
.issue .dot.crit{background:var(--danger);} .issue .dot.warn{background:var(--warn);}
.issue .who{font-weight:600; font-size:13px; min-width:120px;}
.issue .what{color:var(--txt-2); font-size:13px; flex:1; min-width:0;}
.issue button{flex:0 0 auto;}
.empty{padding:22px 16px; color:var(--txt-3); font-size:13px; text-align:center;}
.issue-rich{align-items:flex-start; gap:12px;}
.issue-rich .dot{margin-top:7px;}
.issue-text{flex:1; min-width:0;}
.issue-head{font-size:13px; display:flex; gap:8px; flex-wrap:wrap; align-items:baseline;}
.issue-head b{font-weight:600;}
.issue-head span{color:var(--txt-2);}
.issue-hint{margin-top:4px; font-size:12.5px; color:var(--txt-3); line-height:1.5; max-width:78ch;}

.issue-rich button{flex:0 0 auto;}

/* ── Таблицы ────────────────────────────────────────────────────────────── */
.table-wrap{border:1px solid var(--line); background:var(--panel); overflow-x:auto;}
table{width:100%; border-collapse:collapse;}
th{
  text-align:left; font-size:12px;
  color:var(--txt-3); font-weight:600; padding:10px 14px; border-bottom:1px solid var(--line);
  white-space:nowrap; background:var(--panel-2); position:sticky; top:0; z-index:2;
}
th.sortable{cursor:pointer; user-select:none;}
th.sortable:hover{color:var(--txt-2);}
td{padding:11px 14px; border-bottom:1px solid var(--line); font-size:13px; vertical-align:middle;}
tbody tr:hover td{background:var(--panel-2);}
/* Итоговая строка — та же таблица, только тяжелее: отделена линией, не цветом. */
tfoot td{font-weight:600; background:var(--panel-2); border-top:1px solid var(--line-strong); border-bottom:0;}
tbody tr.expanded td{background:var(--panel-2);}
tr.details td{background:var(--bg); padding:0;}
.num{font-variant-numeric:tabular-nums;}
/* Деньги читают колонкой: единицы под единицами, тысячи под тысячами. Правило
   живёт на таблице целиком, а не на каждой ячейке, и только на широком экране —
   на телефоне таблица превращается в карточку, где метка слева, а значение и так
   справа (сессия 262). */
@media (min-width:861px){
  table.nums td.num{text-align:right;}
}
.muted{color:var(--txt-3);}
/* Мелкая подпись — классом, а не inline: inline-размер перебивает мобильное
   правило про нижнюю границу текста, и такие подписи оставались нечитаемыми
   ровно там, где их и читают — с телефона (сессия 226). */
.small{font-size:11.5px;}
.nowrap{white-space:nowrap;}

/* ── Мелкие элементы ────────────────────────────────────────────────────── */
.pill{display:inline-flex; align-items:center; gap:5px; padding:2px 8px; font-size:11.5px; font-weight:600; white-space:nowrap;}
.pill.ok{background:var(--ok-soft); color:var(--ok);}
.pill.warn{background:var(--warn-soft); color:var(--warn);}
.pill.bad{background:var(--danger-soft); color:var(--danger);}
.pill.off{background:var(--tint); color:var(--txt-3);}
.dot-i{display:inline-block; width:7px; height:7px; vertical-align:middle; margin-right:6px;}

button{
  font:inherit; font-size:13px; height:var(--control-h); padding:0 14px; cursor:pointer;
  display:inline-flex; align-items:center; justify-content:center; gap:6px; white-space:nowrap;
  background:var(--panel-2); color:var(--txt); border:1px solid var(--line-strong); border-radius:3px;
}
button:hover{background:var(--hover);}
button:disabled{opacity:.45; cursor:default;}
button.primary{background:var(--acc-fill); border-color:var(--acc-fill); color:#fff; font-weight:600;}
button.primary:hover{filter:brightness(1.08);}
button.ghost{background:transparent; border-color:transparent; color:var(--txt-2); padding:0 10px;}
button.ghost:hover{background:var(--hover); color:var(--txt);}
button.danger{color:var(--danger); border-color:rgba(229,72,77,.4);}
button.danger:hover{background:var(--danger-soft);}
button.sm{height:var(--control-h-sm); padding:0 11px; font-size:12px;}
.btn-row{display:flex; gap:10px; flex-wrap:wrap; align-items:center;}

input,select{
  font:inherit; font-size:15px; height:var(--control-h); padding:0 11px; width:100%;
  background:var(--bg); color:var(--txt); border:1px solid var(--line-strong); border-radius:3px;
}
textarea{
  font:inherit; font-size:15px; padding:9px 11px; width:100%;
  background:var(--bg); color:var(--txt); border:1px solid var(--line-strong); border-radius:3px;
}
/* ── Свои контролы вместо браузерных ────────────────────────────────────────
   Браузерные список, календарь, счётчик и галочка рисуются системой: на тёмной
   панели они приезжают светлыми, со своими шрифтами и своей высотой, и ломают
   и вид, и правило единой высоты ряда. Поэтому все четыре собраны здесь — из
   тех же 1px-линий и той же переменной высоты, что и остальные поля.
   Каждый компонент держит настоящее значение в поле с тем же id, что и раньше:
   окно собирает значения по id (см. modal()), и менять этот договор ради вида
   не надо (сессия 262). */

/* Галочка. Единственный случай, где хватает самого поля: рисунок снимается
   `appearance:none`, а состояние остаётся браузерным — весь существующий код,
   который читает `.checked` и ставит `disabled`, продолжает работать. */
input[type=checkbox]{
  appearance:none; -webkit-appearance:none; position:relative; cursor:pointer;
  width:18px; height:18px; flex:0 0 auto; padding:0; margin:0;
  background:var(--bg); border:1px solid var(--line-strong); border-radius:3px;
}
input[type=checkbox]:hover:not(:disabled){border-color:var(--txt-2);}
input[type=checkbox]:checked{background:var(--acc); border-color:var(--acc);}
input[type=checkbox]:checked::after{
  content:''; position:absolute; left:5px; top:1px; width:4px; height:9px;
  border:solid #fff; border-width:0 2px 2px 0; transform:rotate(45deg);
}
input[type=checkbox]:disabled{opacity:.45; cursor:default;}

/* Выпадающий список */
.cs{position:relative; width:100%;}
.cs-btn{
  position:relative; width:100%; height:var(--control-h); padding:0 32px 0 11px;
  font-size:15px; font-weight:400; text-align:left;
  background:var(--bg); border:1px solid var(--line-strong); border-radius:3px;
  color:var(--txt); display:flex; align-items:center; justify-content:flex-start;
  overflow:hidden;
}
.cs-btn .cs-val{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
/* Класс `empty` у подсказки пустого списка совпал с общим «пустым экраном»
   (отступ 22×16, центр), и подсказка уезжала вправо на 16 точек (сессия 339). */
.cs-btn .cs-val.empty{color:var(--txt-3); padding:0; font-size:inherit; text-align:left;}
.cs-btn::after{
  content:''; position:absolute; right:12px; top:50%; margin-top:-2px;
  border:4px solid transparent; border-top-color:var(--txt-2);
}
.cs-btn:hover{background:var(--hover);}
.cs-btn.open{border-color:var(--acc);}
.cs-btn:disabled{opacity:.45; cursor:default;}
.cs-menu{
  position:fixed; z-index:320; max-height:300px; overflow-y:auto; padding:4px 0;
  background:var(--panel); border:1px solid var(--line-strong); border-radius:3px;
  box-shadow:var(--shadow);
}
.cs-opt{
  display:flex; align-items:center; justify-content:flex-start; gap:8px;
  width:100%; min-height:var(--control-h);
  padding:7px 12px; border:0; border-radius:0; background:transparent;
  color:var(--txt); font-size:14px; font-weight:400; text-align:left; white-space:normal;
}
.cs-opt .cs-note{margin-left:auto; padding-left:10px;}
.cs-opt:hover, .cs-opt.cursor{background:var(--hover);}
.cs-opt.on{color:var(--acc); font-weight:600;}
.cs-opt .cs-note{color:var(--txt-3); font-size:12px; white-space:nowrap;}

/* Поле даты: слева набирают руками, справа открывают календарь. Оба пути пишут
   в одно скрытое поле в машинном виде — снаружи компонент неотличим от прежнего
   поля с датой. */
.cdate{display:flex; width:100%;}
.cdate .cdate-text{border-radius:3px 0 0 3px; border-right-width:0;}
.cdate .cdate-text.bad{border-color:var(--danger);}
.cdate .cdate-btn{
  flex:0 0 auto; width:var(--control-h); height:var(--control-h); padding:0;
  border-radius:0 3px 3px 0; font-size:15px; color:var(--txt-2);
}
.cdate .cdate-btn.open{border-color:var(--acc); color:var(--txt);}
.cal{
  position:fixed; z-index:320; width:264px; padding:10px;
  background:var(--panel); border:1px solid var(--line-strong); border-radius:3px;
  box-shadow:0 14px 34px rgba(0,0,0,.55);
}
.cal-head{display:flex; align-items:center; gap:6px; margin-bottom:8px;}
.cal-head button{width:var(--control-h-sm); height:var(--control-h-sm); padding:0; font-size:14px;}
.cal-title{flex:1; text-align:center; font-size:13.5px; font-weight:600;}
.cal-grid{display:grid; grid-template-columns:repeat(7,1fr); gap:2px;}
.cal-dow{
  font-size:11px; color:var(--txt-3); text-align:center; padding:3px 0;
}
.cal-day{
  height:32px; padding:0; border:1px solid transparent; border-radius:3px;
  background:transparent; color:var(--txt); font-size:13px; font-weight:400;
}
.cal-day:hover{background:var(--hover);}
.cal-day.out{color:var(--txt-3); opacity:.45;}
.cal-day.today{border-color:var(--line-strong);}
.cal-day.on{background:var(--acc-fill); border-color:var(--acc-fill); color:#fff; font-weight:600;}
.cal-foot{display:flex; gap:6px; margin-top:8px;}
.cal-foot button{flex:1;}

/* Счётчик: стрелки браузера мелкие и появляются только по наведению — здесь это
   две кнопки в рост поля, попасть можно и пальцем. */
.cnum{display:flex; width:100%;}
.cnum button{
  flex:0 0 auto; width:var(--control-h); height:var(--control-h); padding:0;
  font-size:16px; color:var(--txt-2);
}
.cnum button:first-child{border-radius:3px 0 0 3px;}
.cnum button:last-child{border-radius:0 3px 3px 0;}
.cnum .cnum-input{border-radius:0; border-left-width:0; border-right-width:0; text-align:center;}

/* Дата и время одной строкой — для отложенной отправки. */
.cdt{display:flex; gap:8px; width:100%;}
.cdt .cdate{flex:1 1 auto;}
.cdt .cdt-time{flex:0 0 84px; text-align:center;}

/* Конструктор тарифа: форма слева, расчёт справа. Панель, а не сетка `.needs` —
   у той своя раскладка под сигналы, и подписи в ней разъезжались. */
.sim-form{border:1px solid var(--line); background:var(--panel); padding:16px 18px;}
.sim-form .field{margin-bottom:12px;}
.sim-form .field label{display:block; margin-bottom:5px; font-size:12.5px; color:var(--txt-2);}
.sim-form .eyebrow:first-child{margin-top:0;}
/* Поле в пол-экрана под число из трёх цифр читается как ошибка вёрстки. */
.sim-form .cnum, .sim-form .cs{max-width:280px;}
.sim-out .facts{border:1px solid var(--line); background:var(--panel);}
input:focus,select:focus,textarea:focus{outline:none; border-color:var(--acc);}
textarea{font-family:var(--mono); font-size:13px; line-height:1.5; resize:vertical;}
label{display:block; font-size:12px; color:var(--txt-2); margin-bottom:5px;}
.field{margin-bottom:14px;}
.field .help{font-size:11.5px; color:var(--txt-3); margin-top:5px;}
.grid-2{display:grid; grid-template-columns:1fr 1fr; gap:14px;}
.search{max-width:280px;}

/* ── Детали школы ───────────────────────────────────────────────────────── */
/* ── Школы плитками ─────────────────────────────────────────────────────────
   Таблица из восьми колонок держала на экране сорок значений одного веса, и что
   требует действия сегодня, по строке не читалось. Плитка говорит три вещи:
   кто это, сколько платит, что с ней не так — и всё фразами, а не сокращениями
   вроде «3/3» и «5 адресов» (сессия 214). */
/* Линии рисуют сами плитки, а фон сетки убран: при фоне-разделителе последняя
   ячейка ряда оставалась пустой и в светлой теме читалась как серая плитка без
   содержимого. Отрицательные отступы схлопывают соседние границы в одну линию. */
.tiles{display:grid; grid-template-columns:repeat(auto-fill,minmax(268px,1fr));
  gap:0; background:transparent; border:0;}
.tile{
  background:var(--panel); padding:17px 19px 18px;
  /* Границы у самой плитки: соседние схлопываются отрицательным отступом в одну
     линию, а хвост ряда остаётся просто пустым местом, а не серой плиткой. */
  border:1px solid var(--line); border-top:3px solid var(--line-strong);
  margin:0 -1px -1px 0;
  text-align:left; color:inherit; font:inherit; cursor:pointer;
  display:flex; flex-direction:column; align-items:stretch; justify-content:flex-start;
  gap:10px; border-radius:0; height:auto; min-height:164px; white-space:normal;
}
.tile:hover{background:var(--hover);}
.tile.pay{border-top-color:var(--acc);}
.tile.bad{border-top-color:var(--danger);}
.tile.quiet{border-top-color:var(--warn);}
.tile.free{border-top-color:var(--txt-3);}
.tile.off{border-top-color:var(--txt-3); opacity:.75;}
.tile h4{font-size:16px; font-weight:650; letter-spacing:-.02em; line-height:1.25;}
.tile .slug{font-family:var(--mono); font-size:11.5px; color:var(--txt-3); margin-top:3px; display:block;}
.tile .money{font-size:22px; font-weight:700; letter-spacing:-.02em; font-variant-numeric:tabular-nums; line-height:1.1;}
.tile .money.zero{color:var(--txt-3);}
.tile .money small{display:block; margin-top:6px; font-size:12.5px; font-weight:400; letter-spacing:0; color:var(--txt-3); line-height:1.4;}
.tile .money small.bad{color:var(--danger);}
.tile .state{margin-top:auto; font-size:13px; line-height:1.45; color:var(--txt-3);}
.tile .state.bad{color:var(--danger);} .tile .state.warn{color:var(--warn);}
.tile .state .more{color:var(--txt-3); font-weight:400;}
/* Итог по деньгам — последней плиткой в той же сетке: цифра «сколько мне платят»
   не была видна нигде, а искать её глазами по колонке «Тариф» — работа. */
.tile.total{cursor:default; border-top-color:transparent; justify-content:center; gap:7px;
  background:var(--panel-2);}
.tile.total:hover{background:var(--panel);}
.tile.total b{font-size:20px; font-weight:700; letter-spacing:-.02em; font-variant-numeric:tabular-nums;}
.tile.total span{font-size:12.5px; color:var(--txt-3); line-height:1.45;}
.tile.total span.bad{color:var(--danger);}

/* Карточка школы: та же начинка, что была в раскрытой строке, но занимает экран
   целиком — сетка уезжает, и ничто не сдвигается под руками. */
.school-card{border:1px solid var(--line); background:var(--panel);}
.school-card .card-top{display:flex; align-items:center; gap:12px; flex-wrap:wrap;
  padding:12px 18px; border-bottom:1px solid var(--line); background:var(--panel-2);}
.school-card .card-top .stage-pick{max-width:220px;}
.school-card .card-top .stage-note{max-width:260px;}
.school-card .card-top h3{font-size:18px; letter-spacing:-.02em;}
.school-card .card-top .slug{font-family:var(--mono); font-size:12px; color:var(--txt-3);}
.school-card .details-inner{border-top:0;}

/* ── Карточка школы: строки «что это → сколько → чем поменять» ───────────────
   Девять одинаковых кнопок в четырёх колонках не говорили, что сделают. Теперь у
   каждой слева стоит имя и текущее значение (сессия 214). */
.facts{border:1px solid var(--line); background:var(--panel);}
.fact{display:grid; grid-template-columns:minmax(150px,210px) minmax(0,1fr) auto;
  gap:10px 18px; align-items:center; padding:12px 16px; border-bottom:1px solid var(--line);}
.fact:last-child{border-bottom:0;}
.fact-name{font-size:13px; font-weight:600;}
.fact-name span{display:block; margin-top:3px; font-size:11.5px; font-weight:400; color:var(--txt-3); line-height:1.4;}
.fact-value{font-size:13px; color:var(--txt-2); min-width:0;}
.fact-value b{color:var(--txt); font-weight:600;}
.fact-act{display:flex; gap:7px; flex-wrap:wrap; justify-content:flex-end;}

/* Что требует действия — над фактами, кнопка в той же строке. */
.needs{border:1px solid var(--line); background:var(--panel); padding:14px 16px;
  display:flex; flex-direction:column; gap:12px;}
.needs.calm{flex-direction:row; align-items:center; gap:10px; font-size:13px; color:var(--txt-2);}
.need{display:grid; grid-template-columns:9px minmax(0,1fr) auto; gap:12px; align-items:start;}
.need > div{font-size:13px; line-height:1.5; color:var(--txt-2);}
.need > div b{color:var(--txt); font-weight:600;}
.need .dot-i{margin-top:6px;}
.need button{align-self:start;}

/* Опасное — не кнопкой в общем ряду, а строкой с последствиями. */
.danger-zone .danger-line{display:flex; align-items:center; gap:16px; flex-wrap:wrap;
  padding:12px 0; border-bottom:1px solid var(--line);}
.danger-zone .danger-line:last-child{border-bottom:0;}
.danger-zone .danger-line > div{flex:1; min-width:220px;}
.danger-zone .danger-line b{display:block; font-size:13px; font-weight:600;}
.danger-zone .danger-line span{display:block; margin-top:3px; font-size:12px; color:var(--txt-3); line-height:1.45;}

.details-inner{padding:20px 24px 22px; border-top:1px solid var(--line);}
/* Колонки разделены линиями, а не воздухом: так карточка читается как таблица, а не
   как россыпь плашек. Кнопки прижаты к низу — их ряд один на всю ширину карточки. */
.details-grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:0; border:1px solid var(--line); background:var(--panel);}
.details-col{padding:14px 16px; border-right:1px solid var(--line);
  display:flex; flex-direction:column; min-width:0;}
.details-col:last-child{border-right:0;}
.details-col .btn-row{margin-top:auto; padding-top:12px; gap:6px; flex-wrap:wrap;}
.kv{font-size:13px; margin-bottom:6px; display:flex; justify-content:space-between; gap:12px; align-items:baseline;}
.kv b{color:var(--txt-3); font-weight:400; flex:0 0 auto;}
.kv span{min-width:0; text-align:right; overflow-wrap:anywhere;}
.sig{display:flex; gap:10px; align-items:flex-start; padding:10px 0; font-size:13px;
  border-top:1px solid var(--line);}
.sig .spacer{flex:1 1 auto;}
.sig button{flex:0 0 auto; align-self:flex-start;}
.sig:first-of-type{border-top:0;}
.danger-zone{margin-top:18px; padding-top:14px; border-top:1px solid var(--line);}
@media (max-width:760px){
  .details-col{border-right:0; border-bottom:1px solid var(--line);}
  .details-col:last-child{border-bottom:0;}
  /* На телефоне три колонки строки факта не помещаются: имя, значение и кнопки
     идут друг под другом, кнопки прижимаются к левому краю. */
  .fact{grid-template-columns:1fr; gap:7px;}
  .fact-act{justify-content:flex-start;}
  .need{grid-template-columns:9px minmax(0,1fr);}
  .need button{grid-column:2; justify-self:start;}
}

/* ── Мои уведомления ────────────────────────────────────────────────────── */
/* Список подписок — строки с 1px-линиями, как остальные перечни панели.
   Вложенные подписки «проблем школ» с отступом: видно, что они живут под мастером. */
.prefs{border:1px solid var(--line); background:var(--panel);}
.pref{display:flex; gap:12px; padding:12px 16px; border-bottom:1px solid var(--line);
  align-items:flex-start; margin:0; cursor:pointer; font-size:13px; color:var(--txt);}
.pref:last-child{border-bottom:0;}
.pref:hover{background:var(--panel-2);}
.pref.sub{padding-left:46px;}
.pref input[type=checkbox]{flex:0 0 auto; margin:1px 0 0;}
.pref .t{display:block;}
.pref .d{display:block; font-size:12px; color:var(--txt-3); margin-top:3px; line-height:1.45;}
.pref.dim{opacity:.45; cursor:default;}
.pref-wrap{min-width:0;}

/* ── Обращения ──────────────────────────────────────────────────────────── */
.filters{display:flex; gap:6px; flex-wrap:wrap;}
/* Высота раздела считается от экрана, а не от содержимого: раньше блок кончался
   по контенту, и под перепиской оставалась пустая полоса в треть экрана. 170px —
   это шапка панели, отступ раздела и строка фильтров над списком. */
/* Три колонки: очередь, переписка, карточка клиента. Полка справа прячется —
   на ноутбуке три колонки тесно, и её убирают на время длинного ответа. */
.support{display:grid; grid-template-columns:minmax(260px,320px) minmax(0,1fr) 302px;
  border:1px solid var(--line); background:var(--panel); min-height:520px; height:calc(100vh - 110px);}
.support.no-side{grid-template-columns:minmax(260px,320px) minmax(0,1fr);}
.support.no-side .thread-side{display:none;}
@media (max-width:1180px){
  /* Полке нужна ширина, которой на узком экране нет: сворачиваем её сами, а кнопка
     в шапке переписки остаётся — по ней полка открывается поверх переписки. */
  .support{grid-template-columns:minmax(240px,300px) minmax(0,1fr);}
  .support .thread-side{display:none;}
  .support.side-over .thread-side{display:flex; grid-column:2; grid-row:1;
    border-left:1px solid var(--line-strong);}
  .support.side-over .chat{display:none;}
}
.thread-list{border-right:1px solid var(--line); overflow-y:auto; min-height:0;}
.thread-item .wait{font-family:var(--mono); font-variant-numeric:tabular-nums; white-space:nowrap;}
.thread-item .wait.late{color:var(--danger); font-weight:700;}
.who-chip{
  display:inline-flex; align-items:center; padding:2px 6px; font-size:10.5px;
  background:var(--tint); color:var(--txt-3); letter-spacing:.02em;
}
.thread-item{display:block; width:100%; box-sizing:border-box; min-width:0; text-align:left;
  padding:10px 12px; border-bottom:1px solid var(--line); background:transparent;
  border-left:3px solid transparent; height:auto; border-radius:0; border-top:0; border-right:0;}
.thread-item:hover{background:var(--hover);}
/* Выбранное обращение отличаем фоном и правой кромкой, а НЕ риской: риска занята
   ответом на вопрос «чей ход», и перекрашивать её значит терять этот ответ ровно
   у той строки, которую сейчас читают (сессия 213). */
.thread-item.on{background:var(--panel-2); box-shadow:inset -3px 0 0 var(--acc);}
/* Риска слева: оранжевая — ход наш, серая — ждём клиента, жёлтая — ждёт доработки,
   красная — просрочили срок первого ответа. Объявляется ПОСЛЕ основного правила:
   его шорткат border-left иначе сбрасывает ширину обратно. */
.thread-item.turn-us{border-left-color:var(--acc);}
.thread-item.turn-client{border-left-color:var(--txt-3);}
.thread-item.turn-dev{border-left-color:var(--warn);}
.thread-item.turn-late{border-left-color:var(--danger);}
.thread-item .who{display:flex; align-items:center; gap:8px; font-size:13px; font-weight:600;}
.thread-item .who .when{margin-left:auto; font-size:11px; color:var(--txt-3); font-weight:400;}
.thread-item .prev.first{color:var(--txt-2);}
/* Последняя реплика — приглушённее и со стрелкой: она уточняет, а не называет обращение. */
.thread-item .prev.last{opacity:.75;}
.thread-item .prev{display:block; font-size:12px; color:var(--txt-3); margin-top:4px;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap; max-width:100%;}
.thread-item .tags{display:flex; align-items:center; gap:6px; margin-top:6px; flex-wrap:wrap;}
.thread-item .badge{background:var(--acc-fill); color:#fff; font-size:10.5px; font-weight:700; padding:1px 6px; border-radius:9px;}
.chat{display:flex; flex-direction:column; min-width:0; min-height:0;}
.chat-top{display:contents;}
.chat-head{display:flex; align-items:center; gap:10px; padding:9px 14px; border-bottom:1px solid var(--line); flex-wrap:wrap;}
/* Одна лента вместо четырёх выпадающих списков. Стадию меняют по десять раз в день —
   она обязана быть одним движением, а не выбором из списка (сессия 213). */
.stages{display:flex; border-bottom:1px solid var(--line); background:var(--panel-2);}
.stages button{
  flex:1; height:var(--control-h-sm); padding:0 6px; font-size:11.5px; font-weight:600;
  color:var(--txt-3); background:transparent; border:0; border-right:1px solid var(--line);
  cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.stages button:last-child{border-right:0;}
.stages button:hover:not(:disabled){background:var(--hover); color:var(--txt);}
.stages button.past{color:var(--txt-2);}
.stages button.now{background:var(--acc-fill); color:#fff;}
.stages button:disabled{cursor:default;}
/* Факты, которые правят раз в жизни обращения: тип, школы, ответственный. Строкой
   ниже и мелким шрифтом — они не должны спорить со стадией за внимание. */
/* Строка фактов — запаска для случая, когда карточка клиента спрятана: при открытой
   карточке она повторяла её слово в слово и занимала полосу над перепиской. */
.chat-head b{font-size:14px;}
/* min-height:0 обязателен: без него flex-элемент не даёт себя сжать, переписка
   распирает колонку, и поле ответа уезжает за нижний край экрана. */
.chat-body{flex:1; min-height:0; overflow-y:auto; padding:12px 14px; display:flex; flex-direction:column; gap:8px;}
.bubble{max-width:min(560px,80%); padding:9px 12px; font-size:13.5px; line-height:1.5; white-space:pre-wrap; word-break:break-word;}
.bubble.in{background:var(--panel-2); border:1px solid var(--line); align-self:flex-start;}
.bubble.out{background:var(--acc-fill); color:#fff; align-self:flex-end;}
.bubble .meta{display:block; font-size:10.5px; opacity:.65; margin-top:5px;}
/* Предпросмотр рассылки (сессия 273). Показываем ВХОДЯЩИМ облаком: клиент увидит
   наше сообщение именно так — слева и чужим, а не своим исходящим. */
.chat-preview{display:flex; padding:12px; background:var(--tint); border:1px solid var(--line);
  border-radius:10px; margin-bottom:6px;}
.chat-preview .bubble{max-width:100%; border-radius:12px;}
/* ── Полка «кто это» ────────────────────────────────────────────────────── */
.thread-side{
  border-left:1px solid var(--line); background:var(--panel); overflow-y:auto; min-height:0;
  display:flex; flex-direction:column;
}
.side-sec{padding:12px 13px; border-bottom:1px solid var(--line); display:flex; flex-direction:column; gap:8px;}
.side-sec:last-child{border-bottom:0;}
.side-sec > .eyebrow{margin:0;}
.side-title{font-size:16px; font-weight:650; letter-spacing:-.02em; line-height:1.25;}
.side-line{display:flex; align-items:baseline; justify-content:space-between; gap:10px; font-size:12.5px;}
.side-line > span:first-child{color:var(--txt-3); flex:0 0 auto;}
.side-line > span:last-child, .side-line > select{
  color:var(--txt); text-align:right; font-variant-numeric:tabular-nums;
  overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
}
/* Счёт в две строки: номер с суммой и, если есть, просрочка словом. Соседние
   строки карточки однострочные намеренно, но здесь обрезать нечего — номер нужен
   целиком (по нему ищут платёж в выписке), а «просрочен» цветом одним не
   передать. */
.side-line.wrap > span:last-child{white-space:normal; overflow-wrap:anywhere; line-height:1.4;}
.side-line select{width:auto; max-width:160px; height:var(--control-h-sm); font-size:12px;}
.side-line .cs{width:auto; max-width:160px;}
.side-line .cs-btn{height:var(--control-h-sm); font-size:12px; padding:0 26px 0 8px;}
.side-line .cdate{width:auto; max-width:150px;}
/* Несколько школ у одного обращения (сессия 289): метки с крестиком и список
   «добавить» в одну строку, переносом, если не влезли. Высота метки и крестика —
   компактная высота контролов, как у списка рядом. */
.side-line.multi{align-items:flex-start;}
.side-line.multi > span:first-child{line-height:var(--control-h-sm);}
.side-chips{display:flex; flex-wrap:wrap; justify-content:flex-end; gap:4px; min-width:0;}
.side-chip{display:inline-flex; align-items:center; height:var(--control-h-sm); padding-left:8px;
  border:1px solid var(--line); font-size:12px; color:var(--txt); white-space:nowrap;}
.side-chip button{width:calc(var(--control-h-sm) - 2px); height:calc(var(--control-h-sm) - 2px); min-height:0; padding:0;
  border:0; background:none; color:var(--txt-3); font-size:14px; line-height:1; cursor:pointer;}
.side-chip button:hover{color:var(--danger);}
.side-school + .side-school{border-top:1px dashed var(--line); padding-top:8px;}
.side-school{display:flex; flex-direction:column; gap:8px;}
.side-alert{border-left:2px solid var(--danger); padding-left:9px; font-size:12px; color:var(--txt-2); line-height:1.45;}
.side-alert.warn{border-left-color:var(--warn);}
.side-link{
  display:block; text-align:left; font-size:12.5px; color:var(--txt-2);
  border-left:2px solid var(--line-strong); padding:4px 0 4px 9px; background:none;
  border-top:0; border-right:0; border-bottom:0; cursor:pointer; width:100%;
}
.side-link:hover{color:var(--txt); border-left-color:var(--acc); background:var(--hover);}
.side-empty{font-size:12px; color:var(--txt-3); line-height:1.5;}
.side-back{display:none; align-self:flex-start;}
.support.side-over .side-back{display:inline-flex;}

.chat-foot{border-top:1px solid var(--line); padding:10px 14px; display:flex; gap:10px; align-items:flex-end;}
.composer{flex:1; min-width:0; display:flex; flex-direction:column; gap:6px;}
/* Панель разметки: значки те же, что уходят в текст (**жирный**), поэтому кнопка
   показывает результат, а не название тега. */
/* Шесть текстов регламента — кнопками. Их набирали руками или ходили копировать
   в соседний раздел; формулировка при этом каждый раз получалась своя. */
.scripts{display:flex; align-items:center; gap:6px; flex-wrap:wrap; margin:6px 0 2px;}
.scripts button{
  height:var(--control-h-sm); padding:0 10px; font-size:11.5px; color:var(--txt-2);
  background:transparent; border:1px solid var(--line); cursor:pointer; white-space:nowrap;
}
.scripts button:hover{background:var(--hover); color:var(--txt); border-color:var(--line-strong);}
.fmt-bar{display:flex; align-items:center; gap:2px;}
.fmt-bar .fmt{height:var(--control-h-sm); min-width:var(--control-h-sm); padding:0 7px;
  font-size:12.5px; background:transparent; border:1px solid transparent; color:var(--txt-2);}
.fmt-bar .fmt:hover{background:var(--hover); color:var(--txt); border-color:var(--line);}
.fmt-bar .fmt.wide{padding:0 9px;}
/* Открытая полка помечена — иначе непонятно, почему под кнопкой появился ряд. */
.fmt-bar .fmt.on{background:var(--panel-2); border-color:var(--line-strong); color:var(--txt);}
.fmt-bar.marks{margin-top:4px;}
.fmt-bar .sep{width:1px; height:16px; background:var(--line); margin:0 5px;}
.fmt-bar .spacer{flex:1;}
.fmt-bar .hint{font-size:11px; color:var(--txt-3);}
/* Выбранный файл виден до отправки: без плашки непонятно, уйдёт вложение или нет. */
.attach-chip{display:flex; align-items:center; gap:10px; padding:7px 10px;
  border:1px solid var(--line); background:var(--panel-2); font-size:12.5px;}
.attach-chip img{width:38px; height:38px; object-fit:cover; border:1px solid var(--line);}
.attach-chip .nm{overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
.attach-chip .sz{color:var(--txt-3); font-size:11.5px; white-space:nowrap;}
.attach-chip .drop{margin-left:auto;}
.composer.drag textarea{border-color:var(--acc); background:var(--acc-soft);}
/* Вложения в переписке. Картинку показываем сразу — по скрину видно проблему,
   а по строчке «photo.jpg» не видно ничего. */
/* Правка и удаление ответа (сессия 199). Кнопки проявляются на наведении: в
   переписке важен текст, а не панель инструментов над каждым пузырём. */
.bubble{position:relative;}
.bubble-tools{
  position:absolute; top:4px; right:6px; display:flex; gap:2px;
  opacity:0; transition:opacity .12s;
}
.bubble:hover .bubble-tools, .bubble-tools:focus-within{opacity:1;}
.bubble-tools button{
  height:22px; min-width:22px; padding:0 5px; font-size:12px; line-height:1;
  background:var(--panel); border:1px solid var(--line); color:var(--txt-2);
}
.bubble-tools button:hover{color:var(--txt); border-color:var(--line-strong);}
/* На телефоне наведения нет, и панель, висящая поверх пузыря, закрывала короткое
   сообщение целиком («Вопрос решён?» пропадал под тремя кнопками). Поэтому здесь
   она не висит, а раскрывается тапом по сообщению — как в мессенджерах — и встаёт
   в поток, над текстом. Кнопки ростом с компактный контрол: 22 точки нажимаются
   мышью, пальцем — нет, а «ответить на сообщение» жмут часто (сессия 221). */
@media (hover:none){
  .bubble-tools{display:none;}
  .bubble.picked .bubble-tools{
    display:flex; position:static; opacity:1; width:100%; gap:6px;
    justify-content:flex-end; margin-bottom:7px;
  }
  .bubble.picked .bubble-tools button{
    height:var(--control-h-sm); min-width:var(--control-h-sm); font-size:14px;
  }
}
.bubble .meta .edited{margin-left:6px; opacity:.75;}
/* Реакции под пузырём: наша и клиента. Значок крупнее меты — его считывают
   взглядом, а не вчитываются, и он должен быть виден при беглом просмотре ленты. */
.bubble .rxn{display:inline-flex; align-items:center; gap:5px; margin-top:6px;
  margin-right:5px; padding:2px 8px; border:1px solid var(--line); border-radius:999px;
  background:var(--panel-2); font-size:14px; line-height:1.35;}
.bubble.out .rxn{border-color:rgba(255,255,255,.3); background:rgba(0,0,0,.16);}
.bubble .rxn .by{font-size:10.5px; opacity:.7;}
/* Выбор реакции: всплывает у пузыря по кнопке в наборе инструментов. */
.rxn-pick{position:absolute; z-index:5; top:-34px; right:0; display:flex; gap:2px;
  padding:3px 4px; border:1px solid var(--line-strong); border-radius:999px;
  background:var(--panel); box-shadow:var(--shadow-soft);}
.rxn-pick button{font-size:16px; line-height:1; padding:3px 5px; border:0;
  background:none; cursor:pointer; border-radius:50%;}
.rxn-pick button:hover{background:var(--panel-2);}

.bubble .media{display:block; max-width:100%; max-height:320px; margin-bottom:6px;
  border:1px solid var(--line); cursor:zoom-in; background:var(--panel-2);}
.bubble.out .media{border-color:rgba(255,255,255,.25);}
.bubble audio.media{cursor:default; height:40px; width:260px; max-width:100%;}
.bubble .file{display:flex; align-items:center; gap:9px; margin-bottom:6px; padding:8px 10px;
  border:1px solid var(--line); background:var(--panel-2);}
.bubble.out .file{border-color:rgba(255,255,255,.3); background:rgba(0,0,0,.16);}
.bubble .file .nm{overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:12.5px;}
.bubble .file .sz{color:var(--txt-3); font-size:11px; white-space:nowrap;}
.bubble.out .file .sz{color:rgba(255,255,255,.75);}
.bubble .file .get{margin-left:auto; height:var(--control-h-sm); padding:0 10px; font-size:12px;}
.bubble .media-wait{font-size:12px; color:var(--txt-3); padding:6px 0;}
.bubble.out .media-wait{color:rgba(255,255,255,.8);}
/* ── Ответ на конкретное сообщение (сессия 221) ────────────────────────────
   Цитата над текстом: полоска слева и две строки — кто и что сказал. Так же, как
   в телеграме, откуда клиент и приходит: узнаваемая форма не требует объяснений. */
.bubble .quote{
  display:block; width:100%; box-sizing:border-box; text-align:left; margin-bottom:7px;
  padding:4px 0 4px 9px; border:0; border-left:2px solid currentColor;
  background:var(--tint); color:inherit; font:inherit; cursor:pointer;
}
.bubble.in .quote{background:var(--tint);}
.bubble .quote.flat{cursor:default;}
.bubble .quote:not(.flat):hover{background:var(--tint-2);}
.bubble .q-who{display:block; font-size:11px; font-weight:650; opacity:.85;
  letter-spacing:.01em; white-space:nowrap;}
.bubble .q-text{
  display:block; font-size:12px; opacity:.75; margin-top:1px; line-height:1.35;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
/* Куда привёл прыжок по цитате. Гаснет само — подсветка нужна на то мгновение,
   пока глаз ищет сообщение. */
.bubble.flash{animation:bubbleFlash 1.6s ease-out;}
@keyframes bubbleFlash{
  0%{box-shadow:0 0 0 2px var(--acc);} 60%{box-shadow:0 0 0 2px var(--acc);}
  100%{box-shadow:0 0 0 2px transparent;}
}
/* Плашка «в ответ …» над полем: видно, куда уйдёт ответ, до того как он написан. */
.reply-chip{
  display:flex; align-items:center; gap:10px; padding:6px 10px;
  border:1px solid var(--line); border-left:2px solid var(--acc); background:var(--panel-2);
}
.reply-chip .q-go{
  flex:1; min-width:0; text-align:left; background:none; border:0; padding:0;
  color:var(--txt-2); cursor:pointer; font:inherit;
}
.reply-chip .q-who{display:block; font-size:11px; font-weight:650; color:var(--acc);}
.reply-chip .q-text{
  display:block; font-size:12.5px; margin-top:1px;
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.reply-chip .drop{flex:0 0 auto;}
/* Разметка внутри пузыря: текст и так pre-wrap, поэтому теги только меняют начертание. */
.bubble b{font-weight:700;} .bubble i{font-style:italic;} .bubble s{text-decoration:line-through;}
.bubble code{font-family:var(--mono); font-size:.92em; background:rgba(0,0,0,.28); padding:1px 4px;}
.bubble pre{font-family:var(--mono); font-size:12px; margin:4px 0; padding:8px 10px;
  background:rgba(0,0,0,.28); overflow-x:auto; white-space:pre;}
.bubble.in code, .bubble.in pre{background:var(--tint);}
.bubble a{color:inherit; text-decoration:underline;}
.bubble .spoiler{background:currentColor; border-radius:2px; cursor:pointer;}
.bubble .spoiler.open{background:transparent;}
/* Просмотр картинки во весь экран — кликом по превью. */
.lightbox{position:fixed; inset:0; background:rgba(0,0,0,.86); z-index:300;
  display:flex; align-items:center; justify-content:center; padding:24px; cursor:zoom-out;}
.lightbox img{max-width:100%; max-height:100%; object-fit:contain;}
/* Поле ответа стартует ровно с высоты кнопки и растёт по мере набора: разъезд
   «поле 62 — кнопка 38» в одном ряду читается как небрежность. */
.chat-foot textarea{
  font-family:inherit; font-size:14px; line-height:20px;
  height:var(--control-h); min-height:var(--control-h); max-height:160px;
  padding:8px 11px; resize:none; overflow-y:auto;
}
/* Пустое поле — ровно одна строка (правило единой высоты контролов), поэтому
   подсказка в нём не переносится: на узком экране она обрывалась на середине
   второй строки. Как только начинают печатать, перенос возвращается. */
.chat-foot textarea:placeholder-shown{white-space:nowrap;}
.chat-empty{flex:1; display:flex; align-items:center; justify-content:center; color:var(--txt-3);
  font-size:13px; padding:40px 20px; text-align:center; overflow-wrap:anywhere;}
.hide-desktop{display:none;}
@media (max-width:860px){ .hide-desktop{display:inline-flex;} }
@media (max-width:860px){
  /* На телефоне список и переписка идут друг под другом, и фиксированная высота
     раздела резала бы нижний блок. Высоту отдаём содержимому. */
  /* Специфичность: `.support.no-side` и `.support.side-over` — (0,2,0), а голое
     `.support` в медиа — (0,1,0), и мобильное правило проигрывало. На телефоне
     из-за этого оставалась вторая колонка в 40 пикселей — та самая пустота справа. */
  .support, .support.no-side, .support.side-over{grid-template-columns:1fr; height:auto;}
  .thread-list{border-right:0; border-bottom:1px solid var(--line); max-height:none;}
  .support.reading .thread-list{display:none;}
  /* Обратное правило было нужнее прямого: пока обращение не выбрано, колонка
     переписки на телефоне рисовала заглушку «Выберите обращение» ПОВЕРХ списка,
     и длинный @ник бота распирал страницу вбок (сессия 214). */
  .support:not(.reading) .chat{display:none;}
  .support.side-over .thread-side{grid-column:1; border-left:0;}

  /* «Экран целиком» на телефоне работает против себя: раздел выше экрана, и всё
     внутри сжимается в полоски. Отдаём высоту содержимому и обычной прокрутке. */
  /* Нижний отступ в 60 точек оставлял под полем ответа чёрную полосу: раздел —
     рабочее место, поле стоит в конце переписки, и подпирать его пустотой нечем.
     Оставляем только безопасную зону телефона (полоса-домой у iPhone). */
  .content.full{height:auto; overflow:visible;
    padding:0 0 max(12px, env(safe-area-inset-bottom));}
  /* Раздел во всю ширину: боковые поля и рамка отнимали 30 точек из 390 —
     на них ничего не написано, а переписке их не хватает. */
  .content.full .support{border-left:0; border-right:0;}
  .support.reading .chat-body{min-height:52vh;}

  /* Шапка раздела — рабочая полка, а не заголовок страницы. Она занимала 154
     точки из 844 (три ряда контролов плюс отступы) и уезжала вверх, стоило
     пролистать список: фильтры и поиск приходилось искать прокруткой назад.
     Держим её под шапкой панели и укладываем в два ряда. */
  .content.full .section-head{
    position:sticky; top:var(--mobile-bar); z-index:30; background:var(--bg);
    margin:0; padding:8px 12px; gap:6px; border-bottom:1px solid var(--line);
  }
  /* Поиск и «Архив» — один ряд, и по правилу одной высоты оба ростом с поле. */
  .content.full .section-head .search{flex:1 1 120px; max-width:none; font-size:16px;}
  .content.full .section-head > button{flex:0 0 auto; height:var(--control-h);}
  /* Фильтры — свой ряд и весь компактный: три кнопки ростом с поле ввода занимали
     треть полки, а полка прибита к верху и висит над списком всегда (сессия 222). */
  .content.full .section-head .filters{gap:5px;}
  .content.full .section-head .filters button{height:var(--control-h-sm); font-size:12.5px; padding:0 10px;}
  /* Пока читают переписку, фильтры списка не нужны: они отнимают у неё четверть
     экрана, а вернуться к списку можно кнопкой в шапке переписки. */
  .content.full .section-head.reading{display:none;}

  /* Пять шагов стадии в ряд не помещаются: подписи обрезались до «дём клиен».
     Лента прокручивается вбок и сохраняет порядок шагов. */
  .stages{overflow-x:auto; -webkit-overflow-scrolling:touch;}
  .stages button{flex:0 0 auto; padding:0 14px;}

  /* Шесть готовых ответов вставали в столбик и занимали пол-экрана над полем. */
  .scripts{flex-wrap:nowrap; overflow-x:auto; -webkit-overflow-scrolling:touch; padding-bottom:2px;}
  .scripts button{flex:0 0 auto;}

  /* Шапка раздела: справка и служебные кнопки прячутся, остаются фильтры и поиск.
     Счётчик «5 обращений открыто» — тоже: он занимал целый ряд ради числа,
     которое уже стоит на кнопке «Все». */
  .desk-only{display:none !important;}
  .content.full .section-head .hint{display:none;}
  .section-head .filters{flex:1 1 100%;}
  .section-head .filters button{flex:1;}

  /* Шапка переписки вместе с лентой стадий держится наверху при листании.
     Раньше липла только шапка, а стадии уезжали — и чтобы перевести обращение
     в другое состояние, приходилось листать переписку до самого верха. */
  .chat-top{display:block; position:sticky; top:var(--mobile-bar); z-index:29;
    background:var(--panel); border-bottom:1px solid var(--line);}
  /* Шапка переписки — ОДНА строка. Три ряда (кнопка назад, имя, метка «чей ход»,
     действия) занимали 85 точек из 844, и это над каждым обращением, всегда:
     прибитая шапка съедала пятую часть экрана до первого сообщения (сессия 222).
     Ключ — nowrap: без него всё переносится, как только имя длиннее ладони. */
  .chat-head{gap:8px; padding:5px 12px; background:var(--panel); flex-wrap:nowrap;}
  .chat-head b{flex:1 1 auto; min-width:0; overflow:hidden;
    text-overflow:ellipsis; white-space:nowrap; font-size:13.5px;}
  .chat-head .pill{flex:0 0 auto; padding:2px 7px;}
  .chat-head .muted{display:none;}          /* «срок — 30 мин» есть в подсказке метки */
  .chat-head button{flex:0 0 auto;}
  .chat-head .sm{height:var(--control-h-sm); padding:0 8px; font-size:12px;}
  .chat-foot{padding:8px 12px;}
  /* Строка обращения: четыре яруса на телефоне — это семь строк на экран. Метки
     мельче и ниже, отступы плотнее: на экран помещается десяток, а не семь. */
  .thread-item{padding:9px 12px;}
  .thread-item .tags{gap:5px; margin-top:5px;}
  .thread-item .pill{padding:1px 6px;}
  .thread-item .who-chip{padding:1px 5px;}
  .thread-item .prev{margin-top:3px;}
}

/* ── Заметка команде, отложенная отправка, выбор адресата (сессия 226) ─── */
/* Заметка — не пузырь переписки: она не «слева» и не «справа», а на полях. Жёлтая
   кромка и подпись сверху, чтобы через неделю её не прочитали как ответ клиенту. */
.bubble.note{
  align-self:stretch; max-width:none; background:rgba(245,158,11,.07);
  border:1px solid rgba(245,158,11,.28); border-left:3px solid var(--warn);
  color:var(--txt-2);
}
.note-tag{
  display:block; margin-bottom:5px; font-size:11.5px; font-weight:700;
  color:var(--warn);
}
/* Отложенное: пунктир — «этого у клиента ещё нет». */
.bubble.later{border-style:dashed; opacity:.9;}
/* Пузырь исходящего залит акцентом, и серая подпись на нём не читалась вовсе —
   вместе с кнопкой «отменить», которая была акцентной на акцентном. Держим оба
   светлыми и полупрозрачными: это подпись к сообщению, а не само сообщение. */
.later-tag{
  display:flex; align-items:center; gap:8px; margin-bottom:5px;
  font-size:11px; color:rgba(255,255,255,.72);
}
.later-tag button{
  height:auto; padding:0; background:none; border:0; color:#fff;
  font-size:11px; text-decoration:underline; cursor:pointer; opacity:.85;
}
.later-tag button:hover{background:none; opacity:1;}
/* Кому пишем и чем отправляем — одной колонкой справа от поля. */
.send-col{display:flex; flex-direction:column; gap:6px; flex:0 0 auto;}
.to-switch{display:flex; border:1px solid var(--line-strong); border-radius:3px; overflow:hidden;}
.to-switch button{
  height:var(--control-h-sm); padding:0 10px; font-size:11.5px; border:0; border-radius:0;
  background:var(--panel-2); color:var(--txt-3);
}
.to-switch button.on{background:var(--acc-fill); color:#fff; font-weight:600;}
.to-switch button.on.note{background:var(--warn); color:#111;}
.send-row{display:flex; gap:6px;}
.send-row .primary{flex:1;}
/* Ряд отправки — одной высоты: «Ответить» и значок часов стоят рядом. */
.send-row button{height:var(--control-h);}

/* ── Сигналы «Обзора», сгруппированные по школам (сессия 226) ──────────── */
/* Школа — заголовок, её проблемы — строками под ним. Раньше три поломки одной
   школы шли тремя одинаковыми строками, и «сколько у меня всего горит»
   приходилось считать глазами. */
/* Между школами — воздух, а не только линия: иначе последняя строка одной школы
   и заголовок следующей читаются как одна запись. */
.issue-group{background:var(--panel); border:1px solid var(--line); margin-bottom:10px;}
.issue-group:last-child{margin-bottom:0;}
.issue-group-head{
  display:flex; align-items:center; gap:10px; padding:11px 16px;
  background:var(--panel-2); border-bottom:1px solid var(--line);
}
.issue-group-head b{font-size:13.5px;}
.issue-group-head .muted{font-size:12px;}
.issue-group.crit .issue-group-head{border-left:3px solid var(--danger);}
.issue-group.warn .issue-group-head{border-left:3px solid var(--warn);}
.issue-line{
  display:flex; align-items:flex-start; gap:12px; padding:10px 16px 10px 32px;
  border-bottom:1px solid var(--line); font-size:13px; color:var(--txt-2);
}
.issue-line:last-child{border-bottom:0;}
.issue-line .issue-text{flex:1; min-width:0;}
.issue-line button{flex:0 0 auto;}

/* ── Поиск по всей панели (сессия 226) ─────────────────────────────────── */
/* Строка в меню: не пункт навигации, поэтому выглядит иначе — рамка и подсказка
   с горячей клавишей. */
.nav-search{
  display:flex; align-items:center; gap:8px; margin:10px 8px 2px; width:calc(100% - 16px);
  height:var(--control-h); padding:0 10px; justify-content:flex-start;
  background:var(--bg); border:1px solid var(--line-strong); color:var(--txt-3);
  font-size:13px; cursor:pointer;
}
.nav-search:hover{background:var(--hover); color:var(--txt);}
.nav-search kbd{
  margin-left:auto; font-family:var(--mono); font-size:11px; color:var(--txt-3);
  background:var(--panel-2); border:1px solid var(--line); border-radius:3px; padding:1px 5px;
}
/* На телефоне поиск — значком в верхней строке, справа от названия раздела. */
button.search-float{display:none;}
.search-modal{width:560px;}
.search-hit{
  display:flex; flex-direction:column; align-items:flex-start; gap:2px; width:100%;
  height:auto; padding:9px 11px; margin-bottom:4px; text-align:left;
  background:var(--panel-2); border:1px solid var(--line);
}
.search-hit:hover{background:var(--hover); border-color:var(--line-strong);}
.search-hit b{font-size:13.5px; color:var(--txt); font-weight:600;}
.search-hit span{font-size:12px; color:var(--txt-3);}
/* Переход к серверному поиску обращений: он ищет по всей переписке и по старым,
   и это честно отличается от выдачи по загруженному. */
.search-hit.deeper{margin-top:10px; border-style:dashed; background:transparent;}

/* ── Модальное окно ─────────────────────────────────────────────────────── */
.overlay{position:fixed; inset:0; background:var(--scrim); z-index:200; display:flex; align-items:center; justify-content:center; padding:20px;}
/* Фон под окном стоит на месте: без этого палец мимо окна листал страницу, а
   один запрет прокрутки (overflow) отбрасывал её в начало. */
html.modal-open{overflow:hidden;}
html.modal-open body{position:fixed; left:0; right:0; width:100%; overflow:hidden;}
.modal{background:var(--panel); border:1px solid var(--line-strong); width:460px; max-width:100%; max-height:86vh; overflow-y:auto;}
.modal-head{padding:18px 20px 0;}
.modal-head h3{font-size:15px;}
.modal-head p{margin:8px 0 0; font-size:13px; color:var(--txt-2); line-height:1.55;}
.modal-body{padding:18px 20px 0;}
/* Абзацы объяснения последствий (окно модуля «Боты»): без правила браузер даёт
   свои поля в 1em, и «что произойдёт / что с данными / чем рискуем» разъезжается. */
.modal-body p{margin:0 0 12px; font-size:13px; color:var(--txt-2); line-height:1.55;}
.modal-body p:last-child{margin-bottom:0;}
.modal-body p b{color:var(--txt); font-weight:600;}
.modal-foot{padding:20px; display:flex; gap:10px; justify-content:flex-end;}
/* Окно кода из Telegram встаёт поверх окна действия (сессия 336). Поле кода — от
   16px на любой ширине: iOS иначе увеличит страницу при фокусе. */
.overlay.overlay-top{z-index:250;}
.code-input{font-size:16px; letter-spacing:.3em; font-variant-numeric:tabular-nums;}

/* ── Тосты ──────────────────────────────────────────────────────────────── */
#toasts{position:fixed; right:18px; bottom:18px; display:flex; flex-direction:column; gap:8px; z-index:300; max-width:min(420px,92vw);}
.toast{
  background:var(--panel); border:1px solid var(--line-strong); border-left:3px solid var(--acc);
  padding:11px 14px; font-size:13px; cursor:pointer; box-shadow:var(--shadow); line-height:1.45;
}
.toast.ok{border-left-color:var(--ok);} .toast.err{border-left-color:var(--danger);}

/* ── Вход ───────────────────────────────────────────────────────────────── */
.login-wrap{min-height:100vh; display:flex; align-items:center; justify-content:center; padding:20px;}
.login{width:340px; max-width:100%;}
.login .brand-big{font-size:22px; font-weight:650; letter-spacing:-.02em; margin-bottom:4px;}
.login .brand-sub{font-size:12.5px; color:var(--txt-3); margin-bottom:26px;}
.login form{border:1px solid var(--line); background:var(--panel); padding:20px;}
/* Капча (сессия 314): обычно невидима — Cloudflare проверяет молча; галочку
   рисует, только если засомневался. Пустой блок места не занимает. */
.login .captcha-box{display:flex; justify-content:center; margin:0 0 12px;}
.login .captcha-box:empty{display:none;}
.err{color:var(--danger); font-size:12.5px; margin-top:10px; min-height:16px;}

.hide{display:none !important;}
/* Меню сворачивается на любом экране, а не только на телефоне: в «Обращениях»
   двести точек ширины — это половина карточки клиента (сессия 222). Свёрнутое меню
   не исчезает совсем — оно открывается тем же значком поверх содержимого. */
.burger{display:inline-flex; flex:0 0 auto; width:var(--control-h); padding:0;}
/* Значок поверх содержимого — на случай, когда меню не на экране: свёрнуто на
   компьютере или закрыто на телефоне. Иначе открыть его было бы нечем. */
/* Значок меню поверх содержимого — на компьютере, когда меню свёрнуто. Там он
   маленький и стоит в углу: содержимое под ним начинается с отступа раздела. */
/* `button.ghost` объявлен выше и задаёт прозрачный фон — весит столько же,
   поэтому здесь тег назван явно. Иначе строка просвечивает, и сквозь неё видно
   список, который под ней проезжает (сессия 226). */
/* `fixed`, а не `absolute`: привязанный к верху раздела значок уезжал вверх при
   прокрутке, и свёрнутое меню становилось недоступным — чтобы его открыть, надо
   было пролистать страницу в начало (сессия 262). */
button.burger-float{
  display:none; position:fixed; z-index:60; left:10px; top:10px;
  height:var(--control-h); padding:0 12px; gap:8px;
  background:var(--panel); border:1px solid var(--line-strong);
  font-size:13.5px; color:var(--txt); max-width:calc(100% - 20px);
}
/* Название раздела рядом со значком — только на телефоне: на широком экране его
   видно по подсветке в меню, и вторая копия там лишняя. */
#burgerLabel{display:none; overflow:hidden; text-overflow:ellipsis; white-space:nowrap;}
/* Только на компьютере: на телефоне значок живёт своей жизнью — тонкой строкой в
   потоке (ниже, в телефонном блоке), и это правило с ним спорило по весу. */
@media (min-width:861px){
  .shell.side-off button.burger-float{display:inline-flex;}
  /* Значок стоит в собственной полосе слева, а не поверх содержимого. Отступ с
     обеих сторон — чтобы раздел остался по центру, а не сполз вправо на 56 точек. */
  .shell.side-off .main{padding-inline:var(--burger-rail);}
}
.shell.side-off .side{
  position:fixed; left:0; top:0; z-index:100; transform:translateX(-100%);
  transition:transform .18s;
}
.shell.side-off .side.open{transform:translateX(0);}
.side-scrim{position:fixed; inset:0; z-index:99; background:var(--scrim-side); border:0;}

/* ── Деньги: подразделы, сводка, постоянные сервисы (сессия 339) ─────────
   Раздел стал восемью вкладками со своими адресами. Вкладки — сверху и одной
   строкой: на телефоне она листается вбок, а край подсказывает, что вкладок
   больше, чем видно. Выбранная — подложкой и жирным, без полосы сбоку. */
.money-tabs{display:flex; gap:2px; overflow-x:auto; scrollbar-width:none;
  margin:0 0 18px; border-bottom:1px solid var(--line);}
.money-tabs::-webkit-scrollbar{display:none;}
.money-tab{flex:0 0 auto; height:var(--control-h); background:transparent; border:0;
  border-radius:3px 3px 0 0; color:var(--txt-2); padding:0 14px; font-size:13.5px;}
.money-tab.on{background:var(--tint-2); color:var(--txt); font-weight:650;}
.money-tab:active, .money button:active{transform:scale(.97);}
@media (hover:hover) and (pointer:fine){
  .money-tab:hover{background:var(--tint); color:var(--txt);}
  .money-tab.on:hover{background:var(--tint-2);}
}
@media (prefers-reduced-motion:reduce){
  .money-tab:active, .money button:active{transform:none;}
}
.money button{transition:transform .12s cubic-bezier(.23,1,.32,1);}
.money .hint{font-size:12px; color:var(--txt-3); line-height:1.45;}
.money .bad{color:var(--danger);}
/* Сумма не рвётся: на телефоне ячейка — строка «метка · значение · пояснение», и
   «4 450» с «₽» разъезжались по двум строкам (сессия 339). */
.money td.num > b, .money td.num > span:not(.hint){white-space:nowrap; flex:0 0 auto;}
.money h2{font-size:14.5px; font-weight:650; margin:0;}
.money section + section{margin-top:26px;}
.money .money-top > section{margin-top:0;}
.money-bar{display:flex; align-items:center; gap:8px; flex-wrap:wrap; margin:0 0 18px;}
.money-bar > button{margin-left:auto;}
.period-nav{display:flex; align-items:center; gap:6px; flex-wrap:wrap;}
.period-title{font-size:14px; font-weight:650; min-width:13ch; text-align:center;}
button.sq{width:var(--control-h-sm); padding:0;}
.period-kind{width:auto; min-width:150px;}
.period-kind .cs-btn{height:var(--control-h-sm); font-size:12.5px;}
.block-head{display:flex; align-items:center; gap:10px; flex-wrap:wrap; margin:0 0 10px;}
.block-head h2{margin-right:auto;}
.money-top{display:grid; grid-template-columns:minmax(0,1.25fr) minmax(0,1fr); gap:16px;
  align-items:start; margin-bottom:26px;}
.ladder, .todo{border:1px solid var(--line); background:var(--panel); padding:18px 20px;}
.ladder h2, .todo h2{margin-bottom:4px;}
.ladder-big{font-size:34px; font-weight:650; letter-spacing:-.02em; line-height:1.15;
  font-variant-numeric:tabular-nums; margin-bottom:10px;}
.ladder-big.good{color:var(--ok);}
.ladder-big.bad{color:var(--danger);}
.ladder-row{display:grid; grid-template-columns:minmax(0,1fr) auto; gap:3px 14px; padding:10px 0;
  border-top:1px solid var(--line); align-items:baseline;}
.ladder-row .k{font-size:13.5px;}
.ladder-row .v{font-size:15px; font-weight:650; font-variant-numeric:tabular-nums;
  white-space:nowrap; text-align:right;}
.ladder-row .how{grid-column:1 / -1; font-size:12px; color:var(--txt-3); line-height:1.45;}
.ladder-row .act{grid-column:1 / -1; margin-top:6px;}
.ladder-row .warn-line{color:var(--warn);}
.ladder-note{font-size:12px; color:var(--txt-3); margin:8px 0 0; padding-top:10px;
  border-top:1px solid var(--line); line-height:1.45;}
.todo-item{display:flex; gap:12px; align-items:flex-start; justify-content:space-between;
  padding:11px 0; border-top:1px solid var(--line);}
.todo-item b{font-weight:600;}
.todo-item .hint{margin-top:3px;}
.todo-item > button{flex:0 0 auto;}
.todo > p.hint{margin:8px 0 0;}
.todo > p.hint + button, .ladder-note + button{margin-top:8px;}
.due.overdue{color:var(--danger); font-weight:600;}
.due.today, .due.soon{color:var(--warn); font-weight:600;}
.due.later{color:var(--txt-3);}
.svc-sug{margin-top:10px; font-size:12.5px; color:var(--txt-2); display:flex; flex-wrap:wrap;
  gap:8px 14px; align-items:center;}
.svc-sug-item{display:inline-flex; align-items:center; gap:8px;}
.seg{display:inline-flex; border:1px solid var(--line-strong); border-radius:3px; overflow:hidden;}
.seg button{border:0; border-radius:0; background:transparent; color:var(--txt-2);}
.seg button + button{border-left:1px solid var(--line-strong);}
.seg button.on{background:var(--tint-2); color:var(--txt); font-weight:650;}
.seg-row{display:flex; align-items:center; gap:8px 10px; flex-wrap:wrap; margin:0 0 14px;}
.seg-label{font-size:12.5px; color:var(--txt-2);}
/* Подпись и её переключатель переносятся вместе: оторванное «Сервер делим» в
   конце строки читалось как подпись к чужим кнопкам. */
.seg-pair{display:inline-flex; align-items:center; gap:8px; flex-wrap:nowrap;}
.money-foot{margin-top:18px;}
details.how-box{margin-top:12px; border:1px solid var(--line); background:var(--panel); padding:10px 14px;}
details.how-box > summary{cursor:pointer; font-size:13px; color:var(--txt-2); min-height:24px; line-height:24px;}
details.how-box p{font-size:12.5px; color:var(--txt-2); line-height:1.5; margin:8px 0 2px;}
th.r{text-align:right;}
.row-acts{text-align:right;}
.row-acts button + button{margin-left:6px;}
details.more-fields{border-top:1px solid var(--line); margin:4px 0 14px; padding-top:10px;}
details.more-fields > summary{cursor:pointer; font-size:13px; color:var(--txt-2);
  margin-bottom:12px; min-height:24px; line-height:24px;}
.modal-foot .aside{margin-right:auto;}
.modal-body label.pref{margin-bottom:14px;}
.modal [hidden]{display:none !important;}
@media (max-width:860px){
  /* Вкладки держатся под шапкой панели: сменить подраздел, не листая наверх. */
  .money-tabs{position:sticky; top:var(--mobile-bar); z-index:30; background:var(--bg);
    margin:-16px -14px 14px; padding:6px 38px 0 10px;
    -webkit-mask-image:linear-gradient(to right, #000 calc(100% - 34px), transparent);
            mask-image:linear-gradient(to right, #000 calc(100% - 34px), transparent);}
  .money-top{grid-template-columns:1fr;}
  .ladder, .todo{padding:14px;}
  .ladder-big{font-size:30px;}
  .money-bar > button{margin-left:0;}
  .todo-item{flex-direction:column; gap:8px;}
  .row-acts{text-align:left;}
  .period-kind{min-width:0; flex:1 1 140px;}
  /* Карточка строки начинается с того, что это: «FirstVDS», «СЧ-2026-0001», а не
     с даты — по названию карточку и ищут глазами. */
  .money tbody tr{display:flex; flex-direction:column;}
  .money td.head-cell{order:-1;}
}

/* ── Телефон ────────────────────────────────────────────────────────────── */
@media (max-width:860px){
  /* На телефоне закреплённого меню не бывает — оно всегда поверх, независимо от
     того, свёрнуто оно на компьютере или нет.
     Открытое меню закрывалось только выбором раздела: гамбургер оказывается под
     самим меню, и нажать его нельзя. Тап по затемнению рядом — обычный способ. */
  /* Палец — не курсор. Компактный контрол в 30 точек мал для тапа (общепринятый
     минимум — 44, у нас основной 38), и промахи в «Пользователях» дорогие: там
     «Удалить» стоит в одном ряду с «Паролем». Поднимаем переменную, а не три
     десятка правил: высоту все контролы берут из неё (сессия 226). */
  :root{--control-h-sm:38px;}

  /* Нижняя граница текста — 12 точек. На мониторе десятипиксельная подпись под
     меткой читается, в дороге с телефона — нет, а именно там панель и открывают
     чаще всего. Поднимаем носителей мелкого: надзаголовки, метки статусов, слаги,
     время ожидания, подписи под сообщениями (сессия 226). */
  .eyebrow, .pill, .who-chip, .slug, .muted, .when, .wait,
  .tile .slug, .bubble .meta, .thread-item .prev, .field .help,
  .figure span, .side-line, .note-tag, .later-tag{font-size:12px;}
  code, .mono{font-size:12px;}
  .nav-group{font-size:12px;}      /* меню на телефоне выезжает панелью — читают и его */
  /* Время ожидания в строке списка объявлено как `.thread-item .who .when` —
     весит больше голого класса, поэтому названо тем же путём. */
  .thread-item .who .when{font-size:12px;}
  .side{position:fixed; left:0; top:0; z-index:100; transform:translateX(-100%); transition:transform .18s;}
  .side.open{transform:translateX(0);}
  .content{padding:16px 14px 60px;}
  /* Полоса над содержимым убрана целиком (сессия 226): шестьдесят точек ради
     слова «Обращения» и приписки «обновлено только что», которую на телефоне не
     читают. Значок меню — плавающий, поверх содержимого. */
  /* На телефоне это не плавающая кнопка, а тонкая строка в потоке: плавающая
     ложилась поверх содержимого — в «Обзоре» накрывала первую плитку с числом.
     44 точки против прежних 60 у полосы, и в них помещается и значок меню,
     и название раздела — обе вещи нужные, в отличие от «обновлено только что».
     Высота задана ЗДЕСЬ и только здесь: к ней прибиты все липкие полки. */
  button.burger-float{
    display:flex; position:sticky; top:0; left:auto; z-index:60;
    width:100%; max-width:none; height:var(--mobile-bar); justify-content:flex-start;
    border:0; border-bottom:1px solid var(--line); border-radius:0;
    /* Справа стоит значок поиска — оставляем ему место, иначе длинное название
       («Аналитика · Школы») уезжает под него. */
    background:var(--bg); padding:0 56px 0 14px;
  }
  #burgerLabel{display:inline; font-weight:600;}
  /* Поиск значком в той же строке — своей он не занимает. */
  button.search-float{
    display:inline-flex; position:fixed; top:0; right:0; z-index:61;
    height:var(--mobile-bar); width:48px; padding:0; border:0; border-radius:0;
    background:transparent; color:var(--txt-2); font-size:20px;
  }
  .shell.reading button.search-float{display:none;}
  .nav-search{margin:10px 8px;}
  /* В открытой переписке значка меню нет вовсе: он ложился ровно на кнопку
     «← к списку», и обе оказывались в одной точке. Навигация при этом не
     теряется — из переписки выходят той самой стрелкой, а из списка меню
     открывается как обычно. */
  .shell.reading button.burger-float{display:none;}
  /* Плотность: числа и плитки рисовались под монитор. На телефоне шесть чисел
     занимали весь первый экран, а школ помещалось полторы — до «что требует
     внимания» и до второй школы приходилось листать. */
  .figure{flex:1 1 50%; border-bottom:1px solid var(--line); padding:13px 14px;}
  .figure b{font-size:24px;}
  .figure span{margin-top:4px;}
  .tile{padding:13px 14px 14px; gap:7px; min-height:0;}

  /* Шапка раздела уезжала вверх при первом же движении: чтобы сменить фильтр,
     что-то найти или нажать «Добавить», приходилось листать обратно наверх.
     Держим её под шапкой панели во всех разделах и во всю ширину экрана. */
  .section-head{
    position:sticky; top:var(--mobile-bar); z-index:30; background:var(--bg);
    gap:8px; margin:-16px -14px 12px; padding:10px 14px;
    border-bottom:1px solid var(--line);
  }
  /* Одна высота на весь ряд: поле 38 рядом с кнопкой 30 — ряд собран наспех. */
  .section-head button{flex:0 0 auto; height:var(--control-h);}
  .section-head .search{max-width:none; flex:1 1 140px;}
  /* Шапка без единого контрола (регламент) на телефоне только повторяет заголовок
     из шапки панели — держать её на экране незачем. */
  .section-head.plain{display:none;}
  /* Поле мельче 16px iOS зумит при фокусе — страница уезжает вбок, и обратно её
     возвращают пальцами. Мелкие поля внутри строк тоже. */
  input, select, textarea,
  .stage-pick, .stage-note, .mini-pick, .side-line select, .chat-foot textarea,
  .cs-btn, .cs-opt, .cnum .cnum-input, .cdate .cdate-text,
  .stage-pick .cs-btn, .mini-pick .cs-btn, .side-line .cs-btn{font-size:16px;}
  /* Заголовок карточки-строки: название школы без метки и во всю ширину — на телефоне
     оно и есть заголовок, а метка «ШКОЛА» съедала треть строки. */
  td.head-cell{display:block; padding-top:10px;}
  td.head-cell::before{display:none;}
  /* Пустые поля («—», «не указано») на телефоне не рисуем: карточка школы из-за них
     растягивалась вдвое, а полезного в этих строках нет. */
  td.empty-cell{display:none;}
  .grid-2{grid-template-columns:1fr;}
  /* Таблицы на телефоне — карточками: горизонтальный скролл в панели управления
     означает, что половина данных не видна, а именно там принимают решения. */
  table, thead, tbody, tfoot, tr, td{display:block; width:100%;}
  thead{display:none;}
  tbody tr{border-bottom:1px solid var(--line); padding:10px 0;}
  tbody tr:last-child{border-bottom:0;}
  td{border:0; padding:5px 14px; display:flex; gap:10px; align-items:baseline;}
  td::before{content:attr(data-l); flex:0 0 92px; font-size:12px; color:var(--txt-3);}
  /* Ячейка без метки (ряд действий) не должна резервировать 92 точки под пустое
     место: из-за них «Удалить» не помещалась в строку и уезжала под кнопки. */
  td[data-l=""]::before, td:not([data-l])::before{display:none;}

  /* Адреса выхода: карточка из четырёх строк на каждый адрес превращала пул из
     шестнадцати штук в ленту на три экрана. Свернули в две строки: сверху сам
     адрес и его состояние, снизу — где он живёт и чья школа его держит. */
  table.ips tbody tr{display:grid; grid-template-columns:1fr auto; gap:3px 10px;
    padding:9px 14px; align-items:center;}
  table.ips td{padding:0; display:block; min-width:0;}
  table.ips td::before{display:none;}
  table.ips td[data-l="Адрес"]{grid-column:1; grid-row:1;}
  table.ips td[data-l="Статус"]{grid-column:2; grid-row:1; justify-self:end;}
  /* «Выдан школе» рядом с названием школы — то же самое, сказанное дважды.
     Показываем состояние, только когда оно требует внимания. */
  table.ips td[data-st="assigned"]{display:none;}
  table.ips td[data-l="Где"]{grid-column:1; grid-row:2; font-size:11.5px; color:var(--txt-3);}
  table.ips td[data-l="Школа"]{grid-column:2; grid-row:2; justify-self:end;
    font-size:11.5px; color:var(--txt-2);}
  /* Кнопка «Убрать» есть только у свободного адреса — пустая ячейка не должна
     занимать третий ряд у остальных пятнадцати. */
  table.ips td[data-l=""]{grid-column:1 / -1; grid-row:3;}
  table.ips td[data-l=""]:empty{display:none;}

  /* Переключатель месяца остаётся одним куском: растянутый на строку, он разводит
     стрелки по краям экрана, и они перестают читаться как пара к названию. */
  .month-nav{flex:0 0 auto;}

  /* Доступы школы: ключ и значение в одну строку не помещаются — адрес рвётся на
     четыре куска и жмётся к правому краю. Ключ сверху, значение под ним по левому
     краю: так его читают и так же выделяют, чтобы скопировать. */
  .kv.wide{display:block; margin-bottom:12px;}
  .kv.wide span{display:block; text-align:left; margin-top:3px;}
  td.full{display:block;}
  td.full::before{display:block; margin-bottom:6px;}
  /* Ряд действий в карточке: «Пароль · Отключить · Удалить» не помещался в 390
     точек, и «Удалить» уезжала за край — нажать её было нечем. */
  td.nowrap{white-space:normal; flex-wrap:wrap; row-gap:6px;}
  /* Опасное отодвинуто от безопасного. На пальце «Отключить» и «Удалить» стояли
     в восьми точках друг от друга, и промах стоит учётной записи: одно действие
     снимается тумблером обратно, второе — нет (сессия 226). */
  td.nowrap .danger{margin-left:auto;}
  tr.details td{padding:0;}
  /* Строка сигнала на телефоне: текст во всю ширину, кнопка под ним. Иначе
     кнопка забирает половину ряда, «ждёт ответа 3 ч» сжимается в колонку по
     одному слову, а сама кнопка наезжает на текст (сессия 226). */
  .issue{flex-wrap:wrap;}
  .issue .who{min-width:0; flex:1 1 auto;}
  .issue .what{flex:1 1 100%;}
  .issue > button{width:100%; margin-top:10px;}
  /* Кнопка сигнала на телефоне — своей строкой во всю ширину. Иначе она отжимает
     текст в колонку по два слова, и «что случилось» читается хуже всего именно там,
     где панель чаще всего и открывают. */
  .issue-rich .issue-text{flex:1 1 100%;}
  .issue-rich button{width:100%; margin-top:10px;}
  /* В группе кнопка школы остаётся в шапке (там она одна), а действия строк
     уходят под текст: рядом с ним они отжимают его в колонку по два слова. */
  .issue-group-head{flex-wrap:wrap; padding:10px 12px;}
  .issue-line{flex-wrap:wrap; padding:10px 12px 10px 22px;}
  .issue-line button{width:100%; margin-top:8px;}
  /* Пояснение к сигналу — восемь строк. Показываем по кнопке над списком. */
  .issues:not(.with-hints) .issue-hint{display:none;}
  .eyebrow-row button{width:auto; margin-top:0;}
  /* Полоса значка скрыта в открытой переписке (правило ниже по файлу) — значит и
     отступ под неё равен нулю. Иначе сверху остаётся мёртвый пояс в 44 точки, и
     сообщения проезжают под шапкой переписки (сессия 262). */
  .shell.reading{--mobile-bar:0px;}
}

/* ── Широкие мониторы ───────────────────────────────────────────────────────
   Потолок ширины растёт ступенями, а не тянется до края: таблица во весь
   двухметровый монитор читается хуже, чем та же таблица в полтора экрана. */
@media (min-width:1700px){ :root{--content-max:1600px;} }
@media (min-width:2000px){ :root{--content-max:1840px;} }
@media (min-width:2400px){ :root{--content-max:2100px;} }

/* Раздел «Схема проекта»: карта сама рисует своё меню и панель, ей нужна вся ширина. */
.content.map{max-width:none; padding:14px 18px 18px;}
.map-head{display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap; margin-bottom:10px;}
.map-head .hint{display:block; margin-top:2px;}
.map-frame{display:block; width:100%; height:calc(100vh - 96px); min-height:520px; border:1px solid var(--line, #dce5ea); border-radius:12px; background:#fff;}
@media (max-width:860px){ .map-frame{height:calc(100vh - 150px);} }
