/* =========================================================
   Админ-панель — дизайн по спецификации.
   Только CSS поверх готовой разметки; цвета берём из переменных проекта.

   Обязательное правило: JS показывает/скрывает блоки атрибутом hidden,
   поэтому [hidden] должен побеждать любые display:flex/grid ниже.
   ========================================================= */

.admin-page [hidden] { display: none !important; }

.admin-page {
  /* локальная палитра поверх переменных проекта */
  --a-surface: color-mix(in srgb, var(--text) 4%, transparent);    /* карточка */
  --a-sunken: color-mix(in srgb, var(--page-bg) 70%, transparent); /* вложенный блок */
  --a-deep: color-mix(in srgb, var(--page-bg) 92%, transparent);   /* раскрытая форма */
  --a-border2: color-mix(in srgb, var(--text) 7%, transparent);    /* слабая граница */

  --a-warn: #e0a83c;   /* янтарный: чувствительное / предупреждение */
  --a-danger: #e5484d; /* красный: только опасное и ошибки */

  display: grid;
  gap: 22px;
  padding: 18px 20px 40px;
  font-family: var(--font-ui);
}

/* ---------- заголовок-линейка секции ---------- */
.admin-section { display: grid; gap: 12px; }

.admin-sectionHead {
  display: flex;
  align-items: center;
  gap: 9px;
}

.admin-sectionHead__mark {
  width: 8px;
  height: 8px;
  border-radius: 3px;
  background: var(--primary);
  flex: 0 0 auto;
}

.admin-sectionHead__title {
  margin: 0;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--text);
  white-space: nowrap;
}

.admin-sectionHead__meta {
  font-size: 11.5px;
  color: var(--muted);
  white-space: nowrap;
}

.admin-sectionHead__line {
  flex: 1 1 auto;
  height: 1px;
  background: var(--a-border2);
}

/* внутренний разделитель групп (Биржи / Площадки) — тише внешнего */
.admin-sectionHead--inner {
  cursor: pointer;
  user-select: none;
  padding: 2px 0;
}

.admin-sectionHead--inner .admin-sectionHead__mark {
  width: 6px;
  height: 6px;
  background: var(--muted);
}

.admin-sectionHead--inner .admin-sectionHead__title {
  font-size: 10.5px;
  color: var(--muted);
  letter-spacing: .1em;
}

.admin-sectionHead--inner:hover .admin-sectionHead__title,
.admin-sectionHead--inner:hover .admin-sectionHead__mark { color: var(--text); }
.admin-sectionHead--inner:hover .admin-sectionHead__mark { background: var(--primary); }

.admin-group { display: grid; gap: 9px; }

.admin-group__chevron {
  width: 11px;
  height: 11px;
  flex: 0 0 auto;
  background: var(--muted);
  transition: transform .15s ease;
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.admin-group.is-open .admin-group__chevron { transform: rotate(180deg); }

.admin-group__body { display: none; }

.admin-group.is-open .admin-group__body {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
  gap: 9px;
  align-items: start;
}

/* ---------- панель инструментов ---------- */
.admin-toolbar {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-wrap: wrap;
}

.admin-page .btn,
.admin-page .admin-badge,
.admin-page .admin-team__code { white-space: nowrap; }

.admin-page .btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 999px;
  font-size: 12.5px;
  padding: 7px 14px;
  height: auto;
  cursor: pointer;
  transition: var(--transition);
}

.admin-page .btn:hover { border-color: color-mix(in srgb, var(--text) 22%, transparent); }

.admin-page .btn.primary {
  background: var(--primary);
  border-color: var(--primary);
  color: #08130c;
  font-weight: 600;
  padding: 8px 16px;
}

.admin-page .btn.primary:hover { background: var(--primary-2); border-color: var(--primary-2); }

/* тихая вспомогательная кнопка («Изменить», «Проверить», «Сгенерировать») */
.admin-page .btn--xs {
  font-size: 10.5px;
  padding: 2px 9px;
  color: var(--muted);
  border-color: var(--a-border2);
}

.admin-page .btn--xs:hover { color: var(--text); border-color: var(--border); }

.admin-page .btn--sm {
  font-size: 11px;
  font-weight: 600;
  padding: 4px 11px;
}

/* кнопка-иконка (редактирование) */
.admin-page .btn--icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border-radius: 7px;
  border-color: var(--a-border2);
  flex: 0 0 auto;
}

.admin-page .btn--icon .icon {
  width: 13px;
  height: 13px;
  background: var(--muted);
  transition: var(--transition);
}

.admin-page .btn--icon:hover {
  border-color: color-mix(in srgb, var(--primary) 45%, transparent);
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}

.admin-page .btn--icon:hover .icon { background: var(--primary); }

/* текстовая кнопка отмены */
.admin-page .btn--text {
  border: none;
  background: none;
  color: var(--muted);
  padding: 2px 6px;
  font-size: 11.5px;
}

.admin-page .btn--text:hover { color: var(--text); }

/* «добавить новое» — пунктир + акцент */
.admin-page .btn--dashed {
  border: 1px dashed color-mix(in srgb, var(--primary) 45%, transparent);
  background: none;
  color: var(--primary);
  font-size: 11px;
  padding: 4px 11px;
}

.admin-page .btn--dashed:hover {
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  border-color: var(--primary);
}

/* опасное действие */
.admin-page .btn--danger {
  color: var(--a-danger);
  border-color: color-mix(in srgb, var(--a-danger) 40%, transparent);
}

.admin-page .btn--danger:hover {
  background: color-mix(in srgb, var(--a-danger) 12%, transparent);
  border-color: var(--a-danger);
}

.admin-page .btn--dangerSolid {
  background: var(--a-danger);
  border-color: var(--a-danger);
  color: #fff;
  font-weight: 600;
}

.admin-page .btn--dangerSolid:hover { filter: brightness(1.08); }

/* ---------- поиск ---------- */
.admin-searchWrap {
  position: relative;
  flex: 1 1 260px;
  max-width: 420px;
  display: inline-flex;
  align-items: center;
}

.admin-searchWrap__icon {
  position: absolute;
  left: 11px;
  width: 13px;
  height: 13px;
  pointer-events: none;
  background: var(--muted);
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.2-3.2'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2.2' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.2-3.2'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.admin-filters {
  display: inline-flex;
  gap: 6px;
  align-items: center;
  flex-wrap: wrap;
  margin-left: auto;
}

/* ---------- поля ввода ---------- */
.admin-page input,
.admin-page select { box-sizing: border-box; min-width: 0; max-width: 100%; }

.admin-page .input,
.admin-page .select {
  /* Поле занимает свою ячейку целиком: без этого в сетке форм ширина шла от
     содержимого, и соседние поля получались разной длины. */
  width: 100%;
  min-width: 0;
  background: var(--input-bg);
  border: 1px solid var(--border);
  border-radius: 7px;
  padding: 6px 10px;
  height: auto;
  font-size: 12.5px;
  color: var(--text);
  font-family: inherit;
}

.admin-page .input:focus,
.admin-page .select:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--primary) 60%, transparent);
  box-shadow: 0 0 0 3px var(--input-focus);
}

.admin-page .input--sm,
.admin-page .select--sm { padding: 4px 8px; font-size: 12px; }

/* Поиск: отступ слева под иконку. Правило идёт ПОСЛЕ общего .input,
   иначе его padding перебивает наш и текст наезжает на лупу. */
.admin-page .admin-search {
  width: 100%;
  padding: 7px 14px 7px 32px;
  border-radius: 999px;
}

.admin-page .input--mono,
.admin-val--mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }

/* чувствительные поля: 2FA, API Secret, пароли */
.admin-page .input--sensitive {
  background: color-mix(in srgb, var(--a-warn) 8%, var(--input-bg));
  border: 1px dashed color-mix(in srgb, var(--a-warn) 45%, transparent);
}

.admin-page .field--sensitive .field-label,
.admin-field--sensitive .admin-field__label {
  color: var(--a-warn);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.admin-page .field--sensitive .field-label::before,
.admin-field--sensitive .admin-field__label::before {
  content: "";
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--a-warn);
  flex: 0 0 auto;
}

/* ---------- формы создания (уровень 1) ---------- */
/* Форма создания — карточка ограниченной ширины, а не полоса во весь экран.
   Растянутая на всю ширину, она разъезжалась в один ряд из семи полей: глаз
   не находил, что с чем связано, а короткие поля вроде пароля становились
   уже длинных. */
.admin-form:not([hidden]) {
  display: grid;
  gap: 12px;
  width: min(100%, 760px);
  background: var(--a-surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 15px 16px 14px;
  box-shadow: 0 8px 24px -18px rgba(0, 0, 0, .7);
}

.admin-form__head {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  padding-bottom: 10px;
  border-bottom: 1px dashed var(--a-border2);
}

.admin-form__title { font-size: 13.5px; font-weight: 700; }
.admin-form__note { font-size: 11px; color: var(--muted); }

/* Две колонки: пары «подпись — поле» стоят рядом и читаются как пары. */
.admin-form__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 11px 14px;
}

.admin-page .field { display: grid; gap: 4px; align-content: start; }
.admin-page .field--wide { grid-column: 1 / -1; }

.admin-page .field-label {
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.admin-page .req { color: var(--a-danger); margin-left: 2px; }

.admin-form__actions {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
  padding-top: 11px;
  border-top: 1px dashed var(--a-border2);
}
.admin-form__hint { font-size: 12px; color: var(--muted); }
.admin-form__hint.is-ok { color: var(--primary); }
.admin-form__hint.is-bad { color: var(--a-danger); }

/* Пароль и кнопка генерации: поле не должно съёживаться до «минимум…» —
   именно это и происходило, когда ряд полей делили поровну. */
.admin-pwd { display: flex; gap: 6px; align-items: center; }
.admin-pwd .input { flex: 1 1 auto; min-width: 0; }
.admin-pwd .btn { flex: 0 0 auto; }

/* пароль, показанный один раз */
.admin-form__hint.admin-pwdShown {
  color: var(--text);
  background: color-mix(in srgb, var(--a-warn) 10%, transparent);
  border: 1px dashed color-mix(in srgb, var(--a-warn) 50%, transparent);
  border-radius: 7px;
  padding: 5px 10px;
}

.admin-pwdShown__val {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-weight: 700;
}

/* Памятка живёт вне формы: форма после создания сворачивается, а пароль
   восстановить нельзя — он должен остаться на экране. */
.admin-pwdNote {
  font-size: 12px;
  color: var(--text);
  background: color-mix(in srgb, var(--a-warn) 10%, transparent);
  border: 1px dashed color-mix(in srgb, var(--a-warn) 50%, transparent);
  border-radius: 7px;
  padding: 7px 11px;
  margin-bottom: 10px;
}

.admin-pwdNote .admin-pwdShown__val.is-copied { color: var(--primary); }

/* подсказка после сброса пароля живёт внутри карточки пользователя */
.admin-pwdNote--reset { margin: 4px 0 6px; }

/* подтверждение сброса — сразу под строкой «Пароль», у места клика */
.admin-pwdConfirm { margin: 4px 0 6px; }

.admin-ro--pwd .btn--xs { flex: 0 0 auto; margin-left: 4px; }

/* ---------- бейджи ---------- */
.admin-badge {
  display: inline-flex;
  align-items: center;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  padding: 1.5px 8px;
  border: 1px solid transparent;
  line-height: 1.6;
}

.admin-badge--ok {
  background: color-mix(in srgb, var(--primary) 13%, transparent);
  color: var(--primary);
}

.admin-badge--bad {
  background: color-mix(in srgb, var(--a-danger) 13%, transparent);
  color: var(--a-danger);
}

.admin-badge--warn {
  background: color-mix(in srgb, var(--a-warn) 13%, transparent);
  color: var(--a-warn);
}

.admin-badge--muted {
  background: color-mix(in srgb, var(--text) 7%, transparent);
  color: var(--muted);
}

.admin-badge--accent {
  background: color-mix(in srgb, var(--primary) 15%, transparent);
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 30%, transparent);
}

/* Разработчик — таких единицы, и роль старшая: отдельный цвет, чтобы не
   путать с админом. */
