/**
 * Общие стили интерфейса: то, чего Bootstrap не даёт из коробки и что нужно
 * ОБОИМ приложениям — тенанту и админке.
 *
 * Файл лежал двумя копиями: web-ui-admin/static/css/app.css совпадал с
 * web-ui-tenant/static/css/app.css строка в строку (102 из 102 строк). Копии
 * расходятся молча — правку в одной никто не переносит во вторую, и админка
 * годами живёт со старым поведением. Подключается из base.mustache ДО
 * пакетного app.css, поэтому приложение может доопределить что-то поверх.
 */

/* ── Дизайн-слой ──────────────────────────────────────────────────────────
   Токены и надстройка над Bootstrap: фирменный вид продукта в одном месте.

   До этого интерфейс был стоковым Bootstrap 5.3 — синий primary, дефолтные
   рамки, никаких токенов. Поэтому «поменять акцент» или «сделать карточки
   мягче» означало искать по всем шаблонам. Теперь это правки здесь, и они
   доезжают до каждого экрана обоих приложений.

   Bootstrap 5.3 читает --bs-body-* и --bs-border-* во время исполнения, а вот
   кнопки собраны из --bs-btn-* на этапе сборки Sass: переопределить
   --bs-primary недостаточно, поэтому .btn-primary перекрашивается явно. */
:root {
  /* Акцент: фирменный мятный. В светлой теме — тёмный оттенок: белый текст на
     прежнем #14a273 давал 3.3:1, ссылки на фоне страницы — 3.0:1, а для
     обычного текста нужно 4.5:1 (WCAG AA). #0b7a55 — 5.3:1 и 5.0:1. В тёмной
     теме акцент светлый, и текст поверх него тёмный (11:1). */
  --vs-accent: #0b7a55;
  --vs-accent-contrast: #ffffff;
  --vs-accent-soft: rgba(11, 122, 85, 0.12);
  /* Уровни критичности — своя шкала, а не success/warning/danger: «низкий» не
     зелёный (зелёный читается как «всё хорошо», а это всё-таки уязвимость).
     Светлые варианты подобраны на ≥4.5:1 к белому: подпись пилюли — текст. */
  --vs-sev-low: #5b4ae8;
  --vs-sev-medium: #15803d;
  --vs-sev-high: #b45309;
  --vs-sev-critical: #c2263a;
  --vs-radius: 0.875rem;
  --vs-radius-sm: 0.5rem;
  /* Дельта к прошлому периоду: рост угроз — плохо, спад — хорошо. */
  --vs-delta-good: #0b7a55;
  --vs-delta-bad: #c2263a;
  /* Рамка поля ввода. Граница элемента управления обязана отличаться от фона
     хотя бы на 3:1 (WCAG 1.4.11); общая рамка карточек (#e3e6ea) даёт 1.25:1,
     и поля выглядели выключенными. */
  --vs-input-border: #868e96;
  --vs-input-bg: #ffffff;
  --vs-input-disabled-bg: #eceef1;
}

[data-bs-theme="dark"] {
  --vs-accent: #3ddc97;
  --vs-accent-contrast: #06231a;
  --vs-accent-soft: rgba(61, 220, 151, 0.14);
  --vs-sev-low: #7c5cff;
  --vs-sev-medium: #22e06a;
  --vs-sev-high: #f59e0b;
  --vs-sev-critical: #ef4444;
  --vs-delta-good: #3ddc97;
  --vs-delta-bad: #ef4444;

  --bs-body-bg: #0b0c0e;
  --bs-body-color: #e9eaec;
  --bs-emphasis-color: #ffffff;
  --bs-secondary-color: #8a8f98;
  --bs-secondary-bg: #16181b;
  --bs-tertiary-bg: #1a1c20;
  --bs-border-color: #26292e;
  --bs-border-color-translucent: rgba(255, 255, 255, 0.08);
  --bs-heading-color: #ffffff;

  --vs-input-border: #61676f;
  --vs-input-bg: #0f1113;
  --vs-input-disabled-bg: #1f2226;
}

[data-bs-theme="light"] {
  --bs-body-bg: #f6f7f9;
  --bs-secondary-bg: #ffffff;
  --bs-tertiary-bg: #f1f3f5;
  --bs-border-color: #e3e6ea;
}

:root {
  --bs-primary: var(--vs-accent);
  --bs-link-color: var(--vs-accent);
  --bs-link-hover-color: var(--vs-accent);
}

