/* ПАЛИТРА ЦЕЛИКОМ, обе темы. Ни одного цвета в правилах ниже быть не должно:
   пока тема была одна, записанный по месту #3a1414 ничего не стоил, а со второй
   он остаётся тёмно-красным на белом фоне. Двадцать четыре таких цвета и
   переехали сюда — это и есть вся работа по светлой теме, остальное Pico
   переключает у себя сам по атрибуту data-theme.

   Тёмная — умолчание, и задана на голом :root: она была здесь всегда, и
   переключатель не должен менять поведение тех, кто им не пользовался. */
:root{
  --bg:#0f1216; --panel:#171b21; --line:#252b33; --fg:#dbe2ea; --mut:#8b96a3;
  --accent:#4ea1ff; --warn:#e0a54a; --err:#ff5f56; --ok:#5fd07a;

  --field:#0c0f13;          /* фон поля ввода */
  --hover:#12171d;          /* строка таблицы под курсором */
  --navhover:#1d2129;       /* пункт навигации под курсором */
  --navon:#1a222e;          /* текущий раздел в колонке */
  --btn:#1d3a5f; --btnhover:#26507f; --btnfg:#fff;
  --danger:#5f1d1d; --dangerhover:#7f2626;
  --errbg:#3a1414; --errfg:#ffd9d6;
  --warnbg:#3a2f14; --warnfg:#ffeccd;
  --okbg:#14301c; --okfg:#d6ffe2;
  --offbg:#2a2a2a;          /* статус «выведено из эксплуатации» */
  --rowalert:#2a1414; --rowalerthover:#3a1a1a;   /* строка активного прослушивания */
}

/* Светлая. Синий accent взят ТЕМНЕЕ тёмнотемного: #4ea1ff на белом даёт
   контраст 2,3:1 — ссылку видно, а прочитать её тяжело. */
[data-theme=light]{
  --bg:#f4f6f9; --panel:#fff; --line:#d7dce3; --fg:#1b2027; --mut:#5b6570;
  --accent:#1a5fbf; --warn:#8a5a00; --err:#b3261e; --ok:#1b6b38;

  --field:#fff;
  --hover:#eef1f5;
  --navhover:#e9edf3;
  --navon:#e2ebf8;
  --btn:#1a5fbf; --btnhover:#154e9e; --btnfg:#fff;
  --danger:#a33027; --dangerhover:#8a251d;
  --errbg:#fdeceb; --errfg:#7a1b15;
  --warnbg:#fbf1de; --warnfg:#5f4300;
  --okbg:#e7f5ec; --okfg:#12522b;
  --offbg:#e6e9ee;
  --rowalert:#fdeceb; --rowalerthover:#f9dcd9;
}

/* ---- слой совместимости с Pico -------------------------------------------
   Pico лежит НИЖЕ нас и в большинстве мест перебивается порядком подключения.
   Здесь перечислено ровно то, что порядком не перебивается: либо селектор у
   Pico специфичнее нашего, либо правила у нас не было вовсе. Каждая строка
   объяснена — иначе через месяц её снимут как лишнюю. */

:root{
  /* Pico растит КОРНЕВОЙ кегль вместе с шириной окна: пять ступеней
     (106,25 → 131,25 %) на 576/768/1024/1280/1536 px, а `html` берёт кегль
     отсюда. На мониторе 1920 один rem стал бы 21 px, все отступы Pico выросли
     бы на треть, а весь наш CSS написан в px и не вырос бы. Пришпиливаем: один
     rem равен 14 px, то есть кеглю body. Медиазапросы специфичности не
     добавляют, поэтому безусловный :root перекрывает все пять ступеней. */
  --pico-font-size:87.5%;
  --pico-line-height:1.45;

  /* Плотность. Умолчания Pico рассчитаны на документ, а здесь операторская
     консоль с таблицами до десяти колонок. Значения подобраны так, чтобы
     воспроизвести сегодняшний вид, а не завести свой: смысл этапа — не
     ухудшить плотность, а внешность меняется отдельно и осознанно. */
  --pico-spacing:.7rem;
  --pico-typography-spacing-vertical:.6rem;
  --pico-form-element-spacing-vertical:.57rem;   /* даёт сегодняшние 8px */
  --pico-form-element-spacing-horizontal:.57rem;
  --pico-block-spacing-vertical:1.43rem;
  --pico-block-spacing-horizontal:1.14rem;
  --pico-nav-element-spacing-vertical:.25rem;
  --pico-nav-element-spacing-horizontal:.35rem;
  --pico-nav-link-spacing-vertical:.25rem;
  --pico-nav-link-spacing-horizontal:.35rem;
}

