/* Стили Fleet Control Center.
   Правится ТОЛЬКО этот файл. Имена классов не переименовывать — на них опираются шаблоны.
   Цвета, размеры, ширину колонки менять ЧЕРЕЗ ТОКЕНЫ в :root ниже.

   Что изменено в этой ревизии:
   1. Одна ширина колонки. --col задаёт единственную меру страницы; .mw-m/.mw-l больше
      не сужают блоки, поэтому формы, таблицы, панели и линейки заголовков стоят на одном
      левом и правом краю. Раньше форма была 640, таблица 1180 — страница выглядела рваной.
   2. Два шрифта вместо одного: --ui (интерфейс и текст) и --mono (данные: адреса, порты,
      ключи, конфиги, числа, значения полей). Моноширинный остался там, где он значит
      «это машинные данные», и ушёл оттуда, где мешал читать.
   3. Состояния .st различимы не только цветом: у каждого свой знак в ::before.
   4. Опасное заметнее безопасного: .zone и .btn-danger усилены, .btn-quiet ослаблена. */

/* ═══ 1. ТОКЕНЫ ═══════════════════════════════════════════════════════ */
:root{
  color-scheme:dark;                 /* тёмные <select>, скроллбары, пикеры */

  --bg:#0e1319;      /* фон страницы            */
  --panel:#151c24;   /* панели, таблицы, шапка  */
  --panel-2:#1d2733; /* строка под курсором, обычная кнопка, поповер */
  --sunk:#0a0f14;    /* утопленное: поля ввода, <pre> */

  --edge:#27313e;    /* обычная линия  */
  --edge-hi:#3a4857; /* граница интерактивного */

  --fg:#d3dde9;      /* основной текст */
  --fg-hi:#f0f5fb;   /* заголовки, числа, имена сущностей */
  --mut:#96a6b9;     /* подписи, метаданные */
  --mut-2:#78879a;   /* плейсхолдеры, выключенные символы */

  --acc:#7d9dff;     /* ЕДИНСТВЕННЫЙ интерактивный цвет: ссылка, главная кнопка, фокус */
  --acc-hi:#9db4ff;
  --acc-ink:#0a1130; /* текст на акцентной заливке */
  --acc-soft:#1c2547;

  /* СОСТОЯНИЯ — ровно пять, других не заводить */
  --ok:#63d189;   --ok-bg:#10281b;   --ok-edge:#1f4a2f;   /* норма            */
  --run:#38d6c3;  --run-bg:#0b2b28;  --run-edge:#1a534c;  /* идёт сейчас      */
  --attn:#ecbb5c; --attn-bg:#2c2411; --attn-edge:#57451b; /* нужно решение    */
  --bad:#f57b76;  --bad-bg:#2e1817;  --bad-edge:#642c2c;  /* сломалось        */
  --off:#93a4b7;  --off-bg:#1c242e;  --off-edge:#333e4c;  /* выключено/нет    */
  --bad-solid:#cf4741;
  --bad-sunk:#1a1013;                /* фон опасной зоны */

  --sp1:4px; --sp2:8px; --sp3:12px; --sp4:16px; --sp5:24px; --sp6:32px;
  --r1:5px; --r2:8px;
  --tap:44px;        /* минимальная сторона нажимаемого на тач-устройстве */
  --sidebar:246px;

  --col:1680px;      /* рабочая ширина: таблицы используют экран, на узких main сжимается сам */
  --mw-s:520px;      /* короткая форма в 2–3 поля (.mw-s) */
  --measure:70ch;    /* мера строки для длинных пояснений */

  --ui:-apple-system,system-ui,"Segoe UI",Helvetica,Arial,sans-serif;
  --mono:ui-monospace,SFMono-Regular,Menlo,Consolas,"Liberation Mono",monospace;

  --shadow:0 12px 32px #00000073;
}

/* ═══ 2. СБРОС И ТИПОГРАФИКА ══════════════════════════════════════════ */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;background:var(--bg);color:var(--fg);
  font:14px/1.6 var(--ui);letter-spacing:.005em;text-wrap:pretty}
h1{margin:0;color:var(--fg-hi);font-size:21px;font-weight:650;line-height:1.2;
   letter-spacing:-.01em}
h2{display:flex;align-items:center;gap:var(--sp2);
   margin:var(--sp6) 0 var(--sp3);color:var(--fg-hi);
   font-size:12.5px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;
   border-bottom:1px solid var(--edge);padding-bottom:7px}
h3{margin:var(--sp4) 0 var(--sp2);color:var(--fg-hi);font-size:13.5px;font-weight:650;
   letter-spacing:0}
p{margin:0 0 var(--sp3)}
b,strong{color:var(--fg-hi);font-weight:650}
hr{border:0;border-top:1px solid var(--edge);margin:var(--sp5) 0}
a{color:var(--acc);text-decoration:none}
a:hover{color:var(--acc-hi)}
code,kbd,samp{padding:1px 5px;background:var(--panel-2);border:1px solid var(--edge);
     border-radius:var(--r1);color:var(--fg-hi);
     font:12.5px/1.4 var(--mono);overflow-wrap:anywhere}
:focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:var(--r1)}
::selection{background:var(--acc-soft);color:var(--fg-hi)}

