/* Переиспользуемые виджеты. Ни одного литерала #rrggbb, кроме белого текста на
   залитой цветом кнопке: литерал в компоненте означает, что тёмная тема
   потребует править сам компонент. */

/* ------------------------------------------------------------------- кнопки */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-2);
  height: var(--control-h);
  padding: 0 var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-md);
  cursor: pointer;
  white-space: nowrap;
  transition: border-color 0.12s ease, background 0.12s ease;
}

.btn:hover:not(:disabled) {
  border-color: var(--border-strong);
  background: var(--bg-hover);
}

/* :active объявляется ОТДЕЛЬНО от :hover: кнопка, нажатая С КЛАВИАТУРЫ, бывает
   :active, ни разу не побывав :hover. */
.btn:active:not(:disabled) {
  background: var(--bg-active);
}

.btn:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn--sm {
  height: var(--control-h-sm);
  padding: 0 var(--sp-2);
  font-size: var(--fs-sm);
}

.btn--primary {
  background: var(--accent-500);
  border-color: var(--accent-600);
  color: #fff;
}

.btn--primary:hover:not(:disabled) {
  background: var(--accent-600);
  border-color: var(--accent-700);
}

.btn--danger {
  background: var(--danger-500);
  border-color: var(--danger-700);
  color: #fff;
}

.btn--danger:hover:not(:disabled) {
  background: var(--danger-700);
}

/*
 * ⚠️ КРАСНЫЙ КОНТУР, А НЕ ЗАЛИВКА (§10.7 хендоффа). Сплошной красный оставлен
 * там, где решение действительно принимается, — на кнопке подтверждения в
 * диалоге. Цвет, помечающий почти всё, не помечает ничего.
 */
.btn--caution {
  color: var(--danger-ink-surface);
  border-color: var(--danger-500);
  background: var(--bg-surface);
}

.btn--caution:hover:not(:disabled) {
  border-color: var(--danger-700);
  background: var(--bg-surface);
}

.btn--ghost {
  border-color: transparent;
  background: transparent;
}

.btn--ghost:hover:not(:disabled) {
  border-color: var(--border);
  background: var(--bg-hover);
}

.btn--icon {
  width: 28px;
  padding: 0;
}

/* Тональные кнопки — ТОНИРОВАННЫЕ, а не насыщенные: те же тона в силе чипа
   различимы с одного взгляда и перестают кричать. Контур здесь не украшение:
   заливка почти не отделяется от панели, и именно ОБВОДКА говорит «это контрол»
   (WCAG 1.4.11, 3:1). */
.btn--tone-ok {
  background: var(--ok-100);
  border-color: var(--ok-500);
  color: var(--ok-ink);
}

.btn--tone-warn {
  background: var(--warn-100);
  border-color: var(--warn-500);
  color: var(--warn-ink);
}

.btn--tone-danger {
  background: var(--danger-100);
  border-color: var(--danger-500);
  color: var(--danger-ink);
}

/* ------------------------------------------------------------------- поля */

.field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-width: 0;
}

