/* packages/ui/admin/admin.css
   Закрытый словарь классов раздела «Админка» (console-core-admin, Шаг 4).

   Владелец правки словаря — этот шаг. Экраны (Шаги 12-21) этот файл НЕ
   редактируют: если экрану не хватило класса, шаг-экран эскалирует, правка
   вносится отдельной задачей (см. план, Шаг 4, Implementation Notes).

   Полный словарь (проверяется гейтом G1, tests/test_ui_admin_assets.py):
   .adm .adm-head .adm-list .adm-cell .adm-cell.wide .adm-toolbar .adm-filter .adm-group
   .adm-group-title .adm-form .adm-row .adm-field .adm-label .adm-input
   .adm-select .adm-actions .adm-btn .adm-btn.primary .adm-btn.danger
   .adm-btn[disabled] .adm-err .adm-ok .adm-badge .adm-badge.direct
   .adm-badge.expired .adm-group-name .adm-facet
   .adm-picker .adm-picker-list .adm-picker-item
   .adm-picker-item.on .adm-picker-dept .adm-perms .adm-perm .adm-pager
   .adm-note .adm-mono

   Все цвета — только var(--…) из 20 токенов packages/theme/tokens.css;
   литеральный hex только #fff/#ffffff (репозиторный гейт, как и везде в
   packages/ui). Тёмной темы и её механизма здесь нет и не будет — см.
   packages/theme/README.md.
*/

/* Шапка раздела: горизонтальный ряд вкладок, который НЕ растягивается по
   высоте. `flex: none` здесь несущий — см. комментарий в admin.js::mount. */
.adm-head {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex: none;
  padding: 0 1.1rem;
  border-bottom: 1px solid var(--border);
}

/* Тело раздела — общий контейнер всех шести экранов (каждый начинает свой
   mount с `el.className = "adm"`).

   `position: relative` ОБЯЗАТЕЛЕН: `.state` (states.css) позиционируется
   абсолютно внутри `inset: 0`, и без позиционированного хозяина экран
   состояния уезжает на ближайшего позиционированного предка — а его выше по
   дереву нет вовсе, так что плашка занимала весь вьюпорт. Та же ловушка уже
   описана в services.css, metrics.css, weekly.css и
   tickets.css; здесь она оставалась открытой. */
.adm {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .9rem;
  min-height: 0;
  flex: 1;
  overflow: auto;
  padding: 1.1rem;
}

/* Список-сетка (роли, назначения) вместо ряда полей ФОРМЫ.

   `.adm-row` — это flex с `flex-wrap`: у каждой строки своя ширина
   содержимого, поэтому поле ввода каждой следующей строки начиналось со
   своего отступа — та самая «лесенка». Сетка задана на СПИСКЕ, а ячейки
   лежат в ней напрямую (`.adm-cell`), поэтому колонки считаются по всем
   строкам сразу: строка без кнопки «Удалить» больше не сдвигает соседей.
   Обёртка на каждую строку сломала бы ровно это (у каждой обёртки была бы
   своя, независимая сетка). */
.adm-list {
  display: grid;
  grid-template-columns: minmax(10rem, 1fr) max-content max-content;
  align-items: center;
}

/* Разделительная линия — на ячейках, а промежуток между колонками задан их
   же внутренним отступом (не `column-gap`): при зазоре сетки линии соседних
   ячеек не смыкались и строка подчёркивалась пунктиром из трёх обрубков. */
.adm-cell {
  min-width: 0;
  padding: .55rem .9rem .55rem 0;
  border-bottom: 1px solid var(--divider);
}
.adm-cell:last-child {
  padding-right: 0;
}
/* Пустая ячейка (например, строка без ошибки) не должна рисовать ни
   отступа, ни линии — иначе под каждой строкой висела бы вторая полоса. */
.adm-cell:empty {
  padding: 0;
  border-bottom: 0;
}
.adm-cell.wide {
  grid-column: 1 / -1;
}

.adm-toolbar {
  display: flex;
  align-items: center;
  gap: .6rem;
  flex-wrap: wrap;
}

.adm-filter {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-left: auto;
}

.adm-group {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  border-top: 1px solid var(--divider);
  padding-top: .75rem;
}
.adm-group:first-child {
  border-top: 0;
  padding-top: 0;
}

.adm-group-title {
  font-size: .78rem;
  font-weight: 600;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.adm-form {
  display: flex;
  flex-direction: column;
  gap: .7rem;
}

.adm-row {
  display: flex;
  align-items: flex-end;
  gap: .6rem;
  flex-wrap: wrap;
}

.adm-field {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  min-width: 160px;
}

.adm-label {
  font-size: .78rem;
  color: var(--ink-2);
}

.adm-input,
.adm-select {
  border: 1px solid var(--border-2);
  background: var(--surface);
  border-radius: 6px;
  padding: .4rem .6rem;
  font: inherit;
  color: var(--ink);
}
.adm-input:focus-visible,
.adm-select:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 1px;
}

.adm-actions {
  display: flex;
  align-items: center;
  gap: .5rem;
}