.admin-badge--dev {
  background: color-mix(in srgb, #a78bfa 18%, transparent);
  color: #c4b5fd;
  border-color: color-mix(in srgb, #a78bfa 40%, transparent);
}

/* бейдж площадки: одинаковая насыщенность, различие только по хью */
.admin-badge--platform {
  --p: #8b93a7;
  background: color-mix(in srgb, var(--p) 13%, transparent);
  color: var(--p);
  border-color: color-mix(in srgb, var(--p) 32%, transparent);
}

.admin-badge--platform[data-platform="bybit"] { --p: #f0a13a; }
.admin-badge--platform[data-platform="ikra"]  { --p: #4aa3f0; }
.admin-badge--platform[data-platform="deora"] { --p: #a97bf0; }
.admin-badge--platform[data-platform="zavod"] { --p: #46bfa3; }

/* ---------- карточка аккаунта (уровень 1) ---------- */
.admin-accounts { display: grid; gap: 14px; }

.admin-acc {
  background: var(--a-surface);
  border: 1px solid var(--border);
  border-radius: 11px;
  padding: 11px 12px;
  display: grid;
  gap: 8px;
}

.admin-acc__head {
  display: flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  user-select: none;
  flex-wrap: wrap;
}

.admin-acc__badges { display: inline-flex; gap: 4px; flex-wrap: wrap; }

.admin-acc__chevron {
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  background: var(--muted);
  transition: transform .15s ease;
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.admin-acc.is-open .admin-acc__chevron { transform: rotate(180deg); }

/* ---------- рубильник аккаунта биржи ----------
   Работает ли аккаунт на портале. Стоит в шапке последним перед шевроном:
   это действие над всей карточкой, и место у него там же, где у значка её
   раскрытия. Виден только разработчику (см. accountCardHtml). */

.admin-power {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  line-height: 0;
}

.admin-power__track {
  width: 30px;
  height: 16px;
  border-radius: 999px;
  background: var(--input-bg);
  border: 1px solid var(--border);
  position: relative;
  transition: background var(--transition), border-color var(--transition);
}

.admin-power__knob {
  position: absolute;
  top: 1px;
  left: 1px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--muted);
  transition: transform var(--transition), background var(--transition);
}

.admin-power.is-on .admin-power__track {
  background: color-mix(in srgb, var(--primary) 30%, var(--input-bg));
  border-color: color-mix(in srgb, var(--primary) 55%, var(--border));
}

.admin-power.is-on .admin-power__knob {
  transform: translateX(14px);
  background: var(--primary);
}

.admin-power:hover .admin-power__track {
  border-color: color-mix(in srgb, var(--primary) 40%, var(--border));
}

/* Пока ответ не пришёл, нажимать второй раз нельзя: два запроса подряд
   разошлись бы с тем, что уже нарисовано. */
.admin-power:disabled { cursor: progress; }
.admin-power:disabled .admin-power__track { opacity: .55; }

.admin-power:focus-visible .admin-power__track {
  outline: 2px solid color-mix(in srgb, var(--primary) 60%, transparent);
  outline-offset: 2px;
}

/* Выключенный аккаунт должен быть виден в списке из сотни — но остаться
   читаемым: гасим имя и бейджи, а не всю карточку. */
.admin-acc.is-off .admin-acc__name,
.admin-acc.is-off .admin-acc__badges { opacity: .55; }

/* свёрнутая карточка: в шапке остаются имя и бейджи площадок */
.admin-acc__body { display: none; }
.admin-acc.is-open .admin-acc__body { display: grid; gap: 8px; }
.admin-acc__name { font-size: 13.5px; font-weight: 700; }

.admin-acc__meta {
  font-size: 10.5px;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

.admin-acc__hint {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
}

.admin-acc__hint.is-ok { color: var(--primary); }
.admin-acc__hint.is-bad { color: var(--a-danger); }

.admin-acc__proxy,
.admin-acc__services { display: grid; gap: 6px; }

.admin-note { font-size: 11.5px; color: var(--muted); font-style: italic; }

/* детали прокси (адрес/логин/пароль — копируются по клику) */
.admin-proxyInfo {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: baseline;
  padding: 0 0 0 68px; /* по левому краю значений соседних строк */
}

.admin-proxyInfo__item { display: inline-flex; align-items: baseline; gap: 4px; min-width: 0; }

.admin-proxyInfo__label {
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.admin-proxyInfo .admin-copy { font-size: 12px; }

.admin-copy--mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 11.5px; }

/* ---------- строка «значение + Изменить» ---------- */
/* Строка поля НЕ переносится: при сужении сокращается само значение,
   иначе кнопка редактирования уезжает на вторую строку. */
.admin-field {
  display: flex;
  align-items: center;
  gap: 6px;
  min-height: 23px;
  flex-wrap: nowrap;
  min-width: 0;
}

.admin-field__label {
  flex: 0 0 62px;
  font-size: 9.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.admin-field__view:not([hidden]) {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 0;
  min-width: 0;
  flex-wrap: nowrap;
}

/* режим редактирования может переноситься — там несколько контролов */
.admin-field__edit:not([hidden]) {
  display: flex;
  align-items: center;
  gap: 6px;
  flex: 1 1 0;
  min-width: 0;
  flex-wrap: wrap;
}

.admin-val {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12px;
  color: var(--text);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.admin-val--empty { color: var(--muted); font-style: italic; }

.admin-field__edit .input,
.admin-field__edit .select { flex: 1 1 120px; }

/* ---------- блок площадки (уровень 2) ---------- */
.admin-svc {
  background: var(--a-sunken);
  border: 1px solid var(--a-border2);
  border-radius: 8px;
  padding: 8px 9px;
  display: grid;
  gap: 6px;
}

.admin-svc__head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

.admin-svc__who {
  margin-left: auto;
  font-size: 10px;
  color: var(--muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
}

/* Кнопка входа на площадку — прижата к правому краю шапки.
   margin-left:auto здесь же, что и у ника: если рядом стоит ник (у бирж),
   вправо уедет он, а кнопка встанет следом — у площадок ника не бывает. */
.admin-svc__login {
  margin-left: auto;
  flex: none;
}
.admin-svc__who + .admin-svc__login { margin-left: 6px; }

.admin-svc__fields { display: grid; gap: 3px; }

/* ---------- раскрытые формы (уровень 3) ---------- */
.admin-keyform,
.admin-newproxy:not([hidden]),
.admin-addsvc:not([hidden]) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(130px, 1fr));
  gap: 6px;
  background: var(--a-deep);
  border: 1px dashed var(--a-border2);
  border-radius: 7px;
  padding: 7px;
  width: 100%;
}

.admin-keyform { margin-top: 2px; }

.admin-acc__add { display: grid; gap: 6px; justify-items: start; }
.admin-acc__add .admin-addsvc { justify-items: stretch; }

/* ---------- команды ---------- */
/* Ширина по содержимому: карточка команды занимает столько, сколько нужно,
   и не растягивается на пустое место. */
.admin-teams {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  align-items: flex-start;
}

.admin-team {
  flex: 0 1 auto;
  max-width: 100%;
  background: var(--a-surface);
  border: 1px solid var(--border);
  border-radius: 11px;
  padding: 11px 12px;
  display: grid;
  gap: 8px;
}

.admin-team__head { display: flex; align-items: center; gap: 8px; }

.admin-team__code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
  font-weight: 700;
  color: var(--primary);
  background: color-mix(in srgb, var(--primary) 12%, transparent);
  border-radius: 6px;
  padding: 2px 8px;
}

.admin-team__name { font-size: 13px; font-weight: 600; }
.admin-team__count { margin-left: auto; font-size: 11px; color: var(--muted); }

.admin-team__rows { display: grid; gap: 5px; }

.admin-teamrow {
  background: var(--a-sunken);
  border: 1px solid var(--a-border2);
  border-radius: 8px;
  padding: 7px 9px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.admin-teamrow__name { font-size: 12px; font-weight: 600; }

.admin-teamrow__id {
  font-size: 11px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 190px;
}

.admin-teamrow__move { margin-left: auto; display: flex; gap: 6px; align-items: center; }
.admin-teamrow__hint { flex: 1 1 100%; }

.admin-teamrow__msg { font-size: 11px; color: var(--muted); }
.admin-teamrow__msg.is-bad { color: var(--a-danger); }

/* ---------- подтверждение опасного действия ---------- */
.admin-confirm {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  background: color-mix(in srgb, var(--a-danger) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--a-danger) 35%, transparent);
  border-radius: 8px;
  padding: 7px 9px;
  margin-top: 4px;
}

.admin-confirm__text { flex: 1 1 auto; font-size: 11px; color: var(--text); }

/* ---------- пользователи ---------- */
/* «Тетрис»: карточки одинаковой ширины укладываются скриптом (layoutUsers)
   в самую короткую колонку, не оставляя дыр под соседями. Ширина колонки
   зависит только от экрана, поэтому live-обновления раскладку не трогают;
   раскрытие карточки двигает соседей с анимацией. */
.admin-users {
  position: relative;
}

.admin-users .admin-user {
  position: absolute;
  top: 0;
  left: 0;
  min-width: 0;
}

/* Анимация сдвигов включается ПОСЛЕ первой расстановки: иначе карточки
   съезжались бы в кучу из угла при каждой перерисовке списка. */
.admin-users.is-laid .admin-user {
  transition: transform .28s ease;
}

/* Автопрокрутка к раскрывшемуся блоку не прижимает его вплотную к краю. */
.admin-user__body,
.admin-user__sessBody {
  scroll-margin: 14px;
}

.admin-user {
  background: var(--a-surface);
  border: 1px solid var(--border);
  border-radius: 11px;
  overflow: hidden;
}

.admin-user.is-off { opacity: .6; }

/* Свёрнутая карточка: первой строкой ФИО, второй — статусы и переключатель.
   Так карточка не растягивается в длинную полосу. */
.admin-user__head {
  position: relative;
  display: flex;
  align-items: center;
  gap: 8px;
  row-gap: 6px;
  flex-wrap: wrap;
  padding: 9px 30px 9px 12px;
  cursor: pointer;
  user-select: none;
  transition: var(--transition);
}

.admin-user__head > .admin-user__name { flex: 1 1 100%; }

.admin-user__head:hover { background: color-mix(in srgb, var(--text) 3%, transparent); }

.admin-user__name { font-size: 13.5px; font-weight: 700; }

.admin-user__hint {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
}

.admin-user__head .admin-user__hint:empty { display: none; }

.admin-user__hint.is-ok { color: var(--primary); }
.admin-user__hint.is-bad { color: var(--a-danger); }

.admin-user__chevron {
  position: absolute;
  top: 12px;
  right: 12px;
  width: 12px;
  height: 12px;
  flex: 0 0 auto;
  background: var(--muted);
  transition: transform .15s ease;
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.admin-user.is-open .admin-user__chevron { transform: rotate(180deg); }

.admin-user__confirm:not([hidden]) { padding: 0 12px 9px; }

.admin-user__body:not([hidden]) {
  display: grid;
  gap: 10px;
  padding: 10px 12px 12px;
  border-top: 1px dashed var(--a-border2);
}

/* Данные — в две колонки: подписи короткие, и длинный столбец из семи строк
   выглядел пустым наполовину. */
.admin-user__info {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 3px 16px;
  align-content: start;
}

/* Пароль со своей кнопкой — на всю ширину, иначе кнопка ломает колонку. */
.admin-ro--pwd { grid-column: 1 / -1; }

/* ---------- секции внутри карточки ---------- */
.admin-section2 {
  margin-top: 10px;
  padding-top: 9px;
  border-top: 1px dashed var(--a-border2);
}

.admin-section2__head {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 7px;
}

.admin-section2__title {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--text);
}

.admin-section2__note { font-size: 10.5px; color: var(--muted); }
.admin-section2__save { margin-left: auto; }
.admin-section2__save[disabled] { opacity: .45; cursor: default; }

/* группа внутри секции: подпись слева, набор справа */
.admin-group2 {
  display: grid;
  grid-template-columns: 92px 1fr;
  gap: 6px 10px;
  align-items: start;
  padding: 3px 0;
}

.admin-group2__label {
  font-size: 10px;
  color: var(--muted);
  padding-top: 3px;
}

/* ---------- переключатель роли ---------- */
/* Три варианта — сегменты, а не выпадающий список: выбор в один клик, и
   системный список выбивался из оформления панели.
   Подсветку ведёт один ползунок: он переезжает к выбранному, и по его
   прозрачности видно, зафиксирован выбор или ещё ждёт подтверждения. */
.admin-seg {
  --seg-at: 0;
  --seg-w: 104px;

  position: relative;
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--seg-w);
  padding: 3px;
  background: var(--a-sunken);
  border: 1px solid var(--a-border2);
  border-radius: 9px;
}

.admin-seg__thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: var(--seg-w);
  height: calc(100% - 6px);
  border-radius: 7px;
  background: color-mix(in srgb, var(--primary) 20%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 45%, transparent);
  transform: translateX(calc(var(--seg-at) * var(--seg-w)));
  transition: transform .26s cubic-bezier(.4, 0, .2, 1), opacity .2s ease, background .2s ease;
}

/* Выбор ещё не подтверждён: ползунок доехал, но пунктирный и полупрозрачный. */
.admin-seg.is-pending .admin-seg__thumb {
  opacity: .55;
  background: color-mix(in srgb, var(--primary) 10%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--primary) 35%, transparent);
}

.admin-seg__btn {
  position: relative;
  padding: 4px 0;
  font: inherit;
  font-size: 11.5px;
  color: var(--muted);
  background: none;
  border: none;
  border-radius: 7px;
  cursor: pointer;
  transition: color .2s ease;
}

.admin-seg__btn:hover { color: var(--text); }
.admin-seg__btn.is-active { color: var(--text); }

/* Подтверждение смены роли — рядом с самим переключателем. */
.admin-roleConfirm:not([hidden]) { margin-top: 7px; animation: admin-slideIn .2s ease; }
.admin-roleConfirm__wait { font-size: 11px; color: var(--muted); }

@keyframes admin-slideIn {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

/* ---------- права в панели: группа и подпункты ---------- */
.admin-caps { display: grid; gap: 5px; }

.admin-cap__head { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }

/* Счётчик подпунктов — он же кнопка раскрытия. */
.admin-cap__more {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  padding: 1px 7px;
  font: inherit;
  font-size: 10px;
  color: var(--muted);
  background: none;
  border: 1px solid var(--a-border2);
  border-radius: 999px;
  cursor: pointer;
  transition: var(--transition);
}

.admin-cap__more::after {
  content: "";
  width: 7px;
  height: 7px;
  background: currentColor;
  transition: transform .2s ease;
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.admin-cap__more:hover { color: var(--text); border-color: var(--border); }
.admin-cap.is-open .admin-cap__more::after { transform: rotate(180deg); }

.admin-cap__hint { font-size: 10px; color: var(--muted); }

.admin-cap__kids:not([hidden]) {
  display: grid;
  gap: 4px;
  margin: 5px 0 2px 14px;
  padding-left: 10px;
  border-left: 1px dashed var(--a-border2);
  animation: admin-slideIn .18s ease;
}

.admin-chip--kid { font-size: 11px; }

/* Выключенная группа: подпункты видны, но серые — сразу понятно, что их
   сначала нужно открыть галкой сверху. */
.admin-cap:not(.is-on) .admin-cap__kids { opacity: .5; }

/* ---------- «таблетки» вместо голых галочек ---------- */
.admin-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.admin-chips--wide { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }

.admin-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 9px;
  font-size: 11.5px;
  color: var(--muted);
  background: var(--a-sunken);
  border: 1px solid var(--a-border2);
  border-radius: 999px;
  cursor: pointer;
  user-select: none;
  transition: var(--transition);
}

.admin-chip:hover { border-color: color-mix(in srgb, var(--primary) 35%, transparent); }

/* Выбранное состояние — на самой таблетке: так набор читается одним взглядом,
   не выискивая галочки. */
.admin-chip:has(input:checked) {
  color: var(--text);
  background: color-mix(in srgb, var(--primary) 13%, transparent);
  border-color: color-mix(in srgb, var(--primary) 45%, transparent);
}

.admin-chip.is-disabled { opacity: .5; cursor: default; }
.admin-chip input { accent-color: var(--primary); cursor: inherit; margin: 0; }

/* read-only строка */
.admin-ro { display: flex; align-items: baseline; gap: 8px; min-height: 20px; }

.admin-ro__label {
  flex: 0 0 72px;
  font-size: 9.5px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

.admin-ro__val { font-size: 12.5px; color: var(--text); min-width: 0; }
.admin-ro__val--empty { color: var(--muted); font-style: italic; }
.admin-ro__val--muted { color: var(--muted); }
.admin-ro__note { font-size: 10.5px; color: var(--muted); }

/* Значение-кнопка: код 2FA и маска пароля копируются кликом.
   Подчёркивания нет намеренно — в списке полей оно рябило бы на каждой
   строке; хватает веса шрифта и подсветки при наведении. */
.admin-val--copy {
  cursor: pointer;
  font-weight: 600;
  letter-spacing: .04em;
  transition: var(--transition);
}

.admin-val--copy:hover { color: var(--primary); }

/* Последние секунды кода — чтобы не диктовать то, что вот-вот сменится. */
.admin-val--copy.is-expiring { color: var(--a-warn); }

/* Копируемое значение. Подчёркивания нет намеренно: копируется здесь почти
   всё, и пунктир под каждой строкой превращал карточку в рябь. Достаточно
   веса шрифта и короткой вспышки после нажатия. */
.admin-copy {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: inherit;
  cursor: pointer;
  border-radius: 4px;
  transition: color .15s ease, background .15s ease;
}

.admin-copy:hover { color: var(--primary); }

/* Вспышка вместо всплывающей подсказки — видна там, куда смотрит глаз. */
.admin-copy.is-copied,
.admin-val--copy.is-copied {
  color: var(--primary);
  background: color-mix(in srgb, var(--primary) 14%, transparent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 14%, transparent);
}

.admin-copy.is-copyFail,
.admin-val--copy.is-copyFail { color: var(--a-danger); }


/* ---------- сессии: видно без раскрытия карточки ---------- */
/* Третьей строкой в шапке. Устройств может быть несколько — тогда строк
   становится больше, карточка растёт вниз, а не вширь. */
/* Мини-карточка устройств: кликабельна целиком (раскрытие подробностей). */
.admin-user__sess {
  flex: 1 1 100%;
  min-width: 0;
  display: grid;
  gap: 3px;
  padding: 5px 4px 2px;
  margin: 0 -4px -2px;
  border-top: 1px dashed var(--a-border2);
  border-radius: 0 0 6px 6px;
  cursor: pointer;
  transition: var(--transition);
}

.admin-user__sess:not(.is-open):not(.is-empty):hover {
  background: color-mix(in srgb, var(--text) 4%, transparent);
}

.admin-user__sess.is-empty { cursor: default; }

.admin-user__sessHead {
  display: flex;
  align-items: center;
  gap: 8px;
  user-select: none;
}

/* Раскрытые подробности замещают краткие строки, а не дублируют их. */
.admin-user__sess.is-open .admin-sess__list--brief { display: none; }

.admin-user__sessBody:not([hidden]) {
  display: grid;
  gap: 7px;
  padding-top: 4px;
}

.admin-sess__state {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

/* Точка «в сети» — единственный цветной элемент строки, поэтому её видно сразу. */
.admin-sess__state.is-on { color: var(--primary); }

.admin-sess__state::before {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--muted);
  opacity: .5;
}

.admin-sess__state.is-on::before {
  background: var(--primary);
  opacity: 1;
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary) 20%, transparent);
}

.admin-sess__list { display: grid; gap: 3px; }

/* Строка устройства/постороннего захода. Не путать с .admin-sessLive — это
   индикатор живости сессии площадки в шапке аккаунта. */
.admin-sess {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  font-size: 11.5px;
  color: var(--muted);
  min-width: 0;
}

.admin-sess.is-on { color: var(--text); }
.admin-sess.is-out { opacity: .55; }

.admin-sess__dev { font-weight: 600; white-space: nowrap; }
.admin-sess__geo { min-width: 0; overflow-wrap: anywhere; }
.admin-sess__geo--wait { font-style: italic; opacity: .7; }

/* Вторая строка ряда: геосправка и метки адреса. Фиксированные две строки —
   свободный перенос ставил одинаковые данные в карточках по-разному. */
.admin-sess__line2 {
  flex: 1 1 100%;
  display: flex;
  align-items: center;
  gap: 6px;
  min-width: 0;
  font-size: 10.5px;
  color: var(--muted);
}

/* колёсико, пока справка по адресу в пути */
.admin-spin {
  display: inline-block;
  width: 11px;
  height: 11px;
  flex: 0 0 auto;
  border: 2px solid color-mix(in srgb, var(--muted) 35%, transparent);
  border-top-color: var(--muted);
  border-radius: 50%;
  animation: admin-spin .7s linear infinite;
}

@keyframes admin-spin { to { transform: rotate(360deg); } }

.admin-sess__when {
  margin-left: auto;
  font-size: 10.5px;
  white-space: nowrap;
  opacity: .8;
}

.admin-sess .admin-copy { font-size: 11.5px; }

/* сводка и шеврон в шапке блока устройств */
.admin-devcard__sum {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

.admin-devcard__chevron {
  width: 11px;
  height: 11px;
  flex: 0 0 auto;
  background: var(--muted);
  transition: transform .15s ease;
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

.admin-user__sess.is-open .admin-devcard__chevron { transform: rotate(180deg); }

/* одно устройство со статистикой и действиями */
.admin-dev {
  display: grid;
  gap: 5px;
  min-width: 0;
  padding: 8px 9px;
  border-radius: 7px;
  background: var(--a-sunken);
  border: 1px solid var(--a-border2);
}

.admin-dev.is-on { border-color: color-mix(in srgb, var(--primary) 30%, transparent); }
.admin-dev.is-blocked { border-color: color-mix(in srgb, var(--a-danger) 35%, transparent); opacity: .75; }

.admin-dev__top {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  font-size: 12px;
  min-width: 0;
}

.admin-dev__stats {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  font-size: 10.5px;
  color: var(--muted);
}

/* Действия своим рядом внизу справа: вперемешку со статусами они «ехали». */
.admin-dev__actions {
  display: flex;
  justify-content: flex-end;
  gap: 6px;
  flex-wrap: wrap;
}

.admin-dev__confirm:not([hidden]) { margin-top: 2px; }

/* ---------- посторонние заходы ---------- */
.admin-sectionHead__mark--danger { background: var(--a-danger); }

.admin-note--intruders { max-width: 720px; }

/* Пустые списки не занимают места вовсе — состояние видно по «чисто». */
.admin-intruders:empty { display: none; }

.admin-intruders {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(430px, 100%), 1fr));
  gap: 8px;
  align-items: start;
}

.admin-intruder {
  display: grid;
  gap: 5px;
  min-width: 0;
  padding: 8px 10px;
  border-radius: 9px;
  background: var(--a-surface);
  border: 1px solid var(--border);
  border-left-width: 3px;
}

.admin-intruder__top {
  display: flex;
  align-items: center;
  gap: 7px;
  flex-wrap: wrap;
  font-size: 12px;
  min-width: 0;
}

.admin-intruder__top .admin-sess__when { margin-left: auto; }

/* Попытка входа — единственное, что должно бросаться в глаза издалека. */
.admin-intruder.is-tried {
  border-color: color-mix(in srgb, var(--a-danger) 40%, transparent);
  border-left-color: var(--a-danger);
  background: color-mix(in srgb, var(--a-danger) 5%, var(--a-surface));
}

.admin-intruder__logins {
  font-size: 11px;
  color: var(--a-danger);
  overflow-wrap: anywhere;
}

/* Служебные детали — под спойлером, чтобы список читался как сводка. */
.admin-intruder__foot {
  display: flex;
  align-items: start;
  gap: 8px;
  min-width: 0;
}

.admin-intruder__more { flex: 1 1 auto; min-width: 0; }

.admin-intruder__more summary {
  font-size: 10.5px;
  color: var(--muted);
  cursor: pointer;
  user-select: none;
  width: fit-content;
}

.admin-intruder__more summary:hover { color: var(--text); }

.admin-intruder__more[open] summary { margin-bottom: 4px; }

.admin-intruder__foot .btn { flex: 0 0 auto; }

/* пути, которые перебирал источник стука */
.admin-probe__paths {
  display: grid;
  gap: 2px;
  margin: 2px 0 4px;
}

.admin-probe__paths code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10.5px;
  color: var(--text);
  overflow-wrap: anywhere;
}

/* переключатель доступа */
.admin-switch {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  cursor: pointer;
  flex: 0 0 auto;
}

.admin-switch input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
}

.admin-switch__track {
  width: 28px;
  height: 16px;
  border-radius: 999px;
  background: var(--border);
  display: inline-flex;
  align-items: center;
  padding: 2px;
  transition: background .15s ease;
  flex: 0 0 auto;
}

.admin-switch__knob {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: #fff;
  transition: transform .15s ease;
}

.admin-switch input:checked + .admin-switch__track { background: var(--primary); }
.admin-switch input:checked + .admin-switch__track .admin-switch__knob { transform: translateX(12px); }

.admin-switch__label { font-size: 11px; color: var(--muted); }
.admin-switch input:checked ~ .admin-switch__label { color: var(--primary); }

/* ---------- служебные состояния ---------- */
.admin-alert:not([hidden]) {
  display: flex;
  align-items: center;
  gap: 8px;
  background: color-mix(in srgb, var(--a-warn) 10%, transparent);
  border: 1px solid color-mix(in srgb, var(--a-warn) 35%, transparent);
  border-radius: 8px;
  padding: 9px 12px;
  font-size: 12px;
  color: var(--text);
}

.admin-alert__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--a-warn);
  flex: 0 0 auto;
}