/* Карточка — основной контейнер макета: мягкий радиус, приглушённая рамка,
   поверхность на тон светлее фона. */
.card {
  --bs-card-bg: var(--bs-secondary-bg);
  --bs-card-border-color: var(--bs-border-color);
  --bs-card-border-radius: var(--vs-radius);
  --bs-card-inner-border-radius: var(--vs-radius);
}

.btn {
  --bs-btn-border-radius: var(--vs-radius-sm);
}

.btn-primary {
  --bs-btn-bg: var(--vs-accent);
  --bs-btn-border-color: var(--vs-accent);
  --bs-btn-color: var(--vs-accent-contrast);
  --bs-btn-hover-bg: color-mix(in srgb, var(--vs-accent) 86%, #000);
  --bs-btn-hover-border-color: color-mix(in srgb, var(--vs-accent) 86%, #000);
  --bs-btn-hover-color: var(--vs-accent-contrast);
  --bs-btn-active-bg: color-mix(in srgb, var(--vs-accent) 74%, #000);
  --bs-btn-active-border-color: color-mix(in srgb, var(--vs-accent) 74%, #000);
  --bs-btn-active-color: var(--vs-accent-contrast);
  --bs-btn-disabled-bg: var(--vs-accent);
  --bs-btn-disabled-border-color: var(--vs-accent);
  --bs-btn-disabled-color: var(--vs-accent-contrast);
}

.btn-outline-primary {
  --bs-btn-color: var(--vs-accent);
  --bs-btn-border-color: var(--vs-accent);
  --bs-btn-hover-bg: var(--vs-accent);
  --bs-btn-hover-border-color: var(--vs-accent);
  --bs-btn-hover-color: var(--vs-accent-contrast);
  --bs-btn-active-bg: var(--vs-accent);
  --bs-btn-active-border-color: var(--vs-accent);
  --bs-btn-active-color: var(--vs-accent-contrast);
  --bs-btn-disabled-color: var(--vs-accent);
  --bs-btn-disabled-border-color: var(--vs-accent);
}

.bg-primary {
  background-color: var(--vs-accent) !important;
  color: var(--vs-accent-contrast) !important;
}

.text-primary {
  color: var(--vs-accent) !important;
}

.form-check-input:checked {
  background-color: var(--vs-accent);
  border-color: var(--vs-accent);
}

/* Поля ввода. Bootstrap красит их фоном страницы, а он на тон темнее
   карточки: поле на карточке выглядело углублением без рамки. Хуже того,
   выключенное поле он красит --bs-secondary-bg, который у нас белый, — и
   выключенное смотрелось активнее включённого. */
.form-control,
.form-select {
  background-color: var(--vs-input-bg);
  border-color: var(--vs-input-border);
}

.form-check-input {
  border-color: var(--vs-input-border);
}

.form-control:disabled,
.form-select:disabled,
.form-control[readonly]:not(.form-control-plaintext) {
  background-color: var(--vs-input-disabled-bg);
  color: var(--bs-secondary-color);
}

.form-control:focus,
.form-select:focus,
.form-check-input:focus {
  border-color: var(--vs-accent);
  box-shadow: 0 0 0 0.2rem var(--vs-accent-soft);
}

/* Заголовки. Bootstrap даёт h1 в 2.5rem — в админке заголовок списка был
   размером с баннер, а у тенанта страницы шли в h4/h5: три приложения, три
   шкалы. Одна шкала на всех: страница — h1, раздел — h2, блок — h3. */
h1,
.h1 {
  font-size: calc(1.3rem + 0.6vw);
  font-weight: 600;
}

h2,
.h2 {
  font-size: calc(1.2rem + 0.3vw);
  font-weight: 600;
}

h3,
.h3 {
  font-size: 1.15rem;
  font-weight: 600;
}

@media (min-width: 1200px) {
  h1,
  .h1 {
    font-size: 1.75rem;
  }

  h2,
  .h2 {
    font-size: 1.4rem;
  }
}

/* Шапка: на тёмной теме она сливалась с телом страницы (обе почти чёрные) —
   отделяем линией, а не разницей фонов. */
[data-bs-theme="dark"] .navbar {
  background-color: var(--bs-secondary-bg) !important;
  border-bottom: 1px solid var(--bs-border-color);
}

/* Название продукта в шапке — единственное место фирменного акцента в хроме.
   Шапка тёмная в обеих темах, поэтому здесь всегда светлый вариант акцента:
   тёмный светлотемный #0b7a55 на #212529 почти не читался бы. */
.navbar-brand {
  color: #3ddc97 !important;
  font-weight: 700;
  letter-spacing: 0.01em;
}

/* Кнопки шапки — «призраки»: без плашки в покое, подсветка только под курсором.
   Серые коробки вокруг иконок в тёмной теме выглядели как недоделка. */
.navbar .vs-nav-btn {
  --bs-btn-bg: transparent;
  --bs-btn-border-color: transparent;
  --bs-btn-color: rgba(255, 255, 255, 0.85);
  --bs-btn-hover-bg: rgba(255, 255, 255, 0.1);
  --bs-btn-hover-border-color: transparent;
  --bs-btn-hover-color: #ffffff;
  --bs-btn-active-bg: rgba(255, 255, 255, 0.16);
  --bs-btn-active-border-color: transparent;
}

/* На телефоне шапка разваливалась на три строки (~140px): бургер, название и
   иконки не помещались рядом. Название организации и пользователя прячем —
   они есть в меню настроек, — а ряд делаем неразрывным. */
.navbar .container-fluid {
  flex-wrap: nowrap;
}

.vs-nav-role {
  color: #6edff6;
}

@media (max-width: 767.98px) {
  .navbar .vs-nav-btn {
    --bs-btn-padding-x: 0.45rem;
  }

  .navbar .vs-nav-btn-label {
    display: none;
  }
}

/* Уведомления — под шапкой, а не поверх неё. */
.vs-toast-container {
  margin-top: 60px;
}

.vs-page {
  max-width: 1600px;
}

.vs-footer {
  font-size: 0.75rem;
}

/* Подпись над показателем: мелкая, приглушённая — чтобы цифра под ней читалась
   первой. */
.vs-label {
  font-size: 0.78rem;
  line-height: 1.25;
  color: var(--bs-secondary-color);
}

/* Показатель: крупная цифра, ради которой существует плитка. */
.vs-figure {
  font-size: 1.9rem;
  font-weight: 700;
  line-height: 1.1;
  color: var(--bs-emphasis-color);
  font-variant-numeric: tabular-nums;
}

/* Дельта к прошлому периоду — пилюля рядом с цифрой, не отдельная строка. */
.vs-delta {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  padding: 0.1rem 0.4rem;
  border-radius: 999px;
  font-size: 0.72rem;
  font-weight: 600;
  background: var(--vs-accent-soft);
  color: var(--vs-delta-good);
}

.vs-delta-bad {
  background: rgba(224, 54, 74, 0.14);
  color: var(--vs-delta-bad);
}

/* Пилюля уровня критичности / состояния: цвет берётся по каноническому
   значению, а не по подписи — подпись переводится, значение нет. */
.vs-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.1rem 0.45rem;
  border-radius: var(--vs-radius-sm);
  font-size: 0.72rem;
  font-weight: 600;
  border: 1px solid currentcolor;
  background: transparent;
}

.vs-pill::before {
  content: "";
  width: 0.35rem;
  height: 0.35rem;
  border-radius: 50%;
  background: currentcolor;
}

.vs-pill[data-pill="low"] {
  color: var(--vs-sev-low);
}

.vs-pill[data-pill="medium"] {
  color: var(--vs-sev-medium);
}

.vs-pill[data-pill="high"] {
  color: var(--vs-sev-high);
}

.vs-pill[data-pill="critical"] {
  color: var(--vs-sev-critical);
}

.vs-pill[data-pill="open"] {
  color: var(--bs-secondary-color);
}

.vs-pill[data-pill="fixed"] {
  color: var(--vs-sev-medium);
}

.vs-pill[data-pill="accepted"],
.vs-pill[data-pill="false_positive"] {
  color: var(--vs-sev-high);
}

/* Состояния запусков и процессов — та же пилюля, чтобы «выполняется»,
   «готово», «ошибка» выглядели одинаково на всех экранах, а не как набор
   бейджей разного размера и цвета (голубой с белой подписью, 10px жирный…). */
.vs-pill[data-pill="running"],
.vs-pill[data-pill="pending"] {
  color: var(--bs-info-text-emphasis);
}

.vs-pill[data-pill="completed"],
.vs-pill[data-pill="done"],
.vs-pill[data-pill="ok"] {
  color: var(--vs-sev-medium);
}

.vs-pill[data-pill="failed"],
.vs-pill[data-pill="timed_out"],
.vs-pill[data-pill="error"] {
  color: var(--vs-sev-critical);
}

.vs-pill[data-pill="warn"],
.vs-pill[data-pill="partial"] {
  color: var(--vs-sev-high);
}

.vs-pill[data-pill="cancelled"],
.vs-pill[data-pill="muted"] {
  color: var(--bs-secondary-color);
}

/* «Тихое» удаление: иконка в конце ряда действий, красная только под курсором.
   Красная кнопка «Удалить» рядом с «Открыть» весила столько же, сколько
   основное действие, и на каждой карточке звала нажать на себя. */
.vs-btn-quiet-danger {
  --bs-btn-color: var(--bs-secondary-color);
  --bs-btn-bg: transparent;
  --bs-btn-border-color: transparent;
  --bs-btn-hover-color: var(--bs-danger-text-emphasis);
  --bs-btn-hover-bg: var(--bs-danger-bg-subtle);
  --bs-btn-hover-border-color: transparent;
  --bs-btn-active-color: var(--bs-danger-text-emphasis);
  --bs-btn-active-bg: var(--bs-danger-bg-subtle);
  --bs-btn-active-border-color: transparent;
}

/* Метка на карточке («общий», «SQL») — спокойная, не спорит с заголовком. */
.vs-tag {
  display: inline-block;
  padding: 0.05rem 0.4rem;
  border-radius: var(--vs-radius-sm);
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--bs-secondary-color);
  background: var(--bs-tertiary-bg);
  white-space: nowrap;
}

/* Заголовок карточки в сетке: обычный размер, полужирный, до трёх строк. */
.vs-card-title {
  font-weight: 600;
  line-height: 1.3;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

/* Поле-фильтр над списком и строчная форма создания: не на всю ширину. */
.vs-filter-field {
  max-width: 20rem;
}

.vs-inline-form {
  max-width: 40rem;
}

.vs-inline-form-select {
  max-width: 14rem;
}

/* Подпись к цифре в строке истории: цифра со значком без слов понятна только
   тому, кто навёл курсор. */
.vs-stat-label {
  color: var(--bs-secondary-color);
  font-size: 0.85em;
}

/* Layout - navbar height compensation */
.main-content {
  padding-top: 1rem;
  min-height: calc(100vh - 56px);
}

/* Navigation - offcanvas submenu indent */
.nav-group-items {
  padding-left: 1rem;
}

/* HTMX - loading indicators (standard HTMX pattern) */
.htmx-indicator {
  display: none;
}

.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator {
  display: inline-block;
}

/* HTMX - global loading overlay */
#global-loader {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.3);
  z-index: 9999;
  display: none;
  align-items: center;
  justify-content: center;
}

#global-loader.htmx-request {
  display: flex;
}

/* Tables - text truncation with hover expand */
.table-truncate td {
  max-width: 200px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.table-truncate td:hover {
  overflow: visible;
  white-space: normal;
  word-break: break-word;
}

/* Tables - sticky header */
.table-sticky thead {
  position: sticky;
  top: 0;
  z-index: 10;
}

.table-sticky thead th {
  background-color: var(--bs-tertiary-bg);
  box-shadow: inset 0 -1px 0 var(--bs-border-color);
}

/* Collapsible sections - chevron rotation */
.collapsible-header h2 {
  margin-bottom: 0;
}

.collapsible-header .bi-chevron-down {
  transition: transform 0.2s;
}

.collapsible-header.collapsed .bi-chevron-down {
  transform: rotate(-90deg);
}

/* CodeMirror - code editor styling */
.code-editor-wrapper {
  width: 100%;
}

.code-editor-container {
  font-size: 14px;
}

.code-editor-container .CodeMirror {
  height: 400px;
  border-radius: 0.375rem;
}

.code-editor-wrapper.is-invalid .code-editor-container {
  border-color: var(--bs-danger);
}

/* CodeMirror dark theme adjustments */
[data-bs-theme="dark"] .CodeMirror:not(.cm-s-dracula) {
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
}

/* Readonly code display */
pre.form-control-plaintext {
  font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
  font-size: 13px;
  white-space: pre-wrap;
  word-break: break-word;
}


/* --- Доступность (аудит UX-3, U13) ---------------------------------------
   Фокус с клавиатуры: у кнопок шапки он был виден только по едва заметному
   фону rgba(255,255,255,.1). Явная рамка — только для клавиатуры
   (:focus-visible), щелчок мышью её не рисует. */
.navbar .vs-nav-btn:focus-visible,
.navbar .nav-link:focus-visible,
.navbar .navbar-brand:focus-visible {
  outline: 2px solid #6edff6;
  outline-offset: 2px;
  box-shadow: none;
}

.btn:focus-visible,
.nav-link:focus-visible,
a:focus-visible {
  outline: 2px solid var(--bs-primary);
  outline-offset: 2px;
}

/* «К содержимому»: невидима, пока не получит фокус клавишей Tab. */
.vs-skip-link:focus {
  position: fixed;
  top: 0.5rem;
  left: 0.5rem;
  z-index: 2000;
  padding: 0.5rem 1rem;
  background: var(--bs-body-bg);
  color: var(--bs-body-color);
  border: 2px solid var(--bs-primary);
  border-radius: 0.375rem;
}

/* Тёмная тема: вторичные кнопки (#6c757d на почти чёрном — 3,3–3,8:1) и
   счётчики истории (success/danger по умолчанию — ~3,9:1) не дотягивали до
   4,5:1. Берём более светлые оттенки тех же цветов. */
[data-bs-theme="dark"] .btn-outline-secondary {
  --bs-btn-color: #c3c8ce;
  --bs-btn-border-color: #6c757d;
  --bs-btn-hover-color: #0b0c0e;
  --bs-btn-hover-bg: #c3c8ce;
  --bs-btn-hover-border-color: #c3c8ce;
  --bs-btn-active-color: #0b0c0e;
  --bs-btn-active-bg: #c3c8ce;
}

[data-bs-theme="dark"] .btn-link.text-secondary,
[data-bs-theme="dark"] .text-secondary {
  color: #c3c8ce !important;
}

[data-bs-theme="dark"] .ws-run-stats .text-success {
  color: #3ddc97 !important;
}

[data-bs-theme="dark"] .ws-run-stats .text-danger {
  color: #ff8a8a !important;
}

/* Плитки-ссылки дашборда выглядят как соседние плитки, но подсвечиваются. */
.vs-tile-link {
  color: inherit;
}

.vs-tile-link:hover {
  background: var(--bs-tertiary-bg);
}

/* Диалог подтверждения (static/js/confirm.js) вместо window.confirm. */
.vs-confirm {
  max-width: min(28rem, calc(100vw - 2rem));
  padding: 1.25rem;
  color: var(--bs-body-color);
  background: var(--bs-secondary-bg);
  border: 1px solid var(--bs-border-color);
  border-radius: 0.5rem;
}

.vs-confirm::backdrop {
  background: rgba(0, 0, 0, 0.45);
}

/* Переключатель организации администратора: полсотни пунктов — с прокруткой,
   а не на всю высоту экрана. */
.vs-act-as-menu {
  max-height: 70vh;
  overflow-y: auto;
}

/* Узкий экран (аудит UX-3, U14): таблицы «Находки» и «Пользователи» на 375px
   уходили вправо, колонка «Состояние» с «Изменить» была за краем. Под 576px
   строка становится карточкой, подпись колонки — над значением (data-label). */
@media (max-width: 575.98px) {
  table.vs-stack-sm thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
  }

  table.vs-stack-sm,
  table.vs-stack-sm tbody,
  table.vs-stack-sm tr,
  table.vs-stack-sm td {
    display: block;
    width: 100%;
  }

  table.vs-stack-sm tr {
    margin-bottom: 0.75rem;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--bs-border-color);
    border-radius: 0.5rem;
  }

  table.vs-stack-sm td {
    padding: 0.25rem 0;
    border: 0;
    text-align: start !important;
    white-space: normal !important;
  }

table.vs-stack-sm td[data-label]::before {
    display: block;
    content: attr(data-label);
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
  }
}

/* On a phone, the report's configured quarter/third-width cards leave KPI
   labels unreadable. Keep authored spans on wider screens and stack report
   columns in the screen preview; print/PDF keep the configured layout. */
@media screen and (max-width: 575.98px) {
  .vs-report .rep-grid > .rep-col {
    flex-basis: 100%;
  }
}