.field__label {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.field__hint {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

/* Единственная строка в форме, которую НАДО прочитать, — 12 px на обычной
   поверхности. Почему не сырой тон — см. --danger-ink-surface в tokens.css. */
.field__error {
  font-size: var(--fs-sm);
  color: var(--danger-ink-surface);
}

.input,
.select,
.textarea {
  height: var(--control-h);
  padding: 0 var(--sp-2);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg-surface);
  color: var(--text);
  font: inherit;
  font-size: var(--fs-md);
  min-width: 0;
  width: 100%;
}

.textarea {
  height: auto;
  min-height: 76px;
  padding: var(--sp-2);
  resize: vertical;
  line-height: var(--lh-normal);
}

.input:disabled,
.select:disabled,
.textarea:disabled {
  background: var(--bg-sunken);
  color: var(--text-muted);
  cursor: not-allowed;
}

/* Валидация — НА САМОМ КОНТРОЛЕ, а не только текстом рядом: aria-invalid
   одновременно и семантика, и селектор. */
.input[aria-invalid='true'],
.textarea[aria-invalid='true'],
.select[aria-invalid='true'] {
  border-color: var(--danger-500);
}

.input[aria-invalid='true']:focus,
.textarea[aria-invalid='true']:focus {
  box-shadow: 0 0 0 3px var(--danger-100);
}

/*
 * Сетка формы: auto-fit без единой контрольной точки, но с ПОТОЛКОМ в три
 * колонки — «порядок и есть вёрстка»: двенадцать полей читаются смысловыми
 * четвёрками только пока ложатся по три в ряд.
 */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(max(200px, (100% - 2 * var(--sp-4)) / 3), 1fr));
  gap: var(--sp-4);
  /* Без align-items: start каждое поле в ряду растягивается до высоты самого
     высокого, и одна подсказка под одним контролом молча раздвигает соседей. */
  align-items: start;
}

/* Всё, что НЕ является полем, занимает в сетке целую строку: предупреждение,
   втиснутое в треть ширины, читается как четвёртое поле без контрола. */
.form-grid > :not(.field) {
  grid-column: 1 / -1;
}

/* Связанные галочки занимают ПОЛНУЮ строку: булево в карточке — это
   ПРЕДЛОЖЕНИЕ, а предложение в дорожке 200 px переносится в три строки, левый
   край которых уже ни с чем не совпадает. */
.form-grid > .field--check {
  grid-column: 1 / -1;
}

/*
 * Галочка — единственный контрол, чья подпись идёт СБОКУ, а не сверху. Правило
 * покрывает все написания сразу плюс страховку по содержимому: неопознанный
 * модификатор откатывается не в «ничего», а в .field, то есть в колонку, и
 * коробка уезжает НАД своей подписью.
 */
.check,
.field--check,
.field:has(> input[type='checkbox']),
.field:has(> input[type='radio']) {
  display: inline-flex;
  flex-direction: row;
  /* start, а не center: подписи переносятся, и против трёхстрочного блока
     центрированная коробка указывает на среднюю строку и ни на что конкретно. */
  align-items: start;
  gap: var(--sp-2);
  cursor: pointer;
  font-size: var(--fs-md);
  line-height: var(--lh-normal);
  user-select: none;
}

.check input[type='checkbox'],
.field--check input[type='checkbox'],
.check input[type='radio'],
.field--check input[type='radio'] {
  /* ⚠️ `flex: none` — НЕСУЩАЯ СТРОКА. Без неё коробка растягивается на ширину
     своей дорожки, а растянутый чекбокс рисует галку в центре этой ширины. */
  flex: none;
  margin-block-start: 2px;
  accent-color: var(--accent-500);
}

/* Отключённая галочка не исчезает, а гаснет: то, что менять нельзя, всё равно
   надо читать. */
.check:has(input:disabled),
.field--check:has(input:disabled) {
  opacity: 0.55;
  cursor: not-allowed;
}

/* ------------------------------------------------------------------ бейджи */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  height: 20px;
  padding: 0 var(--sp-2);
  border-radius: var(--radius-pill);
  font-size: var(--fs-xs);
  font-weight: 600;
  white-space: nowrap;
  background: var(--bg-sunken);
  color: var(--text-muted);
  border: 1px solid transparent;
}

.badge__dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

.badge--ok {
  background: var(--ok-100);
  color: var(--ok-ink);
  border-color: var(--ok-500);
}

.badge--warn {
  background: var(--warn-100);
  color: var(--warn-ink);
  border-color: var(--warn-500);
}

.badge--danger {
  background: var(--danger-100);
  color: var(--danger-ink);
  border-color: var(--danger-500);
}