.admin-empty {
  display: grid;
  justify-items: center;
  gap: 5px;
  padding: 26px 16px;
  text-align: center;
}

.admin-empty__icon {
  width: 30px;
  height: 30px;
  background: var(--muted);
  opacity: .5;
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.2-3.2'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'><circle cx='11' cy='11' r='7'/><path d='M20 20l-3.2-3.2'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

.admin-empty__title { font-size: 13px; font-weight: 600; }
.admin-empty__sub { font-size: 11.5px; color: var(--muted); }

/* скелетон загрузки */
.admin-skeleton { display: grid; gap: 8px; }

.admin-skeleton__row {
  height: 54px;
  border-radius: 8px;
  background: color-mix(in srgb, var(--text) 10%, transparent);
  animation: adminSkeleton 1.4s ease-in-out infinite;
}

.admin-skeleton__row:nth-child(2) { animation-delay: .15s; }
.admin-skeleton__row:nth-child(3) { animation-delay: .3s; }

@keyframes adminSkeleton {
  0%, 100% { opacity: .45; }
  50% { opacity: 1; }
}

/* ---------- сужение ---------- */
@media (max-width: 900px) {
  .admin-teamrow__move { margin-left: 0; }
  .admin-filters { margin-left: 0; }
}

/* История смены ролей в карточке пользователя: кто, когда и с какой на какую. */
.admin-roleLog {
  margin-top: 8px;
  font-size: 11px;
  line-height: 1.5;
  color: var(--muted);
}

.admin-roleLog__row {
  display: grid;
  grid-template-columns: minmax(0, 148px) minmax(0, 1fr) minmax(0, 1.2fr);
  gap: 8px;
  padding: 3px 0;
  border-top: 1px solid var(--border);
}

.admin-roleLog__row:first-child { border-top: 0; }
.admin-roleLog__when { font-variant-numeric: tabular-nums; }
.admin-roleLog__what b { color: var(--text); }
.admin-roleLog__who { overflow-wrap: anywhere; }

@media (max-width: 720px) {
  .admin-roleLog__row { grid-template-columns: 1fr; gap: 0; }
}

/* ===== Здоровье системы (панель надзора, 16.08.2026) ===== */
.admin-opsHealth { font-size: 13px; display: grid; gap: 10px; }
/* ---------- здоровье системы (редизайн 19.08.2026) ----------
   Было пять плотных таблиц с техническими именами — понять, что именно
   отслеживается, можно было только по исходникам. Стало: вывод сверху,
   карточки по смыслу, у каждой строки название и описание. */

/* Вывод одной строкой: нужно ли вникать. */
.ops-verdict {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 12px;
  padding: 10px 12px;
  margin-bottom: 12px;
  border-radius: 10px;
  border: 1px solid var(--border);
  font-size: 12.5px;
}

.ops-verdict b { font-size: 13px; }
.ops-verdict span { color: var(--muted); }

.ops-verdict.is-ok {
  border-color: color-mix(in srgb, #2ecc71 40%, var(--border));
  background: color-mix(in srgb, #2ecc71 8%, transparent);
}

.ops-verdict.is-warn {
  border-color: color-mix(in srgb, #e0a53c 45%, var(--border));
  background: color-mix(in srgb, #e0a53c 8%, transparent);
}

.ops-verdict.is-bad {
  border-color: color-mix(in srgb, #e74c3c 45%, var(--border));
  background: color-mix(in srgb, #e74c3c 8%, transparent);
}

.ops-verdict__alerts { color: #e74c3c; }

/* Карточки: на широком экране рядом, на узком — колонкой. */
.ops-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(340px, 1fr));
  gap: 12px;
  align-items: start;
}

.ops-card {
  border: 1px solid var(--border);
  border-radius: 10px;
  overflow: hidden;
  min-width: 0;
}

/* Шапка — кнопка: нажатие раскрывает список. Цвет шапки = ХУДШЕЕ состояние
   внутри, поэтому свёрнутая карточка всё равно говорит правду. */
.ops-card__head {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 10px 12px;
  text-align: left;
  font: inherit;
  color: inherit;
  background: color-mix(in srgb, var(--text) 3%, transparent);
  border: none;
  border-left: 3px solid transparent;
  cursor: pointer;
  transition: background .16s ease, border-color .16s ease;
}

.ops-card__head:hover { background: color-mix(in srgb, var(--text) 6%, transparent); }

.ops-card__head:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: -2px;
}

/* Три состояния. Цвет никогда не единственный признак: рядом точка и подпись
   «N требует внимания / под присмотром / всё в норме». */
.ops-card.is-ok   .ops-card__head { border-left-color: #2ecc71; }
.ops-card.is-warn .ops-card__head { border-left-color: #e0a53c; background: color-mix(in srgb, #e0a53c 7%, transparent); }
.ops-card.is-bad  .ops-card__head { border-left-color: #e74c3c; background: color-mix(in srgb, #e74c3c 8%, transparent); }

.ops-card__titles { min-width: 0; }
.ops-card__title { display: block; font-size: 12.5px; font-weight: 600; }
.ops-card__about { display: block; margin-top: 2px; font-size: 11px; color: var(--muted); }

.ops-card__summary {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

.ops-card.is-warn .ops-card__summary { color: #e0a53c; }
.ops-card.is-bad .ops-card__summary { color: #e74c3c; }

/* Уголок поворачивается при раскрытии — единственная подвижная деталь шапки. */
.ops-card__chevron {
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-right: 1.5px solid var(--muted);
  border-bottom: 1.5px solid var(--muted);
  transform: rotate(-45deg);
  transition: transform .22s cubic-bezier(.4, 0, .2, 1);
}

.ops-card.is-open .ops-card__chevron { transform: rotate(45deg); }

/* Раскрытие через grid-template-rows: работает с любой высотой содержимого,
   не требуя замеров в JS (тот же приём, что у карточек аккаунтов Bybit). */
.ops-card__bodyWrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows .26s cubic-bezier(.4, 0, .2, 1);
}

.ops-card.is-open .ops-card__bodyWrap { grid-template-rows: 1fr; }

.ops-card__body {
  overflow: hidden;
  border-top: 1px solid transparent;
  transition: border-color .26s ease;
}

.ops-card.is-open .ops-card__body { border-top-color: var(--border); }

@media (prefers-reduced-motion: reduce) {
  .ops-card__bodyWrap,
  .ops-card__chevron,
  .ops-card__head { transition: none; }
}

/* Строка наблюдения: состояние, название, факт, описание. */
.ops-row {
  padding: 9px 12px;
  border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  min-width: 0;
}

.ops-row:last-child { border-bottom: none; }

/* Требует внимания — заметно, но без крика: полоса слева, не заливка. */
.ops-row.is-bad { box-shadow: inset 3px 0 0 #e74c3c; }
.ops-row.is-warn { box-shadow: inset 3px 0 0 #e0a53c; }

.ops-row__head {
  display: flex;
  align-items: baseline;
  gap: 7px;
  flex-wrap: wrap;
}

.ops-row__title { font-size: 12px; font-weight: 600; }

.ops-row__when {
  margin-left: auto;
  font-size: 11px;
  color: var(--muted);
  white-space: nowrap;
}

.ops-row__about {
  margin-top: 3px;
  font-size: 11px;
  line-height: 1.45;
  color: var(--muted);
}

.ops-row__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 12px;
  margin-top: 4px;
  font-size: 11px;
  color: var(--muted);
}

.ops-warn { color: #e0a53c; }
.ops-err { color: #e74c3c; overflow-wrap: anywhere; }

.ops-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto; }
.ops-dot.is-ok { background: #2ecc71; }
.ops-dot.is-warn { background: #e0a53c; }
.ops-dot.is-bad { background: #e74c3c; }

/* ---------- живость сессии площадки ----------
   Состояние сессии видно в шапке карточки, а не только в логах сервера.
   Цвет — единственное отличие состояний, поэтому рядом всегда есть подпись:
   по одному цвету состояние читать нельзя (правило доступности).

   Имя своё: до 28.08.2026 этот блок звался .admin-sess, как строка устройства
   выше по файлу, и, стоя ниже, перекрывал ей display, margin-left и кегль —
   строки посторонних заходов становились инлайновыми и уезжали на 6px. */
.admin-sessLive {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  margin-left: 6px;
  font-size: 11px;
  color: var(--muted);
}

.admin-sessDot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  flex: 0 0 auto;
  background: var(--muted);
}

/* Цвета точек — литералами: токенов --ok/--info/--danger в проекте НЕТ, и
   работал всегда фолбэк. Прятался он за собственным именем класса
   (`.drep-row--ok::before` выглядит как объявление `--ok`), поэтому сторож
   css_tokens его не видел до 28.08.2026. */

/* Доступ действует. */
.admin-sessDot.is-live { background: #3fb950; }

/* Доступ протух, но продление на месте — это НОРМА, а не беда: короткий токен
   так и живёт. Поэтому спокойный синий, а не жёлтый «внимание». */
.admin-sessDot.is-renews { background: #4b8bf5; }

/* Обновлять нечем — нужен вход. */
.admin-sessDot.is-dead { background: #f85149; }

/* Сессии нет вовсе. */
.admin-sessDot.is-none { background: color-mix(in srgb, var(--text) 25%, transparent); }

.admin-sess__text { white-space: nowrap; }

.admin-sess__stop,
.admin-sess__off {
  padding: 1px 6px;
  border-radius: 999px;
  font-size: 10px;
  white-space: nowrap;
  border: 1px solid var(--border);
}

/* Остановленный автовход — это требует человека, поэтому заметно. */
.admin-sess__stop {
  color: #f85149;
  border-color: color-mix(in srgb, #f85149 45%, var(--border));
}

/* Выключенный или неготовый автовход — просто факт, без тревоги. */
.admin-sess__off { color: var(--muted); }

/* Известная ошибка: пунктир показывает, что при наведении есть объяснение. */
.ops-err--known {
  text-decoration: underline dotted currentColor 1px;
  text-underline-offset: 3px;
  cursor: help;
}


/* =========================================================
   РАЗДЕЛ «ПРОКСИ»
   Реестр прокси портала: назначение, состояние, привязки.
   Палитра — общая для админки: акцент, янтарный для внимания,
   красный только для опасного.
   ========================================================= */

/* ---------- сворачивание секций верхнего уровня ---------- */
.admin-section--fold > .admin-sectionHead {
  cursor: pointer;
  user-select: none;
}

.admin-section--fold > .admin-sectionHead:hover .admin-sectionHead__title { color: var(--primary); }

/* Шапка получает фокус с клавиатуры (`tabindex="0"`), значит обязана его
   ПОКАЗЫВАТЬ: невидимый фокус — это фокус, который некуда поставить глазами.
   Обводка снаружи, чтобы не двигать содержимое шапки. */
.admin-section--fold > .admin-sectionHead:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 3px;
  border-radius: 6px;
}

.admin-section--fold > .admin-sectionHead .admin-group__chevron { transform: rotate(-90deg); }
.admin-section--fold.is-open > .admin-sectionHead .admin-group__chevron { transform: rotate(0deg); }

.admin-section__body { display: none; }
.admin-section--fold.is-open > .admin-section__body { display: grid; gap: 12px; }

/* ---------- чипы фильтра ---------- */
.proxy-chips {
  display: inline-flex;
  gap: 6px;
  flex-wrap: wrap;
  align-items: center;
}

.proxy-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 10px;
  border-radius: 999px;
  border: 1px solid var(--a-border2);
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 11px;
  font-weight: 600;
  cursor: pointer;
  transition: var(--transition);
}

.proxy-chip:hover { color: var(--text); border-color: var(--border); }

.proxy-chip.is-on {
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 45%, transparent);
  background: color-mix(in srgb, var(--primary) 10%, transparent);
}

.proxy-chip__num {
  font-size: 10px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.proxy-chip.is-on .proxy-chip__num { color: var(--primary); }

/* Янтарным горит только непустое «требуют внимания»: пустое — это норма,
   и красить нечего. */
.proxy-chip.is-warn:not(.is-on) {
  color: var(--a-warn);
  border-color: color-mix(in srgb, var(--a-warn) 35%, transparent);
}

/* ---------- список ---------- */
.proxy-list { display: grid; gap: 10px; }

.proxy-group__body {
  /* КАРТОЧКИ В СЕТКЕ, а не строки во всю ширину (28.08.2026, решение
     владельца: «для целой строчки не имеет смысла»).

     Строка отдавала одному прокси всю ширину экрана под содержимое примерно в
     четыреста пикселей — отсюда и ощущение, что раздел занимает много места.
     Карточка занимает треть ряда: двенадцать адресов встают в четыре ряда
     вместо двенадцати полос, и список садится с ~700px до ~310px. */
  display: none;
  grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)) !important;
  gap: 8px;
}

.admin-group.is-open > .proxy-group__body { display: grid; }

.proxy-row {
  border: 1px solid var(--a-border2);
  border-radius: 10px;
  background: var(--a-surface);
  overflow: hidden;
  transition: border-color .18s cubic-bezier(.2,.8,.2,1);
}

.proxy-row:hover { border-color: var(--border); }

.proxy-row.is-disabled { opacity: .55; }

/* ---------- карточка прокси (28.08.2026) ----------
   Рисовка собрана заново, на ФЛЕКСАХ. Сетка с колонками `max-content` не
   умеет ужимать содержимое: длинное имя выезжало поверх состояния справа, а
   список направлений — за границу карточки. Флекс с `min-width: 0` не
   накладывается никогда — он ужимает соседа или переносит его на новую строку.

   Назначение говорит полоса слева; текстовый бейдж при этом остаётся в ярусе
   действий: цвет не имеет права быть единственным носителем смысла. */
.proxy-row { border-left-width: 3px; }
.proxy-row--work { border-left-color: var(--primary); }
.proxy-row--service { border-left-color: #4aa3f0; }
.proxy-row--both { border-left-color: #a06ff0; }

.proxy-card { display: flex; flex-direction: column; gap: 3px; padding: 7px 10px 8px; min-width: 0; }

/* Ярус 1 — кто это и жив ли. */
.proxy-card__top { display: flex; align-items: center; gap: 7px; min-width: 0; }
.proxy-card__id { display: flex; align-items: baseline; gap: 6px; flex: 1 1 auto; min-width: 0; overflow: hidden; }
/* Порядок сжатия задан явно: метка режется ПОСЛЕДНЕЙ — по ней прокси и
   опознают, — а город ужимается в сто раз охотнее и до конца. */
.proxy-name__label { flex: 0 1 auto; min-width: 0; font-size: 12.5px; font-weight: 600; color: var(--text); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proxy-name__geo { flex: 0 100 auto; min-width: 0; font-size: 10.5px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.proxy-card__top > .proxy-switch,
.proxy-card__top > .proxy-more { flex: none; }
/* Состояние — В ОДНУ строку. Старое правило было сеточным («точка/текст» и
   «пусто/цифры» двумя ярусами) — в карточке это давало «в норме» и «120 мс»
   друг под другом и лишние восемь пикселей высоты на каждой из двенадцати. */
.proxy-state {
  flex: none;
  display: flex; align-items: center; gap: 5px; white-space: nowrap; min-width: 0;
}

/* Ярус 2 — куда и как ходит, кому служит. Переносится, если направлений много:
   растёт только та карточка, которой правда есть что показать. */
.proxy-card__mid { display: flex; align-items: center; gap: 8px; min-width: 0; flex-wrap: wrap; }
.proxy-card__mid > .proxy-addr { flex: 0 1 auto; min-width: 0; }
.proxy-card__mid > .proxy-used { flex: 1 1 auto; min-width: 0; justify-content: flex-end; }

/* Ярус 3 — действия. Держать их в каждой карточке значило бы отдавать
   постоянное место тому, что жмут раз в месяц; показывать при наведении
   ПОВЕРХ содержимого нельзя — карточка плотная, и кнопки накрывали бы адрес.
   Поэтому постоянная «⋯» в шапке, а ярус раскрывается и толкает соседей
   движением. На тач-устройстве работает так же: наведения там нет, нажатие
   есть. */
.proxy-more {
  width: 22px; height: 20px; padding: 0;
  display: inline-grid; place-items: center;
  border: 1px solid transparent; border-radius: 6px;
  background: none; color: var(--muted); cursor: pointer;
  font: 600 13px/1 var(--font-ui); letter-spacing: 1px;
}
.proxy-more:hover,
.proxy-row.is-acts .proxy-more { color: var(--text); border-color: var(--a-border2); background: var(--a-sunken); }
.proxy-card__acts {
  display: none; align-items: center; gap: 5px;
  margin-top: 4px; padding-top: 6px;
  border-top: 1px solid var(--a-border2);
}
.proxy-row.is-acts .proxy-card__acts { display: flex; }
.proxy-card__gap { flex: 1 1 auto; }

/* ДВИЖЕНИЕ. Вспышек нет — только движение: правило раздела. `transform`
   перечислен ПОИМЁННО, `all` вернул бы мерцание через подсветку наведения.
   Кто просил не анимировать — тому ничего не двигается. */
.proxy-row.is-moving { transition: transform .3s cubic-bezier(.2,.8,.2,1); }
@media (prefers-reduced-motion: reduce) { .proxy-row.is-moving { transition: none; } }

.proxy-flag { font-size: 15px; line-height: 1; text-align: center; }

/* назначение — кликабельный бейдж */
.proxy-badge {
  padding: 2px 9px;
  border-radius: 999px;
  border: 1px solid transparent;
  font: inherit;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .04em;
  cursor: pointer;
  transition: var(--transition);
}

.proxy-badge--work {
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 35%, transparent);
  background: color-mix(in srgb, var(--primary) 10%, transparent);
}

.proxy-badge--service {
  color: #4aa3f0;
  border-color: color-mix(in srgb, #4aa3f0 35%, transparent);
  background: color-mix(in srgb, #4aa3f0 10%, transparent);
}

.proxy-badge:hover { filter: brightness(1.15); }

.proxy-addr { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }

.proxy-addr__proto {
  flex: 0 0 auto;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .04em;
  color: var(--muted);
  border: 1px solid var(--a-border2);
  border-radius: 5px;
  padding: 1px 5px;
}

/* Протокол, который портал подключать не умеет, обязан быть виден ДО того,
   как прокси назначат: молча не работающий прокси хуже отсутствующего. */
.proxy-addr__proto.is-warn {
  color: var(--a-warn);
  border-color: color-mix(in srgb, var(--a-warn) 40%, transparent);
}

.proxy-addr__host {
  font-size: 11.5px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* к чему прикреплено */
.proxy-used { display: flex; gap: 5px; flex-wrap: wrap; min-width: 0; }

.proxy-used__none { font-size: 11px; color: color-mix(in srgb, var(--muted) 70%, transparent); }

.proxy-used__item {
  font-size: 10.5px;
  padding: 1px 7px;
  border-radius: 6px;
  background: var(--a-sunken);
  border: 1px solid var(--a-border2);
  color: var(--muted);
  max-width: 160px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.proxy-used__item--usage { color: #4aa3f0; border-color: color-mix(in srgb, #4aa3f0 25%, transparent); }

/* состояние */
.proxy-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--muted);
}

.proxy-row.is-ok .proxy-dot { background: var(--primary); }
.proxy-row.is-slow .proxy-dot { background: var(--a-warn); }
.proxy-row.is-down .proxy-dot { background: var(--a-danger); }
.proxy-row.is-off .proxy-dot,
.proxy-row.is-unknown .proxy-dot { background: color-mix(in srgb, var(--muted) 60%, transparent); }

.proxy-dot.is-busy { background: var(--primary); animation: proxyPulse 1s ease-in-out infinite; }

/* Нет связи — пульсация медленная и красная: это состояние живёт долго,
   и частое мигание в списке из сотни строк невыносимо. */
.proxy-row.is-down .proxy-dot { animation: proxyPulse 2.2s ease-in-out infinite; }

@keyframes proxyPulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .45; transform: scale(.8); }
}

.proxy-state__text { font-size: 11.5px; color: var(--text); }
.proxy-state__meta { font-size: 10px; color: var(--muted); font-variant-numeric: tabular-nums; }

.proxy-row.is-down .proxy-state__text { color: var(--a-danger); }
.proxy-row.is-slow .proxy-state__text { color: var(--a-warn); }

/* рубильник */
.proxy-switch { position: relative; width: 30px; height: 17px; cursor: pointer; }
.proxy-switch input { position: absolute; inset: 0; opacity: 0; cursor: pointer; margin: 0; }

.proxy-switch__slider {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 12%, transparent);
  transition: background .18s cubic-bezier(.2,.8,.2,1);
}

.proxy-switch__slider::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--muted);
  transition: transform .18s cubic-bezier(.2,.8,.2,1), background .18s;
}

.proxy-switch input:checked + .proxy-switch__slider { background: color-mix(in srgb, var(--primary) 30%, transparent); }
.proxy-switch input:checked + .proxy-switch__slider::after { transform: translateX(13px); background: var(--primary); }

.proxy-row__err {
  padding: 5px 10px 8px;
  font-size: 10.5px;
  color: var(--a-danger);
}

/* ---------- полосы подтверждения ---------- */
.proxy-confirm {
  display: flex;
  align-items: center;
  gap: 9px;
  flex-wrap: wrap;
  padding: 8px 12px;
  border-top: 1px solid var(--a-border2);
  animation: proxyReveal .2s cubic-bezier(.2,.8,.2,1);
}

.proxy-confirm--delete { background: color-mix(in srgb, var(--a-danger) 10%, transparent); }
.proxy-confirm--move { background: color-mix(in srgb, var(--a-warn) 10%, transparent); }

.proxy-confirm__text { flex: 1 1 260px; font-size: 11.5px; color: var(--text); }

.admin-page .btn--warn {
  color: var(--a-warn);
  border-color: color-mix(in srgb, var(--a-warn) 40%, transparent);
}
.admin-page .btn--warn:hover { background: color-mix(in srgb, var(--a-warn) 12%, transparent); }

@keyframes proxyReveal {
  from { opacity: 0; transform: translateY(-4px); }
  to { opacity: 1; transform: none; }
}

/* ---------- панель правки ---------- */
.proxy-edit {
  display: grid;
  /* 170px, а не 150: в колонку кладут адрес с портом и названия шлюзов, и на
     150 они упирались в многоточие уже на втором слове. */
  grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px 12px;
  padding: 12px;
  border-top: 1px solid var(--a-border2);
  background: var(--a-deep);
  animation: proxyReveal .24s cubic-bezier(.2,.8,.2,1);
}

/* Грид-ребёнок по умолчанию не ужимается меньше содержимого: длинное значение в
   списке распирало колонку, и соседние поля наезжали друг на друга. */
.proxy-edit .field,
.admin-page .field { min-width: 0; }

/* Шлюз — на всю ширину: в его строке и название, и адрес с портом, и в узкой
   колонке от неё оставалось многоточие. */
.proxy-edit__gw { gap: 5px; }

.proxy-edit__gwNote {
  font-size: 11px;
  line-height: 1.4;
  color: var(--muted);
}

.proxy-edit__acts {
  grid-column: 1 / -1;
  display: flex;
  gap: 7px;
  align-items: center;
}

/* ---------- форма создания ---------- */
.proxy-modes { display: inline-flex; gap: 6px; }

.proxy-mode {
  padding: 4px 12px;
  border-radius: 999px;
  border: 1px solid var(--a-border2);
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  cursor: pointer;
  transition: var(--transition);
}

.proxy-mode:hover { color: var(--text); }

.proxy-mode.is-on {
  color: var(--primary);
  border-color: color-mix(in srgb, var(--primary) 45%, transparent);
  background: color-mix(in srgb, var(--primary) 10%, transparent);
}

.proxy-kinds { display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); gap: 8px; }

.proxy-kind {
  display: grid;
  gap: 2px;
  text-align: left;
  padding: 8px 11px;
  border-radius: 9px;
  border: 1px solid var(--a-border2);
  background: none;
  font: inherit;
  cursor: pointer;
  transition: var(--transition);
}

.proxy-kind:hover { border-color: var(--border); }

.proxy-kind.is-on {
  border-color: color-mix(in srgb, var(--primary) 45%, transparent);
  background: color-mix(in srgb, var(--primary) 8%, transparent);
}

.proxy-kind__title { font-size: 12px; font-weight: 600; color: var(--text); }
.proxy-kind__note { font-size: 10.5px; color: var(--muted); }

.proxy-kind.is-on .proxy-kind__title { color: var(--primary); }

.proxy-bulk {
  min-height: 90px;
  resize: vertical;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11.5px;
  line-height: 1.5;
}

.proxy-preview {
  display: grid;
  gap: 3px;
  max-height: 140px;
  overflow: auto;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid var(--a-border2);
  background: var(--a-sunken);
  font-size: 11px;
  color: var(--muted);
}

.proxy-preview__row { display: flex; align-items: center; gap: 8px; }
.proxy-preview__row.is-bad { color: var(--a-danger); }
.proxy-preview__proto { font-size: 9.5px; font-weight: 700; color: var(--muted); }
.proxy-preview__auth { font-size: 10px; color: color-mix(in srgb, var(--muted) 80%, transparent); }

.proxy-checkNow {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--muted);
  cursor: pointer;
}

/* ---------- утилитные запросы ----------
   ПЕРЕДЕЛАНЫ 28.08.2026 (владелец: «вообще ноль удобства»).

   Было: полоса во всю ширину, выбранные адреса свёрнуты в подпись «ams-01
   ash-parser ещё 1», под ней итог. Итог сообщался, а причина пряталась: чтобы
   понять, почему «запросы остановлены», надо было раскрыть панель, а потом
   уйти глазами в список выше и сверить состояние каждого адреса.

   Стало: карточка, а выбранные — ЧИПАМИ, и каждый несёт свою точку состояния.
   Видно разом, кто выбран, кто из них жив и из-за кого утилита встала. Снять —
   крестик, одним щелчком. Утилит четыре, карточки встают в два ряда. */
.proxy-usages { display: grid; grid-template-columns: repeat(auto-fit, minmax(390px, 1fr)); gap: 8px; }

.proxy-usage {
  display: grid;
  gap: 7px;
  padding: 9px 11px 10px;
  border: 1px solid var(--a-border2);
  border-radius: 10px;
  background: var(--a-surface);
  transition: border-color .18s cubic-bezier(.2,.8,.2,1);
}
.proxy-usage.is-open {
  border-color: color-mix(in srgb, var(--primary) 30%, transparent);
  /* Раскрытая панель выбора шире карточки — отдаём ей весь ряд, иначе плитки
     сжимаются вдвое и список становится нечитаемым. */
  grid-column: 1 / -1;
}

/* Имя утилиты НЕ переносится и не ужимается: «Стакан / P2P» в две строки
   ломало высоту карточки, а «Авто-режим TOP1» налезал на итог справа.
   Ужимается подпись — она пояснение, а не название. */
.proxy-usage__head { display: flex; align-items: baseline; gap: 8px; min-width: 0; }
.proxy-usage__title { flex: none; white-space: nowrap; font-size: 12px; font-weight: 600; color: var(--text); }
.proxy-usage__head > .proxy-usage__note { flex: 1 1 auto; }
.proxy-usage__note {
  font-size: 10.5px; color: var(--muted);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Итог — справа в шапке и ТЕМ ЦВЕТОМ, который он значит. Зелёное «запросы
   остановлены» было ошибкой того же рода, что и всё прочее здесь: цвет
   говорил обратное содержанию. Зелёным остаётся только рабочее состояние. */
.proxy-usage__state { margin-left: auto; flex: none; font-size: 10.5px; color: var(--primary); white-space: nowrap; }
.proxy-usage__state.is-stopped { color: var(--a-warn); }

.proxy-usage__picks { display: flex; flex-wrap: wrap; gap: 5px; align-items: center; }
.proxy-usage__empty { font-size: 11px; color: var(--muted); }

.proxy-chipPick {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 3px 4px 3px 8px;
  border: 1px solid var(--a-border2); border-radius: 20px;
  background: var(--a-sunken); font-size: 11px;
}
/* Выбран, но в дело не пойдёт — выключен, не сервисный или чужого протокола.
   Красным, потому что это и есть причина остановки. */
.proxy-chipPick.is-dead { color: var(--a-danger); border-color: color-mix(in srgb, var(--a-danger) 30%, transparent); }
.proxy-chipPick__name { font-weight: 600; }
.proxy-chipPick__x {
  width: 16px; height: 16px; display: inline-grid; place-items: center;
  border: 0; border-radius: 50%; background: none; color: var(--muted);
  cursor: pointer; font: 600 12px/1 var(--font-ui);
}
.proxy-chipPick__x:hover { color: var(--a-danger); background: color-mix(in srgb, var(--a-danger) 14%, transparent); }

.proxy-add {
  border: 1px dashed var(--a-border2); border-radius: 20px; background: none;
  color: var(--muted); font: inherit; font-size: 11px; padding: 3px 10px; cursor: pointer;
}
.proxy-add:hover:not(:disabled) { color: var(--text); border-color: var(--border); }
.proxy-add:disabled { opacity: .5; cursor: default; }

.proxy-usage__foot { display: flex; align-items: center; gap: 8px; font-size: 10.5px; color: var(--muted); }
/* «Без прокси не работает» — свойство утилиты, а не настройка, поэтому
   тумблера у неё НЕТ вовсе: выключенный рядом с настраиваемым читается как
   «можно включить», и оператор ищет, почему не включается. */
.proxy-usage__fixed { border: 1px dashed var(--a-border2); border-radius: 7px; padding: 3px 8px; }

/* ---------- выбор прокси у утилиты ---------- */
/* Панель раскрывается ПОД карточкой, во всю её ширину. Всплывающего слоя нет
   намеренно: список перерисовывается от каждого действия, и слой пришлось бы
   всякий раз ловить и возвращать на место.

   Свёрнутого «триггера» здесь больше нет — выбранные показаны чипами прямо в
   карточке, и панель нужна только чтобы ДОБАВИТЬ. Правила `.proxy-trigger*`
   удалены вместе с ним: мёртвое правило переживает функцию и путает следующего.
*/

/* Панель выбора занимает всю ширину строки: она грид-ребёнок, и своя колонка
   ей не нужна. */
.proxy-picker {
  grid-column: 1 / -1;
  display: grid;
  gap: 8px;
  margin-top: 9px;
  padding: 10px;
  border-radius: 9px;
  border: 1px solid var(--a-border2);
  background: var(--a-deep);
  animation: proxyReveal .22s cubic-bezier(.2,.8,.2,1);
}

.proxy-picker__head {
  display: flex;
  align-items: center;
  gap: 9px;
}

.proxy-picker__search { flex: 1 1 auto; font-size: 11.5px; padding: 5px 9px; }
.proxy-picker__count { font-size: 10.5px; color: var(--muted); white-space: nowrap; }

/* Сетка, а не столбец: адресов бывает много, и колонка на 40 строк — это
   экран прокрутки ради одного щелчка. Высота ограничена: список не имеет
   права выталкивать всё, что под ним. */
.proxy-picker__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(210px, 1fr));
  gap: 5px;
  max-height: 232px;
  overflow-y: auto;
  padding-right: 2px;
}

.proxy-opt {
  display: grid;
  grid-template-columns: 14px 16px 1fr auto;
  align-items: center;
  gap: 7px;
  padding: 6px 9px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: var(--a-surface);
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: var(--transition);
}

.proxy-opt:hover { border-color: var(--a-border2); }

.proxy-opt.is-on {
  border-color: color-mix(in srgb, var(--primary) 45%, transparent);
  background: color-mix(in srgb, var(--primary) 10%, transparent);
}

/* Галочка рисуется маской: она же индикатор выбора, и в свободном состоянии
   остаётся пустой рамкой — так видно, что строку можно выбрать. */
.proxy-opt__tick {
  width: 14px;
  height: 14px;
  border-radius: 4px;
  border: 1px solid var(--a-border2);
  transition: var(--transition);
}

.proxy-opt.is-on .proxy-opt__tick {
  border-color: var(--primary);
  background: var(--primary);
  -webkit-mask-image: none;
  mask-image: none;
  position: relative;
}

.proxy-opt.is-on .proxy-opt__tick::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--page-bg);
  -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12.5l4.2 4.2L19 7'/></svg>");
  mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3.5' stroke-linecap='round' stroke-linejoin='round'><path d='M5 12.5l4.2 4.2L19 7'/></svg>");
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
  -webkit-mask-position: center;
  mask-position: center;
}

/* Выбран, но в дело не пойдёт: выключен или не того назначения/протокола.
   Обычная «невыбранная» подача тут врала бы — набор его всё ещё содержит. */
.proxy-opt.is-bad {
  border-color: color-mix(in srgb, var(--a-warn) 45%, transparent);
  background: color-mix(in srgb, var(--a-warn) 8%, transparent);
}

.proxy-opt.is-bad .proxy-opt__tick { border-color: var(--a-warn); background: var(--a-warn); }
.proxy-opt.is-bad .proxy-opt__name { color: var(--a-warn); }

.proxy-opt__flag { font-size: 13px; line-height: 1; }

.proxy-opt__body { display: grid; min-width: 0; }
.proxy-opt__name {
  font-size: 11.5px;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.proxy-opt__addr {
  font-size: 10px;
  color: var(--muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.proxy-opt__state {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Точка статуса здесь та же, что в строке прокси, и красится теми же
   правилами: состояние адреса должно читаться одинаково в обоих местах. */
.proxy-opt__state.is-ok .proxy-dot { background: var(--primary); }
.proxy-opt__state.is-slow .proxy-dot { background: var(--a-warn); }
.proxy-opt__state.is-down .proxy-dot { background: var(--a-danger); }
.proxy-opt__state.is-off .proxy-dot,
.proxy-opt__state.is-unknown .proxy-dot { background: color-mix(in srgb, var(--muted) 60%, transparent); }
.proxy-opt__state .proxy-dot { animation: none; }

.proxy-picker__foot {
  display: flex;
  align-items: center;
  gap: 9px;
  padding-top: 2px;
}

.proxy-picker__sum { flex: 1 1 auto; font-size: 11px; color: var(--muted); }

@media (max-width: 900px) {
  .proxy-picker__grid { grid-template-columns: 1fr; max-height: 46vh; }
  .proxy-usage { grid-template-columns: 1fr; }
  .proxy-usage__direct { justify-self: start; }
}

.proxy-usage__warn {
  font-size: 10.5px;
  color: var(--a-warn);
}

.proxy-usage__name { display: grid; gap: 1px; min-width: 0; }
/* Право работать без прокси — отдельной колонкой: это решение про
   безопасность, и оно не должно теряться среди адресов. */
.proxy-usage__direct {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  justify-self: end;
}

.proxy-switch--sm { width: 26px; height: 15px; }
.proxy-switch--sm .proxy-switch__slider::after { width: 11px; height: 11px; }
.proxy-switch--sm input:checked + .proxy-switch__slider::after { transform: translateX(11px); }

.proxy-usage__directText { font-size: 10.5px; color: var(--muted); white-space: nowrap; }
.proxy-usage__directText.is-locked { opacity: .6; }

/* ---------- узкий экран ----------
   Правила старой сетки строки удалены вместе с ней: карточка собрана флексами
   и ужимается сама. Остаётся только одно — на телефоне карточки идут в один
   столбец, и утилиты тоже. */
@media (max-width: 900px) {
  .proxy-group__body { grid-template-columns: 1fr !important; }
  .proxy-usages { grid-template-columns: 1fr; }
}

@media (prefers-reduced-motion: reduce) {
  .proxy-dot,
  .proxy-confirm,
  .proxy-edit { animation: none !important; }
}

/* ===== Крюк до прокси ===== */
/* Строка стоит ПОД выбором прокси у аккаунта: там же, где решают, каким прокси
   ходит аккаунт, решается и нужен ли до него крюк. Отступ слева тот же, что у
   .admin-proxyInfo, — значения соседних строк выстроены по одной линии. */
.admin-gwRow {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  padding: 2px 0 0 68px;
}

.admin-gwRow__label {
  font-size: 9px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .06em;
  color: var(--muted);
}

/* Переключатель повторяет тот, что в реестре прокси: один жест — один вид. */
.admin-gwRow__switch { position: relative; width: 30px; height: 17px; cursor: pointer; flex: 0 0 auto; }
.admin-gwRow__switch input { position: absolute; inset: 0; opacity: 0; cursor: pointer; margin: 0; }

.admin-gwRow__slider {
  position: absolute;
  inset: 0;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 12%, transparent);
  transition: background .18s cubic-bezier(.2,.8,.2,1);
}

.admin-gwRow__slider::after {
  content: "";
  position: absolute;
  top: 2px;
  left: 2px;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: var(--muted);
  transition: transform .18s cubic-bezier(.2,.8,.2,1), background .18s;
}

.admin-gwRow__switch input:checked + .admin-gwRow__slider {
  background: color-mix(in srgb, var(--primary) 30%, transparent);
}
.admin-gwRow__switch input:checked + .admin-gwRow__slider::after {
  transform: translateX(13px);
  background: var(--primary);
}

.admin-gwRow__switch input:disabled + .admin-gwRow__slider { opacity: .5; cursor: default; }

.admin-gwRow__note {
  font-size: 12px;
  color: var(--muted);
}

.admin-gwRow.is-on .admin-gwRow__note { color: var(--primary); }

/* Окно авто-сообщений аккаунта биржи.

   Живёт в body: раздел админки лежит внутри .content, у которой свой контекст
   наложения, и окно, оставленное внутри карточки, ушло бы под соседей. Плата за
   переезд — окно оказывается ВНЕ .admin-page и не получает ни её локальных
   токенов (--a-*), ни её правил кнопок (.btn.primary, .btn--sm, .btn--xs): всё
   это объявлено здесь заново. Без этого «Сохранить» выглядит обычной серой
   рамкой, а красный текст ошибки не красится вовсе — так оно и было до
   31.08.2026.

   Раскладка — рельс из восьми правил и ОДНА открытая карточка: у правила теперь
   колода вариантов, и восемь правил по десять полей на экран не помещаются.
   Рельс несёт живые числа, чтобы не потерять то, что давала прежняя сетка:
   видно, где текст есть, а где правило включено вхолостую.

   JS прячет карточки правил, крестики и кнопку добавления атрибутом hidden, а
   правило .admin-page [hidden] сюда не достаёт — своё обязательно. */
.amsg [hidden] { display: none !important; }

.amsg {
  /* Локальная палитра: та же, что у .admin-page, но её переменные сюда не
     наследуются — окно лежит в body. */
  --am-surface: color-mix(in srgb, var(--text) 4%, transparent);
  --am-sunken: color-mix(in srgb, var(--page-bg) 70%, transparent);
  --am-border2: color-mix(in srgb, var(--text) 7%, transparent);
  --am-off: color-mix(in srgb, var(--text) 22%, transparent);
  --am-warn: #e0a83c;
  --am-danger: #e5484d;

  position: fixed;
  inset: 0;
  z-index: 10050;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  font-family: var(--font-ui);
}

/* ---------- кнопки окна (копия правил .admin-page, см. шапку) ---------- */

.amsg .btn {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text);
  border-radius: 999px;
  font-size: 12.5px;
  padding: 7px 14px;
  height: auto;
  white-space: nowrap;
}

.amsg .btn:hover { border-color: color-mix(in srgb, var(--text) 22%, transparent); }

.amsg .btn.primary {
  background: var(--primary);
  border-color: var(--primary);
  color: #08130c;
  font-weight: 600;
  padding: 8px 16px;
}

.amsg .btn.primary:hover { background: var(--primary-2); border-color: var(--primary-2); }
.amsg .btn.primary:disabled { opacity: .6; cursor: default; }

.amsg .btn--sm { font-size: 11.5px; font-weight: 600; padding: 5px 12px; }

/* ---------- оправа ---------- */

.amsg__box {
  width: min(1080px, 100%);
  height: min(700px, 100%);
  display: flex;
  flex-direction: column;
  gap: 12px;
  background: var(--page-bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px;
}

.amsg__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.amsg__title { font-family: var(--font-heading); font-weight: 600; font-size: 15px; }

.amsg__note { font-size: 12px; color: var(--muted); line-height: 1.4; }

/* Общий тумблер отделён от правил рамкой: он про аккаунт целиком, а не про
   выбранное правило, и стоять в одном ряду с ними не должен. */
.amsg__top {
  display: grid;
  gap: 4px;
  padding: 10px 12px;
  border: 1px solid var(--am-border2);
  border-radius: var(--radius);
  background: var(--am-surface);
}

.amsg__master {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
}

.amsg__top .amsg__note { padding-left: 24px; }

/* Пороги времени сделки (04.09.2026) — настройка аккаунта, потому и в блоке
   общего тумблера, а не в карточке правила: они общие для трёх правил по
   времени, и правило «обычная» само по себе их не задаёт. */
.amsg__th {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 14px;
  margin-top: 6px;
  padding-top: 8px;
  border-top: 1px solid var(--am-border2);
}

.amsg__thTitle { font-size: 12.5px; font-weight: 600; }

.amsg__thField {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12.5px;
  color: var(--muted);
}

.amsg__thInput {
  width: 72px;
  height: auto;
  padding: 5px 8px;
  font: inherit;
  font-size: 13px;
  text-align: right;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

.amsg__th.is-bad .amsg__thInput { border-color: var(--am-danger); }

/* Ссылка-кнопка «по умолчанию»: min-height — отбивка тач-высоты из mobile.css,
   вне media-запроса, как у остальных мелких кнопок окна. */
.amsg__thReset {
  min-height: 0;
  border: none;
  background: none;
  color: var(--primary);
  font: inherit;
  font-size: 11.5px;
  padding: 2px 0;
  cursor: pointer;
  text-decoration: underline dotted;
}

.amsg__thReset:hover { color: var(--primary-2); }

.amsg__thSaid { flex: 1 1 100%; font-size: 12px; color: var(--muted); line-height: 1.4; }
.amsg__thSaid:empty { display: none; }
.amsg__th.is-bad .amsg__thSaid { color: var(--am-danger); }

.amsg__body {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns: 236px minmax(0, 1fr);
  gap: 14px;
}

/* ---------- рельс правил ---------- */

.amsg__rail {
  overflow: auto;
  display: grid;
  gap: 14px;
  align-content: start;
  padding-right: 4px;
}

.amsg__railGroup { display: grid; gap: 3px; align-content: start; }

.amsg__railHead {
  display: grid;
  gap: 1px;
  padding: 0 0 6px 2px;
  margin-bottom: 3px;
  border-bottom: 1px solid var(--border);
}

.amsg__railSide { font-weight: 600; font-size: 13px; }

.amsg__railItem {
  display: grid;
  grid-template-columns: 8px minmax(0, 1fr) auto;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 10px;
  border: 1px solid transparent;
  border-radius: 9px;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  text-align: left;
  cursor: pointer;
  transition: var(--transition);
}

.amsg__railItem:hover { background: var(--am-surface); color: var(--text); }

.amsg__railItem.is-active {
  background: var(--am-surface);
  border-color: var(--am-border2);
  color: var(--text);
  font-weight: 600;
}

.amsg__railName { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.amsg__railMeta { font-size: 11px; color: var(--muted); font-variant-numeric: tabular-nums; }

/* Точка состояния: правило работает / включено вхолостую / выключено. Цвет —
   не единственный носитель смысла: рядом стоит число вариантов, а в подсказке
   то же самое сказано словами. */
.amsg__dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  border: 1px solid var(--am-off);
  background: transparent;
}

.amsg__railItem.is-on .amsg__dot { background: var(--primary); border-color: var(--primary); }
.amsg__railItem.is-mute .amsg__dot { background: var(--am-warn); border-color: var(--am-warn); }

/* ---------- карточка правила ---------- */

.amsg__pane { overflow: auto; min-height: 0; padding-right: 4px; }

.amsg__rule { display: grid; gap: 12px; align-content: start; }

.amsg__ruleHead {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 5px 10px;
  padding-bottom: 8px;
  border-bottom: 1px solid var(--border);
}

.amsg__side {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .3px;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 999px;
  border: 1px solid var(--am-border2);
  background: var(--am-surface);
  color: var(--muted);
}

.amsg__ruleTitle { font-family: var(--font-heading); font-weight: 600; font-size: 14.5px; }

/* Порог занимает всю ширину: он объясняет правило и обрывать его переносом
   посреди строки нельзя. */
.amsg__ruleHead .amsg__note { flex: 1 1 100%; }

.amsg__ctl {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 10px;
}

.amsg__on {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}

.amsg__pick {
  display: inline-flex;
  gap: 2px;
  padding: 2px;
  border: 1px solid var(--am-border2);
  border-radius: 999px;
  background: var(--am-sunken);
}

/* min-height здесь и у крестика — отбивка тач-высоты из mobile.css: она поднимает
   ВСЕМ button 40px, и сегмент на телефоне превращался бы в две плашки в палец. */
.amsg__pickBtn {
  min-height: 0;
  border: none;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: var(--transition);
}

.amsg__pickBtn:hover { color: var(--text); }

.amsg__pickBtn.is-on {
  background: color-mix(in srgb, var(--primary) 20%, transparent);
  color: var(--text);
}

/* ---------- варианты ---------- */

.amsg__vars { display: grid; gap: 8px; }

/* Места в сетке заданы ЯВНО: крестик прячется атрибутом hidden, а убранный из
   потока грид-ребёнок сдвигает авторасстановку соседей (ловушка №3 в CLAUDE.md).
   С явными координатами его исчезновение не двигает ничего. */
.amsg__var {
  display: grid;
  grid-template-columns: 20px minmax(0, 1fr) 26px;
  grid-template-rows: auto auto;
  gap: 2px 8px;
  align-items: start;
}

.amsg__varNo {
  grid-area: 1 / 1;
  justify-self: center;
  padding-top: 9px;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.amsg__text {
  grid-area: 1 / 2;
  width: 100%;
  height: auto;
  min-height: 58px;
  resize: vertical;
  padding: 8px 12px;
  font: inherit;
  font-size: 13px;
  line-height: 1.45;
}

.amsg__varDel {
  grid-area: 1 / 3;
  min-height: 0;
  width: 26px;
  height: 26px;
  margin-top: 6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--am-border2);
  border-radius: 8px;
  background: none;
  color: var(--muted);
  font-size: 15px;
  line-height: 1;
  cursor: pointer;
  transition: var(--transition);
}

.amsg__varDel:hover {
  color: var(--am-danger);
  border-color: color-mix(in srgb, var(--am-danger) 45%, transparent);
}

.amsg__count {
  grid-area: 2 / 2;
  justify-self: end;
  font-size: 11px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.amsg__addRow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  padding-left: 28px;
}

.amsg__add {
  min-height: 0;
  border: 1px dashed color-mix(in srgb, var(--primary) 45%, transparent);
  background: none;
  color: var(--primary);
  font: inherit;
  font-size: 11.5px;
  font-weight: 600;
  padding: 5px 12px;
  border-radius: 999px;
  cursor: pointer;
  transition: var(--transition);
}

.amsg__add:hover { background: color-mix(in srgb, var(--primary) 10%, transparent); }

.amsg__acts {
  display: flex;
  align-items: center;
  gap: 10px;
}

.amsg__said { font-size: 12.5px; color: var(--muted); }
.amsg__said.is-bad { color: var(--am-danger); }

@media (max-width: 860px) {
  .amsg { padding: 10px; }
  .amsg__box { height: 100%; padding: 14px; }
  .amsg__body { grid-template-columns: minmax(0, 1fr); grid-template-rows: auto minmax(0, 1fr); }
  .amsg__rail { max-height: 34vh; }
}

/* Окно конфига живёт в body: раздел админки лежит внутри .content, у которой
   свой контекст наложения — слой без собственного этажа уехал бы под страницу. */

.gwcfg {
  position: fixed;
  inset: 0;
  z-index: 10050;
  background: rgba(0, 0, 0, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
}

.gwcfg__box {
  width: min(720px, 100%);
  max-height: 80vh;
  overflow: auto;
  background: var(--page-bg-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 18px;
}

.gwcfg__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.gwcfg__title {
  font-family: var(--font-heading);
  font-weight: 600;
}

.gwcfg__note {
  font-size: 13px;
  color: var(--muted);
  line-height: 1.45;
  margin-bottom: 12px;
}

.gwcfg__code {
  background: var(--input-bg);
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) - 6px);
  padding: 12px;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre;
  overflow-x: auto;
  margin: 0 0 12px;
}

.gwcfg__acts {
  display: flex;
  align-items: center;
  gap: 10px;
}

.gwcfg__said {
  font-size: 12px;
  color: var(--primary);
}

/* Пометка «через шлюз» стоит рядом с направлениями: там же ищут, куда этот
   прокси ходит, — и путь браузера часть того же ответа. */
.proxy-used__item--gw {
  border-color: color-mix(in oklab, var(--primary) 45%, transparent);
  color: var(--primary);
}

/* ===== Назначение прокси ===== */
/* Три положения: работа → сервис → общий. «Общий» — свой цвет, чтобы совмещённый
   адрес был виден в списке сразу, а не вычислялся по вкладке. */
.proxy-badge--both {
  background: color-mix(in srgb, #7c5cff 18%, transparent);
  border-color: color-mix(in srgb, #7c5cff 45%, transparent);
  color: #a892ff;
}

/* Крюк включён, а шлюз у прокси не выбран — вести некуда. Красным, потому что
   это не состояние, а незаконченная настройка: расширение пойдёт напрямую. */
.admin-gwRow__note.is-bad {
  color: var(--a-danger, #f97373);
}

/* ============================================================
   Раздел «Проверки BybitEye» (js/pages/admin/bybiteye.js)
   ============================================================ */
.admin-page .axbe {
  margin-top: 18px;
  padding: 16px;
  background: var(--card-bg);
  border: 1px solid var(--border);
  border-radius: var(--radius);
}
.admin-page .axbe-head {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 8px;
}
.admin-page .axbe-head h3 { margin: 0; font-family: var(--font-heading); font-size: 16px; }
.admin-page .axbe-note { color: var(--muted); font-size: 13px; margin-bottom: 14px; }
.admin-page .axbe-ok { color: var(--primary); font-weight: 600; }
.admin-page .axbe-warn { color: #e0a53a; font-weight: 600; }

.admin-page .axbe-power {
  margin-left: auto;
  font: 600 12.5px/1 var(--font-ui);
  padding: 8px 14px;
  border-radius: 10px;
  border: 1px solid var(--border);
  cursor: pointer;
  background: var(--input-bg);
  color: var(--muted);
}
.admin-page .axbe-power.is-on { background: color-mix(in srgb, var(--primary) 18%, transparent); color: var(--primary); border-color: transparent; }
.admin-page .axbe-power.is-off { background: color-mix(in srgb, #e0574d 16%, transparent); color: #e0574d; border-color: transparent; }

.admin-page .axbe-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; }
.admin-page .axbe-empty { color: var(--muted); font-size: 13px; font-style: italic; padding: 8px 2px; }

.admin-page .axbe-acc { border: 1px solid var(--border); border-radius: 12px; overflow: hidden; background: var(--input-bg); }
.admin-page .axbe-acc__head {
  display: flex; align-items: center; gap: 10px;
  padding: 11px 14px; cursor: pointer; user-select: none;
}
.admin-page .axbe-acc__head:hover { background: color-mix(in srgb, var(--text) 4%, transparent); }
.admin-page .axbe-acc__login { font-weight: 600; font-variant-numeric: tabular-nums; }
.admin-page .axbe-acc__caret { margin-left: auto; color: var(--muted); }

.admin-page .axbe-badge { font-size: 11px; font-weight: 600; padding: 2px 8px; border-radius: 20px; }
.admin-page .axbe-badge--primary { background: color-mix(in srgb, var(--primary) 18%, transparent); color: var(--primary); }
.admin-page .axbe-badge--off { background: color-mix(in srgb, var(--muted) 20%, transparent); color: var(--muted); }

.admin-page .axbe-acc__body {
  display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
  padding: 4px 14px 14px;
  border-top: 1px solid var(--border);
}
.admin-page .axbe-field { display: flex; flex-direction: column; gap: 5px; font-size: 12.5px; color: var(--muted); }
.admin-page .axbe-field input, .admin-page .axbe-field select {
  height: var(--control-h); padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--page-bg-2); color: var(--text);
  font: 14px/1 var(--font-ui);
}
.admin-page .axbe-acc__actions { grid-column: 1 / -1; display: flex; gap: 8px; flex-wrap: wrap; }

.admin-page .btn--ghost { background: transparent; }

.admin-page .axbe-add {
  display: flex; gap: 8px; flex-wrap: wrap; align-items: center;
  padding-top: 12px; border-top: 1px solid var(--border);
}
.admin-page .axbe-add input, .admin-page .axbe-add select {
  height: var(--control-h); padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--border); background: var(--page-bg-2); color: var(--text);
  font: 14px/1 var(--font-ui); flex: 1 1 160px; min-width: 120px;
}

@media (max-width: 640px) { .admin-page .axbe-acc__body { grid-template-columns: 1fr; } }

/* ===== Установки расширения (site/js/pages/admin/ext_devices.js) =====
 *
 * Отзыв — опасное действие: он выключает рабочее место оператора. Поэтому
 * подтверждение живёт внутри карточки и называет последствия, а сама кнопка
 * красная. Отозванные строки не прячем: видно, кто и когда пользовался.
 */
.admin-page .axdev { margin-top: 22px; }
.admin-page .axdev__head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.admin-page .axdev__title { margin: 0; font-size: 18px; font-weight: 700; }
.admin-page .axdev__note {
  margin: 8px 0 14px;
  font-size: 13px;
  line-height: 1.55;
  color: var(--muted, #8b93a7);
  max-width: 760px;
}
/* Плитка, а не строки во всю ширину: данных на карточке мало (подпись, логин,
   версия, адрес, давность), и растянутая на весь экран строка была почти пустой
   — глазами приходилось идти через полтора метра пустоты к кнопке справа.
   Плитками парк из пяти-десяти машин виден целиком, без прокрутки. */
.admin-page .axdev__list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 10px;
  align-items: start;
}
/* Карточка с открытым подтверждением занимает всю ширину: текст там длинный, и
   в узкой плитке он превратился бы в колонку из отдельных слов. */
.admin-page .axdev__list > .axdev__card:has(.axdev__confirm) { grid-column: 1 / -1; }
.admin-page .axdev__empty {
  padding: 18px;
  border-radius: 12px;
  background: var(--a-surface);
  color: var(--muted, #8b93a7);
  font-size: 13px;
  line-height: 1.5;
}
.admin-page .axdev__card {
  padding: 12px 14px;
  border-radius: 12px;
  background: var(--a-surface);
  border: 1px solid transparent;
  min-width: 0;
}
.admin-page .axdev__card.is-revoked { opacity: 0.72; border-color: rgba(248, 113, 113, 0.35); }
.admin-page .axdev__name { font-size: 14px; font-weight: 700; display: flex; align-items: center; gap: 8px; }
.admin-page .axdev__nameText { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.admin-page .axdev__meta {
  font-size: 12px;
  color: var(--muted, #8b93a7);
  margin-top: 3px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Давность последнего рукопожатия — то, ради чего смотрят на список: по ней
   видно забытые и снесённые установки. Цвет несёт смысл, поэтому дублируется
   словом: «на связи» против «молчит». */
.admin-page .axdev__seen {
  display: flex;
  align-items: center;
  gap: 7px;
  margin-top: 8px;
  font-size: 12px;
  color: var(--muted, #8b93a7);
}
.admin-page .axdev__dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.admin-page .axdev__card.is-live  .axdev__seen { color: #4ade80; }
.admin-page .axdev__card.is-quiet .axdev__seen { color: var(--muted, #8b93a7); }
.admin-page .axdev__card.is-stale .axdev__seen { color: #fcd34d; }
.admin-page .axdev__card.is-lost  .axdev__seen { color: #f87171; }
/* Молчит больше недели — это уже вопрос, а не наблюдение: помечаем и рамкой. */
.admin-page .axdev__card.is-stale { border-color: rgba(251, 191, 36, 0.28); }
.admin-page .axdev__card.is-lost  { border-color: rgba(248, 113, 113, 0.28); }

.admin-page .axdev__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
}
.admin-page .axdev__id { font-family: ui-monospace, monospace; font-size: 11px; opacity: 0.7; }
.admin-page .axdev__sum {
  margin-right: auto;
  font-size: 12px;
  color: var(--muted, #8b93a7);
}
.admin-page .axdev__confirm {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}
.admin-page .axdev__confirmText { font-size: 12px; line-height: 1.5; color: var(--muted, #8b93a7); max-width: 560px; }
.admin-page .axdev__confirmBtns { display: flex; gap: 8px; flex: none; }

/* Подпись машины. Без неё в списке восемь случайных букв на строку, и «своя»
   установка неотличима от чужой; с подписью новая видна сразу — у неё подписи
   нет. Сам `.axdev__name` объявлен выше, вместе с остальной карточкой. */
.admin-page .axdev__new {
  font-size: 11px;
  font-weight: 600;
  padding: 2px 7px;
  border-radius: 999px;
  background: rgba(251, 191, 36, 0.14);
  color: #fcd34d;
}
.admin-page .axdev__card.is-unnamed { border-color: rgba(251, 191, 36, 0.3); }
.admin-page .axdev__edit {
  border: none;
  background: none;
  color: var(--muted, #8b93a7);
  cursor: pointer;
  font-size: 13px;
  padding: 0 2px;
  line-height: 1;
}
.admin-page .axdev__edit:hover { color: var(--text, #e8ecf4); }
.admin-page .axdev__nameEdit { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.admin-page .axdev__input {
  flex: 1;
  min-width: 180px;
  max-width: 320px;
  padding: 6px 10px;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(0, 0, 0, 0.25);
  color: inherit;
  font: inherit;
  font-size: 13px;
}
