:root{--bg:#0f1b2a;--panel:#16263a;--line:#2a3f58;--fg:#e8eef5;--muted:#8fa9c4;--acc:#7fd1ff}
*{box-sizing:border-box}
body{margin:0;font-family:system-ui,Arial;background:var(--bg);color:var(--fg)}
/* вход */
#login{min-height:100vh;display:flex;align-items:center;justify-content:center}
.box{background:var(--panel);padding:32px;border-radius:12px;width:320px}
.box h2{margin:0 0 20px;color:var(--acc);text-align:center}
.box input{width:100%;margin:8px 0;padding:12px;border:1px solid var(--line);border-radius:8px;background:var(--bg);color:var(--fg)}
.box button{width:100%;margin-top:16px;padding:12px;border:0;border-radius:8px;background:var(--acc);color:var(--bg);font-weight:600;cursor:pointer}
.err{color:#ff8a8a;font-size:.9rem;min-height:1.2em;margin-top:10px;text-align:center}
/* «Забыли пароль?» — ссылкой под кнопкой входа, а не второй кнопкой */
.fgl{text-align:center;margin-top:12px}
/* .box button (0,1,1) перебивал .blink (0,1,0) и красил ссылку в заливку кнопки во всю
   ширину — «Забыли пароль?» выглядела второй кнопкой входа, ровно тем, чем не должна.
   Возвращаем вид ссылки весом селектора, а не !important. */
.box .fgl button.blink{width:auto;margin-top:0;padding:10px 4px;background:transparent;
  color:var(--muted);font-weight:400;border-radius:0}
.box .fgl button.blink:hover{color:var(--acc);text-decoration:underline}
/* требования к паролю: зеленеют, когда введённое им отвечает */
.pwh{color:var(--muted);font-size:.82rem;line-height:1.35;margin-top:8px}
.pwh.ok{color:#8aff9e}
/* поле пароля с глазиком: кнопка поверх правого края, тексту оставлен отступ */
.pwf{position:relative}
.pwf input{padding-right:44px}
/* .box button задаёт кнопкам ширину 100% и отступ — глазик перебивает это двумя классами */
.pwf .pweye{position:absolute;right:6px;top:50%;transform:translateY(-50%);width:auto;margin:0;
  background:transparent;border:0;padding:6px 8px;color:var(--muted);cursor:pointer;
  font-size:1rem;line-height:1;opacity:.75}
.pwf .pweye:hover{opacity:1}
.pwf .pweye.on{opacity:1;color:var(--acc)}
/* Глазик — встроенный SVG в currentColor, а не эмодзи. U+1F441 на телефоне и в Windows
   рисуется цветной картинкой: наш color до неё не доходит, и состояние «пароль виден /
   скрыт» передать нечем — глаз всегда выглядит открытым. Иконки две, различаются ровно
   одной чертой; переключает их класс .on, который и так ставит togglePw(). */
.pwf .pweye svg{display:block;width:20px;height:20px;fill:none;stroke:currentColor;
  stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.pwf .pweye .eo{display:none}      /* пароль скрыт — показываем перечёркнутый глаз */
.pwf .pweye.on .eo{display:block}  /* пароль виден — открытый */
.pwf .pweye.on .ec{display:none}
/* незаполненное обязательное поле формы: подсветка снимается первой же правкой */
.box input.inv,.box select.inv{border-color:#ff8a8a}
/* предупреждение в форме — не ошибка, а предостережение: жёлтым, без блокировки сохранения */
.fwarn{color:#ffd27f;font-size:.85rem;line-height:1.35;margin:6px 0 0}
/* приложение */
#app{display:none;max-width:1100px;margin:0 auto;padding:16px}
/* заглушка на время, пока не известно, какой экран домашний */
#boot{display:none;min-height:60vh;align-items:center;justify-content:center;color:var(--muted)}
#boot.on{display:flex}
header{display:flex;flex-wrap:wrap;align-items:center;gap:12px;margin-bottom:16px}
header h1{font-size:1.3rem;color:var(--acc);margin:0;flex:1}
/* клиент-владелец рядом с названием объекта — только у сотрудников Стража */
.tcli{color:var(--muted);font-size:.92rem;font-weight:400;white-space:nowrap}
select,.rng button,.lg{background:var(--panel);color:var(--fg);border:1px solid var(--line);border-radius:8px;padding:8px 12px;cursor:pointer}
.rng button.on{background:var(--acc);color:var(--bg);font-weight:600;border-color:var(--acc)}
/* автообновление и разовое «Обновить» */
.rfr{display:flex;align-items:center;gap:8px}
.rfr select{font-size:.9rem}
.rfb:disabled{opacity:.45;cursor:default;border-color:var(--line)}
/* неброская текстовая ссылка возврата: кнопок в шапке и так много */
.blink{background:transparent;border:0;padding:0;color:var(--muted);font:inherit;font-size:.9rem;cursor:pointer}
.blink:hover{color:var(--acc);text-decoration:underline}
/* возврат отдельной строкой под шапкой, справа — одинаково на дашборде и в разделах */
.backrow{display:flex;justify-content:flex-end;margin:-4px 0 12px}
.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;margin-bottom:18px}
/* содержимое карточки по центру; значение прижато к низу — страховка на случай подписи,
   которая не влезет в одну строку: иначе её значение уезжает ниже соседних */
.card{background:var(--panel);border-radius:10px;padding:12px 14px;position:relative;
  display:flex;flex-direction:column;align-items:center;text-align:center}
.card .k{color:var(--muted);font-size:.78rem;margin-bottom:6px}
.card .v{font-size:1.5rem;font-weight:600;line-height:1.2;margin-top:auto}
.card .v.sm{font-size:1rem;line-height:1.35} /* перечень компрессоров длиннее одного слова */
.card .u{color:var(--muted);font-size:.8rem}
/* вторая строка карточки тревог: «Подтвердите (N)» — ссылка к журналу.
   Лежит в НИЖНЕМ ПОЛЕ карточки (position:absolute поверх padding-bottom), поэтому строка
   не добавляет карточке ни одной лишней строки и не растягивает ряд по вертикали —
   карточка остаётся ровно такой же высоты, как соседние.
   Цвет — внимание (жёлтый), а не тревога: красный занят активными тревогами. Без мигания.
   nowrap с многоточием — страховка от узкой карточки: перенос вернул бы прежнюю беду. */
.card .cx{position:absolute;left:6px;right:6px;bottom:1px;
  color:#ffd27f;font-size:.7rem;line-height:1;cursor:pointer;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.card .cx:hover{text-decoration:underline}
/* компрессоры в одной карточке: до трёх, перенос только между ними */
.mch{white-space:nowrap}
.mch.good{color:#8aff9e}
.msep{color:var(--muted);margin:0 4px}
/* данные прошлого объекта не показываем: значения гаснут до прихода /api/current */
.cards.wait .card .v,.cards.wait .card .cx{opacity:.35}
/* связи с объектом нет: карточки приглушены целиком, но значения ОСТАЮТСЯ читаемыми —
   старые данные диспетчеру полезнее пустого экрана (стандарт SCADA) */
.cards.dim{opacity:.45;transition:opacity .2s}
/* баннер потери связи над карточками */
.stale{background:#3a2a1a;border-left:3px solid #ffd27f;color:#ffd27f;
  border-radius:8px;padding:10px 14px;margin-bottom:12px;font-size:.92rem}
/* каналы связи контроллера в шапке объекта: те же значки, что на плитках — один язык
   на весь кабинет. Ряд приглушённый, чтобы не спорить со staleness-баннером над ним */
.linkline{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:.85rem;margin:-4px 0 12px}
.bad{color:#ff8a8a}.good{color:#8aff9e}.warn{color:#ffd27f}
.panel{background:var(--panel);border-radius:12px;padding:14px 16px;margin-bottom:18px}
.panel h3{margin:0 0 10px;font-size:1rem;color:var(--acc)}
/* шапка панели с переключателем в правом углу */
.phead{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;margin-bottom:10px}
.phead h3{margin:0}
.rng.sm button{padding:5px 10px;font-size:.85rem}
.cwrap{position:relative;height:300px}
.chart{width:100%;height:100%}
/* постоянные подписи границ окна навигатора (dataZoom) */
.zlab{position:absolute;bottom:2px;color:#8fa9c4;font-size:.82rem;pointer-events:none;font-variant-numeric:tabular-nums;white-space:nowrap}
.zlab.l{left:56px}
.zlab.r{right:56px;text-align:right}
/* узкие экраны: подписи мельче и ближе к краям, чтобы не наезжать друг на друга/на слайдер */
@media (max-width:480px){ .zlab{font-size:.72rem;bottom:1px} .zlab.l{left:8px} .zlab.r{right:8px} }
.sub{color:var(--muted);font-size:.9rem;margin-top:8px}
.al{display:flex;align-items:flex-start;gap:10px;padding:8px 0;border-bottom:1px solid var(--line);font-size:.92rem}
.al:last-child{border-bottom:0}
.al .alb{flex:1}
.al .dot{width:10px;height:10px;border-radius:50%;margin-top:5px;flex:none}
/* квитирование */
.alh{padding:4px 0 10px}
.ackb{flex:none;align-self:center}
.ackm{color:#8aff9e}
.al.cl .ackm{color:var(--muted)}
.al.act .dot{background:#ff5c5c}.al.cl .dot{background:var(--muted)}
.al.act{color:var(--fg)}.al.cl{color:var(--muted)}
.al .t{color:var(--muted);font-size:.82rem}
/* название объекта в сводных журналах по всей организации */
.advl{color:var(--acc)}
.act .advl{font-size:.86rem}
.msg{color:var(--muted);padding:12px 0}
.pager{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;margin-top:12px;padding-top:12px;border-top:1px solid var(--line)}
.pgrows{color:var(--muted);font-size:.9rem}
.pager select{background:var(--bg);color:var(--fg);border:1px solid var(--line);border-radius:6px;padding:4px 8px}
.pgnav{display:flex;align-items:center;gap:10px}
.pgnav span,.pager .t{color:var(--muted);font-size:.9rem}
.pgnav button{background:var(--panel);color:var(--fg);border:1px solid var(--line);border-radius:6px;padding:6px 12px;cursor:pointer}
.pgnav button:disabled{opacity:.4;cursor:default}
/* разделы управления и экран выбора объекта поверх дашборда */
.page{display:none;max-width:1100px;margin:0 auto;padding:16px}
.page.on{display:block}
/* ---- стартовый экран выбора объекта (волна 4.1) ---- */
/* отступ до сводных журналов — такой же, как между панелями дашборда */
.ogrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(290px,1fr));gap:14px;margin-bottom:18px}
/* --orow/--osp: высота строки значений и спарклайна. Заглушка «Не выбран параметр»
   занимает ровно их сумму, поэтому плитка без выбранных точек ростом не отличается */
.ocard{background:var(--panel);border:1px solid transparent;border-radius:12px;padding:14px 16px;cursor:pointer;
       --orow:1.35rem;--osp:60px}
.ocard:hover{border-color:var(--acc)}
.ohead{display:flex;align-items:flex-start;justify-content:space-between;gap:10px}
.otitle{font-size:1.05rem;font-weight:600;line-height:1.3}
.ocard:hover .otitle{color:var(--acc)}
/* тревоги на плитке: «2 активные · 5 без подтверждения». Строки при нулях нет совсем —
   высоту плиток в ряду это не ломает, сетка их и так растягивает по самой высокой */
.oal{margin-top:8px;color:var(--muted);font-size:.85rem}
.oab{color:#ff8a8a;font-weight:600}
.otemps{display:flex;flex-wrap:wrap;gap:2px 14px;margin:10px 0 4px;min-height:var(--orow);
        font-size:.95rem;font-variant-numeric:tabular-nums}
.ov{white-space:nowrap}
.ovl{color:var(--muted);font-size:.82rem}
/* pointer-events:none на всём блоке: canvas ECharts иначе перехватывает наведение и гасит
   cursor:pointer плитки в её нижней половине. Спарклайн silent, ни кликов, ни подсказок
   ему не нужно — надёжнее снять события целиком, чем переопределять курсор поверх canvas */
.ospark{position:relative;height:var(--osp);pointer-events:none}
.ospark .spc{width:100%;height:100%}
/* ни одной точки «На главный»: место значений и графика занимает одна подпись той же высоты */
.onone{display:flex;align-items:center;justify-content:center;margin:10px 0 4px;
       height:calc(var(--orow) + var(--osp));color:var(--muted);font-size:.9rem}
/* период спарклайна — вместо осей и пояснений под сеткой */
.splab{position:absolute;right:2px;bottom:0;color:var(--muted);font-size:.7rem;opacity:.8;pointer-events:none}
/* индикатор связи: кружок по свежести данных + макет каналов */
.olink{display:flex;align-items:center;gap:6px;flex:none;color:var(--muted);font-size:.8rem}
.odot{width:9px;height:9px;border-radius:50%;background:var(--muted);flex:none}
.odot.on{background:#8aff9e}
.olink .ost.on{color:#8aff9e}
/* макет каналов LAN/Wi-Fi/GSM: контроллер link_type/rssi пока не публикует — все серые.
   Активный канал получит класс on (зелёный), сегменты уровня — s.on. */
.lnk{display:flex;align-items:center;gap:5px;margin-left:3px}
.li{width:15px;height:15px;flex:none;color:#55708e;fill:none;stroke:currentColor;stroke-width:1.4;
  stroke-linecap:round;stroke-linejoin:round}
.li.on{color:#8aff9e}
.li .s{opacity:.5}
.li .s.on{opacity:1}
.li .dot{fill:currentColor;stroke:none;opacity:.5}
.li .dot.on{opacity:1}
.li.gsm .s{fill:currentColor;stroke:none}
/* Уровень сигнала и заряд — мелкой подписью ВПЛОТНУЮ к своему значку (без минуса и без
   слова «сигнал»): так она читается как подпись значка, а не как отдельная строка.
   На плитках подписей нет вовсе — там только значки. */
.lrs{color:var(--muted);font-size:.7rem;white-space:nowrap;margin-left:-2px}
/* значок батареи и его процент — одной связкой, чтобы подпись не отрывалась от иконки */
.lnkb{display:inline-flex;align-items:center;gap:2px}
/* батарея щита: корпус обводкой, уровень заливкой — как на телефоне */
.li.batt{width:20px}
.li.batt .case,.li.batt .tip{stroke:currentColor;fill:none}
.li.batt .fill{fill:currentColor;stroke:none}
.li.batt.low{color:#ff8a8a}
/* работа без внешнего питания — событие само по себе, даже при полном заряде */
.li.batt.unplug{color:#ffd27f}
.trow{display:flex;flex-wrap:wrap;align-items:center;gap:10px;padding:10px 0;border-bottom:1px solid var(--line);font-size:.92rem}
.trow:last-child{border-bottom:0}
.trow.off{opacity:.55}
.tn{flex:1 1 190px;min-width:150px}
.tm{color:var(--muted);font-size:.85rem}
/* контакты сотрудника значениями, а не значками — директору звонить прямо с этого экрана */
.ucon{margin-top:2px;word-break:break-word}
.tb{background:var(--bg);color:var(--fg);border:1px solid var(--line);border-radius:6px;padding:6px 12px;cursor:pointer;font-size:.85rem}
.tb:hover{border-color:var(--acc)}
.tb.acc{background:var(--acc);color:var(--bg);border-color:var(--acc);font-weight:600}
.tb.del{color:#ff8a8a;border-color:#4a2b34}
.tb.del:hover{border-color:#ff8a8a}
.pbtn{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.upick{flex:none;display:flex;align-items:center}
.upick input{width:16px;height:16px;cursor:pointer}
.upick input:disabled{cursor:default;opacity:.35}
/* объект в карточке клиента открывается кликом */
.dvl{cursor:pointer}
.dvl:hover b{color:var(--acc)}
.tag{display:inline-block;border:1px solid var(--line);border-radius:6px;padding:2px 7px;color:var(--muted);font-size:.78rem}
.tag.bad{color:#ff8a8a;border-color:#ff8a8a}
/* поля в модалках */
.box select{width:100%;margin:8px 0;padding:12px;border:1px solid var(--line);border-radius:8px;background:var(--bg);color:var(--fg)}
/* подпись секции формы — всегда по левому краю, как заголовок над своим блоком */
.fl{color:var(--muted);font-size:.85rem;margin-top:10px;text-align:left}
.fchk{display:flex;align-items:center;gap:8px;color:var(--muted);font-size:.9rem;margin:10px 0;cursor:pointer}
.fchk input{width:auto;margin:0}
.flist{max-height:44vh;overflow-y:auto;margin:8px 0}
.pwbig{font-family:ui-monospace,Consolas,monospace;font-size:1.35rem;font-weight:600;letter-spacing:.08em;
  text-align:center;background:var(--bg);border:1px solid var(--line);border-radius:8px;padding:14px;margin:12px 0;user-select:all}
/* ссылка на бота в модалке привязки: единственная настоящая <a> в кабинете */
.tglink{display:block;text-align:center;color:var(--acc);font-size:.95rem;margin:4px 0 2px}
/* строка канала в «Уведомлениях»: галка слева, состояние и кнопка справа */
.ntrow{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:10px;
  padding:10px 0;border-top:1px solid var(--line)}
.ntrow:first-child{border-top:0}
.ntrow .fchk{margin:0}
.ntst{color:var(--muted);font-size:.85rem}
/* подкатегория канала («SMS при отсутствии связи»): отступом влево, чтобы читалась как
   вложенная в свою строку, а не как ещё три равноправных канала */
.ntsub{padding:2px 0 10px 26px}
.ntsub .fchk{margin:4px 0}
/* реквизиты организации в «Настройках»: подпись поля приглушена, значение обычным текстом */
.ovrow{padding:3px 0;color:var(--fg)}
.ovk{display:inline-block;min-width:132px;color:var(--muted);font-size:.85rem}
/* уставки */
.sprow{display:flex;flex-wrap:wrap;align-items:center;gap:12px;padding:9px 0;border-bottom:1px solid var(--line)}
.sprow:last-child{border-bottom:0}
.spn{flex:1 1 150px;min-width:120px}
.spf,.spc{color:var(--muted);font-size:.85rem;display:flex;align-items:center;gap:6px}
.spc{cursor:pointer}
.spf input{width:80px;background:var(--bg);color:var(--fg);border:1px solid var(--line);border-radius:6px;padding:6px 8px}
.spb{background:var(--acc);color:var(--bg);border:0;border-radius:6px;padding:6px 14px;font-weight:600;cursor:pointer}
.spb:disabled{background:var(--bg);color:var(--muted);border:1px solid var(--line);cursor:default}
.spmsg{font-size:.85rem;color:#8aff9e;min-width:80px}
.spmsg.bad{color:#ff8a8a}
.spmsg.lock{color:var(--muted);min-width:0}
.spn{display:flex;align-items:center;gap:6px;flex-wrap:wrap}
/* переименование точки — в режиме инженера */
.ptb{background:transparent;border:0;color:var(--muted);cursor:pointer;font-size:.95rem;padding:0 4px;line-height:1}
.ptb:hover{color:var(--acc)}
/* «На главный» — личная настройка точки, поэтому тише имени и уставок */
.sph{display:flex;align-items:center;gap:5px;color:var(--muted);font-size:.8rem;cursor:pointer;white-space:nowrap}
.sph:hover{color:var(--fg)}
.sph input{cursor:pointer}
/* фильтры журнала действий */
.actf{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-bottom:10px}
.actf select,.actf input{background:var(--bg);color:var(--fg);border:1px solid var(--line);border-radius:6px;padding:6px 8px;font:inherit;font-size:.85rem}
.actf input[type=date]{color-scheme:dark}
.actf #afq{flex:1 1 180px;min-width:140px}
.afl{display:flex;align-items:center;gap:6px;color:var(--muted);font-size:.85rem}
/* модалка смены пароля */
.modal{display:none;position:fixed;inset:0;background:rgba(8,14,22,.72);align-items:center;justify-content:center;z-index:10}
.modal.on{display:flex}
.box button.sec{background:var(--panel);color:var(--fg);border:1px solid var(--line);font-weight:400;margin-top:8px}
.box.wide{width:min(420px,92vw)}
/* Запасное правило на будущий рост форм: если содержимое не влезло, прокручивается САМА
   модалка, а не страница под ней. Экран за модалкой не должен уезжать. */
.modal .box{max-height:92vh;overflow-y:auto;position:relative}
/* Закрытие — крестиком в углу, а не кнопкой внизу: «Закрыть» стояла в одном ряду с
   действием окна и весила столько же, хотя это выход, а не поступок. Esc работает как
   работал. Селектор с .box, иначе общее правило .box button растянет крестик на всю ширину. */
.box button.mx{position:absolute;top:6px;right:8px;width:32px;height:32px;margin:0;padding:0;
  background:none;border:0;border-radius:8px;color:var(--muted);font-size:1.5rem;line-height:1;
  font-weight:400;cursor:pointer}
.box button.mx:hover{color:var(--fg);background:rgba(255,255,255,.07)}
/* повторная отправка кода — строка, а не кнопка: действие в окне одно, «Подтвердить» */
.phag{margin-top:12px;text-align:center;font-size:.9rem;color:var(--muted)}
.phag.on{color:var(--acc);cursor:pointer}
.phag.on:hover{text-decoration:underline}
/* Форма пользователя выросла до четырёх контактов и перестала помещаться в ноутбучный
   экран целиком. Ужимаем именно её: контакты парами, отступы плотнее. */
#usrm .box{padding:22px 24px}
#usrm h2{margin-bottom:14px}
/* :not(checkbox) обязателен — иначе правило по id перебьёт .fchk input и раздует галочки */
#usrm input:not([type=checkbox]),#usrm select{margin:5px 0;padding:9px 12px}
#usrm .fl{margin-top:12px;margin-bottom:2px}
#usrm .fchk{margin:7px 0}
#usrm button{margin-top:10px}
/* пара полей в строку; на узком экране колонка сама схлопывается в одну */
#usrm .f2{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:0 10px}
/* «Объекты (необязательно):» — заголовок своего списка, а не строка между блоками */
#usrm .flist{margin:2px 0 0}
.mtext{color:var(--muted);font-size:.92rem;line-height:1.45;margin:0}
.err.ok{color:#8aff9e}
/* гамбургер-меню */
.umenu{position:relative;display:flex;align-items:center;gap:10px}
.uwho{color:var(--muted);font-size:.86rem;white-space:nowrap}
.menu{position:absolute;right:0;top:calc(100% + 6px);min-width:220px;background:var(--panel);
  border:1px solid var(--line);border-radius:10px;padding:6px;display:none;z-index:20;
  box-shadow:0 10px 28px rgba(0,0,0,.4)}
.menu.on{display:block}
/* имя пользователя строкой в меню: показывается только на телефоне, где .uwho убрано из шапки */
.mwho{display:none}
.menu button{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;
  background:transparent;border:0;color:var(--fg);font:inherit;font-size:.92rem;text-align:left;
  padding:10px 12px;border-radius:8px;cursor:pointer}
.menu button:hover{background:var(--bg)}
.sw{width:34px;height:18px;border-radius:10px;background:var(--line);position:relative;flex:none}
.sw::after{content:'';position:absolute;top:2px;left:2px;width:14px;height:14px;border-radius:50%;background:var(--muted);transition:left .15s}
.sw.on{background:var(--acc)}
.sw.on::after{left:18px;background:var(--bg)}
/* журнал действий */
.act{padding:8px 0;border-bottom:1px solid var(--line);font-size:.92rem;line-height:1.4}
.act:last-child{border-bottom:0}
.act .t{color:var(--muted);font-size:.86rem}
/* всплывающее сообщение */
.toast{position:fixed;left:50%;transform:translateX(-50%);bottom:24px;background:var(--panel);
  border:1px solid var(--line);border-radius:10px;padding:10px 16px;z-index:30;display:none}
.toast.on{display:block}

/* ──────────────────────────────────────────────────────────────────────────────
   ТЕЛЕФОН (волна мобильной вёрстки, очередь 1)
   Кабинет открывают с телефона так же часто, как с ноутбука, но вся вёрстка выше
   рассчитана на ширину экрана. Здесь перестраивается ровно то, что на 360-390px
   ломалось: шапка, меню, поле графика, строки уставок, фильтры журнала и размеры
   целей под палец. Всё собрано одним блоком в конце файла и живёт только ниже
   640px — десктопные правила выше не тронуты ни одной строкой.
   ────────────────────────────────────────────────────────────────────────────── */
@media (max-width:640px){
 #app,.page{padding:12px}

 /* --- шапка: было пять рядов и заголовок в три строки по одному слову.
    Стало: название с бургером в одной строке, дальше селектор объекта, пресеты
    и автообновление — каждый своей строкой во всю ширину --- */
 header{gap:8px;margin-bottom:12px}
 header h1{order:1;flex:1 1 auto;min-width:0;font-size:1.15rem}
 .umenu{order:2;flex:none;margin-left:auto}
 /* имя пользователя переехало строкой в само меню: в шапке оно занимало целый ряд */
 .uwho{display:none}
 .mwho{display:block;padding:8px 12px 10px;margin-bottom:4px;border-bottom:1px solid var(--line);
   color:var(--muted);font-size:.85rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
 #devsel{order:3;flex:1 1 100%;width:100%}
 #appHead .rng{order:4;flex:1 1 100%;display:flex;gap:8px}
 #appHead .rng button{flex:1 1 0;padding:10px 6px}
 .rfr{order:5;flex:1 1 100%}
 .rfr select{flex:1 1 auto;min-width:0}

 /* меню: бургер теперь у правого края, поэтому right:0 больше не уводит список за
    левый край экрана (пункты теряли первые буквы). Ширину всё равно ограничиваем */
 .menu{min-width:0;width:max-content;max-width:calc(100vw - 24px)}

 /* --- цели под палец: 44px — рекомендованный минимум и в iOS, и в Android.
    Поднимаем отступами и высотой, размер шрифта не трогаем --- */
 .rng button,.lg,.tb,.spb,.pgnav button,select,.box button{min-height:44px}
 .spf input,.actf input,.actf select,.pager select,.box input{min-height:44px}
 #burger,.pgnav button{min-width:44px}
 input[type=checkbox]{width:20px;height:20px}
 .sph,.spc,.fchk{min-height:44px}
 .blink{padding:10px 0}
 .backrow{margin:-6px 0 8px}

 /* --- графики: подписям периода отведена своя полоса под слайдером. Раньше они
    лежали на одной высоте с ручками слайдера, и ручки резали «19.08 15:45» пополам.
    Полосу даёт padding-bottom обёртки: канва графика в неё не заходит --- */
 .cwrap{height:326px;padding-bottom:24px}
 .zlab{bottom:4px}

 /* --- уставки: имя точки своей строкой, «Верх» и «Низ» парой, «вкл» и «Сохранить»
    следом. Раньше поля разъезжались по трём рядам с рваным выравниванием --- */
 .sprow{gap:8px 10px;padding:12px 0}
 .spn{flex:1 1 100%;min-width:0}
 .spf{flex:1 1 calc(50% - 5px);min-width:0;justify-content:space-between;gap:8px;white-space:nowrap}
 .spf input{width:auto;flex:1 1 auto;min-width:0}
 .spc{flex:0 0 auto}
 .spb{flex:1 1 auto}
 .spmsg{flex:1 1 100%;min-width:0}

 /* фильтры журнала действий: поиск, пара дат, сброс — тремя ровными рядами */
 .actf>select{flex:1 1 100%}
 .actf #afq{flex:1 1 100%}
 .actf .afl{flex:1 1 calc(50% - 4px)}
 .actf .afl input{flex:1 1 auto;min-width:0}
 .actf>button.tb{flex:1 1 100%}

 /* «Активные»/«Архив» — вкладки подраздела, а не две отдельные кнопки. Разметка штатная
    (.rng sm, тот же сегментный ряд, что у пресетов графика), меняем только вид: убираем
    зазор, даём общую рамку и скругление по внешним краям, неактивную гасим.
    Селектор с #stf: пресеты графика и «Средние/Все фазы» должны остаться прежними. */
 #stf .phead .rng.sm{gap:0;border:1px solid var(--line);border-radius:10px;overflow:hidden}
 #stf .phead .rng.sm button{border:0;border-radius:0;min-height:44px;padding:0 16px;font-size:.9rem}
 #stf .phead .rng.sm button+button{border-left:1px solid var(--line)}
 #stf .phead .rng.sm button:not(.on){background:transparent;color:var(--muted)}

 /* плитки: одна в ряд, заголовок не жмёт индикатор связи */
 .ogrid{grid-template-columns:1fr;gap:12px}
 /* grid-элементу по умолчанию min-width:auto, и плитка не ужималась ниже ширины своего
    содержимого: вылезала на 6px за колонку и торчала правее панелей журналов */
 .ogrid>.ocard{min-width:0}
 .ospark,.ospark .spc{min-width:0}
 .otitle{font-size:1rem}
 .ohead{gap:8px}
}

/* ──────────────────────────────────────────────────────────────────────────────
   ТЕЛЕФОН, очередь 2: разделы, модалки, экран входа.
   ────────────────────────────────────────────────────────────────────────────── */
@media (max-width:640px){
 /* цели под палец в модалках: глазик, крестик закрытия, ссылка на бота */
 .pwf .pweye{min-width:44px;min-height:44px;padding:6px 12px}
 .box button.mx{width:44px;height:44px;top:2px;right:4px;font-size:1.6rem}
 .tglink{padding:12px 0}
 .phag{padding:10px 0}
 /* галки в flex-строках сжимались до 14px — запрещаем им ужиматься */
 .fchk input,.sph input,.spc input,.upick input{flex:none}

 /* строки уведомлений: канал своей строкой, состояние и кнопка — второй. Строго #ntBody:
    тот же класс .ntrow носят строки панели «Пользователь» («Логин … director»), а их
    в две строки разворачивать незачем — они и так помещаются.
    Раньше email-строка переносилась, а остальные нет: ряды выходили разной высоты */
 #ntBody .ntrow{flex-direction:column;align-items:stretch;gap:6px}
 #ntBody .ntrow .ntst{display:flex;align-items:center;justify-content:space-between;gap:10px}
 .ntsub{padding-left:14px}

 /* экран входа: коробка по ширине экрана вместо жёстких 320px */
 #login .box{width:min(400px,calc(100% - 24px));padding:24px 20px}

 /* строка сотрудника: данные своей строкой, кнопки ровной сеткой по две */
 .trow{gap:8px}
 .trow>.tn{flex:1 1 100%;min-width:0}
 .trow>.tb{flex:1 1 calc(50% - 4px)}
}