.badge--info {
  background: var(--info-100);
  color: var(--info-ink);
  border-color: var(--info-500);
}

/* --------------------------------------------------------------- поверхности */

.panel {
  background: var(--bg-surface);
  border: 1px solid var(--border-subtle);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.panel__header {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  min-height: var(--header-h);
  /* Резерв под правый верхний угол оболочки — контракт --topright-w (§10.2). */
  padding: var(--sp-2) calc(var(--sp-3) + var(--topright-w, 0px)) var(--sp-2) var(--sp-3);
  background: var(--bg-surface);
  border-bottom: 1px solid var(--border-subtle);
  flex-wrap: wrap;
  row-gap: var(--sp-2);
}

.panel__body {
  padding: var(--sp-4);
}

/* ------------------------------------------------------------------ таблица */

.data-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-md);
}

.data-table th,
.data-table td {
  padding: var(--sp-2) var(--sp-3);
  text-align: left;
  border-bottom: 1px solid var(--border-subtle);
  white-space: nowrap;
  max-width: 320px;
}

.data-table td:has(> .u-truncate) {
  max-width: 260px;
}

.data-table__head {
  position: sticky;
  top: 0;
  z-index: 1;
  background: var(--bg-surface);
  color: var(--text-muted);
  font-size: var(--fs-sm);
  font-weight: 600;
  user-select: none;
}

.data-table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  border: 0;
  background: transparent;
  color: inherit;
  font: inherit;
  font-weight: inherit;
  padding: 0;
  cursor: pointer;
  max-width: 100%;
}

/* Слот стрелки зарезервирован ВСЕГДА, чтобы сортировка колонки не сдвигала
   каждый заголовок вбок. */
.data-table__arrow {
  display: inline-block;
  width: 10px;
  text-align: center;
  color: var(--text-muted);
}

.data-table .is-num,
.data-table .is-num .data-table__sort {
  text-align: right;
  justify-content: flex-end;
}

.data-table tbody tr:hover td {
  background: var(--bg-hover);
}

.data-table tbody tr.is-selected td {
  background: var(--bg-active);
}

/*
 * Необязательный значок перед значением рисуется ВСЕГДА — пустым, если его нет,
 * иначе колонка читается рваным краем, а не списком.
 */
.cell-slot {
  display: inline-block;
  width: var(--cell-slot-w, 22px);
  vertical-align: middle;
}

/* ⚠️ ОТСТУП ТОЛЬКО КОГДА БЕЙДЖ ИДЁТ ЗА ЧЕМ-ТО. Бейдж, который в ячейке ПЕРВЫЙ,
   является её значением, а не добавкой, и 8 px перед ним ставят строки-бейджи
   этой колонки на 8 px правее её же строк простым текстом. */
.data-table td > .badge:not(:first-child) {
  margin-left: var(--sp-2);
}

/* -------------------------------------------------------------- действия строки */

.row-actions {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
}

/*
 * Кнопка, живущая только на :hover, — это кнопка, которой нет у половины
 * пользователей. Три условия вместо одного: она остаётся КНОПКОЙ и в порядке
 * обхода (прозрачна, но не display:none и не tabindex=-1), показывается по
 * наведению И по фокусу, и просто есть там, где наводить нечем.
 */
.row-actions__btn {
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.1s ease;
}

.data-table tbody tr:hover .row-actions__btn,
.data-table tbody tr:focus-within .row-actions__btn,
.row-actions__btn:focus-visible {
  opacity: 1;
  pointer-events: auto;
}

.row-actions__btn--primary,
.row-actions__btn--always {
  opacity: 1;
  pointer-events: auto;
}

@media (hover: none) {
  .row-actions__btn {
    opacity: 1;
    pointer-events: auto;
  }
}

/* Разрушающая кнопка, стоящая открытой рядом с безобидной, получает ЗАЗОР: три
   квадрата 28×28 без промежутка ставят «Удалить» в пиксель от «Скачать». */