/* Pico центрирует `body>header` и `body>main` автополями и режет их лесенкой
   max-width. У нас под это правило попадают ОБА: шапка стала бы полосой
   посередине экрана с дырами по краям — а под ней живут строки «аварийный
   вход» и «шина не отвечает», которым дыры по краям противопоказаны. */
body>header{max-width:none;margin-inline:0}

*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);
  font:14px/1.45 system-ui,-apple-system,Segoe UI,Roboto,sans-serif}
a{color:var(--accent);text-decoration:none}
a:hover{text-decoration:underline}
.muted{color:var(--mut)}

/* Навигация. Ниже 1100 px — полоса сверху, выше — колонка слева.
   Умолчание именно полоса, а не колонка: на узком экране колонка в 14rem
   отбирает пятую часть ширины у таблиц, ради которых консоль и существует. */
.top{display:flex;align-items:flex-start;gap:16px;padding:10px 16px;
  background:var(--panel);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:5}
.brand{font-weight:600;flex-shrink:0}
.top nav{display:flex;gap:6px 18px;flex-wrap:wrap;align-items:baseline}
.navgroup{display:flex;gap:10px;flex-wrap:wrap;align-items:baseline}
/* Название группы на узком экране прячется: в строку оно превращает навигацию
   в кашу из заголовков и ссылок, а группы там и так видны промежутками. */
.navtitle{display:none}
.top nav a{color:var(--fg);padding:4px 2px;border-bottom:2px solid transparent}
.top nav a.on{border-bottom-color:var(--accent);color:var(--accent)}
.who{margin-left:auto;color:var(--mut);display:flex;align-items:center;gap:10px;flex-shrink:0}


.inline{display:inline}
.link{background:none;border:0;color:var(--mut);cursor:pointer;font:inherit;text-decoration:underline}

/* полосы состояния */
.alarm{background:var(--errbg);border-bottom:1px solid var(--err);color:var(--errfg);padding:8px 16px}
.warn{background:var(--warnbg);border-bottom:1px solid var(--warn);color:var(--warnfg);padding:8px 16px}
.err{background:var(--errbg);border:1px solid var(--err);color:var(--errfg);padding:8px 10px;border-radius:6px;margin:10px 0}

/* Селектор поднят до body>main НАМЕРЕННО: у Pico тут `body>main` (0,0,2), а
   голый `main` (0,0,1) проигрывает ему по специфичности — порядок подключения
   в этом единственном месте не спасает. margin-inline возвращает колонку влево:
   Pico центрирует её, и на широком мониторе таблицы уезжают от глаза. */
body>main{padding:20px 16px;max-width:1200px;margin-inline:0}
/* Шкала задана ДО КОНЦА, а не до h2. Раньше h3 и h4 не были описаны вовсе —
   пока заголовков ниже второго уровня не было видно, это не мешало. С Pico они
   получили его размеры и стали КРУПНЕЕ своих же h2: подзаголовок больше
   раздела, в котором лежит. */
h1{font-size:20px;margin:0 0 6px}
h2{font-size:15px;margin:0 0 6px}
h3{font-size:14px;margin:0 0 4px;font-weight:600}
h4{font-size:13px;margin:0 0 4px;font-weight:600}
h5,h6{font-size:13px;margin:0 0 4px;font-weight:600;color:var(--mut)}
/* Пояснение под заголовком или таблицей: почему тут так, а не иначе. Ширина
   ограничена — длинная строка на широком экране читается плохо, а этот текст
   читают целиком, в отличие от таблицы рядом. */
.hint{color:var(--mut);font-size:13px;max-width:68ch;margin:6px 0 0}

/* карточки обзора */
.cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:12px;margin-top:16px}
.card{display:block;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:14px;color:var(--fg)}
.card:hover{border-color:var(--accent);text-decoration:none}
.card p{color:var(--mut);margin:0}

