/* ═══════════════════════════════════════════════════════════════════
   smit-ui — базовые UI-примитивы СмИТ Биллинг (build 1690).

   Дополняет уже существующие компоненты (SmitToast, SmitConfirm,
   SmitCopy, SmitPhone, SmitHelpIcon, OrgBadge, CallButton …) теми
   кирпичиками, которые до сих пор копировались по страницам:
     · smit-tbl    — таблица, которая на телефоне становится карточками
     · smit-scroll — прокрутка для таблиц без <thead>
     · smit-badge  — бейдж статуса на семафоре токенов
     · smit-tile   — KPI-плитка
     · smit-empty  — пустое состояние
     · smit-sr     — текст только для скринридера

   Всё на токенах из tokens.css, поэтому одинаково работает в админке
   (body.dark-theme) и в ЛК ([data-bs-theme=dark]).
   Каталог с живыми примерами: /admin/ui-kit/
   ═══════════════════════════════════════════════════════════════════ */

.smit-sr{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}

/* ─────────────────── Бейдж статуса ─────────────────── */
.smit-badge{
  display:inline-flex; align-items:center; gap:5px; white-space:nowrap;
  font-size:var(--font-size-xs); font-weight:700;
  border-radius:var(--radius-pill); padding:3px 9px;
  background:var(--surface-muted); color:var(--text-muted);
}
.smit-badge.ok, .smit-badge.active, .smit-badge.paid, .smit-badge.success{
  color:var(--smit-state-ok);     background:rgba(25,135,84,.12); }
.smit-badge.warn, .smit-badge.pending{
  color:var(--smit-state-warn);   background:rgba(253,126,20,.12); }
.smit-badge.err, .smit-badge.error, .smit-badge.blocked, .smit-badge.overdue{
  color:var(--smit-state-danger); background:rgba(220,53,69,.12); }