/* ═══ 3. ЛЕВОЕ МЕНЮ ═══════════════════════════════════════════════════ */
body.with-sidebar{min-height:100vh;display:grid;grid-template-columns:var(--sidebar) minmax(0,1fr)}
.sidebar{position:sticky;top:0;z-index:40;display:flex;grid-column:1;grid-row:1;
  min-width:0;height:100vh;flex-direction:column;background:#111927;border-right:1px solid var(--edge)}
.side-brand{display:flex;min-height:66px;align-items:center;gap:10px;padding:0 18px;
  border-bottom:1px solid var(--edge);color:var(--fg-hi);font-size:16px;font-weight:750;
  letter-spacing:-.015em;white-space:nowrap}
.side-brand:hover{color:var(--fg-hi)}
.side-brand svg{width:26px;height:26px;fill:var(--acc)}
.side-nav{display:flex;min-height:0;flex:1 1 auto;flex-direction:column;gap:4px;
  padding:18px 9px;overflow-y:auto}
.side-nav a,.side-logout{display:flex;min-height:42px;align-items:center;gap:12px;padding:0 13px;
  border:1px solid transparent;border-radius:var(--r2);color:var(--mut);font-size:13.5px;
  font-weight:600;white-space:nowrap}
.side-nav a:hover,.side-logout:hover{background:var(--panel-2);color:var(--fg-hi)}
.side-nav a[aria-current="page"]{background:var(--acc-soft);border-color:#26345f;color:#70a6ff}
.side-nav svg,.side-logout svg{width:18px;height:18px;flex:0 0 18px;fill:none;
  stroke:currentColor;stroke-width:1.7;stroke-linecap:round;stroke-linejoin:round}
.side-footer{display:flex;flex-direction:column;gap:6px;padding:12px 9px 16px;border-top:1px solid var(--edge)}
.side-user{display:flex;min-width:0;align-items:center;gap:10px;padding:8px 12px;color:var(--mut)}
.side-user>span:last-child{display:flex;min-width:0;flex-direction:column;line-height:1.25}
.side-user b{overflow:hidden;text-overflow:ellipsis;font-size:13px;white-space:nowrap}
.side-user small{color:var(--mut-2);font-size:11px}
.side-avatar{display:flex;width:32px;height:32px;flex:0 0 32px;align-items:center;justify-content:center;
  border:1px solid #36527b;border-radius:50%;background:var(--acc-soft);color:var(--acc-hi);font-weight:800}
.side-logout:hover{color:var(--bad)}

/* ═══ 4. КАРКАС СТРАНИЦЫ ══════════════════════════════════════════════
   Одна колонка --col. Всё, что раньше сужалось само (.mw-m/.mw-l), теперь
   выравнено по ней же — см. секцию 12.                                   */
main{max-width:var(--col);margin:0 auto;position:relative;
  padding:var(--sp4) var(--sp3) max(72px,env(safe-area-inset-bottom))}
body.with-sidebar>main{grid-column:2;grid-row:1;width:100%}
@media (min-width:820px){main{padding:var(--sp5) var(--sp5) 80px}}
@media (max-width:900px){
  body.with-sidebar{display:block}
  .sidebar{position:sticky;width:100%;height:auto;max-height:none;border-right:0;border-bottom:1px solid var(--edge)}
  .side-brand{min-height:50px;padding:0 var(--sp3);border-bottom:0;font-size:14px}
  .side-brand svg{width:22px;height:22px}
  .side-nav{flex-direction:row;gap:2px;padding:0 var(--sp2) var(--sp2);overflow-x:auto;scrollbar-width:none}
  .side-nav::-webkit-scrollbar{display:none}
  .side-nav a{min-height:38px;padding:0 11px}
  .side-nav a span{display:none}
  .side-nav a[aria-current="page"] span{display:inline}
  .side-footer{display:none}
  body.with-sidebar>main{width:auto}
}
.back{display:inline-flex;align-items:center;gap:6px;min-height:32px;margin-bottom:var(--sp2);
  color:var(--mut);font-weight:650;font-size:12.5px}
.back:hover{color:var(--fg)}
.phead{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp3);margin-bottom:var(--sp3);
  padding-bottom:var(--sp1)}
.phead h1{flex:1 1 auto}
.sub{margin:calc(-1 * var(--sp2)) 0 var(--sp5);color:var(--mut);font-size:12.5px}
.sub b,.sub code{font-family:var(--mono)}
/* когда .sub — не подзаголовок страницы, а строка значений над рядом управления */
.sub:has(+.check-row),.sub:has(+.form-inline),.sub:has(+.row-sm),
.sub:has(+form),.sub:has(+.actions){margin-bottom:var(--sp3)}
main>h1+p.muted,main>p.muted{color:var(--mut)}
@media (max-width:520px){.phead>.btn-nav{flex:1 1 100%}}

/* ═══ 5. ДЕЙСТВИЯ ═════════════════════════════════════════════════════
   ЗАКОН ТРЁХ ФОРМ:
   залито (серым/акцентом/красным) = <button> в <form method=post>, сработает сразу;
   прозрачное в рамке + стрелка →/+ = <a>, откроет страницу, где действие делается;
   цветной текст = <a>, просто переход.
   Порядок заметности сверху вниз: primary → danger → обычная → quiet.        */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;
  min-height:38px;padding:7px 15px;border:1px solid var(--edge-hi);border-radius:var(--r1);
  background:var(--panel-2);color:var(--fg);
  font:650 13px/1 var(--ui);letter-spacing:.01em;
  white-space:nowrap;text-decoration:none;cursor:pointer;
  transition:background .12s,border-color .12s,color .12s;
  -webkit-tap-highlight-color:transparent}
.btn:hover{background:#26313e;border-color:#495868;color:var(--fg-hi)}
.btn:active{transform:translateY(1px)}
.btn:disabled,.btn.is-off{opacity:.4;pointer-events:none}

.btn-primary{background:var(--acc);border-color:var(--acc);color:var(--acc-ink)}
.btn-primary:hover{background:var(--acc-hi);border-color:var(--acc-hi);color:var(--acc-ink)}
/* ОДИН вид у главных действий: без модификатора кнопка выглядит как «Сохранить и проверить».
   Вторая кнопка рядом остаётся тихой (.btn-quiet), опасная — красной (.btn-danger). */
.btn:not(.btn-primary,.btn-quiet,.btn-danger,.btn-nav){
  background:var(--acc);border-color:var(--acc);color:var(--acc-ink)}
.btn:not(.btn-primary,.btn-quiet,.btn-danger,.btn-nav):hover{
  background:var(--acc-hi);border-color:var(--acc-hi);color:var(--acc-ink)}
/* в строке таблицы действия остаются нейтральными — иначе список кричит всеми строками */
td .btn:not(.btn-primary,.btn-quiet,.btn-danger,.btn-nav){
  background:var(--panel-2);border-color:var(--edge-hi);color:var(--fg)}
td .btn:not(.btn-primary,.btn-quiet,.btn-danger,.btn-nav):hover{
  background:#26313e;border-color:#495868;color:var(--fg-hi)}

.btn-quiet{background:transparent;border-color:var(--edge);color:var(--mut);font-weight:650}
.btn-quiet:hover{background:var(--panel-2);border-color:var(--edge-hi);color:var(--fg)}

/* опасное: красная рамка и красный текст в покое, полная заливка под курсором */
.btn-danger{background:var(--bad-bg);border-color:var(--bad);color:#ffb3b0;
  box-shadow:inset 0 0 0 1px #ffffff08}
.btn-danger:hover{background:var(--bad-solid);border-color:var(--bad-solid);color:#fff}

.btn-nav{background:transparent;border-color:var(--edge-hi);color:var(--acc)}
.btn-nav:hover{background:var(--acc-soft);border-color:var(--acc);color:var(--acc-hi)}

.btn-sm{min-height:30px;padding:5px 11px;font-size:12.5px}
.btn-icon{width:32px;min-height:32px;padding:0;font-size:14px}
.btn-block{display:flex;width:100%}

a.lnk{color:var(--acc);font-weight:650}
a.lnk:hover{color:var(--acc-hi);text-decoration:underline;text-underline-offset:3px}
a.lnk-q{color:var(--mut);font-weight:650}          /* второстепенный переход в таблице */
a.lnk-q:hover{color:var(--fg);text-decoration:underline;text-underline-offset:3px}

.actions{display:flex;flex-wrap:wrap;gap:var(--sp2);align-items:center;margin-top:var(--sp4)}
.actions form{display:flex;margin:0}
.sticky-act{position:sticky;bottom:0;z-index:20;display:flex;flex-wrap:wrap;
  gap:var(--sp2);align-items:center;margin-top:var(--sp5);
  padding:var(--sp3) 0 max(var(--sp3),env(safe-area-inset-bottom));
  border-top:1px solid var(--edge);background:var(--bg)}
.sticky-act form{display:flex;margin:0}

@media (pointer:coarse){
  .btn{min-height:var(--tap);padding:8px 16px}
  .btn-sm{min-height:var(--tap);padding:8px 14px;font-size:13px}
  .btn-icon{width:var(--tap);min-height:var(--tap);font-size:15px}
  td a.lnk,td a.lnk-q{display:inline-flex;align-items:center;min-height:38px}
}
@media (max-width:520px){
  .actions>.btn,.actions>form,.actions>form>.btn,
  .sticky-act>.btn,.sticky-act>form,.sticky-act>form>.btn{flex:1 1 100%}
}
@media (prefers-reduced-motion:reduce){
  .btn{transition:none}
  .btn:active{transform:none}
}

/* ═══ 6. ТАБЛИЦЫ ══════════════════════════════════════════════════════
   Данные — моноширинные и выровнены по разряду; имена и подписи — интерфейсным.  */
.tw{overflow-x:auto;-webkit-overflow-scrolling:touch;
    background:var(--panel);border:1px solid var(--edge);border-radius:var(--r2)}
table{width:100%;border-collapse:collapse;font-size:13px}
th,td{padding:9px 13px;text-align:left;vertical-align:middle;
      border-bottom:1px solid var(--edge)}
th{position:relative;background:var(--panel);color:var(--mut);
   font-size:11.5px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;
   white-space:nowrap;padding-top:9px;padding-bottom:9px}
thead th{border-bottom-color:var(--edge-hi)}
tbody tr:last-child td,table>tr:last-child td{border-bottom:0}
tbody tr:hover td{background:var(--panel-2)}      /* чинит мёртвое #20283300 */
td.t-key{color:var(--fg-hi);font-weight:650}
td.t-meta,td.muted{color:var(--mut);font-family:var(--mono);font-size:12.5px}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums}
td.num{font-family:var(--mono);color:var(--fg-hi)}
td.t-act{width:1%;white-space:nowrap;text-align:right}
.rowacts{display:flex;flex-wrap:nowrap;gap:var(--sp2);align-items:center;justify-content:flex-end}
.rules-save-status{white-space:nowrap}
.rules-save-status.is-dirty{color:var(--warn,#f2b84b)}
.rules-editor-table tr.rule-row-new td{background:color-mix(in srgb,var(--acc) 7%,transparent)}
.host-order-help{display:flex;min-height:32px;align-items:center;justify-content:space-between;gap:var(--sp3);
  margin:-4px 0 var(--sp2);color:var(--mut-2);font-size:12px}
.host-order-status{color:var(--mut);font-weight:650;white-space:nowrap}
.host-order-status.is-ok{color:var(--ok)}.host-order-status.is-bad{color:var(--bad)}
.host-name-cell{display:flex;align-items:center;gap:9px}
.host-name-line{display:flex;flex:1 1 auto;flex-wrap:wrap;align-items:center;gap:4px 7px;min-width:0}
.host-drag-handle{display:inline-flex;width:28px;height:30px;flex:0 0 28px;align-items:center;
  justify-content:center;padding:0;border:1px solid transparent;border-radius:var(--r1);
  background:transparent;color:var(--mut-2);font:19px/1 var(--ui);cursor:grab;user-select:none}
.host-drag-handle:hover,.host-drag-handle:focus-visible{border-color:var(--edge-hi);
  background:var(--sunk);color:var(--acc-hi)}
.host-drag-handle:active{cursor:grabbing}
.host-sort-row.is-dragging{opacity:.38}.host-sort-row.is-dragging td{background:var(--acc-soft)}
.host-sort-row.is-saving{opacity:.72}
@media (max-width:760px){.rowacts{justify-content:flex-start}}
.rowacts form{display:flex;margin:0}
@media (pointer:fine){    /* в строке кнопка ниже обычной: строки не должны расти вдвое */
  td .btn{min-height:30px;padding:5px 11px;font-size:12.5px}
  td .btn-icon{width:30px;min-height:30px;padding:0}
}
/* Отделяем верхнеуровневую строку фильтра/добавления от следующей таблицы. */
main>.form-inline+.tw{margin-top:var(--sp4)}
main>.tw+p,main>.tw+.msg{margin-top:var(--sp3)}
form.inline{display:inline-flex;align-items:center;gap:var(--sp1);margin:0;vertical-align:middle}
.t-empty{padding:var(--sp4);color:var(--mut);font-size:13px}
.c-xs{width:44px} .c-sm{width:90px} .c-md{width:150px} .c-lg{width:30%}

/* карточный режим: строка → карточка. Требует <thead> и data-l на каждой <td>. */
@media (max-width:760px){
  .t-stack{border:0;background:transparent}
  .tw:has(.t-stack){border:0;background:transparent;overflow:visible}
  .t-stack thead{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0)}
  .t-stack,.t-stack tbody,.t-stack tr,.t-stack td{display:block;width:auto}
  .t-stack tbody tr{margin-bottom:var(--sp3);padding:0 0 var(--sp2);
    background:var(--panel);border:1px solid var(--edge);border-radius:var(--r2)}
  .t-stack tbody tr:hover td{background:transparent}
  .t-stack td{display:flex;gap:var(--sp3);align-items:baseline;justify-content:space-between;
    padding:6px var(--sp3);border:0;text-align:right}
  .t-stack td::before{content:attr(data-l);flex:0 0 auto;max-width:44%;
    color:var(--mut);font:11.5px/1.5 var(--ui);text-transform:uppercase;letter-spacing:.08em;
    text-align:left}
  .t-stack td[data-l=""]::before,.t-stack td:not([data-l])::before{content:none}
  .host-order-help{align-items:flex-start;flex-direction:column;gap:0}
  .host-name-cell{width:100%;justify-content:flex-start;text-align:left}
  .t-stack td.t-head{display:block;text-align:left;padding:var(--sp3);
    background:var(--panel-2);border-bottom:1px solid var(--edge);
    border-radius:var(--r2) var(--r2) 0 0;font-size:15px;margin-bottom:var(--sp1)}
  .t-stack td.t-act{width:auto;text-align:left;padding-top:var(--sp2)}
  .t-stack .rowacts{justify-content:stretch;padding-top:var(--sp1)}
  .t-stack .rowacts>*{flex:1 1 auto}
  .col-opt{display:none}          /* колонка, скрываемая на телефоне целиком */
}

/* ═══ 7. ФОРМЫ ════════════════════════════════════════════════════════
   Значение в поле — данные, поэтому моноширинное; подпись и пояснение — текст.  */
input,select,textarea{width:100%;margin:0;padding:9px 12px;min-height:38px;
  background:var(--sunk);border:1px solid var(--edge-hi);border-radius:var(--r1);
  color:var(--fg-hi);font:13px/1.4 var(--mono)}
input:hover,select:hover,textarea:hover{border-color:#4a5968}
input::placeholder,textarea::placeholder{color:var(--mut-2);font-family:var(--mono)}
input:disabled,select:disabled,textarea:disabled{
  color:var(--mut);background:#11171e;border-color:var(--edge);cursor:not-allowed}
input:focus-visible,select:focus-visible,textarea:focus-visible{
  outline:none;border-color:var(--acc);box-shadow:0 0 0 3px var(--acc-soft)}
textarea{min-height:160px;line-height:1.55;resize:vertical}
select{appearance:none;padding-right:32px;cursor:pointer;font-family:var(--ui);
  background-repeat:no-repeat;
  background-position:right 11px center;background-size:9px 6px;
  background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath fill='%2396a6b9' d='M0 0h10L5 6z'/%3E%3C/svg%3E")}
select option{background:var(--panel);color:var(--fg)}
input[type=file]{width:auto;max-width:100%;padding:7px 9px;
  font:12.5px/1.4 var(--ui);background:transparent;border-style:dashed;cursor:pointer}
input[type=file]::file-selector-button{margin-right:var(--sp3);min-height:30px;padding:0 12px;
  border:1px solid var(--edge-hi);border-radius:var(--r1);
  background:var(--panel-2);color:var(--fg);font:650 12.5px/1 var(--ui);cursor:pointer}
input[type=checkbox],input[type=radio]{width:18px;height:18px;min-height:0;flex:0 0 auto;
  padding:0;accent-color:var(--acc);cursor:pointer}

.field{margin-bottom:var(--sp4)}
/* одинаковая подпись и в .field, и там, где <label> лежит в форме напрямую (вход, новый список) */
label{color:var(--mut);font:650 12.5px/1.4 var(--ui);letter-spacing:.01em}
form>label:not(.check):not(.sr),fieldset>label:not(.check):not(.sr){display:block;margin:var(--sp4) 0 6px}
form>label:not(.check):not(.sr):first-child{margin-top:0}
.field>label,.lbl{display:flex;align-items:center;gap:6px;margin:0 0 6px;
  color:var(--mut);font:12.5px/1.4 var(--ui);letter-spacing:.01em}
.field>label{font-weight:650}
.lbl>label{color:var(--mut);font-weight:650}
.field-note{margin:6px 0 var(--sp4);color:var(--mut);
  font-size:12.5px;line-height:1.55}
.field .field-note:last-child{margin-bottom:0}
.field-err{margin:6px 0 0;color:var(--bad);font-size:12.5px;font-weight:650}
.field.is-bad input,.field.is-bad select,.field.is-bad textarea{
  border-color:var(--bad);box-shadow:0 0 0 3px #f57b7622}
.check{display:inline-flex;align-items:center;gap:var(--sp2);min-height:var(--tap);
  color:var(--fg);font-size:13.5px;line-height:1.45;cursor:pointer}
.check-row{display:flex;flex-wrap:wrap;gap:var(--sp3) var(--sp4);align-items:flex-end}
.check-row>form{flex:0 0 auto;flex-wrap:nowrap}   /* форма в ряду: кнопка остаётся рядом с полем,
   переносы делает сам ряд */
.grid{display:grid;gap:var(--sp3) var(--sp4);
  grid-template-columns:repeat(auto-fit,minmax(200px,1fr));align-items:end}
.grid>.field{display:flex;flex-direction:column;justify-content:flex-end;height:100%;
  margin-bottom:0}       /* расстояния в сетке задаёт gap, иначе пояснение под сеткой
                              отрывается от поля сильнее, чем остальные пояснения */
/* Несколько .grid подряд — это отдельные строки одной формы, им тоже нужен вертикальный gap. */
form>.grid+.grid{margin-top:var(--sp3)}
.grid-wide>.field{margin-bottom:0}
.grid+.field-note,.grid-wide+.field-note{margin-top:6px}
.grid-wide{display:grid;gap:var(--sp3) var(--sp4);
  grid-template-columns:repeat(auto-fit,minmax(280px,1fr))}
.span2{grid-column:span 2}
@media (max-width:600px){.span2{grid-column:auto}}
.form-inline{display:flex;flex-wrap:wrap;gap:var(--sp2) var(--sp3);align-items:flex-end}
.form-inline .field,.row>.field,.row-sm>.field{margin-bottom:0}
.form-inline .field{flex:1 1 140px;min-width:0}
/* в inline-форме .span2 — широкое поле: растёт втрое быстрее остальных,
   чтобы короткие поля и кнопка умещались в одну строку */
.form-inline .field.span2{flex:3 1 240px}
/* поле лежит в inline-форме без .field: без этого width:100% съедает всю строку
   и выталкивает кнопку на следующую; короткие числовые поля держат свою меру */
.form-inline>input,.form-inline>select,.form-inline>textarea{flex:1 1 240px;width:auto;
  max-width:420px;min-width:0}
.form-inline>input[size],.form-inline>input[inputmode=numeric],
.form-inline>input[type=number]{flex:0 0 auto;width:auto;max-width:140px}
.form-inline .btn{flex:0 0 auto}
@media (pointer:fine){    /* в строке с полем кнопка ровно такого же роста, что и поле */
  .form-inline>.btn,.form-inline>form>.btn,
  form:not(.form-inline):has(>input:not([type=hidden])+.btn)>.btn{min-height:38px}
}
/* форма из одного поля и кнопки без .form-inline в разметке (добавить ключ):
   кнопка стоит рядом с полем, а не под ним */
form:not(.form-inline):has(>input:not([type=hidden])+.btn){display:flex;flex-wrap:wrap;
  gap:var(--sp2) var(--sp3);align-items:flex-end}
form:not(.form-inline):has(>input:not([type=hidden])+.btn)>input{flex:1 1 260px;width:auto;min-width:0}
form:not(.form-inline):has(>input:not([type=hidden])+.btn)>.btn{flex:0 0 auto}
@media (max-width:520px){
  form:not(.form-inline):has(>input:not([type=hidden])+.btn)>input,
  form:not(.form-inline):has(>input:not([type=hidden])+.btn)>.btn{flex:1 1 100%}
}
@media (max-width:520px){.form-inline .btn{flex:1 1 100%}}

/* ═══ 8. СОСТОЯНИЕ И КЛАССИФИКАЦИЯ ════════════════════════════════════
   .st  — «нужно ли мне что-то делать»: ровно 5 значений. Знак в ::before, чтобы
          состояние читалось и без цвета (низкая яркость экрана, дальтонизм).
   .tag — «что это такое»: цвета нет, моноширинный — это техническое значение.
   .obs — наблюдаемость узла центром: точка, не плашка.                       */
.st{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;
  border:1px solid transparent;border-radius:var(--r1);
  font:650 12px/1.4 var(--ui);letter-spacing:.02em;white-space:nowrap;vertical-align:middle}
.st::before{flex:0 0 auto;font-size:10px;line-height:1}
.st-ok  {background:var(--ok-bg);  color:var(--ok);  border-color:var(--ok-edge)}
.st-ok::before{content:"●"}
.st-run {background:var(--run-bg); color:var(--run); border-color:var(--run-edge)}
.st-attn{background:var(--attn-bg);color:var(--attn);border-color:var(--attn-edge)}
.st-attn::before{content:"▲"}
.st-bad {background:var(--bad-bg); color:var(--bad); border-color:var(--bad-edge)}
.st-bad::before{content:"✕";font-weight:700}
.st-off {background:var(--off-bg); color:var(--off); border-color:var(--off-edge)}
.st-off::before{content:"○"}
.st-run::before{content:"";width:7px;height:7px;border-radius:50%;
  background:currentColor;animation:st-pulse 1.4s ease-in-out infinite}
@keyframes st-pulse{50%{opacity:.2}}
@media (prefers-reduced-motion:reduce){.st-run::before{animation:none}}

.tag{display:inline-block;padding:2px 8px;border:1px solid var(--edge);border-radius:var(--r1);
  background:var(--panel-2);color:var(--mut);
  font:12px/1.5 var(--mono);white-space:nowrap;vertical-align:middle}
.obs{color:var(--mut);font-size:12.5px;white-space:nowrap;vertical-align:middle}
.obs::before{margin-right:5px;font-size:11px}
.obs-live::before{content:"●";color:var(--ok)}
.obs-desired::before{content:"○";color:var(--mut-2)}
.host-observation .st{margin-left:8px}
.client-direct-yes{color:var(--ok);font-size:17px;font-weight:800;line-height:1}
td.t-key.client-name-active,td.t-key.client-name-active .lnk{color:var(--ok)}
td.t-key.client-name-paused,td.t-key.client-name-paused .lnk{color:var(--off)}
td.t-key.client-name-active .lnk:hover,td.t-key.client-name-paused .lnk:hover{color:var(--fg-hi)}
.date-input.is-empty,
.date-input.is-empty::-webkit-datetime-edit{color:var(--mut)}
.date-input:not(.is-empty){color:var(--fg)}
.fact{color:var(--mut);font:12.5px/1.5 var(--mono);white-space:nowrap}

/* ═══ 9. УВЕДОМЛЕНИЯ И ПУСТЫЕ СОСТОЯНИЯ ══════════════════════════════
   .msg встречается в двух видах разметки: с внутренним <div> и с текстом прямо внутри.
   Поэтому блок, а не flex: иначе текстовые узлы становятся отдельными flex-элементами
   и баннер рассыпается на колонки. Значок — абсолютом в отступе слева.               */
.msg{position:relative;display:block;margin:0 0 var(--sp3);
  padding:11px 14px 11px 40px;background:var(--panel);
  border:1px solid var(--edge);border-left:3px solid var(--mut);border-radius:var(--r2);
  font-size:13.5px;line-height:1.6;overflow-wrap:anywhere}
.msg::before{position:absolute;left:13px;top:12px;
  display:inline-flex;align-items:center;justify-content:center;
  width:18px;height:18px;border-radius:50%;
  font:700 11px/1 var(--ui);background:#ffffff0d}
.msg-ok  {border-left-color:var(--ok);border-color:var(--ok-edge)}
.msg-ok::before  {content:"✓";color:var(--ok)}
.msg-bad {border-left-color:var(--bad);border-color:var(--bad-edge);background:var(--bad-bg)}
.msg-bad::before{content:"✕";color:var(--bad)}
.msg-warn{border-left-color:var(--attn);border-color:var(--attn-edge);background:var(--attn-bg)}
.msg-warn::before{content:"!";color:var(--attn)}
.msg-run {border-left-color:var(--run);border-color:var(--run-edge)}
.msg-run::before {content:"◷";color:var(--run)}
.msg-info{border-left-color:var(--edge-hi)} .msg-info::before{content:"i";color:var(--mut)}
.msg-t{display:block;margin-bottom:2px;font-weight:650;color:var(--fg-hi)}
.job-detail{margin:8px 0 4px;color:var(--fg-hi);font-size:13px;line-height:1.45}
.job-detail>span{color:var(--mut)}
.msg>div,.msg>p{min-width:0;max-width:none;margin:0;overflow-wrap:anywhere}
.msg>div+div,.msg>p+p{margin-top:var(--sp2)}
.msg code{background:#ffffff10}
.empty{margin:var(--sp3) 0;padding:var(--sp5) var(--sp4);
  border:1px dashed var(--edge-hi);border-radius:var(--r2);
  color:var(--mut);font-size:13.5px;text-align:center}

/* ═══ 10. РАСКРЫТИЕ ═══════════════════════════════════════════════════
   .help — пояснение «как это устроено» (текст)
   .hint — «?» у подписи поля или заголовка (короткий текст)
   .fold — редкие ОПЕРАЦИИ (кнопки/формы), нейтральное
   .zone — НЕОБРАТИМЫЕ операции, красное
   .log-fold — свёрнутый журнал завершённой задачи                        */
.help{margin:var(--sp3) 0 var(--sp4);background:var(--panel);
  border:1px solid var(--edge);border-radius:var(--r2)}
.help>summary{display:flex;align-items:center;gap:var(--sp2);min-height:var(--tap);
  padding:6px 12px;list-style:none;cursor:pointer;color:var(--mut);font-size:13px}
.help>summary::-webkit-details-marker{display:none}
.help>summary::before{content:"?";flex:0 0 auto;display:inline-flex;
  align-items:center;justify-content:center;width:19px;height:19px;
  border:1px solid var(--edge-hi);border-radius:50%;font:700 11.5px/1 var(--ui)}
.help>summary::after{content:"▸";margin-left:auto;color:var(--mut-2)}
.help[open]>summary::after{content:"▾"}
.help>summary:hover{color:var(--fg)}
.help[open]>summary{color:var(--fg);border-bottom:1px solid var(--edge)}
.help-b{padding:var(--sp3) var(--sp4) var(--sp4);max-width:none;
  /* Ширину не режем мерой строки: текст выглядел заметно уже самой раскрытой панели,
     и справа зияла пустота. Панель и без того ограничена шириной колонки (--col). */
  color:var(--mut);font-size:13.5px;line-height:1.65}
.help-b>p{margin:0 0 var(--sp2);max-width:none} .help-b>p:last-child{margin:0}
.help-b b{color:var(--fg-hi)}

.hint{display:inline-block;position:relative;vertical-align:middle;margin-left:2px}
.hint>summary{display:inline-flex;align-items:center;justify-content:center;
  width:21px;height:21px;list-style:none;cursor:pointer;
  border:1px solid var(--edge-hi);border-radius:50%;background:var(--panel-2);
  color:var(--mut);font:700 12px/1 var(--ui);text-transform:none;letter-spacing:0}
.hint>summary::-webkit-details-marker{display:none}
.hint>summary:hover{color:var(--fg);border-color:var(--acc)}
.hint[open]>summary{background:var(--acc);border-color:var(--acc);color:var(--acc-ink)}
.hint-b{position:absolute;z-index:30;top:28px;left:-8px;
  width:max-content;max-width:min(360px,calc(100vw - 2 * var(--sp4)));
  padding:var(--sp3) var(--sp4);background:var(--panel-2);
  border:1px solid var(--edge-hi);border-radius:var(--r2);box-shadow:var(--shadow);
  color:var(--fg);font:13px/1.65 var(--ui);font-weight:400;
  white-space:normal;text-align:left;text-transform:none;letter-spacing:0}
.hint-b b{color:var(--fg-hi)}
/* «?» у правого края колонки (заголовки в .spread/.phead и любой .hint-end):
   поповер раскрывается влево, иначе текст уезжает за край экрана */
.hint-end .hint-b,.spread>.hint .hint-b,.phead>.hint .hint-b,
.spread>details.hint>.hint-b,.phead>details.hint>.hint-b,
.grid>.field:not(.span2) .hint-b,.grid-wide>.field:not(.span2) .hint-b{left:auto;right:-8px}
@media (max-width:760px){        /* поповер превращается в обычный блок — не обрежется */
  .hint{position:static;margin-left:2px}
  /* Закрытый «?» остаётся в строке; раскрытый занимает полную строку под подписью. */
  .hint[open]{display:block;flex:1 0 100%;width:100%;margin:var(--sp2) 0 0}
  .lbl:has(>.hint[open]){flex-wrap:wrap}
  .hint>summary{width:26px;height:26px;font-size:13px}
  .hint-b,.hint-end .hint-b,.spread>.hint .hint-b,.phead>.hint .hint-b{
    position:static;width:auto;max-width:none;margin-top:var(--sp2);box-shadow:none}
}
@media (pointer:coarse) and (min-width:761px){.hint>summary{width:26px;height:26px}}

.fold{margin:var(--sp5) 0;border:1px solid var(--edge);border-radius:var(--r2);
  background:var(--panel)}
.fold>summary{display:flex;align-items:center;gap:var(--sp2);min-height:var(--tap);
  padding:0 var(--sp4);list-style:none;cursor:pointer;
  color:var(--mut);font-weight:650;font-size:13.5px}
.fold>summary::-webkit-details-marker{display:none}
.fold>summary:hover{color:var(--fg)}
.fold>summary::after{content:"▸";margin-left:auto;color:var(--mut-2)}
.fold[open]>summary{color:var(--fg);border-bottom:1px solid var(--edge)}
.fold[open]>summary::after{content:"▾"}
.fold-b{padding:var(--sp3) var(--sp4) var(--sp4)}
.fold-b>h2:first-child,.fold-b>h3:first-child{margin-top:var(--sp2)}

/* опасная зона: единственное место с красной рамкой в покое */
.zone{margin:var(--sp6) 0 var(--sp5);border:1px solid var(--bad-edge);border-radius:var(--r2);
  background:var(--bad-sunk);box-shadow:inset 3px 0 0 var(--bad-solid)}
.zone>summary{display:flex;align-items:center;gap:var(--sp2);min-height:var(--tap);
  padding:0 var(--sp4);list-style:none;cursor:pointer;
  color:#ffa9a6;font-weight:700;font-size:13.5px;letter-spacing:.01em}
.zone>summary::-webkit-details-marker{display:none}
.zone>summary::after{content:"▸";margin-left:auto;color:var(--bad)}
.zone>summary:hover{color:#ffc6c4}
.zone[open]>summary{border-bottom:1px solid var(--bad-edge)}
.zone[open]>summary::after{content:"▾"}
.zone-b{display:flex;flex-direction:column;gap:var(--sp5);padding:var(--sp4)}
.zone-b h3{margin:0 0 var(--sp2);color:#ffc6c4}
.zone-b p{color:var(--mut)}

.log-fold{margin:var(--sp3) 0}
.log-fold>summary{display:flex;align-items:center;gap:6px;min-height:36px;
  list-style:none;cursor:pointer;color:var(--mut);font-size:12.5px}
.log-fold>summary::-webkit-details-marker{display:none}
.log-fold>summary:hover{color:var(--fg)}
.log-fold>summary::before{content:"▸"}
.log-fold[open]>summary::before{content:"▾"}

/* ═══ 11. ВЫВОД, ПАНЕЛИ, ПЛИТКИ ═══════════════════════════════════════ */
pre{margin:0 0 var(--sp3);padding:var(--sp3) var(--sp4);
  background:var(--sunk);border:1px solid var(--edge);border-radius:var(--r2);
  color:#c2cfdd;font:12.5px/1.6 var(--mono);
  white-space:pre-wrap;overflow-wrap:anywhere;overflow:auto}
.log{max-height:min(55vh,460px);overscroll-behavior:contain}
/* «Копировать» / «Скачать» стоят РЯДОМ с блоком, который копируют, а не в нём и не строкой ниже */
pre:has(+.btn[data-copy]){display:inline-block;vertical-align:top;width:calc(100% - 119px);
  min-height:38px;padding:8px 12px;margin-bottom:0;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis}   /* одно значение — одна строка
     ровно такой же высоты, что поле ввода; хвост срезается, целиком берётся кнопкой */
pre:has(+.btn[data-dl]){display:inline-block;vertical-align:top;width:calc(100% - 175px);
  margin-bottom:0}
pre+.btn[data-copy],pre+.btn[data-dl]{vertical-align:top;margin-left:6px;
  min-height:38px;                     /* как поле и кнопки в остальных формах */
  background:var(--acc);border-color:var(--acc);color:var(--acc-ink)}
pre+.btn[data-copy]:hover,pre+.btn[data-dl]:hover{
  background:var(--acc-hi);border-color:var(--acc-hi);color:var(--acc-ink)}
@media (max-width:520px){
  pre:has(+.btn[data-copy]),pre:has(+.btn[data-dl]){display:block;width:100%}
  pre+.btn[data-copy],pre+.btn[data-dl]{display:flex;width:100%;margin-left:0}
}
.log-short{max-height:220px}
.log-full{max-height:none}
.panel{padding:var(--sp4);background:var(--panel);
  border:1px solid var(--edge);border-radius:var(--r2)}
.card{max-width:var(--mw-s);margin:8vh auto;padding:var(--sp5);
  background:var(--panel);border:1px solid var(--edge);border-radius:var(--r2);
  box-shadow:var(--shadow)}
.card>h1{margin:var(--sp5);text-align:center}          /* заголовок входа — по центру */
.card>.btn{display:flex;width:100%;margin:var(--sp5) 0}  /* единственное действие — во всю карточку */
.tiles{display:grid;gap:var(--sp3);grid-template-columns:repeat(auto-fit,minmax(190px,1fr));
  margin:var(--sp4) 0 var(--sp5)}
.tile{display:block;padding:var(--sp3) var(--sp4);background:var(--panel);
  border:1px solid var(--edge);border-radius:var(--r2);color:var(--fg)}
.tile:hover{background:var(--panel-2);border-color:var(--acc)}
.tile-n{font:650 26px/1.1 var(--mono);color:var(--fg-hi);font-variant-numeric:tabular-nums}
.tile-t{margin-top:4px;color:var(--acc);font-weight:650;font-size:13.5px}
.tile-d{margin-top:3px;color:var(--mut);font-size:12.5px}

/* Карточка узла: шапка, пользовательские теги и компактные панели из макета узла. */
.node-page h1{font-size:24px;font-weight:700}
.node-page h2{border-bottom:0;padding-bottom:0;margin-top:var(--sp6);margin-bottom:var(--sp3)}
.node-title-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp3);margin-bottom:var(--sp3)}
.node-title-row:has(.node-name-editor[open]){padding-bottom:104px}
.node-name-cluster{position:relative;display:flex;align-items:center;gap:var(--sp3);min-width:0}
.node-title-edit,.node-edit-control{display:inline-grid;place-items:center;width:28px;height:28px;
  padding:0;border:0;background:transparent;color:var(--mut);cursor:pointer}
.node-title-edit:hover,.node-edit-control:hover{color:var(--acc-hi)}
.node-title-edit svg,.node-edit-control svg{width:17px;height:17px;fill:none;stroke:currentColor;
  stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.node-tags-row{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp2);margin-bottom:var(--sp3)}
.node-label{display:inline-flex;align-items:center;min-height:27px;padding:3px 10px;
  border:1px solid;border-radius:var(--r1);font:750 11.5px/1.35 var(--ui);
  letter-spacing:.04em;text-transform:uppercase;white-space:nowrap}
.node-label.is-small{min-height:21px;padding:1px 6px;font-size:10px}
.node-tag-add{display:inline-flex;align-items:center;min-height:28px;padding:3px 10px;
  border:1px solid var(--edge-hi);border-radius:var(--r1);background:var(--panel-2);
  color:var(--mut);font:700 11.5px/1.3 var(--ui);text-transform:uppercase;
  letter-spacing:.04em;cursor:pointer}
.node-tag-add:hover{color:var(--fg-hi);border-color:var(--acc)}
.node-tag-catalog-link{display:inline-block;margin-top:var(--sp4)}
.node-meta-editor>summary{list-style:none}.node-meta-editor>summary::-webkit-details-marker{display:none}
.node-meta-editor[open]{flex:1 0 100%}
.node-name-editor{position:static}
.node-name-editor[open]{flex:0 0 auto}
.node-name-editor .node-editor-panel{position:absolute;z-index:50;top:calc(100% + 8px);left:0;
  width:min(420px,calc(100vw - 48px));margin-top:0;box-shadow:var(--shadow)}
.node-name-form{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:end;gap:var(--sp3)}
.node-name-form .field{margin:0}
.node-editor-panel{margin-top:var(--sp2);padding:var(--sp4);border:1px solid var(--edge);
  border-radius:var(--r2);background:var(--panel);max-width:820px}
.tag-choice-list{display:flex;flex-wrap:wrap;gap:var(--sp2) var(--sp3)}
.tag-choice{display:inline-flex;align-items:center;gap:6px;cursor:pointer}
.tag-choice input{width:auto;margin:0}
.node-new-tag-grid{display:grid;grid-template-columns:minmax(180px,1fr) 76px 76px auto;
  align-items:end;gap:var(--sp3);margin-top:var(--sp4)}
.node-new-tag-grid .field{margin:0}
.tag-color-input{width:54px!important;height:38px;padding:3px;cursor:pointer}
.node-comment-row{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-bottom:var(--sp3);
  color:var(--mut);font-size:13px}
.node-comment-label{white-space:nowrap}
.node-comment-text{color:#ffd700;white-space:pre-wrap}
.node-comment-editor[open]{flex-basis:100%}
.node-comment-editor .node-editor-panel{max-width:820px}
.node-meta{margin:0 0 var(--sp5);font-family:var(--mono);font-size:12.5px}
.node-page .tiles{gap:var(--sp4);margin-top:var(--sp5);margin-bottom:var(--sp6)}
.node-page .tile{padding:var(--sp4) var(--sp5)}
.node-section-head{display:flex;align-items:center;justify-content:space-between;gap:var(--sp3);
  margin-top:var(--sp6);margin-bottom:var(--sp3)}
.node-section-head h2{margin:0;flex:1 1 auto}
.node-dns-card,.node-client-card{padding:var(--sp4) var(--sp5);border:1px solid var(--edge);border-radius:var(--r2);
  background:var(--panel)}
.node-dns-card p{margin:0 0 var(--sp3)}
.node-client-card .client-counts{margin:0}
.host-list-tags{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;gap:4px;margin:0 0 0 auto}
.subnet-compact-table{table-layout:fixed}
.subnet-compact-table td{width:25%;padding:8px 12px;white-space:nowrap}
.subnet-compact-table code{font-size:12.5px}
.tag-admin-list{display:grid;gap:var(--sp4);max-width:980px}
.tag-admin-card{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:var(--sp4);
  padding:var(--sp4) var(--sp5);border:1px solid var(--edge);border-radius:var(--r2);background:var(--panel)}
.tag-admin-summary{grid-column:1/-1;display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp2) var(--sp3)}
.tag-admin-hosts{display:flex;flex-wrap:wrap;gap:4px 10px}
.tag-admin-form{display:grid;grid-template-columns:minmax(180px,1fr) 70px 70px auto;
  align-items:end;gap:var(--sp3);min-width:0}
.tag-admin-form .field{margin:0}.tag-admin-color{align-items:flex-start}
.tag-admin-delete{display:flex;align-items:flex-end}
@media (max-width:680px){
  .node-title-row:has(.node-name-editor[open]){padding-bottom:158px}
  .node-name-form{grid-template-columns:1fr}
  .node-name-form>.btn{width:100%}
  .node-new-tag-grid{grid-template-columns:1fr 70px 70px}
  .node-new-tag-grid>.btn{grid-column:1/-1;width:100%}
  .node-page .tile{padding:var(--sp3) var(--sp4)}
  .tag-admin-card{grid-template-columns:1fr;padding:var(--sp4)}
  .tag-admin-form{grid-template-columns:1fr 70px 70px}
  .tag-admin-form>.btn{grid-column:1/-1;width:100%}
  .tag-admin-delete{justify-content:stretch}.tag-admin-delete>.btn{width:100%}
}
.qr-wrap{display:flex;flex-direction:column;align-items:flex-start;gap:var(--sp2)}
.qr{width:max-content;max-width:100%;padding:var(--sp3);background:#fff;
  border-radius:var(--r2);line-height:0}
.qr-image{display:block;width:min(320px,70vw);height:auto;image-rendering:pixelated}

/* ═══ Карточка клиента ════════════════════════════════════════════════ */
.client-hero{display:flex;align-items:flex-start;justify-content:space-between;gap:var(--sp5);
  margin-bottom:var(--sp5)}
.client-hero-main{min-width:0;flex:1 1 auto}
.client-hero-main h1{margin-bottom:var(--sp3);font-size:24px}
.client-meta{display:flex;flex-wrap:wrap;align-items:center;gap:var(--sp2)}
.client-stat{display:inline-flex;align-items:center;min-height:25px;padding:2px 9px;
  border:1px solid var(--edge);border-radius:var(--r1);background:var(--panel-2);
  color:var(--mut);font:12px/1.4 var(--mono);white-space:nowrap}
.client-stat.obs{font-family:var(--ui)}
.client-rx{color:#8db0ff}.client-tx{color:var(--ok)}
.client-traffic{gap:var(--sp2)}
.client-traffic .client-tx{padding-left:var(--sp2);border-left:1px solid var(--edge-hi)}
.client-counts{display:flex;flex-wrap:wrap;align-items:center;gap:8px 20px;margin-bottom:var(--sp4)}
.client-count{color:var(--mut);font-size:14px;white-space:nowrap}
.client-count b{font:750 17px/1 var(--mono)}
.client-count.is-online b{color:var(--ok)}
.client-count.is-offline b{color:var(--mut)}
.client-count.is-paused b{color:var(--attn)}

.client-hero-actions{display:flex;flex:0 0 auto;align-items:center;justify-content:flex-end;
  flex-wrap:wrap;gap:var(--sp2)}
.client-menu{position:relative}
.client-menu>summary{list-style:none}
.client-menu>summary::-webkit-details-marker{display:none}
.client-menu[open]>summary{border-color:var(--acc);background:var(--acc-soft);color:var(--acc-hi)}
.client-date-button{min-width:132px;font-family:var(--mono);font-size:12px}
.client-menu-panel{position:absolute;z-index:40;top:calc(100% + 8px);right:0;width:310px;
  padding:var(--sp4);background:var(--panel-2);border:1px solid var(--edge-hi);
  border-radius:var(--r2);box-shadow:var(--shadow)}
.client-menu-panel .field{margin-bottom:var(--sp3)}
.client-menu-panel .field-note{margin:var(--sp2) 0 0}
.client-wan-form{margin:0;transition:opacity .12s}
.client-wan-form.is-saving{opacity:.55;pointer-events:none}
.client-wan-toggle.check{display:inline-flex;min-height:38px;padding:5px 10px;gap:var(--sp2);
  border:1px solid var(--edge-hi);border-radius:var(--r1);background:var(--panel-2);
  color:var(--fg);font:700 11px/1 var(--ui);letter-spacing:.04em;cursor:pointer}
.client-wan-toggle b{color:var(--acc)}
.client-wan-toggle input{appearance:none;position:relative;width:34px;height:20px;min-height:20px;
  margin:0;padding:0;border:1px solid var(--edge-hi);border-radius:999px;background:var(--sunk);
  transition:background .12s,border-color .12s}
.client-wan-toggle input::before{content:"";position:absolute;top:2px;left:2px;width:14px;height:14px;
  border-radius:50%;background:var(--mut);transition:transform .12s,background .12s}
.client-wan-toggle input:checked{background:var(--acc);border-color:var(--acc)}
.client-wan-toggle input:checked::before{transform:translateX(14px);background:#fff}

.client-credentials{margin:0 0 var(--sp5);overflow:hidden;background:var(--panel);
  border:1px solid var(--edge-hi);border-radius:var(--r2)}
.client-credentials-title{display:flex;align-items:center;gap:var(--sp2);min-height:42px;
  padding:8px var(--sp4);border-bottom:1px solid var(--edge-hi);color:var(--acc);
  font-size:12.5px;font-weight:650}
.client-credentials-grid{display:grid;grid-template-columns:minmax(0,1fr) minmax(390px,1fr)}
.client-config-pane{min-width:0;padding:var(--sp4);background:var(--sunk);
  border-right:1px solid var(--edge-hi)}
.client-pane-bar{display:flex;align-items:center;justify-content:space-between;gap:var(--sp3);
  margin-bottom:var(--sp3)}
.client-pane-bar code{padding:0;background:transparent;border:0;color:var(--mut)}
.client-pane-actions{display:flex;flex-wrap:wrap;align-items:center;justify-content:flex-end;
  gap:var(--sp2)}
.client-config-pane pre{min-height:235px;max-height:52vh;margin:0;padding:0;border:0;
  border-radius:0;background:transparent;white-space:pre;overflow:auto;overflow-wrap:normal}
.client-qr-pane{display:flex;min-width:0;flex-direction:column;align-items:center;
  justify-content:flex-start;gap:var(--sp4);padding:var(--sp4)}
.client-qr-pane>.client-pane-bar{width:100%}
.client-qr-stage{display:flex;flex:1 1 auto;width:100%;align-items:center;justify-content:center}
.client-qr-pane .qr{align-self:center;width:min(280px,100%);padding:7px}
.client-qr-pane .qr-image{width:100%}

/* История трафика клиента: три календарных масштаба, без внешней chart-библиотеки. */
.client-traffic-panel{margin:0 0 var(--sp5);overflow:hidden;background:#111a2a;
  border:1px solid var(--edge-hi);border-radius:var(--r2)}
.traffic-head{display:flex;min-height:56px;align-items:center;justify-content:space-between;gap:var(--sp3);
  padding:9px var(--sp4);border-bottom:1px solid var(--edge-hi)}
.traffic-heading{display:flex;align-items:center;gap:var(--sp2);color:var(--fg-hi);font-weight:650}
.traffic-heading svg{width:17px;height:17px;fill:none;stroke:#4b91ff;stroke-width:1.8;
  stroke-linecap:round;stroke-linejoin:round}
.traffic-controls{display:flex;align-items:center;gap:var(--sp3)}
.traffic-scales,.traffic-nav{display:inline-flex;align-items:center;padding:2px;background:var(--sunk);
  border:1px solid var(--edge-hi);border-radius:var(--r2)}
.traffic-scales button,.traffic-nav button{min-width:62px;height:32px;padding:0 10px;border:0;
  border-radius:6px;background:transparent;color:var(--mut-2);font:650 12px/1 var(--ui);cursor:pointer}
.traffic-scales button[aria-pressed="true"]{background:var(--panel-2);color:var(--fg-hi);box-shadow:0 1px 4px #0008}
.traffic-scales button:hover,.traffic-nav button:hover:not(:disabled){color:var(--fg-hi);background:var(--panel-2)}
.traffic-nav{gap:3px;padding:0;border:0;background:transparent}
.traffic-nav button{min-width:36px;border:1px solid var(--edge-hi);background:var(--sunk);
  color:var(--mut);font-size:25px;font-weight:400}
.traffic-nav button:disabled{opacity:.35;cursor:not-allowed}
.traffic-summary{display:flex;min-height:42px;align-items:center;justify-content:space-between;gap:var(--sp3);
  padding:8px var(--sp4);color:var(--mut);font-size:12.5px}
.traffic-summary strong{font-size:13px}
.traffic-chart{position:relative;min-height:330px;margin:0 var(--sp4);overflow-x:auto;
  border-bottom:1px solid var(--edge);background:
  repeating-linear-gradient(to bottom,transparent 0,transparent 64px,#263348 65px)}
.traffic-bars{display:grid;min-width:790px;height:310px;grid-template-columns:repeat(var(--traffic-count,24),minmax(18px,1fr));
  align-items:end;gap:8px;padding:28px 5px 34px}
.client-traffic-panel.is-loading .traffic-bars{opacity:.45}
.client-traffic-panel[data-scale="days"] .traffic-bars{min-width:920px;gap:5px}
.client-traffic-panel[data-scale="months"] .traffic-bars{min-width:600px;gap:14px}
.traffic-bar{position:relative;display:flex;min-width:0;height:248px;flex-direction:column;justify-content:flex-end;
  padding:0;border:0;background:transparent;color:var(--mut-2);font:11px/1 var(--mono);cursor:default}
.traffic-stack{display:flex;width:72%;max-width:54px;min-width:8px;height:214px;align-self:center;
  flex-direction:column-reverse;justify-content:flex-start;overflow:hidden;border-radius:3px 3px 1px 1px}
.traffic-segment{display:block;width:100%;min-height:0;transition:filter .12s,height .18s}
.traffic-segment-download{height:var(--download-pct);background:#3b82f6}
.traffic-segment-upload{height:var(--upload-pct);background:#10b981}
.traffic-bar:hover .traffic-segment,.traffic-bar:focus-visible .traffic-segment{filter:brightness(1.18)}
.traffic-label{position:absolute;right:-6px;bottom:-24px;left:-6px;overflow:hidden;text-align:center;
  text-overflow:clip;white-space:nowrap}
.traffic-label.is-muted{color:transparent}
.traffic-max{position:absolute;top:4px;left:5px;z-index:1;color:var(--mut-2);font:10.5px/1 var(--mono)}
.traffic-empty{position:absolute;top:45%;right:var(--sp4);left:var(--sp4);color:var(--mut-2);
  text-align:center;font-size:12.5px}
.traffic-empty[hidden]{display:none}
.traffic-tooltip{position:fixed;z-index:120;min-width:174px;padding:8px 10px;pointer-events:none;
  border:1px solid var(--edge-hi);border-radius:var(--r1);background:#182232;color:var(--fg);
  box-shadow:var(--shadow);font:12px/1.45 var(--ui)}
.traffic-tooltip[hidden]{display:none}
.traffic-tooltip b{display:block;margin-bottom:3px}
.traffic-tooltip .tip-download{color:#76a9ff}.traffic-tooltip .tip-upload{color:#55d7a6}
.traffic-legend{display:flex;align-items:center;gap:var(--sp5);padding:13px var(--sp4) 16px;
  color:var(--mut);font-size:12px}
.traffic-legend span{display:inline-flex;align-items:center;gap:7px}
.traffic-key{display:inline-block;width:12px;height:12px;border-radius:2px}
.traffic-key-download{background:#3b82f6}.traffic-key-upload{background:#10b981}

.client-delete-zone{display:flex;align-items:center;gap:var(--sp3);margin:var(--sp5) 0;
  padding:var(--sp4) var(--sp5);border:1px solid var(--bad-edge);border-radius:var(--r2);
  background:var(--bad-sunk)}
.client-delete-icon{display:flex;flex:0 0 38px;align-items:center;justify-content:center;
  width:38px;height:38px;border-radius:var(--r2);background:var(--bad-bg);color:var(--bad);
  font-size:20px;font-weight:700}
.client-delete-icon svg{display:block}
.client-delete-copy{flex:1 1 auto;min-width:0}
.client-delete-copy h3{margin:0;color:#ffc6c4}
.client-delete-copy p{max-width:none;margin:2px 0 0;color:var(--mut);font-size:12.5px}
.client-delete-zone form{flex:0 0 auto;margin:0}

@media (max-width:900px){
  .client-hero{flex-direction:column;gap:var(--sp3)}
  .client-hero-actions{justify-content:flex-start;width:100%}
  .client-credentials-grid{grid-template-columns:1fr}
  .client-config-pane{border-right:0;border-bottom:1px solid var(--edge-hi)}
}
@media (max-width:560px){
  .client-hero-main h1{font-size:21px}
  .client-hero-actions{display:grid;grid-template-columns:auto 1fr auto auto}
  .client-menu-panel{position:fixed;z-index:80;top:18%;right:var(--sp3);left:var(--sp3);
    width:auto;max-height:70vh;overflow:auto}
  .client-date-button{width:100%;min-width:0}
  .client-wan-toggle.check{width:100%;justify-content:center}
  .client-qr-pane{padding:var(--sp4) var(--sp3)}
  .client-pane-bar{align-items:flex-start}
  .client-pane-bar code{padding-top:8px}
  .client-pane-actions{gap:var(--sp1)}
  .traffic-head{align-items:flex-start;flex-direction:column}
  .traffic-controls{width:100%;justify-content:space-between;gap:var(--sp2)}
  .traffic-scales{flex:1 1 auto}
  .traffic-scales button{min-width:0;flex:1 1 0;padding:0 7px}
  .traffic-summary{align-items:flex-start;flex-direction:column;gap:2px}
  .traffic-chart{margin:0 var(--sp3)}
  .client-delete-zone{align-items:flex-start;flex-wrap:wrap;padding:var(--sp4)}
  .client-delete-zone form,.client-delete-zone form>.btn{width:100%}
}

/* ═══ 12. УТИЛИТЫ — полный список, других не существует ════════════════
   ВАЖНО: .mw-m и .mw-l больше НЕ сужают блок — вся страница живёт в одной
   колонке --col, иначе форма, таблица и линейка заголовка стоят по разным краям.
   Осталась только .mw-s — для форм в 2–3 поля, где длинная строка бессмысленна.  */
.row{display:flex;flex-wrap:wrap;gap:var(--sp3);align-items:center}
.row-sm{display:flex;flex-wrap:wrap;gap:var(--sp2);align-items:center}
.row-top{align-items:flex-start} .row-end{align-items:flex-end}
.col{display:flex;flex-direction:column;gap:var(--sp2)}
.stack>*+*{margin-top:var(--sp3)}
.stack-lg>*+*{margin-top:var(--sp5)}
.f1{flex:1 1 0;min-width:0} .f2{flex:2 1 0;min-width:0} .f3{flex:3 1 0;min-width:0}
.right{margin-left:auto}
.spread{display:flex;flex-wrap:wrap;gap:var(--sp3);align-items:center;justify-content:space-between}
.spread>h2{flex:1 1 auto;margin-right:0}     /* линейка заголовка идёт во всю колонку */
.client-access{margin-bottom:var(--sp5)}
.client-expiry-form .field{flex-basis:360px}
.client-expiry-note{max-width:none;margin-top:var(--sp2)}
.client-direct-field{flex:0 1 190px}
.client-direct-field>.check{margin:0}
.direct-option{min-height:38px;padding:0 12px;border:1px solid var(--edge-hi);
  border-radius:var(--r1);background:var(--input);white-space:nowrap}
.client-direct-form{margin-top:var(--sp3)}
.client-direct-form .client-direct-setting{flex-basis:480px}
.client-direct-setting>.check{margin:0}
.client-direct-setting .field-note{margin:4px 0 0 26px}

/* отступы заголовка переезжают на ряд: иначе «?» центруется по высоте с маржинами
   и оказывается не напротив текста заголовка, а посередине блока */
.spread:has(>h2){margin:var(--sp6) 0 var(--sp3)}
.spread:has(>h2)>h2{margin:0}
.spread:has(>h3){margin:var(--sp4) 0 var(--sp2)}
.spread:has(>h3)>h3{margin:0}
.nowrap{white-space:nowrap}
.mw-s{max-width:var(--mw-s)} .mw-m{max-width:100%} .mw-l{max-width:100%}
.prose{max-width:var(--measure)}
.mt-0{margin-top:0} .mt-1{margin-top:var(--sp2)} .mt-2{margin-top:var(--sp4)}
.mt-3{margin-top:var(--sp5)}
.mb-0{margin-bottom:0} .mb-1{margin-bottom:var(--sp2)} .mb-2{margin-bottom:var(--sp4)}
.t-sm{font-size:12px} .muted{color:var(--mut)} .hi{color:var(--fg-hi)}
/* пояснение под таблицей или формой выглядит так же, как .field-note */
p.muted.t-sm{margin:6px 0 var(--sp4);font-size:12.5px;line-height:1.55}
/* в пояснениях под полем и формой <code> без рамки: иначе одна такая строка
   выглядит иначе, чем все остальные пояснения */
.field-note code,p.muted.t-sm code{padding:0;background:transparent;border:0;color:var(--fg)}
.num{font-variant-numeric:tabular-nums}
.center{text-align:center}
.sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
.hide{display:none}
@media (max-width:760px){.hide-narrow{display:none!important}}
@media (min-width:761px){.hide-wide{display:none!important}}

/* ═══ 14. ПРОСМОТР И ПРАВКА СПИСКА ════════════════════════════════════
   Список — это ТЕКСТ: комментарии «#» разделяют группы, порядок строк значим.
   Показываем как в редакторе кода: номера слева, комментарии приглушены.      */
.src{margin:0 0 var(--sp3);border:1px solid var(--edge);border-radius:var(--r2);
  background:var(--sunk);max-height:60vh;overflow:auto}
.src table{width:100%;border:0;border-radius:0;background:transparent;table-layout:auto}
.src td{padding:1px 12px;border:0;font:12.5px/1.7 var(--mono);white-space:pre-wrap;
  overflow-wrap:anywhere;vertical-align:top;color:var(--fg)}
.src td.n{width:1%;min-width:3ch;padding-right:14px;color:var(--mut-2);text-align:right;
  white-space:nowrap;overflow-wrap:normal;word-break:normal;user-select:none;
  border-right:1px solid var(--edge);background:var(--panel);position:sticky;left:0}
.src tr:hover td{background:var(--panel-2)}
.src tr:hover td.n{background:var(--panel-2)}
.src .cm{color:var(--mut-2);font-style:normal}
.src .gap td{height:8px;padding:0}
.ed{width:100%;min-height:52vh;padding:var(--sp3);border:1px solid var(--edge-hi);
  border-radius:var(--r2);background:var(--sunk);color:var(--fg-hi);
  font:12.5px/1.7 var(--mono);resize:vertical;tab-size:2}
.ed:focus{outline:none;border-color:var(--acc);box-shadow:0 0 0 3px var(--acc-soft)}

/* Ключ центра: строка «ключ + компактная кнопка».
   Раньше кнопка с надписью «Копировать» не помещалась рядом с длинным ключом и уезжала
   под него, ломая строку. Теперь ключ занимает всю доступную ширину и прокручивается сам,
   а кнопка — квадратная иконка фиксированного размера. */
.copy-row{display:flex;align-items:center;gap:.5rem}
.copy-row>pre{flex:1 1 auto;min-width:0;margin:0;overflow-x:auto}
.btn-icon{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;
  width:2.2rem;height:2.2rem;padding:0}
.btn-icon svg{display:block}
.btn-icon .i-check{display:none}
.btn-icon.copied .i-copy{display:none}
.btn-icon.copied .i-check{display:block;color:var(--ok)}
.btn-icon.copied{border-color:var(--ok-edge);background:var(--ok-bg)}


/* Предупреждение за две минуты до завершения серверной сессии. */
.session-warning{position:fixed;right:var(--sp4);bottom:var(--sp4);z-index:1000;
  display:flex;align-items:center;gap:var(--sp4);max-width:min(520px,calc(100vw - 32px));
  padding:var(--sp3) var(--sp4);background:var(--attn-bg);border:1px solid var(--attn-edge);
  border-radius:var(--r2);box-shadow:var(--shadow);color:var(--fg)}
.session-warning[hidden]{display:none}
.session-warning>div{display:flex;flex-direction:column;gap:2px;min-width:0}
.session-warning>div>span{color:var(--mut);font-size:12.5px}
.session-warning .btn{flex:0 0 auto}
.confirm-field{max-width:520px;margin-bottom:var(--sp3)}
@media(max-width:520px){
  .session-warning{left:var(--sp3);right:var(--sp3);bottom:var(--sp3);align-items:stretch;
    flex-direction:column}
  .session-warning .btn{width:100%}
}

.node-comment-badge{position:relative;display:inline-flex;align-items:center;justify-content:center;box-sizing:border-box;min-width:18px;height:18px;padding:0 5px;margin-left:6px;gap:2px;background:transparent;border:1px solid #ffd700;border-radius:5px;color:#ffd700;cursor:help;vertical-align:middle}
.node-comment-badge .ncb-dot{width:3px;height:3px;border-radius:50%;background:currentColor;flex:0 0 auto}
.node-comment-badge:hover{color:#ffc400;border-color:#ffc400}
.node-comment-badge::after{content:attr(data-tip);position:absolute;bottom:calc(100% + 7px);left:50%;transform:translateX(-50%);visibility:hidden;opacity:0;transition:opacity .15s ease;background:#1e2430;color:#ffff00;font-style:italic;font-weight:400;border:1px solid #ffff0066;border-radius:6px;padding:6px 9px;font-size:12px;line-height:1.35;white-space:pre-wrap;max-width:320px;width:max-content;z-index:80;box-shadow:0 4px 14px rgba(0,0,0,.45)}
.node-comment-badge:hover::after{visibility:visible;opacity:1}
.host-name-line{position:relative}

/* Хосты: дать тултипу комментария вылезать за край таблицы */
.tw-noclip{overflow:visible}