/* формы */
form label{display:block;margin:10px 0;color:var(--mut)}
input,select,button,textarea{font:inherit}
/* Флажки и переключатели исключены из общего правила: Pico рисует их сам через
   appearance:none и задаёт им размер (1.25em). Наше `width:100%`, а тем более
   `width:auto` у `.cap input`, оставило бы элемент без ширины вовсе — галочки
   в «Правах», «Реестре» и «Картах» стали бы невидимыми. Ни один тест этого не
   поймал бы: атрибут `checked` в разметке остаётся на месте. */
input:not([type=checkbox],[type=radio]),select,textarea{
  display:block;width:100%;margin-top:4px;padding:8px;border-radius:6px;
  border:1px solid var(--line);background:var(--field);color:var(--fg)}
/* Отбивка снизу верна для формы-столбика и неверна для формы в ячейке таблицы,
   а таких у нас пятьдесят: строки реестра выросли бы на десяток пикселей
   каждая. Высота — от кегля поля, а не от зашитого у Pico 1rem. */
input:not([type=checkbox],[type=radio]),select,textarea{margin-bottom:0;height:auto}
/* [type=submit] перечислен ЯВНО: у Pico это правило висит на атрибуте (0,1,0),
   а у нас на элементе (0,0,1), и порядок подключения тут не помогает — он
   перекрасил бы кнопку входа в свой синий, отличный от всех остальных кнопок
   консоли. Такая кнопка в разметке ровно одна, на странице входа, и полную
   ширину от Pico она оставляет себе: на карточке входа это уместно. */
button,button[type=submit]{padding:8px 14px;border:0;border-radius:6px;
  background:var(--btn);color:var(--btnfg);cursor:pointer}
button:hover,button[type=submit]:hover{background:var(--btnhover)}
button.danger{background:var(--danger)}
button.danger:hover{background:var(--dangerhover)}
/* Кнопка, притворяющаяся ссылкой: htmx вешает запрос на элемент, а «Итог» по
   носителю профиля должен читаться как имя человека, а не как команда. */
button.link{padding:0;background:none;color:var(--accent);text-decoration:underline;
  border-radius:0}
button.link:hover{background:none;color:var(--fg)}
/* Галочки возможностей стоят в столбик: у каждой рядом может оказаться пометка
   «не сработает», и в строку она оторвалась бы от своей возможности. */
.cap{display:flex;align-items:center;gap:6px;margin:2px 0}
.cap input{margin:0}
.cap-dead{color:var(--mut)}
/* Галочка с подписью В СТРОКУ — в отличие от .cap, который стоит столбиком.
   Разница не косметическая: у возможности рядом бывает пометка «не сработает»,
   и она обязана стоять под своей строкой, а у набора карт пометок нет. */
.chk{display:inline-flex;align-items:center;gap:5px;margin:0}
.chk input{margin:0}

/* вход */
.login{max-width:340px;margin:12vh auto;background:var(--panel);
  border:1px solid var(--line);border-radius:12px;padding:22px}

/* таблицы (для следующих разделов) */
table{border-collapse:collapse;width:100%}
/* Фон ячейки Pico красит своим тоном — он на два шага светлее нашего, и
   таблица выглядит наклейкой поверх страницы. Фон таблицы — это фон страницы. */
th,td{text-align:left;padding:6px 8px;border-bottom:1px solid var(--line);
  vertical-align:top;background-color:transparent}
th{color:var(--mut);font-size:12px;font-weight:600}
tr:hover td{background:var(--hover)}
.wrap{overflow-x:auto}

/* Вкладки раздела. Отличаются от навигации по консоли и видом, и смыслом: та
   ведёт между разделами, эти — внутри одного, и путать их нельзя. */
/* justify-content задан ЯВНО: у Pico на голом `nav` стоит space-between, и без
   этой строки четыре вкладки разъезжаются по всей ширине экрана с рваными
   промежутками. Та же ловушка, что и у навигации по консоли. */
.tabs{display:flex;justify-content:flex-start;gap:2px;flex-wrap:wrap;margin:0 0 4px;
  border-bottom:1px solid var(--line)}