.smit-badge.info{
  color:#0a7c8f;                  background:rgba(13,202,240,.14); }
.smit-badge.muted, .smit-badge.unknown, .smit-badge.draft{
  color:var(--text-muted);        background:var(--surface-muted); }
/* точка вместо иконки — когда в строке уже много иконок */
.smit-badge.dot::before{
  content:''; width:6px; height:6px; border-radius:50%;
  background:currentColor; flex:0 0 6px;
}
body.dark-theme .smit-badge.info, [data-bs-theme="dark"] .smit-badge.info{ color:#5bc0de; }

/* ─────────────────── Адаптивная таблица ───────────────────
   Ниже 768px строка превращается в карточку «поле — значение».
   Подписи берёт JS из <thead> и кладёт в data-label (smit-ui.js),
   вручную дублировать не нужно. */
.smit-tbl{ width:100%; border-collapse:collapse; }
.smit-tbl th{
  text-align:left; padding:var(--space-2) var(--space-3);
  font-size:var(--font-size-xs); font-weight:700; color:var(--text-muted);
  border-bottom:1px solid var(--border-subtle);
}
.smit-tbl td{
  padding:var(--space-3); color:var(--text-primary);
  border-bottom:1px solid var(--border-subtle);
  /* Правило admin: в таблицах выравнивание по верху и по левому краю.
     Строки бывают разной высоты (адрес в две строки, длинное описание) —
     при middle соседние ячейки «плавают», глазу не за что зацепиться.
     Числа и действия отводим вправо классами .num / .act. */
  vertical-align:top; text-align:left;
}
.smit-tbl th{ vertical-align:top; }
.smit-tbl tbody tr:last-child td{ border-bottom:none; }
.smit-tbl td.num, .smit-tbl th.num{ text-align:right; font-variant-numeric:tabular-nums; }
.smit-tbl td.act, .smit-tbl th.act{ text-align:right; white-space:nowrap; }

/* `.inline-form` — исторический класс инлайн-таблиц вкладок абонента:
   его мобильная версия жила дублем в theme-smit.css. Теперь это алиас
   smit-tbl (единственный источник правил — здесь); data-label для него
   тоже проставляет SmitTable (smit-ui.js). */
@media (max-width:767.98px){
  .smit-tbl thead, .inline-form thead{
    position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); }
  .smit-tbl, .smit-tbl tbody, .smit-tbl tr, .smit-tbl td,
  .inline-form, .inline-form tbody, .inline-form tr, .inline-form td{
    display:block; width:100%; }
  .smit-tbl tr, .inline-form tr{
    border:1px solid var(--border-subtle); border-radius:var(--radius-lg);
    padding:var(--space-2) var(--space-3); margin-bottom:var(--space-2);
    background:var(--surface-card);
  }
  .smit-tbl td, .inline-form td{
    display:flex; gap:var(--space-3); align-items:center; flex-wrap:wrap;
    justify-content:space-between; text-align:left;
    padding:var(--space-2) 0; border-bottom:1px solid var(--border-subtle);
  }
  .smit-tbl td:last-child, .inline-form td:last-child{ border-bottom:none; }
  .smit-tbl td::before, .inline-form td::before{
    content:attr(data-label); flex:0 0 auto;
    font-size:var(--font-size-xs); font-weight:700; color:var(--text-muted);
  }
  .smit-tbl td[data-label=""]::before, .inline-form td[data-label=""]::before{ content:none; }
  .smit-tbl td.act, .inline-form td.act, .inline-form td:last-child{
    justify-content:flex-end; white-space:normal; }
  .smit-tbl td.act::before, .inline-form td.act::before{ margin-right:auto; }
  /* тач-цели в карточке */
  .smit-tbl td.act .btn, .smit-tbl td.act button{ min-height:44px; }
  .inline-form select{ width:100% !important; max-width:100%; }

  /* Bootstrap-таблицы (.table-bordered/-striped/-hover) и страничные
     фикс-ширины ячеек (width:90px, max-width:240px, nowrap+ellipsis)
     в карточном режиме дают «коробочки» вокруг полей и обрезанный текст.
     В карточке всё это не имеет смысла — нейтрализуем. */
  table.smit-tbl{ --bs-table-bg:transparent; --bs-table-accent-bg:transparent;
                  --bs-table-striped-bg:transparent; --bs-table-hover-bg:transparent; }
  table.smit-tbl > :not(caption) > * > *,
  table.inline-form > :not(caption) > * > *{
    border:0; background:transparent; box-shadow:none;
    width:100% !important; max-width:100% !important; min-width:0 !important;
    white-space:normal !important; overflow:visible !important;
    text-overflow:clip !important;
  }
  table.smit-tbl td, table.inline-form td{
    border-bottom:1px solid var(--border-subtle); }
  table.smit-tbl td:last-child, table.inline-form td:last-child{ border-bottom:0; }
}

/* Таблицы без <thead>: подписи брать неоткуда — даём прокрутку,
   чтобы содержимое не срезалось краем экрана. */
.smit-scroll{ overflow-x:auto; }
.smit-scroll > table{ min-width:max-content; }

/* ─────────────────── KPI-плитка ─────────────────── */
.smit-tiles{ display:grid; grid-template-columns:repeat(auto-fit,minmax(190px,1fr)); gap:var(--space-3); }
.smit-tile{
  position:relative; display:flex; flex-direction:column; gap:2px;
  background:var(--surface-card); border:1px solid var(--border-subtle);
  border-radius:var(--radius-lg); padding:var(--space-3) var(--space-4);
  color:var(--text-primary); text-decoration:none;
}
.smit-tile .val{ font-size:1.5rem; font-weight:800; line-height:1.15; font-variant-numeric:tabular-nums; }
.smit-tile .cap{ font-size:var(--font-size-sm); color:var(--text-muted); }
.smit-tile .lnk{ margin-top:var(--space-1); font-size:var(--font-size-xs); font-weight:600; color:var(--brand-primary); }
.smit-tile .ic{ position:absolute; right:14px; top:14px; font-size:1.1rem; color:var(--text-muted); opacity:.45; }
/* акцент полосой, а не заливкой: на заливке крупная цифра теряет контраст */
.smit-tile.accent{ box-shadow:inset 3px 0 0 var(--brand-primary); }
.smit-tile.ok{     box-shadow:inset 3px 0 0 var(--smit-state-ok); }
.smit-tile.warn{   box-shadow:inset 3px 0 0 var(--smit-state-warn); }
.smit-tile.err{    box-shadow:inset 3px 0 0 var(--smit-state-danger); }
a.smit-tile:hover{ border-color:var(--brand-primary); }

/* ─────────────────── Формы ───────────────────
   Единое оформление полей и ошибок валидации: каждая страница до этого
   оформляла их по-своему. Разметка:
     <div class="smit-form">
       <div class="smit-field"><label>Название</label>
         <input class="form-control form-control-sm" name="name">
         <span class="hint">подсказка</span><span class="err-text"></span></div>
       …
     </div>
   Ошибки с сервера: SmitForm.errors(form, {name: 'Обязательно'}) — подсветит
   поля и покажет тексты; SmitForm.clear(form) — снимет. */
.smit-form{
  display:grid; grid-template-columns:repeat(auto-fit,minmax(230px,1fr));
  gap:var(--space-3) var(--space-4);
}
.smit-form .full{ grid-column:1 / -1; }
@media (max-width:767.98px){ .smit-form{ grid-template-columns:1fr; } }
.smit-field{ display:flex; flex-direction:column; min-width:0; }
.smit-field > label{
  font-size:var(--font-size-xs); font-weight:700; color:var(--text-muted);
  margin:0 0 3px; display:flex; align-items:center; gap:4px;
}
.smit-field > label .req{ color:var(--smit-state-danger); }
.smit-field .hint{
  font-size:var(--font-size-xs); color:var(--text-muted); margin-top:3px;
}
.smit-field .err-text{
  display:none; font-size:var(--font-size-xs); font-weight:600;
  color:var(--smit-state-danger); margin-top:3px;
}
.smit-field.err .err-text{ display:block; }
.smit-field.err .form-control, .smit-field.err .form-select,
.smit-field.err textarea{
  border-color:var(--smit-state-danger);
  box-shadow:0 0 0 .15rem rgba(220,53,69,.15);
}
body.dark-theme .smit-field > label, [data-bs-theme="dark"] .smit-field > label{ color:var(--text-muted); }
body.dark-theme .smit-field .hint, [data-bs-theme="dark"] .smit-field .hint{ color:var(--text-muted); }
body.dark-theme .smit-field .err-text, [data-bs-theme="dark"] .smit-field .err-text{ color:#f87171; }

/* ─────────────────── Пустое состояние ─────────────────── */
.smit-empty{
  display:flex; flex-direction:column; align-items:center; gap:var(--space-2);
  padding:var(--space-5) var(--space-4); text-align:center; color:var(--text-muted);
}
.smit-empty i{ font-size:1.7rem; opacity:.45; }
.smit-empty .t{ font-weight:600; color:var(--text-primary); }
.smit-empty .s{ font-size:var(--font-size-sm); }
.smit-tbl td.smit-empty{ display:table-cell; }
@media (max-width:767.98px){
  .smit-tbl td.smit-empty{ display:block; }
  .smit-tbl td.smit-empty::before{ content:none; }
}

/* ─────────────────── Тёмная тема ───────────────────
   theme-smit.css в тёмной теме сбрасывает цвет потомков .content-wrapper
   на inherit правилом с большей специфичностью — из-за этого бейджи теряли
   семафор (зелёный/красный становились серыми), а приглушённые подписи
   переставали быть приглушёнными. Возвращаем цвета явно: префикс темы
   уравнивает специфичность, а smit-ui.css подключён позже. */
body.dark-theme .smit-badge,
[data-bs-theme="dark"] .smit-badge{ color:var(--text-muted); }
body.dark-theme .smit-badge.ok, body.dark-theme .smit-badge.active,
body.dark-theme .smit-badge.paid, body.dark-theme .smit-badge.success,
[data-bs-theme="dark"] .smit-badge.ok, [data-bs-theme="dark"] .smit-badge.active,
[data-bs-theme="dark"] .smit-badge.paid, [data-bs-theme="dark"] .smit-badge.success{
  color:#4ade80; }
body.dark-theme .smit-badge.warn, body.dark-theme .smit-badge.pending,
[data-bs-theme="dark"] .smit-badge.warn, [data-bs-theme="dark"] .smit-badge.pending{
  color:#fbbf24; }
body.dark-theme .smit-badge.err, body.dark-theme .smit-badge.error,
body.dark-theme .smit-badge.blocked, body.dark-theme .smit-badge.overdue,
[data-bs-theme="dark"] .smit-badge.err, [data-bs-theme="dark"] .smit-badge.error,
[data-bs-theme="dark"] .smit-badge.blocked, [data-bs-theme="dark"] .smit-badge.overdue{
  color:#f87171; }
body.dark-theme .smit-badge.info,
[data-bs-theme="dark"] .smit-badge.info{ color:#5bc0de; }

body.dark-theme .smit-tbl td, [data-bs-theme="dark"] .smit-tbl td{ color:var(--text-primary); }
body.dark-theme .smit-tbl th, [data-bs-theme="dark"] .smit-tbl th{ color:var(--text-muted); }
body.dark-theme .smit-tile .val, [data-bs-theme="dark"] .smit-tile .val{ color:var(--text-primary); }
body.dark-theme .smit-tile .cap, [data-bs-theme="dark"] .smit-tile .cap{ color:var(--text-muted); }
body.dark-theme .smit-tile .lnk, [data-bs-theme="dark"] .smit-tile .lnk{ color:var(--brand-primary); }
body.dark-theme .smit-empty .t, [data-bs-theme="dark"] .smit-empty .t{ color:var(--text-primary); }
body.dark-theme .smit-empty .s, [data-bs-theme="dark"] .smit-empty .s{ color:var(--text-muted); }
body.dark-theme .smit-empty, [data-bs-theme="dark"] .smit-empty{ color:var(--text-muted); }

/* ─────────────────── Нативные виджеты ───────────────────
   Календарь у <input type=date/datetime-local>, чекбоксы и радио браузер
   красит своим синим. accent-color переводит их в фирменный цвет —
   и он же брендируется по организации. */
:root{ accent-color:var(--brand-primary); }

/* ─────────────────── Модалки на мобильном ───────────────────
   Требование admin: на телефоне модальное окно — не «карточка посреди
   экрана», а полноэкранная панель, выезжающая справа (как дровер CRM).
   Так остаётся место под содержимое и привычен жест «закрыть вправо». */
@media (max-width:767.98px){
  .modal-dialog{
    margin:0 !important; max-width:100% !important; width:100% !important;
    min-height:100dvh; display:flex; align-items:stretch;
  }
  /* .modal у Bootstrap имеет боковые отступы, а тема AdminLTE — радиус 5px:
     из-за них панель не доходила до краёв экрана */
  .modal{ padding:0 !important; }
  .modal-content{
    height:100dvh; width:100%; border:0 !important; border-radius:0 !important;
    display:flex; flex-direction:column;
  }
  /* Bootstrap у .modal-dialog-centered задаёт height:calc(100% - 3.5rem) и
     центрирование, а у .modal-dialog-scrollable — свой max-height. Из-за них
     панель не разворачивалась на весь экран: оставалась «карточка посередине».
     Нейтрализуем оба класса, иначе правило работает не для всех модалок. */
  .modal-dialog.modal-dialog-centered,
  .modal-dialog.modal-dialog-scrollable{
    height:100dvh; min-height:100dvh; align-items:stretch;
  }
  .modal-dialog-scrollable .modal-content{ height:100dvh; max-height:100dvh; }
  .modal-dialog-scrollable .modal-body{ overflow-y:auto; }
  .modal-body{ overflow-y:auto; flex:1 1 auto; }
  .modal-header, .modal-footer{ flex:0 0 auto; }
  /* выезд снизу — привычнее для телефона, чем «падение» сверху */
  /* Специфичность: theme-smit.css объявляет `.modal.fade.show .modal-dialog`
     (4 класса) ВНЕ медиа-запроса, поэтому правило из трёх классов внутри
     @media его не перебивало и панель застревала внизу экрана. Держим оба
     селектора на одном уровне — по 4 класса. */
  .modal.fade:not(.show) .modal-dialog{ transform:translateY(100%); transition:transform .25s ease; }
  .modal.fade.show .modal-dialog{ transform:none; }
  /* footer с кнопками — не даём ему уехать за нижний край */
  .modal-footer{ position:sticky; bottom:0; background:var(--surface-card); }
}
@media (max-width:767.98px) and (prefers-reduced-motion:reduce){
  .modal.fade:not(.show) .modal-dialog{ transition:none; }
}