.adm-btn {
  border: 1px solid var(--border-2);
  background: var(--surface);
  border-radius: 6px;
  padding: .42rem .85rem;
  font-size: .85rem;
  font-weight: 500;
  color: var(--ink-2);
}
.adm-btn:hover {
  border-color: var(--ink-3);
  color: var(--ink);
}
.adm-btn.primary {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
}
.adm-btn.primary:hover {
  background: var(--blue-deep);
  border-color: var(--blue-deep);
}
.adm-btn.danger {
  background: var(--surface);
  border-color: var(--err);
  color: var(--err);
}
.adm-btn.danger:hover {
  background: var(--surface-3);
}
.adm-btn[disabled] {
  opacity: .55;
  cursor: default;
  pointer-events: none;
}

.adm-err {
  color: var(--err);
  font-size: .85rem;
}

.adm-ok {
  color: var(--ok);
  font-size: .85rem;
}

.adm-badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  padding: .1rem .55rem;
  font-size: .76rem;
  font-weight: 600;
  background: var(--surface-2);
  color: var(--ink-2);
}
.adm-badge.direct {
  background: var(--blue-wash);
  color: var(--blue-deep);
}
/* Истёкший грант. Плашка, а не скрытие строки: спрятать её значит не
   ответить на вопрос «почему у человека пропал доступ» — администратор
   выдаст грант заново, так и не поняв, что произошло. Цвет — `--warn`
   (предупреждение), не `--err`: истёкший грант это нормальный конец жизни
   временного доступа, а не поломка. */
.adm-badge.expired {
  background: var(--surface-2);
  color: var(--warn);
}

/* `.adm-badge.owner` удалён вместе со своим единственным потребителем:
   каталог ресурсов рисовал оранжевую закладку с сырым значением поля
   `owner` («manual», «registrar»). Цвет ничего не означал, слово читателю
   ни о чём не говорило — теперь там фраза словами. Осталась ровно одна
   закладка, `.adm-badge.direct` («выдано лично» в матрице доступа), и она
   несёт смысл: строка прямого гранта, а не ролевая. */

.adm-picker {
  position: relative;
}

/* Хост состояний СПИСКА — не всего экрана.

   `.state` (states.css) — это `position: absolute; inset: 0`, то есть плашка
   растягивается до ближайшего позиционированного предка. У безымянного `<div>`
   своего позиционирования нет, поэтому ближайшим оказывался `.adm` (см.
   комментарий у него выше), и «Пусто»/«Загрузка»/«Не удалось загрузить»
   ложились НА ВЕСЬ экран раздела — поверх тулбара с селектом и кнопками.

   Наружу это выходило как полностью неотзывчивый экран: 13.08.2026 на живом
   стенде выбор роли без назначений («Владелец модуля: …», все пять заведены
   пустыми) накрывал экран плашкой «Пусто», и ни селект роли, ни «Выдать
   доступ» больше не нажимались. Роль С назначениями беды не показывала —
   таблица рисуется вместо плашки, и оверлей исчезает.

   Почему не лечится в `.state`: там оверлей — осознанный приём для случая,
   когда состояние ЗАМЕЩАЕТ экран целиком (`renderState` чистит хозяина, и
   экраны, отдающие ему свой корень, ведут себя верно). Сломан был именно
   хозяин — сюда состояние отдаёт лишь ЧАСТЬ экрана, и тулбар обязан пережить
   плашку.

   `min-height` — чтобы плашка не схлопнулась в ноль на пустом хосте: у
   `inset: 0` внутри нулевой высоты нет места ни под заголовок, ни под текст. */
.adm-statehost {
  position: relative;
  min-height: 7rem;
}

.adm-picker-list {
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--surface);
  max-height: 220px;
  overflow-y: auto;
}

.adm-picker-item {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .45rem .65rem;
  border-bottom: 1px solid var(--divider);
  cursor: pointer;
}
.adm-picker-item:last-child {
  border-bottom: 0;
}
.adm-picker-item:hover {
  background: var(--surface-2);
}
.adm-picker-item.on {
  background: var(--blue-wash);
}

.adm-picker-dept {
  font-size: .78rem;
  color: var(--ink-3);
}

.adm-perms {
  display: flex;
  flex-direction: column;
  gap: .4rem;
}

.adm-perm {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  padding: .4rem .6rem;
  font-size: .85rem;
}

/* Строка группы каталога в редакторе набора роли: заголовок модуля слева и
   переключатели его граней («Метрики и аналитика», «Настройки», дашборд)
   справа. Перенос по строкам обязателен: у модуля может быть больше двух
   граней, и без него они уезжали бы за край на узком экране. */
.adm-group-name {
  font-weight: 600;
  min-width: 12rem;
}

.adm-facet {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  cursor: pointer;
}

.adm-pager {
  display: flex;
  align-items: center;
  gap: .6rem;
  justify-content: flex-end;
  font-size: .85rem;
  color: var(--ink-2);
}

.adm-note {
  font-size: .82rem;
  color: var(--ink-3);
}

.adm-mono {
  font-family: var(--mono);
  font-size: .82rem;
}