.tabs a{color:var(--mut);padding:6px 12px;border:1px solid transparent;
  border-bottom:0;border-radius:6px 6px 0 0;margin-bottom:-1px}
.tabs a:hover{color:var(--fg);background:var(--navhover);text-decoration:none}
.tabs a.on{color:var(--fg);background:var(--panel);
  border-color:var(--line);border-bottom-color:var(--panel)}

/* разделы и формы внутри них */
section{margin:22px 0;padding-top:6px;border-top:1px solid var(--line)}

.row{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin:0}
/* Флажки исключены и здесь, по той же причине, что и в общем правиле выше:
   `width:auto` поверх нарисованного Pico флажка (appearance:none) схлопывает
   его в вертикальную палочку. Это и случилось при первом заходе — на формах
   записи эфира в «Реестре», и увидел это снимок, а не тест. */
.row input:not([type=checkbox],[type=radio]),.row select{width:auto;margin-top:0}
.row input[type=checkbox],.row input[type=radio]{margin:0}
.addform{margin-top:10px}
.cb{display:flex;align-items:center;gap:6px;color:var(--mut);margin:0}
.cb input{margin:0}
/* Голых <code> в шаблонах тридцать, и почти все стоят внутри строки текста.
   Pico делает их inline-block с отбивкой и своим фоном — строка распухает.
   Фон и рамка нужны только там, где это code.mono, и они ниже. */
code{background:none;padding:0;font-size:inherit}
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:12px;color:var(--mut)}
.okmsg{background:var(--okbg);border:1px solid var(--ok);color:var(--okfg);padding:8px 10px;border-radius:6px;margin:10px 0}
/* Строка активного прослушивания. Красится вся: включённый чужой микрофон —
   это не ещё одна запись в таблице, и заметить её надо не вчитываясь. */
.warnrow td{background:var(--rowalert)}
tr.warnrow:hover td{background:var(--rowalerthover)}

.st{padding:1px 6px;border-radius:4px;font-size:12px}
.st-active{background:var(--okbg);color:var(--ok)}
.st-decommissioned{background:var(--offbg);color:var(--mut)}
.st-lost{background:var(--errbg);color:var(--err)}
/* Белый фон КОДА, а не темы: QR читается сканером по контрасту чёрного на
   белом, и в тёмной теме он остаётся белым намеренно. Единственный цвет в этом
   файле, записанный по месту. */