.row-actions__btn--apart {
  margin-left: var(--sp-3);
}

/* ------------------------------------------------------------------- модалка */

.modal-layer {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-4);
  background: rgba(17, 22, 31, 0.55);
}

.modal {
  display: flex;
  flex-direction: column;
  width: min(720px, 100%);
  max-height: min(90vh, 900px);
  background: var(--bg-surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.modal--wide {
  width: min(1100px, 100%);
}

.modal--narrow {
  width: min(460px, 100%);
}

.modal__header {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3) var(--sp-4);
  border-bottom: 1px solid var(--border-subtle);
}

.modal__title {
  font-size: var(--fs-lg);
  font-weight: 600;
  color: var(--text-strong);
}

.modal__body {
  padding: var(--sp-4);
  overflow: auto;
  flex: 1 1 auto;
}

.modal__footer {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  padding: var(--sp-3) var(--sp-4);
  border-top: 1px solid var(--border-subtle);
  background: var(--bg-surface);
}

.modal__detail {
  margin-top: var(--sp-2);
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

/* -------------------------------------------------------------------- тосты */

.toasts {
  position: fixed;
  right: var(--sp-4);
  bottom: var(--sp-4);
  z-index: 200;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  /* Клики проходят мимо контейнера; ловят их только сами тосты. */
  pointer-events: none;
  max-width: min(420px, calc(100vw - 2 * var(--sp-4)));
}

.toast {
  pointer-events: auto;
  display: flex;
  flex-direction: column;
  gap: var(--sp-2);
  padding: var(--sp-3);
  border-radius: var(--radius);
  border: 1px solid var(--border);
  background: var(--bg-surface);
  box-shadow: var(--shadow-md);
}

.toast--ok {
  border-color: var(--ok-500);
}

.toast--warn {
  border-color: var(--warn-500);
}

.toast--error {
  border-color: var(--danger-500);
}

.toast__title {
  font-weight: 600;
  color: var(--text-strong);
}

.toast__text {
  font-size: var(--fs-md);
  overflow-wrap: anywhere;
}

.toast__details {
  font-size: var(--fs-sm);
  color: var(--text-muted);
}

.toast__details pre {
  margin: var(--sp-2) 0 0;
  padding: var(--sp-2);
  background: var(--bg-sunken);
  border-radius: var(--radius-sm);
  overflow: auto;
  max-height: 200px;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

/* -------------------------------------------------------------------- вкладки */

.tabs {
  display: flex;
  gap: var(--sp-1);
  border-bottom: 1px solid var(--border-subtle);
  padding: 0 var(--sp-4);
  flex-wrap: wrap;
}

.tab {
  border: 0;
  border-bottom: 2px solid transparent;
  background: transparent;
  color: var(--text-muted);
  font: inherit;
  font-size: var(--fs-md);
  padding: var(--sp-2) var(--sp-3);
  cursor: pointer;
}

.tab[aria-selected='true'] {
  color: var(--text-strong);
  border-bottom-color: var(--accent-500);
  font-weight: 600;
}

/* --------------------------------------------------------------------- чипы */

.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-1);
  height: var(--control-h-sm);
  padding: 0 var(--sp-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-pill);
  background: var(--bg-sunken);
  font-size: var(--fs-sm);
  cursor: pointer;
  color: inherit;
  font-family: inherit;
}

/* ---------------------------------------------------------------- пары фактов */

/*
 * Список «подпись — значение» НЕ растягивается на всю строку: замерено, что при
 * растяжении подпись и значение расходятся на сотни пикселей, и число начинает
 * читаться против чужой строки.
 */
.facts {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--sp-2) var(--sp-4);
  align-items: baseline;
  max-width: 640px;
}

.facts__key {
  color: var(--text-muted);
  font-size: var(--fs-sm);
}

.facts__value {
  overflow-wrap: anywhere;
}