.qr{border:1px solid var(--line);border-radius:8px;background:#fff;padding:6px}
.pending{color:var(--warn)}
code.mono{display:inline-block;background:var(--field);border:1px solid var(--line);
  border-radius:6px;padding:6px 8px;word-break:break-all;max-width:100%}
.lvl{padding:1px 6px;border-radius:4px;font-size:12px;font-weight:600}
.lvl.debug,.lvl.trace{color:var(--mut)}
.lvl.info{color:var(--accent)}
.lvl.warn{color:var(--warn)}
.lvl.error,.lvl.fatal,.lvl.panic{color:var(--err)}

/* Карта покрытия. Высота фиксированная: без неё контейнер схлопывается в ноль,
   и карта не рисуется вовсе — maplibre об этом не сообщает. */
.map {
  height: 60vh;
  min-height: 320px;
  margin: 0.75rem 0;
  border: 1px solid var(--line);
  border-radius: 4px;
  overflow: hidden;
}

/* ---- карточки объектов и списки реестра ----------------------------------
   Карточка человека, группы и аппарата (cards.html) и списки, из которых они
   открываются. Правка живёт в карточке, поэтому здесь две заботы: список должен
   читаться одной строкой на объект, а карточка — делиться на панели, чтобы
   глаз находил «вход», «итог» и «назначения» без чтения подряд. */

.crumbs{margin:0 0 4px;font-size:13px}
.cardhead{display:flex;justify-content:space-between;align-items:flex-start;gap:16px;
  margin:0 0 12px}
.cardhead h1{margin:0}
.cardhead .sub{color:var(--mut);font-weight:400}
.meta{display:flex;gap:6px 14px;flex-wrap:wrap;color:var(--mut);font-size:13px;margin-top:4px}

/* Панель — одна смысловая часть карточки. Фон панели, а не линия сверху, как
   у section: в карточке панели стоят рядом, и линии между ними читались бы
   как одна длинная граница. */
.panel{background:var(--panel);border:1px solid var(--line);border-radius:8px;
  padding:12px 14px;margin:0 0 12px}
.panel h2{margin:0 0 10px}
.grid2{display:grid;grid-template-columns:repeat(auto-fit,minmax(340px,1fr));gap:12px}
.grid2>.panel{margin:0}
.grid2+.panel{margin-top:12px}
/* Раздел без полосы сверху: вкладка и так отделяет его от заголовка. */
section.bare{border-top:0;margin-top:10px;padding-top:0}

/* Свойства «имя — значение» в две колонки. */
dl.kv{display:grid;grid-template-columns:max-content 1fr;gap:8px 16px;margin:0}
dl.kv dt{color:var(--mut);font-size:13px;padding-top:6px}
dl.kv dd{margin:0;min-width:0}
dl.kv dd.row{padding-top:0}

/* Чип — объект в строке с крестиком снятия: аппарат у человека, человек у
   аппарата. Крестик — кнопка формы, но выглядеть кнопкой не должна: иначе
   ряд из пяти аппаратов становится рядом из пяти синих плашек. */
.chip{display:inline-flex;align-items:center;gap:2px;padding:2px 4px 2px 8px;margin:0 6px 6px 0;
  border:1px solid var(--line);border-radius:12px;background:var(--field)}
button.x{padding:0 5px;background:none;color:var(--mut);font-size:15px;line-height:1;border-radius:8px}
button.x:hover{background:var(--errbg);color:var(--err)}

/* Значки-пометки в строке: основная, погашено, отключён, замечания. */
.badge{display:inline-block;padding:0 6px;border-radius:4px;font-size:12px;margin-left:4px;
  background:var(--offbg);color:var(--mut);white-space:nowrap}
.badge.ok{background:var(--okbg);color:var(--ok)}
.badge.warn{background:var(--warnbg);color:var(--warn)}
a.badge:hover{text-decoration:none;filter:brightness(1.15)}
.note{padding:6px 10px;border-radius:6px;margin:0 0 8px;font-size:13px}
.warnnote{background:var(--warnbg);color:var(--warnfg);border:1px solid var(--warn)}

/* Списки реестра и назначений: строка на объект, погашенное — приглушено. */
table.list td{vertical-align:middle}
tr.off td{color:var(--mut)}
tr.off td a{color:var(--mut)}
tr.editing td{background:var(--navon)}
/* Строки одной области (две роли на одной группе) не разделяются линией: они
   читаются одной группой, а не двумя. Без :has линия просто останется. */
table.list tr:has(+ tr.cont) td{border-bottom-color:transparent}
td.actions{text-align:right;white-space:nowrap;width:1%}
td.actions form{margin:0}

/* Кнопки второго ряда. Основная синяя кнопка остаётся за главным действием
   панели; «Изменить», «Снять», «Разрешить вход» — рамкой, иначе в таблице из
   двадцати строк синего было бы больше, чем текста. */
button.ghost{background:none;color:var(--accent);border:1px solid var(--line)}
button.ghost:hover{background:var(--navhover)}
button.sm,a.sm{padding:3px 8px;font-size:12px}
button.dangertext{color:var(--err)}
button.dangertext:hover{background:var(--errbg)}
button.warnish{color:var(--warn)}
details.danger-zone{border-left:3px solid var(--warn)}
details.danger-zone summary{cursor:pointer;color:var(--warn)}
a.btnlink{display:inline-block;padding:7px 12px;border:1px solid var(--line);border-radius:6px;white-space:nowrap}
a.btnlink:hover{background:var(--navhover);text-decoration:none}

/* Поле числа не тянется во всю ширину строки: там секунды, а не абзац. */
.row input.num{width:7em}
.row input.wide{min-width:22em}
.toolbar{margin:0 0 10px}
.toolbar input:not([type=checkbox],[type=radio]){min-width:17em}
.hint.inlinehint{display:inline;margin:0}

/* Сводка замечаний модели прав. Свёрнута по умолчанию и раскрыта сама, только
   если есть серьёзное: сплошной список из тридцати одинаковых строк закрывал
   раздел, ради которого сюда пришли. */
details.issues{background:var(--panel);border:1px solid var(--line);border-left:3px solid var(--warn);
  border-radius:0 8px 8px 0;padding:8px 12px;margin:10px 0 12px}
details.issues.serious{background:var(--warnbg);color:var(--warnfg)}
details.issues summary{cursor:pointer}
details.issues ul{margin:8px 0 0;padding-left:18px}
details.issues li{margin:4px 0}

/* Матрица ролей: возможности строками, роли столбцами. */
table.matrix{width:auto;min-width:100%}
table.matrix th,table.matrix td{border-bottom:1px solid var(--line)}
table.matrix thead th{position:sticky;top:0;background:var(--bg);z-index:1;vertical-align:bottom}
table.matrix .capcol{min-width:300px}
table.matrix .rolecol{text-align:center;min-width:92px}
.rid{color:var(--fg);font-weight:600}
.rname,.rholders{font-weight:400;font-size:11px}
table.matrix tr.sec th{background:var(--panel);color:var(--fg);font-size:12px;padding-top:10px}
table.matrix td.cell{text-align:center;vertical-align:middle}
table.matrix td.cell input{margin:0}
.capnote{color:var(--mut);font-size:12px}
.capnote code{color:var(--mut)}
.savebar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin:12px 0}
.roleadmin{margin-top:8px;align-items:center}

/* Правка состава набора прямо в строке, раскрытием. */
details.inline-edit{margin-top:4px}
details.inline-edit summary{cursor:pointer;color:var(--accent);font-size:12px}
.boxes{display:flex;flex-wrap:wrap;gap:4px 14px;margin:6px 0}

/* ---- боковая колонка ------------------------------------------------------
   В КОНЦЕ ФАЙЛА НАМЕРЕННО. Правила раскладки спорят по порядку с базовыми:
   `body>main{margin-inline:0}` из слоя совместимости и `body>main{margin-left}`
   отсюда имеют одинаковую специфичность, и побеждает тот, кто ниже. Стоя рядом
   с остальными правилами шапки — то есть выше — этот блок молча не действовал:
   колонка рисовалась, а содержимое уезжало под неё. */
@media (min-width:1100px){
  /* Колонка ФИКСИРОВАННАЯ: обёртки вокруг содержимого нет и быть не может —
     `<main>` открывается внутри каждого шаблона (см. комментарий в layout.html).
     Фиксация заодно устойчивее к htmx: колонка не в потоке и при подмене
     содержимого не перерисовывается вовсе. */
  .top{position:fixed;inset:0 auto 0 0;width:14rem;flex-direction:column;
       align-items:stretch;gap:14px;overflow-y:auto;
       border-bottom:0;border-right:1px solid var(--line)}
  .top nav{flex-direction:column;gap:14px}
  .navgroup{flex-direction:column;gap:1px}
  .navtitle{display:block;color:var(--mut);font-size:11px;text-transform:uppercase;
            letter-spacing:.04em;margin-bottom:3px}
  /* В колонке подчёркивание снизу читается как разрыв строки: активный раздел
     помечается полосой слева, вдоль края колонки. */
  .top nav a{padding:3px 8px;border-bottom:0;border-left:2px solid transparent;
             border-radius:0 4px 4px 0}
  .top nav a:hover{background:var(--navhover);text-decoration:none}
  .top nav a.on{border-bottom:0;border-left-color:var(--accent);background:var(--navon)}
  .who{margin-left:0;margin-top:auto;padding-top:10px;border-top:1px solid var(--line)}

  body>main{margin-left:14rem}
  /* Полосы состояния идут во всю ширину рядом с колонкой, а не под ней: их
     читают вместо содержимого, а не вместе с ним.
     Селектор ПРЯМЫХ ДЕТЕЙ body обязателен: те же классы носят блоки ВНУТРИ
     `<main>` (замечания модели прав, ошибки разделов), а `main` уже отступил от
     колонки — отступ достался бы им дважды. */
  body>.alarm,body>.warn{margin-left:14rem}
  /* На странице входа навигации нет вовсе — карточке отступать не от чего. */
  main.login{margin-left:auto}
}
