/* unified-bundle.css: shared component layer + fontawesome-subset */
/* Единая дизайн-система для Property Management System */

/* ===== БАЗОВЫЙ RESET ===== */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-family: var(--font-family-sans);
  line-height: var(--line-height-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  scroll-behavior: smooth;
  scroll-padding-top: 0;
}

@media (max-width: 768px) {
  html {
    scroll-padding-top: 0;
  }
}

body {
  background-color: var(--surface-primary);
  color: var(--text-primary);
  font-size: var(--font-size-base);
  min-height: 100vh;
}

html {
  background: var(--bg-primary);
}

body {
  background-color: var(--bg-primary);
  color: var(--text-primary);
  margin: 0;
  padding: 0;
}

body.theme-loading * {
  transition: none !important;
  animation-duration: 0s !important;
}

/* #4 Fix: iOS Safari zoom prevention — inputs must have min 16px font-size */
input,
textarea,
select {
  font-size: var(--font-size-base, 16px);
}

/* Этаж целей нажатия (WCAG 2.5.5) переехал в `ds-components.css`, 22.09.2026.
   Здесь он не работал ни на что: медиазапрос специфичности не добавляет, блок
   стоял в начале файла, и его перебивало каждое более позднее правило с той же
   специфичностью — `.btn { min-height: var(--button-height-md) }` ниже в этом же
   файле давало 34 px, `.app-topbar__drawer` из app-shell.css — 36, кнопки тем —
   32. Замер на 375 px с эмуляцией касания: 178 из 207 интерактивных элементов
   были мельче 44 px при живом на вид правиле. Заодно снят голый `a`: ссылка
   внутри абзаца высотой 44 px разорвала бы текст (WCAG 2.5.8 их исключает). */

/* Базовые стили */
* {
  box-sizing: border-box;
  border-width: 0;
  border-style: solid;
  border-color: var(--border-color);
}

/* ===== ГЛОБАЛЬНЫЕ СТИЛИ ===== */
/* Floating Actions Menu moved to lower section */

/* Custom Confirmation Popup */
.confirm-popup {
  display: none;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--card-padding-md);
  box-shadow: var(--shadow-xl);
  z-index: 10000;
  width: 320px;
  flex-direction: column;
  gap: var(--space-lg);
  animation: fadeIn 0.2s ease;
  text-align: center;
}

.confirm-popup.visible {
  display: flex;
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Утилита скрытия элементов */
.hidden {
  display: none !important;
}

/* Skip-to-content link (WCAG) — скрыт, пока не в фокусе */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 9999;
  padding: 8px 16px;
  background: var(--button-primary-bg);
  color: var(--button-primary-text);
  text-decoration: none;
  border-radius: 0 0 8px 0;
  font-weight: 600;
}
.skip-link:focus {
  left: 0;
}

/* Современная типографика */
body {
  font-family: "Inter", sans-serif;
  font-feature-settings:
    "liga" 1,
    "calt" 1; /* Включаем лигатуры */
  line-height: var(--line-height-normal);
  color: var(--text-primary);
  background-color: var(--bg-primary);
  background-image: var(--subtle-noise),
    radial-gradient(
      1400px 700px at 20% -20%,
      rgba(var(--focus-ring-color-rgb), 0.35),
      transparent 80%
    ),
    linear-gradient(125deg, rgba(var(--primary-rgb), 0.12) 0%, transparent 60%);
  background-attachment: scroll;
  margin: 0;
  padding: 0;
  padding-top: max(env(safe-area-inset-top), 0px);
  padding-bottom: env(safe-area-inset-bottom, 0);
  padding-left: env(safe-area-inset-left, 0);
  padding-right: env(safe-area-inset-right, 0);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.main-wrapper {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background-color: transparent;
}

.main-wrapper > .main-content {
  min-height: 60vh;
}

.main-wrapper :is(h1, h2, h3, h4, h5, h6),
.main-wrapper [id] {
  scroll-margin-top: calc(var(--app-top-offset) + 0.75rem);
}

.container {
  max-width: 1280px; /* Немного шире */
  margin: 0 auto;
  padding: 0 0.5rem; /* Уменьшенные отступы */
}

/* ===== МИНИМАЛИСТИЧНЫЙ ДИЗАЙН ВЕРХНЕГО МЕНЮ ===== */

.app-menu-root {
  position: relative;
  z-index: 2100;
}

/* Unified top bar: brand button + quick strip as one element */
.app-header-bar {
  display: flex;
  align-items: stretch;
  border-radius: 8px;
  background: var(--glass-bg);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border: 1px solid var(--app-header-bar-border);
  box-shadow: 0 2px 16px rgba(2, 6, 23, 0.08);
  margin: 1rem 1rem 0;
}

.app-menu-toggle {
  position: static;
  width: 3.5rem;
  min-width: 3.5rem;
  height: 3.5rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: 0;
  border: none;
  border-radius: 8px 0 0 8px;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  z-index: auto;
  transition:
    background-color 0.22s ease,
    color 0.22s ease;
}

.app-menu-toggle:hover {
  color: var(--text-primary);
}

.app-menu-toggle:focus-visible,
.app-menu-close:focus-visible,
.nav-item:focus-visible,
.theme-toggle-btn:focus-visible {
  outline: 3px solid var(--focus-ring-color);
  outline-offset: 2px;
}

.app-menu-toggle[aria-expanded="true"] .app-menu-toggle-icon {
  transform: translateY(-1px) rotate(-6deg);
}

.app-menu-toggle:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.app-menu-toggle {
  color: var(--app-menu-toggle-color);
}

.app-menu-toggle:hover {
  color: var(--app-menu-toggle-hover-color);
}

.app-quick-strip {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-1);
  padding: var(--space-1) var(--space-1) var(--space-1) var(--space-2);
  height: 3.5rem;
  min-width: 0;
  border: none;
  border-radius: 0 8px 8px 0;
  background: transparent;
  box-shadow: none;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  overflow-x: auto;
  scrollbar-width: none;
  z-index: auto;
  transition:
    opacity 0.22s ease,
    transform 0.22s ease;
}

.admin-layout .app-menu-toggle {
}

.admin-layout .app-quick-strip {
}

/* Кольцо фокуса. Список селекторов расширен 17.08.2026.
   ------------------------------------------------------------------
   В нём не было `summary` — а на нём в этом продукте держится кнопка
   меню строки «…». Замер: «Финансы» 32 такие кнопки, «Приборы» 33,
   кабинет арендатора 4, и ни одна при обходе с клавиатуры никак себя не
   показывала. Туда же попали свёртки «показать ещё» и кнопка
   инструментов в верхней полосе.

   `[tabindex]` — для того, что сделали фокусируемым вручную: строки
   таблицы контрагентов (68 штук) и заголовки разделов в кабинете
   арендатора (7). Отрицательный `tabindex` сюда не попадает по смыслу
   `:focus-visible`: он даётся программно, а не с клавиатуры.

   WCAG 2.1, 2.4.7 (AA): у фокуса должен быть видимый признак. */
button:focus-visible,
a:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
[contenteditable="true"]:focus-visible,
[role="button"]:focus-visible {
  /* Кольцо рисуется `outline`, а не тенью, и это принципиально.
     Тенью его перебивала любая страница, которая украшает поле своей
     тенью: `.contractors-page .filters .filter-control` (0,3,0) сильнее
     общего правила (0,2,0), и на «Контрагентах» кольца не было вовсе.
     `outline` страницы не трогают, и он следует радиусу скругления.

     Непрозрачное: при 0,35 замер 17.08.2026 давал 1,56–1,94 к фону при
     норме 3,0 — признак фокуса формально был, а увидеть его было нельзя.
     Тот же цвет без прозрачности: 4,55–4,76 в светлой теме, 5,71–7,09 в
     тёмной. Цвет серый: кольцо не должно спорить с акцентом. */
  outline: 3px solid var(--focus-ring-color);
  outline-offset: 2px;
  border-color: var(--focus-ring-color);
}

/* То же правило, что в portal_base.css: полю кольцо ставится вплотную,
   иначе рядом с его собственной рамкой получается вторая. Кнопкам и
   ссылкам смещение оставлено. 24.08.2026 */
input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not(
    [type="submit"]
  ):focus-visible,
select:focus-visible,
textarea:focus-visible {
  outline-width: 2px;
  outline-offset: 0;
}

/* Обёртка содержимого — цель ссылки «Перейти к содержимому». Она
   фокусируемая (`tabindex="-1"`), но кольца ей не надо: обводить
   трёхпиксельной тенью всю страницу незачем, а факт перехода человек
   видит по прокрутке. Правило `[tabindex]:focus-visible` выше её бы
   поймало. */
#main-content:focus,
#main-content:focus-visible {
  outline: none;
  box-shadow: none;
}

/* `<summary>` рисует кольцо по своей коробке. У кнопки «…» коробка —
   сам значок, и тень по нему читается как кольцо вокруг кнопки только
   если она не прижата к краю ячейки. */
summary:focus-visible {
  border-radius: var(--radius-sm);
}

.app-quick-strip::-webkit-scrollbar {
  display: none;
}

.app-quick-strip.is-hidden {
  opacity: 0;
  transform: translateY(-8px);
  pointer-events: none;
}

.quick-nav-item {
  position: relative;
  min-height: 2.75rem;
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0;
  padding: var(--space-2) 0.75rem;
  border-radius: 6px;
  color: var(--text-secondary);
  text-decoration: none;
  transition:
    background-color 0.18s ease,
    color 0.18s ease,
    transform 0.18s ease,
    box-shadow 0.18s ease;
  overflow: visible;
}

.quick-nav-item {
  color: var(--quick-nav-item-color);
}

.quick-nav-item::after {
  content: "";
  position: absolute;
  left: 0.75rem;
  right: 0.75rem;
  bottom: 0.18rem;
  height: 2px;
  border-radius: 999px;
  background: transparent;
  transition:
    background-color 0.18s ease,
    opacity 0.18s ease;
  opacity: 0;
  display: none;
}

.quick-nav-item:hover {
  color: var(--secondary-900);
  background: var(--surface-hover);
  transform: translateY(-1px);
  box-shadow: none;
}

.quick-nav-item.active {
  color: var(--violet-600);
  background: rgba(var(--focus-ring-color-rgb), 0.1);
  box-shadow: none;
}

.quick-nav-item.active::after {
  background: var(--violet-600);
  opacity: 1;
}

.quick-nav-item i {
  font-size: var(--font-size-sm);
  color: inherit;
}

.quick-nav-text {
  display: none;
  font-size: var(--font-size-sm);
  font-weight: 600;
  line-height: 1;
  white-space: nowrap;
  max-width: none;
  overflow: visible;
  text-overflow: clip;
}

.quick-strip-tools {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding-left: var(--space-1);
  border-left: none;
  flex: 0 0 auto;
}

.app-menu-root.is-compact .app-quick-strip {
  display: none;
}

.quick-strip-tool {
  min-height: 2.75rem;
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) 10px;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  color: var(--text-secondary);
  text-decoration: none;
  cursor: pointer;
  font: inherit;
  transition:
    background-color 0.18s ease,
    color 0.18s ease,
    border-color 0.18s ease,
    transform 0.18s ease;
}

.quick-strip-tool:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
  border-color: var(--border-color);
  transform: translateY(-1px);
}

.quick-strip-tool-text {
  display: none;
  font-size: var(--font-size-xs);
  font-weight: 600;
  white-space: nowrap;
}

.quick-strip-avatar {
  width: 1.55rem;
  height: 1.55rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: rgba(var(--focus-ring-color-rgb), 0.14);
  /* Было `--primary-color`. В тёмной теме этот токен уходит в
     `--dark-primary-color`, и буква на полупрозрачной подложке давала
     контраст 1.90 при норме 4.5 — инициал не читался. Замер 16.08.2026.
     Берём текстовый токен: он и есть «цвет читаемого текста» в обеих темах. */
  color: var(--text-primary);
  font-size: var(--font-size-xs);
  font-weight: 700;
}

.quick-strip-profile-menu {
  position: relative;
  overflow: visible;
}

.quick-strip-profile-menu > summary,
.quick-strip-floating-menu > summary {
  list-style: none;
}

.quick-strip-profile-menu > summary::-webkit-details-marker,
.quick-strip-floating-menu > summary::-webkit-details-marker {
  display: none;
}

.quick-strip-profile-menu__trigger {
  cursor: pointer;
}

.quick-strip-profile-menu[open] .quick-strip-profile-menu__trigger {
  border-color: rgba(59, 130, 246, 0.28);
  background: rgba(59, 130, 246, 0.1);
}

.quick-strip-profile-menu__dropdown {
  /* 23.08.2026. Было `position: fixed` вместе с `top: calc(100% + 8px)`.
     У фиксированного элемента проценты считаются от ОКНА, а не от родителя,
     поэтому меню вставало на «высота окна + 8 px» — то есть на восемь
     пикселей ниже нижнего края экрана, и открыть его было нельзя. Правило
     писалось под `absolute`: родитель `.quick-strip-floating-menu` и так
     объявлен `position: relative`.
     Привязка к правому краю, а не к левому: кнопка профиля стоит справа,
     и меню, выровненное слева, уезжало бы за правый край окна. */
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  left: auto;
  max-width: min(20rem, calc(100vw - 1rem));
  min-width: 220px;
  padding: 8px;
  border-radius: 8px;
  border: 1px solid var(--color-border, rgba(148, 163, 184, 0.2));
  background: var(--color-bg-card);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.18);
  z-index: 120;
}

.app-quick-strip,
.quick-strip-tools {
  overflow: visible;
}

.quick-strip-profile-menu__meta {
  display: grid;
  gap: 2px;
  padding: 8px 10px 10px;
}

.quick-strip-profile-menu__email {
  font-size: var(--font-size-xs);
  color: var(--color-text-muted);
  overflow: hidden;
  text-overflow: ellipsis;
}

.quick-strip-profile-menu__item {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  padding: 10px;
  border-radius: 6px;
  color: var(--color-text-main);
  text-decoration: none;
  white-space: nowrap;
}

.quick-strip-profile-menu__item:hover {
  background: var(--color-bg-subtle, rgba(148, 163, 184, 0.12));
}

.app-brand-mark {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: 6px;
  background: linear-gradient(135deg, var(--violet-700), var(--blue-600));
  color: var(--text-inverse);
  font-size: var(--font-size-sm);
  font-weight: 800;
  letter-spacing: -0.03em;
  box-shadow: 0 8px 20px rgba(37, 99, 235, 0.22);
  flex: 0 0 auto;
}

.app-brand-lockup {
  display: inline-flex;
  align-items: center;
  gap: 10px;
}

.app-menu-toggle {
  min-width: auto;
}

.workspace-action-link--meta {
  opacity: 0.8;
  pointer-events: none;
  margin-bottom: 0.5rem;
  padding: 0.25rem 0;
}

.quick-strip-floating-menu {
  position: relative;
  flex: 0 0 auto;
}

.quick-nav-item--more i:last-child,
.quick-strip-tool--profile i:last-child {
  font-size: var(--font-size-xs);
  opacity: 0.7;
}

.quick-strip-more-menu__item.is-active {
  color: var(--primary-600);
  background: color-mix(
    in srgb,
    var(--primary-500) 10%,
    var(--surface-primary)
  );
}

.main-wrapper > .main-content {
  transition:
    filter 0.22s ease,
    opacity 0.22s ease;
}

body.app-menu-open .main-wrapper > .main-content {
  filter: blur(6px) saturate(0.86);
  opacity: 0.88;
}

.command-palette-backdrop {
  padding-top: calc(var(--app-top-offset) + 1rem);
}

.app-menu-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(15, 23, 42, 0.24);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.22s ease;
  z-index: 2140;
}

.app-menu-backdrop.is-visible {
  opacity: 1;
  pointer-events: auto;
}

.header-minimal {
  position: fixed;
  top: calc(1rem + 3.5rem + 0.6rem);
  left: 1rem;
  z-index: 2160;
  width: min(20rem, calc(100vw - 2rem));
  max-height: calc(100vh - 6rem);
  opacity: 0;
  pointer-events: none;
  transform: translate3d(0, -0.65rem, 0) scale(0.97);
  transform-origin: top left;
  transition:
    opacity 0.28s cubic-bezier(0.2, 0.8, 0.2, 1),
    transform 0.34s cubic-bezier(0.2, 0.8, 0.2, 1);
}

@media (max-width: 480px) {
  .header-minimal {
    max-height: calc(100dvh - 5.5rem);
    width: calc(100vw - 1rem);
    left: 0.5rem;
  }
}

.header-minimal.is-open {
  opacity: 1;
  pointer-events: auto;
  transform: translate3d(0, 0, 0) scale(1);
  overflow-y: auto;
}

.header-minimal.menu-locked,
.header-minimal.table-sticky-active {
  opacity: 0;
  pointer-events: none;
}

.header-minimal-shell {
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 10px;
  box-shadow: 0 26px 70px rgb(var(--shadow-color-rgb) / 0.24);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  overflow: hidden;
}

.header-minimal-shell {
  border-color: var(--header-minimal-shell-border);
}

.header-minimal-content {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: var(--space-4);
  max-width: 100%;
}

.app-menu-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
}

.logo-minimal {
  display: inline-flex;
  align-items: center;
  min-width: 0;
  color: var(--text-primary);
  font-weight: 600;
  font-size: var(--font-size-lg);
  cursor: default;
  user-select: none;
}

.logo-copy {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.logo-title {
  font-size: var(--font-size-base);
  font-weight: 700;
  line-height: var(--line-height-tight);
}

.logo-subtitle {
  font-size: var(--font-size-xs);
  color: var(--text-secondary);
  line-height: var(--line-height-tight);
}

.workspace-meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.workspace-meta-top {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.workspace-role-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 2px var(--space-2);
  border-radius: 999px;
  background: rgba(var(--focus-ring-color-rgb), 0.14);
  /* Был --primary-color: на собственной подложке бейджа (та же серая, 14 %)
     он даёт 4.49 при размере 10.88 px — на волосок ниже нормы. Замер
     12.08.2026. Вторичный текст на той же подложке — 9.1. */
  color: var(--text-secondary);
  font-size: var(--font-size-xs);
  font-weight: 700;
}

.workspace-switch-link {
  display: flex;
  align-items: center;
  width: 100%;
  border: none;
  background: transparent;
  color: var(--text-muted);
  font-size: var(--font-size-sm);
  min-height: 2.75rem;
  padding: 10px 14px;
  text-align: left;
  line-height: var(--line-height-tight);
  cursor: pointer;
  border-radius: 6px;
}

.workspace-switch-link:hover {
  color: var(--slate-800);
  background: var(--gray-50);
}

.workspace-section {
  border-top: 1px solid var(--border-color);
  padding-top: 14px;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.workspace-section-title {
  font-size: var(--font-size-xs);
  font-weight: 700;
  color: var(--text-secondary);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.workspace-theme-row {
  display: flex;
  gap: var(--space-2);
}

.workspace-theme-btn {
  flex: 1;
  border: 1px solid var(--button-secondary-border);
  background: var(--button-secondary-bg);
  color: var(--button-secondary-text);
  border-radius: 6px;
  min-height: 2.75rem;
  padding: var(--space-2) 0.75rem;
  font-size: var(--font-size-sm);
  font-weight: 600;
  line-height: var(--line-height-tight);
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
  box-shadow: var(--workspace-theme-btn-shadow);
  transition:
    background-color 0.18s ease,
    border-color 0.18s ease,
    color 0.18s ease,
    box-shadow 0.18s ease,
    transform 0.18s ease;
}

.workspace-theme-btn:hover {
  background: var(--button-secondary-bg-hover);
  border-color: var(--button-secondary-border-hover);
  transform: translateY(-1px);
  box-shadow: var(--workspace-theme-btn-hover-shadow);
}

.workspace-theme-btn.is-active {
  background: var(--button-primary-bg);
  border-color: var(--button-primary-border);
  color: var(--button-primary-text);
  box-shadow: var(--button-primary-shadow);
}

.workspace-action-link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 2.75rem;
  border-radius: 6px;
  border: 1px solid var(--workspace-action-link-border);
  background: var(--workspace-action-link-bg);
  color: var(--workspace-action-link-text);
  text-decoration: none;
  padding: var(--space-2) 14px;
  font-size: var(--font-size-sm);
  font-weight: 500;
  line-height: var(--line-height-tight);
}

.workspace-action-link:hover {
  background: var(--button-secondary-bg-hover);
  border-color: var(--button-secondary-border-hover);
  color: var(--text-primary);
}

.workspace-action-link.is-active {
  background: var(--workspace-action-link-active-bg);
  border-color: var(--workspace-action-link-active-border);
  color: var(--workspace-action-link-active-text);
}

/* W2.1: canonical form layer. Page-local copies stay in place until page waves. */
label {
  color: var(--text-primary);
}

.form-card {
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.form-section {
  margin-bottom: var(--space-xl);
}

.form-section:not(:last-child) {
  padding-bottom: var(--space-lg);
  border-bottom: 1px solid var(--border-color);
}

.form-grid,
.form-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: var(--space-lg);
}

.form-group {
  margin-bottom: var(--space-lg);
}

.form-label {
  display: block;
  margin-bottom: var(--space-sm);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  color: var(--text-secondary);
}

.form-label.required::after {
  content: "*";
  color: var(--status-error-text);
}

/* Голый `.required` красит элемент целиком — он заведён под звёздочку
   `<span class="required">*</span>`. Но подпись поля носит ОБА класса
   (`class="form-label required"`, так набраны 20 подписей в
   contracts_normalized и портале), и это правило, объявленное ниже
   `.form-label`, перекрашивало подпись целиком: «Подробности *» читалось
   как ошибка, хотя поле просто обязательное. Красной остаётся звёздочка
   `::after`, подпись живёт своим цветом. 23.08.2026 */
.required:not(.form-label) {
  color: var(--status-error-text);
}

.form-input,
.form-textarea {
  width: 100%;
  padding: var(--space-md);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-base);
  background: var(--input-bg);
  color: var(--text-primary);
  font: inherit;
  transition:
    border-color var(--transition-fast),
    box-shadow var(--transition-fast),
    background-color var(--transition-fast);
}

/* Подсказка в поле — это текст, и норма к ней та же 4,5. Правило было
   написано только под `.form-input`/`.form-textarea`, а половина полей
   в приложении носит общий класс `.filter-control` — они оставались на
   умолчании браузера `#757575`. Замер 17.08.2026: 3,74 в светлой теме
   на «Документах», 3,16 в тёмной, 4,22 на «Контрагентах». Ведём все
   поля на токен: `--text-muted` — это #475569 в светлой и slate-400 в
   тёмной, обе стороны проходят с запасом. 17.08.2026 */
input::placeholder,
textarea::placeholder,
.form-input::placeholder,
.form-textarea::placeholder,
.filter-control::placeholder {
  color: var(--text-muted);
}

/* ── наведение на поле: одинаково у всех четырёх систем ─────────────── */
/* Правило :hover было ровно у одной системы из четырёх — у .filter-control,
   и вело её на --border-color-strong, который в светлой теме СВЕТЛЕЕ рамки
   покоя (наведение гасило поле). Остальные 109 полей на наведение не
   отвечали ничем. Ведём все на --input-border-hover: светлая #334155 (8,4
   к заливке), тёмная slate-300 (12,0). Заливку при наведении не трогаем —
   её подмес давал 1,04 и был не виден. 23.08.2026 */
.form-input:not(:disabled):hover,
.form-textarea:not(:disabled):hover,
.theme-input:not(:disabled):hover,
select.form-select:not(:disabled):hover {
  border-color: var(--input-border-hover);
}

/* ── обязательное поле и поле с ошибкой: общий слой ─────────────────── */
/* Замер 23.08.2026: у 110 полей с атрибутом required видимой метки на
   самом поле не было; правило на ошибку существовало только в login.css.
   Метка — 3px янтарная полоса слева: приём конструктора документов
   (плашка «ОБЯЗАТЕЛЬНО»), распространённый на всю систему. Рисуем
   box-shadow'ом, а не рамкой: страничные правила задают border-color
   селекторами (0,2,0) и перебили бы её молча, а тень им не конкурент.
   Флажки, радио и file исключены — полоса ломает форму контрола. */
input[required]:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
select[required],
textarea[required] {
  box-shadow: inset 3px 0 0 var(--required-accent);
}

/* Комбобокс прячет исходный `select` и рисует своё поле
   (unified.js::initComboBoxes), поэтому полоса обязательности оставалась
   на невидимом элементе. Переносим её на видимую подмену: она лежит в том
   же родителе и носит атрибут `list`. Сам `required` на подмену НЕ
   копируем — у неё намеренно нет `name` (память
   visible-field-must-not-take-the-name), и своя валидация тут только
   помешает. Живые случаи: `tenant_id` и `owner_id` на
   /leases-normalized/create. 23.08.2026 */
:has(> select[data-ds-combobox-init="1"][required]) > input[list] {
  box-shadow: inset 3px 0 0 var(--required-accent);
}

/* Ошибка: обводка тенью + тонировка. :user-invalid не трогает поле, пока
   человек его не коснулся; .is-invalid ставят скрипты (как на /login). */
input.is-invalid,
select.is-invalid,
textarea.is-invalid,
[aria-invalid="true"],
input:user-invalid,
select:user-invalid,
textarea:user-invalid {
  box-shadow:
    inset 3px 0 0 var(--invalid-border),
    inset 0 0 0 1px var(--invalid-border);
  background-color: var(--invalid-bg);
}

.form-input:focus,
.form-textarea:focus {
  outline: 2px solid var(--focus-ring-color);
  outline-offset: 0;
  border-color: var(--focus-ring-color);
}

.form-textarea {
  min-height: 6.25rem;
  resize: vertical;
}

.form-help {
  margin-top: var(--space-xs);
  font-size: var(--font-size-xs);
  color: var(--text-muted);
}

.form-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: wrap;
  gap: var(--space-md);
  margin-top: var(--space-xl);
  padding-top: var(--space-lg);
  border-top: 1px solid var(--border-color);
}

@media (max-width: 768px) {
  .form-grid,
  .form-row {
    grid-template-columns: 1fr;
  }

  .form-actions {
    align-items: stretch;
    flex-direction: column;
  }
}

/* W2.2: canonical page chrome and navigation layer. */
/* Шапка страницы.

   Фиолетовый градиент во всю ширину был здесь значением по умолчанию, и
   от него постепенно уходили: сначала завели исключение
   `.home-page-header`, потом второе — `.page-header--hero`. Кто
   исключение не проставил, получал полосу градиента.

   Проверка 13.08.2026: класс остался всего на четырёх страницах, и на
   трёх из них — `/property-parties`, его карточка связи,
   `/properties-normalized/<id>` — по градиенту шёл тёмный текст
   (#0f172a на #7c3aed, контраст 2.7 при норме 4.5). Белый цвет из этого
   правила перебивался канонической окраской `.page-title`. То есть
   умолчание не использовалось правильно ни разу.

   Умолчание перевёрнуто: шапка обычная, градиент — по классу
   `.page-header--gradient` для того, кто сознательно его захочет.
   Исключения ниже оставлены: они больше ничего не переопределяют, но и
   не мешают, а удалять их вместе с этой правкой — значит смешивать две
   разные вещи в одном изменении. */
.page-header {
  padding: var(--space-2xl) 0;
  margin-bottom: var(--space-2xl);
}

.page-header--gradient {
  background: var(--gradient-primary);
  color: var(--text-inverse);
}
/* W9.5.g fix: page-header VARIANTS WITHOUT gradient (home-dashboard, 404 page-header--hero)
   have background: white/slate-50 → must NOT inherit white text-inverse (CR=1 on white-on-white).
   Override color + page-subtitle/section-kicker for these variant classes only. */
.page-header.home-page-header,
.page-header.page-header--hero {
  color: var(--text-primary);
}
.page-header.home-page-header .page-title,
.page-header.page-header--hero .page-title {
  color: var(--heading-primary-color);
}
.page-header.home-page-header .page-subtitle,
.page-header.page-header--hero .page-subtitle {
  color: var(--text-secondary);
  opacity: 1;
}
.page-header.page-header--hero .section-kicker {
  background: var(--primary-50);
  color: var(--primary-700);
}

.page-title {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-sm);
  margin: 0;
  font-size: clamp(1.75rem, 3vw, 2rem);
  font-weight: var(--font-weight-bold);
  line-height: var(--line-height-tight);
  color: inherit;
}

.page-subtitle {
  margin: var(--space-sm) 0 0;
  font-size: var(--font-size-lg);
  line-height: var(--line-height-normal);
  /* Белым он был потому, что шапка по умолчанию была фиолетовой полосой
     (см. `.page-header` выше). Полоса стала опцией — значит и белый
     текст должен переехать под неё, иначе на светлом фоне подзаголовок
     исчезает: белое по белому, контраст 1.0. Это не гипотеза: ровно так
     он и повёл себя на карточке объекта сразу после снятия градиента. */
  color: var(--text-secondary);
}

.page-header--gradient .page-title,
.page-header--gradient .page-subtitle {
  color: rgb(255 255 255 / 0.88);
}

.page-header--gradient .page-title {
  color: var(--text-inverse);
}

.breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-xs);
  margin-bottom: var(--space-lg);
  font-size: var(--font-size-sm);
  color: rgb(255 255 255 / 0.8);
}

.breadcrumb a {
  color: inherit;
  text-decoration: none;
}

.breadcrumb a:hover {
  color: var(--text-inverse);
  text-decoration: underline;
}

.header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-lg);
}

h1 {
  margin: 0 0 var(--space-md);
  font-size: clamp(1.75rem, 3vw, 2.25rem);
  line-height: var(--line-height-tight);
  color: var(--heading-primary-color);
}

.section-title {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin: 0 0 var(--space-md);
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-snug);
  color: var(--text-primary);
}

/* W2.3: canonical feedback and status layer. */

.alert {
  display: flex;
  align-items: flex-start;
  gap: var(--space-sm);
  padding: var(--space-md) var(--space-lg);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--surface-secondary);
  color: var(--text-primary);
}

/* 15.09.2026. Цвет текста переведён на тема-зависимые токены: в тёмной теме
   ступени 600/700 стоят на тонированном тёмном фоне и не читаются. Замер до:
   успех 3.07, ошибка 2.37 при норме 4.5 — сообщение об ошибке было почти
   невидимо. После: успех 6.49/8.82, ошибка 5.55/5.54, предупреждение
   4.58/6.48 (светлая/тёмная). */
.alert-success {
  background: color-mix(
    in srgb,
    var(--success-500) 12%,
    var(--surface-primary)
  );
  border-color: color-mix(in srgb, var(--success-600) 28%, var(--border-color));
  color: var(--success-text);
}

.alert-error {
  background: color-mix(in srgb, var(--danger-500) 12%, var(--surface-primary));
  border-color: color-mix(in srgb, var(--danger-600) 26%, var(--border-color));
  color: var(--alert-error-text);
}

/* Семья обрывалась на success/error, а `alert-warning` стоит в разметке семь
   раз (мониторинг админки, настройки пользователя) — предупреждение выходило
   нейтральной серой плашкой. */
.alert-warning {
  background: color-mix(
    in srgb,
    var(--warning-500) 12%,
    var(--surface-primary)
  );
  border-color: color-mix(in srgb, var(--warning-600) 28%, var(--border-color));
  color: var(--warning-text);
}

.loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  min-height: 8rem;
  padding: var(--space-2xl);
  text-align: center;
  color: var(--text-muted);
}

.error {
  padding: var(--space-lg);
  border: 1px solid
    color-mix(in srgb, var(--danger-600) 24%, var(--border-color));
  border-radius: var(--radius-md);
  background: color-mix(in srgb, var(--danger-500) 10%, var(--surface-primary));
  color: var(--danger-700);
}

.status-badge,
.status-active,
.status-inactive {
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 0.25rem 0.75rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-tight);
}

.status-badge {
  background: color-mix(in srgb, var(--surface-secondary) 92%, transparent);
  color: var(--text-primary);
  border-color: color-mix(in srgb, var(--border-color) 86%, transparent);
}

.status-active {
  background: color-mix(
    in srgb,
    var(--success-500) 14%,
    var(--surface-primary)
  );
  /* Тот же разбор, что у ссылок в portal_base.css: ступень шкалы
     одинакова в обеих темах, а парный токен — нет. */
  color: var(--status-success-text);
  border-color: color-mix(in srgb, var(--success-600) 24%, var(--border-color));
}

.status-inactive {
  background: color-mix(
    in srgb,
    var(--warning-500) 14%,
    var(--surface-primary)
  );
  color: var(--status-warning-text);
  border-color: color-mix(in srgb, var(--warning-600) 24%, var(--border-color));
}

.beta-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0.25rem 0.625rem;
  border-radius: 999px;
  background: var(--gradient-primary);
  color: var(--text-inverse);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-bold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  box-shadow: var(--shadow-sm);
}

/* W2.4: canonical card and data layout layer. */
.card-title {
  margin: 0;
  font-size: var(--font-size-lg);
  font-weight: var(--font-weight-semibold);
  line-height: var(--line-height-snug);
  color: var(--text-primary);
}

.info-section {
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--card-padding-md);
  box-shadow: var(--shadow-sm);
}

.info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: var(--space-md);
}

.info-label {
  margin-bottom: var(--space-xs);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-muted);
}

.info-value {
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  line-height: var(--line-height-normal);
  color: var(--text-primary);
}

.info-value.empty {
  color: var(--text-muted);
  font-style: italic;
}

.stat-card {
  background: var(--surface-secondary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-md);
  padding: var(--space-lg);
  box-shadow: var(--shadow-sm);
}

.filter-group {
  display: flex;
  flex-direction: column;
  gap: var(--space-xs);
}

@media (max-width: 768px) {
  .page-header {
    padding: var(--space-xl) 0;
    margin-bottom: var(--space-xl);
  }

  .page-title {
    font-size: clamp(1.5rem, 7vw, 1.875rem);
  }

  .page-subtitle {
    font-size: var(--font-size-base);
  }

  .header {
    align-items: stretch;
    flex-direction: column;
  }

  .info-grid {
    grid-template-columns: 1fr;
  }
}

.logo-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  background: var(--primary-color);
  border-radius: 8px;
  color: var(--text-inverse);
  transition: var(--transition);
}

.logo-minimal:hover .logo-icon {
  transform: rotate(10deg) scale(1.1);
  box-shadow: 0 4px 15px rgba(59, 130, 246, 0.4);
}

/* Theme Menu */

.theme-toggle-btn {
  width: 3rem;
  height: 3rem;
  border-radius: 8px;
  background: var(--button-secondary-bg);
  border: 1px solid var(--button-secondary-border);
  color: var(--text-primary);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: var(--transition);
}

.theme-toggle-btn:hover {
  background: var(--button-secondary-bg-hover);
  border-color: var(--button-secondary-border-hover);
  color: var(--violet-200);
  box-shadow: 0 10px 22px rgba(15, 23, 42, 0.2);
}

.theme-mode-btn.active {
  background: var(--surface-primary);
  color: var(--text-primary);
  box-shadow: var(--shadow-sm);
}

/* Анимация переключения темы */
.theme-transition,
.theme-transition *:not(.nav-item):not(.nav-item *) {
  transition:
    background-color 0.3s ease,
    color 0.3s ease,
    border-color 0.3s ease;
}

.nav-item {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3rem;
  padding: var(--space-3) var(--space-4);
  width: 100%;
  text-decoration: none;
  color: var(--text-secondary);
  font-weight: 500;
  font-size: var(--font-size-base);
  border-radius: 8px;
  border: 1px solid transparent;
  transition:
    background-color 0.18s ease,
    color 0.18s ease,
    border-color 0.18s ease,
    transform 0.38s cubic-bezier(0.2, 0.8, 0.2, 1),
    opacity 0.3s ease,
    filter 0.3s ease;
  position: relative;
  opacity: 0;
  transform: translateY(12px) scale(0.985);
  filter: blur(8px);
  transition-delay: calc(var(--menu-index, 0) * 34ms);
}

.nav-item::after {
  content: "";
  position: absolute;
  inset: auto auto auto 0.55rem;
  width: 0.2rem;
  height: calc(100% - 1.1rem);
  border-radius: 999px;
  background: transparent;
  transition: background-color 0.18s ease;
}

.nav-item svg {
  width: 16px;
  height: 16px;
  stroke-width: 2;
  color: var(--text-secondary);
  transition: color 0.18s ease;
  position: relative;
  z-index: 1;
}

.nav-item i.fas,
.nav-item i.far,
.nav-item i.fab {
  font-size: var(--font-size-base);
  color: var(--text-secondary);
  transition: color 0.18s ease;
  position: relative;
  z-index: 1;
  display: inline-block;
  visibility: visible;
  opacity: 1;
  transform: none;
  filter: none;
  animation: none;
}

.nav-item:hover {
  color: var(--text-primary);
  background: var(--surface-hover);
  border-color: var(--border-color-strong);
  transform: translateX(2px);
}

.nav-item:hover i.fas,
.nav-item:hover i.far,
.nav-item:hover i.fab,
.nav-item.active i.fas,
.nav-item.active i.far,
.nav-item.active i.fab {
  color: var(--text-primary);
  display: inline-block;
  visibility: visible;
  opacity: 1;
  transform: none;
  filter: none;
  animation: none;
}

.nav-item:hover svg {
  color: var(--primary-color);
}

.nav-item.active,
.nav-item[aria-current="page"] {
  color: var(--primary-color);
  background: rgba(var(--focus-ring-color-rgb), 0.1);
  border-color: var(--border-color-strong);
  font-weight: 600;
}

.nav-item.active::after,
.nav-item[aria-current="page"]::after {
  background: var(--primary-color);
}

.nav-item.active svg,
.nav-item[aria-current="page"] svg {
  color: var(--primary-color);
}

.header-minimal.is-open .nav-item,
.header-minimal.is-open .app-menu-utility-row,
.header-minimal.is-open .env-badge {
  opacity: 1;
  transform: none;
  filter: none;
}

.app-menu-close {
  width: 2.75rem;
  height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
  border: 1px solid var(--border-color);
  background: var(--surface-primary);
  color: var(--text-secondary);
  cursor: pointer;
  transition:
    background-color 0.18s ease,
    color 0.18s ease,
    border-color 0.18s ease;
}

.app-menu-close:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
  border-color: var(--border-color-strong);
}

.ds-modal-close-btn {
  border-radius: 6px;
  border: 1px solid transparent;
  transition:
    background-color 0.16s ease,
    color 0.16s ease,
    border-color 0.16s ease,
    transform 0.16s ease;
}

.ds-modal-close-btn:hover {
  background: var(--modal-close-hover-bg);
  border-color: var(--modal-close-hover-border);
  color: var(--modal-close-hover-text);
  transform: scale(1.04);
}

.modal-esc-hint {
  display: inline-flex;
  align-items: center;
  color: var(--text-muted);
}

.main-wrapper > .main-content {
  flex: 1;
  padding: 0 0 1.5rem;
}

body.app-menu-open {
  overflow: hidden;
}

body.app-menu-open .main-wrapper {
  pointer-events: none;
}

body.app-menu-open .app-menu-root,
body.app-menu-open #app-menu-panel,
body.app-menu-open #app-menu-backdrop {
  pointer-events: auto;
}

/* Tooltip эффекты */
.nav-item[data-tooltip]:hover::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: -2.75rem;
  left: 50%;
  transform: translateX(-50%);
  background: var(--bg-secondary);
  color: var(--text-primary);
  padding: 0.5rem 1rem;
  border-radius: 0.5rem;
  font-size: var(--font-size-sm);
  font-weight: 500;
  white-space: nowrap;
  opacity: 0;
  animation: tooltipFadeIn 0.2s ease 0.1s forwards;
  z-index: 1001;
  box-shadow: var(--card-shadow);
  border: 1px solid var(--border-color);
}

@keyframes tooltipFadeIn {
  from {
    opacity: 0;
    transform: translateX(-50%) translateY(-5px);
  }
  to {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
  }
}

/* Иконка профиля пользователя */

/* Floating Menu - Standardized Centered Vertical Box */
.floating-menu {
  display: none;
  position: fixed;
  top: auto;
  left: 50%;
  bottom: 16px;
  right: auto;
  transform: translateX(-50%);
  background-color: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: 6px;
  padding: 8px 0;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  z-index: 99999;
  flex-direction: column;
  min-width: 240px;
  width: auto;
  animation: fadeIn 0.1s ease;
  overflow-y: auto;
  overflow-x: hidden;
  height: auto;
  max-height: 80vh;
  box-sizing: border-box;
}

.floating-menu.visible {
  display: flex;
}

.floating-menu-backdrop {
  display: none;
  position: fixed;
  inset: 0;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
  z-index: 99998;
  background-color: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  pointer-events: none;
  margin: 0;
  padding: 0;
  transform: none;
}

.floating-menu-backdrop.visible {
  display: block;
}

.floating-menu-header {
  padding: 8px 16px;
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border-color);
  margin-bottom: 4px;
  white-space: nowrap;
  width: 100%;
  box-sizing: border-box;
  text-align: left;
}

.floating-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  background: transparent;
  border: none;
  border-radius: 0;
  color: var(--text-primary);
  font-size: var(--font-size-sm);
  font-weight: 500;
  cursor: pointer;
  transition: background-color 0.2s;
  width: 100%;
  text-align: left;
  text-decoration: none;
  box-sizing: border-box;
}

.floating-menu-item:hover {
  background: var(--surface-hover);
  color: var(--primary-color);
  text-decoration: none;
}

.floating-menu-item.danger {
  color: var(--danger-text);
}

.floating-menu-item.danger:hover {
  background: var(--color-danger-light);
  color: var(--danger-text);
}

@media (max-width: 768px) {
  .floating-menu {
    top: auto;
    left: 50%;
    right: auto;
    bottom: 12px;
    transform: translateX(-50%);
    width: min(95vw, 420px);
    max-height: 60vh;
    border-radius: 6px;
  }

  .floating-menu-item {
    min-height: 44px;
    font-size: var(--font-size-base);
  }
}

/* Custom Confirmation Popup */
.confirm-popup {
  display: none;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--card-padding-md);
  box-shadow: var(--shadow-xl);
  z-index: var(--z-modal);
  width: 320px;
  flex-direction: column;
  gap: var(--space-lg);
  animation: fadeIn 0.2s ease;
}

.confirm-popup.visible {
  display: flex;
}

.confirm-text {
  font-size: var(--font-size-base);
  color: var(--text-primary);
  text-align: center;
  margin-bottom: 8px;
}

.confirm-actions {
  display: flex;
  gap: 12px;
  justify-content: center;
}

@keyframes slideUp {
  from {
    opacity: 0;
    transform: translate(-50%, 20px);
  }
  to {
    opacity: 1;
    transform: translate(-50%, 0);
  }
}

@keyframes fadeIn {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

.page-container {
  max-width: 1280px;
  margin: 0 auto;
}

.panel-soft {
  background: var(--panel-muted-bg);
  border: 1px solid var(--panel-muted-border);
  box-shadow: var(--panel-muted-shadow);
  border-radius: var(--radius-md);
}

.full-width-section {
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: var(--card-padding-sm);
  box-shadow: var(--shadow-sm);
}

.filters {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-bottom: 16px;
  width: 100%;
}

/* Ensure form inside filters also behaves as a flex container */
.filters > form {
  display: flex;
  flex-direction: column;
  gap: 12px;
  width: 100%;
}

.filters .form-group {
  width: 100%;
}

.filters .form-group label {
  display: block;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  margin-bottom: 6px;
}

/* Make inputs full width on mobile by default */
.filters .form-group input,
.filters .form-group select {
  width: 100%;
  box-sizing: border-box;
}

/* Wide screen styles (Row layout with scroll) */
@media (min-width: 1024px) {
  .filters {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-end;
    overflow-x: visible;
  }

  .filters > form {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: flex-end;
    min-width: 0;
    width: 100%;
  }

  .filters .form-group {
    width: auto;
    flex: 1 1 220px;
    min-width: 220px;
  }

  .filters .form-group.ds-filter-reset {
    flex: 0 0 auto;
    min-width: auto;
    width: auto;
    margin-left: auto;
  }

  .filters .form-group:first-child {
    min-width: 320px;
    flex-basis: 320px;
  }

  .filters .form-group input[type="text"] {
    min-width: 0;
  }
}

#prop-reset-x {
  width: 40px;
  min-width: 40px;
  padding-left: 0;
  padding-right: 0;
}

#contractor-reset-x {
  width: 40px;
  min-width: 40px;
  padding-left: 0;
  padding-right: 0;
}

.filter-control {
  width: 100%;
  background-color: var(--input-bg);
  color: var(--text-primary);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-base);
  padding: 10px 12px;
  font-size: var(--font-size-sm);
  transition:
    background-color var(--transition-fast),
    border-color var(--transition-fast),
    box-shadow var(--transition-fast);
}

.filter-control:not(:disabled):hover {
  border-color: var(--border-color-strong);
  background-color: var(--surface-secondary);
}

.filter-control:focus {
  outline: 2px solid var(--focus-ring-color);
  outline-offset: 0;
  border-color: var(--focus-ring-color);
}

select.filter-control {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding-right: 2.5rem;
  background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
    linear-gradient(135deg, currentColor 50%, transparent 50%);
  background-position:
    calc(100% - 1rem) calc(50% - 0.15rem),
    calc(100% - 0.7rem) calc(50% - 0.15rem);
  background-size:
    0.4rem 0.4rem,
    0.4rem 0.4rem;
  background-repeat: no-repeat;
  cursor: pointer;
}

select.filter-control:disabled {
  cursor: not-allowed;
  opacity: 0.65;
}

.ds-date-wrapper {
  position: relative;
}

.ds-date-wrapper input[data-ds-date="1"] {
  padding-right: 2.5rem;
}

.ds-date-trigger {
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  border: 0;
  background: transparent;
  color: var(--text-secondary);
  cursor: pointer;
  font-size: var(--font-size-base);
  line-height: 1;
  padding: 4px 6px;
}

.ds-date-picker {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

.table-container {
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  overflow-x: auto;
  overflow-y: hidden;
  box-shadow: var(--shadow-sm);
}

/* Table cell overflow protection — allow wrapping instead of truncation */
.table td {
  word-break: break-word;
  overflow-wrap: break-word;
  white-space: normal;
  min-width: 80px;
}

/* Theme text classes for consistent modal styling */
.text-main-theme {
  color: var(--color-text-main);
}

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

.text-muted-theme {
  color: var(--text-muted);
  font-weight: 400;
}

/* Замер 13.08.2026: продолжение правки от 12.08, которая закрыла h4..h6 и
   не тронула верх шкалы. h1, h2 и h3 размера не получали — их рисовал
   браузер: 2em, 1.5em и 1.17em, то есть 32 / 24 / 18.72 px. В шаблонах
   39 h1, 72 h2 и 137 h3. Лестница замыкается: 30 / 24 / 20 / 18 / 16 / 16. */
h1 {
  color: var(--heading-primary-color);
  font-size: var(--font-size-3xl);
  font-weight: 600;
}

h2 {
  color: var(--heading-secondary-color);
  font-size: var(--font-size-2xl);
  font-weight: 600;
}

h3 {
  color: var(--heading-secondary-color);
  font-size: var(--font-size-xl);
  font-weight: 600;
}

/* Замер 13.08.2026: тег `small` размера не получал — браузер даёт ему
   83.33 % от родителя. На /admin/invitations/manage это 62 узла по
   13.33 px, на /admin/workspaces — 11.67 px (small внутри 14 px). Ещё
   одно дробное значение из ниоткуда; в шаблонах 54 тега. */
small {
  font-size: var(--font-size-xs);
}

/* Замер 12.08.2026: размеры заголовкам в системе не назначались вовсе —
   h1..h6 брали размер у браузера, где h5 = 0.83em, а h6 = 0.67em. При
   базовых 16 px это 13.28 и 10.72 — то есть заголовок был МЕЛЬЧЕ обычного
   текста и отличался от него только жирностью. На /api/commercial_properties/
   так набраны заголовки карточек «Фильтры» и «Список объектов»; всего в
   шаблонах 46 тегов h6 и 38 h5. Эталон /admin даёт для заголовка карточки
   16 px / 600 — к нему и приводим. */
h4 {
  color: var(--heading-secondary-color);
  font-size: var(--font-size-lg);
  font-weight: 600;
}

h5,
h6 {
  color: var(--heading-secondary-color);
  font-size: var(--font-size-base);
  font-weight: 600;
}

/* Highlight labels for field names in both themes */
.text-highlight-label {
  color: var(--text-highlight-color);
}

/* Theme input classes for consistent modal styling */
.theme-input {
  background-color: var(--input-bg);
  color: var(--text-primary);
  border: 1px solid var(--input-border);
  border-radius: var(--radius-base);
  padding: 8px 12px;
  transition: all 0.2s ease;
}

.theme-input:focus {
  background-color: var(--surface-primary);
  border-color: var(--focus-ring-color);
  outline: 2px solid var(--focus-ring-color);
  outline-offset: 0;
}

input[type="checkbox"],
.form-check-input {
  accent-color: var(--color-primary);
  border: 1.5px solid var(--form-check-border);
  background: var(--surface-primary);
  box-shadow: inset 0 0 0 1px rgb(var(--shadow-color-rgb) / 0.08);
}

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

.form-check-label {
  color: var(--text-primary);
}

.table input[type="checkbox"] {
  width: 24px;
  height: 24px;
}

input[type="checkbox"]:checked {
  background-color: var(--primary-color);
  border-color: var(--primary-color);
}

input[type="checkbox"]:focus-visible {
  /* Прозрачность 0,55 давала 2,12 к белому фону при норме 3,0. Ведём на
     общий токен, как и остальные кольца. 17.08.2026 */
  outline: 2px solid var(--focus-ring-color);
  outline-offset: 2px;
}

.table {
  width: 100%;
  border-collapse: collapse;
  color: var(--text-primary);
}

.table th {
  text-align: left;
  background: var(--surface-tertiary);
  color: var(--text-secondary);
  /* 13.08.2026, канон шапки таблицы: 12 / 700 / обычный регистр / 0.02em.
     Замер дал четыре вида на семь таблиц; прописные для кириллицы читаются
     хуже строчных, поэтому канон без них. Размер меньше основного текста —
     шапка не должна спорить с содержимым. */
  font-weight: 700;
  font-size: var(--font-size-xs);
  letter-spacing: 0.02em;
  padding: 12px;
  border-bottom: 1px solid var(--border-color);
  white-space: nowrap;
}

.table thead th {
  top: auto;
  z-index: auto;
  background: var(--surface-tertiary);
}

.table.table-sticky thead th {
}

.ds-sticky-table-head.is-visible {
  display: block;
}

.table td {
  padding: 12px;
  border-bottom: 1px solid var(--border-color);
}

.table tr:hover td {
  background: var(--surface-hover);
}

/* ==========================================================================
   Цвет кнопки — через собственные токены `--btn-*`, а не через специфичность
   --------------------------------------------------------------------------
   Было: умолчание нейтральной кнопки записывалось цепочкой
   `.btn:not(.btn-primary):not(.btn-secondary)…` из четырнадцати имён. Цепочка
   работала РЕЕСТРОМ: её специфичность 0,9,0 против 0,1,0 у любого `.btn-*`,
   поэтому вариант, не вписанный в неё, молча получал чужие фон и цвет. Так
   не существовали `.btn-outline-primary` (16 мест в разметке) и `.btn-warning`,
   и так же умирал бы каждый следующий вариант. Дефект было почти не увидеть:
   рамку цепочка не задавала, и кнопка выглядела «просто блёклой».

   Стало: `.btn` объявляет шесть переменных со значениями нейтральной кнопки и
   красится ими. Вариант переопределяет ТОЛЬКО переменные — специфичность у
   всех одна, война выиграна тем, что войны больше нет, а наведение
   автоматически следует за вариантом. Реестр не нужен: новый вариант работает
   сразу, ничего нигде не дописывая.

   Два правила при добавлении варианта:
   1. в `.btn-*` не писать `background` / `color` / `border-color` напрямую —
      только `--btn-bg`, `--btn-fg`, `--btn-bd` и их `-hover`;
   2. объявления переменных должны стоять ПОСЛЕ этого блока (он их задаёт по
      умолчанию и при равной специфичности побеждает всё, что выше).
   ========================================================================== */
.btn {
  --btn-bg: var(--button-secondary-bg);
  --btn-fg: var(--button-secondary-text);
  --btn-bd: var(--button-secondary-border);
  --btn-bg-hover: var(--button-secondary-bg-hover);
  --btn-fg-hover: var(--btn-fg);
  --btn-bd-hover: var(--button-secondary-border-hover);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--button-gap);
  min-height: var(--button-height-md);
  padding: var(--button-padding-y) var(--button-padding-x);
  border-radius: var(--radius-base);
  border: 1px solid var(--btn-bd);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-weight: 600;
  font-size: var(--font-size-sm);
  line-height: var(--line-height-tight);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition:
    background-color var(--transition),
    color var(--transition),
    border-color var(--transition),
    box-shadow var(--transition),
    transform var(--transition-fast);
}

/* Телефон (≤480): кнопка не шире своего контейнера, надпись переносится.
   Замер 03.10.2026 на 320–430 px: в узких рядах кнопки с `nowrap`
   («Сменить пароль», «Сбросить фильтры», «Отправить показания», подвалы
   окон) вылезали за карточку на 7–60 px на десятке страниц. На широком
   окне кнопки по-прежнему в одну строку. */
@media (max-width: 480px) {
  .btn {
    max-width: 100%;
    white-space: normal;
    text-align: center;
  }
}

.btn-sm {
  min-height: var(--button-height-sm);
  padding: var(--space-xs) var(--space-md);
  font-size: var(--font-size-sm);
}

/* 15.09.2026. `btn-xs` стоит в разметке семь раз, а правила размера у него не
   было вовсе — только правила зоны касания. Кнопка выходила обычной. */
.btn-xs {
  min-height: var(--button-height-xs);
  padding: 2px var(--space-sm);
  font-size: var(--font-size-xs);
}

.btn-ghost {
  --btn-bg: var(--button-ghost-bg);
  --btn-fg: var(--button-ghost-text);
  --btn-bd: var(--button-ghost-border);
  --btn-bg-hover: var(--button-ghost-bg-hover);
  --btn-fg-hover: var(--text-primary);
  --btn-bd-hover: var(--button-ghost-border);
  box-shadow: none;
}

.btn:disabled,
.btn[disabled],
.btn.disabled {
  opacity: 0.6;
  cursor: not-allowed;
  pointer-events: none;
}

.btn:hover {
  background: var(--btn-bg-hover);
  color: var(--btn-fg-hover);
  border-color: var(--btn-bd-hover);
  text-decoration: none;
}

.btn:focus-visible {
  outline: 3px solid var(--focus-ring-color);
  outline-offset: 2px;
}

.btn-primary {
  --btn-bg: var(--button-primary-bg);
  --btn-bd: var(--button-primary-border);
  --btn-fg: var(--button-primary-text);
  --btn-bg-hover: var(--button-primary-bg-hover);
  --btn-bd-hover: var(--button-primary-bg-hover);
}

.btn-primary:hover {
  box-shadow: var(--button-primary-shadow);
  transform: translateY(-1px);
}

.btn-primary:active {
  background: var(--button-primary-bg-active);
  border-color: var(--button-primary-bg-active);
  box-shadow: 0 6px 12px rgba(124, 58, 237, 0.2);
  transform: translateY(0);
}

/* Нейтральная кнопка уже описана в `.btn`; `.btn-secondary` оставлен как
   явное имя для разметки и повторяет её значения. */
.btn-secondary {
  --btn-bg: var(--button-secondary-bg);
}

.btn-outline-secondary {
  --btn-bg: transparent;
}

.btn-outline-danger {
  --btn-bg: transparent;
  --btn-bd: var(--button-danger-border);
  /* --button-danger-bg — цвет ЗАЛИВКИ, на нём стоит белый. Здесь он служит
     текстом на фоне страницы, и в тёмной теме давал 3.77. */
  --btn-fg: var(--danger-text);
  --btn-bg-hover: rgba(var(--danger-rgb), 0.12);
  --btn-bd-hover: var(--button-danger-border);
  --btn-fg-hover: var(--text-primary);
}

/* 15.09.2026. Семья контурных кнопок обрывалась на danger, хотя
   `.btn-outline-warning` и `.btn-outline-success` ставит documents_review.js
   (индикатор уверенности и кнопка «Сверить · N расхождений» на карточке
   разбора) и `admin/ocr_quarantine.html`, а `.btn-outline-info` до сих пор жил
   только внутри `.documents-review-entity-card`. Без правил все они
   проваливались до голого `.btn` и выглядели одинаковой нейтральной кнопкой —
   «Пометить решено» не отличалось от «Отменить». Цвет — из `--*-text`,
   подобранных замером контраста (см. variables.css).
   Прозрачность — через `rgba(var(--x), a)`: значения `--*-rgb` записаны через
   запятую, слэш-синтаксис их убивает. */
.btn-outline-warning {
  --btn-bg: transparent;
  --btn-bd: var(--warning-text);
  --btn-fg: var(--warning-text);
  --btn-bg-hover: rgba(var(--warning-rgb), 0.12);
  --btn-bd-hover: var(--warning-text);
  --btn-fg-hover: var(--text-primary);
}

.btn-outline-success {
  --btn-bg: transparent;
  --btn-bd: var(--success-text);
  --btn-fg: var(--success-text);
  --btn-bg-hover: rgba(var(--success-rgb), 0.12);
  --btn-bd-hover: var(--success-text);
  --btn-fg-hover: var(--text-primary);
}

.btn-outline-info {
  --btn-bg: transparent;
  --btn-bd: var(--info-text);
  --btn-fg: var(--info-text);
  --btn-bg-hover: rgba(var(--info-rgb), 0.12);
  --btn-bd-hover: var(--info-text);
  --btn-fg-hover: var(--text-primary);
}

.btn-link {
  --btn-bg: transparent;
  --btn-bd: transparent;
  --btn-fg: var(--primary-color);
  --btn-bg-hover: transparent;
  --btn-bd-hover: transparent;
  --btn-fg-hover: var(--color-primary-hover);
  text-decoration: none;
}

.btn-link:hover {
  text-decoration: none;
}

.btn-danger {
  --btn-bg: var(--button-danger-bg);
  --btn-bd: var(--button-danger-border);
  --btn-fg: var(--button-danger-text);
  --btn-bg-hover: var(--button-danger-bg-hover);
  --btn-bd-hover: var(--button-danger-bg-hover);
}

.btn-icon {
  flex: 0 0 auto;
  width: var(--button-height-md);
  min-width: var(--button-height-md);
  padding-inline: 0;
}

.btn-icon.btn-sm {
  width: var(--button-height-sm);
  min-width: var(--button-height-sm);
}

.btn-icon.btn-lg {
  width: var(--button-height-lg);
  min-width: var(--button-height-lg);
}

.btn-icon-round {
  border-radius: 999px;
}

.btn-archive-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--button-gap);
  min-height: var(--button-height-md);
  padding: var(--button-padding-y) var(--button-padding-x);
  border-radius: var(--radius-base);
  background: var(--button-secondary-bg);
  border: 1px solid var(--button-secondary-border);
  color: var(--button-secondary-text);
  font-weight: 600;
  font-size: var(--font-size-sm);
  cursor: pointer;
  transition:
    background-color var(--transition),
    color var(--transition),
    border-color var(--transition);
}

.btn-archive-toggle:hover {
  background: var(--button-secondary-bg-hover);
  border-color: var(--button-secondary-border-hover);
}

/* Общая карточка берёт СВОИ токены.
   ---------------------------------------------------------------------
   Здесь стояли `--surface-primary` / `--border-color` / `--shadow-sm` —
   токены страницы, а не карточки. В светлой теме разницы нет:
   `--card-bg` там объявлен псевдонимом `--surface-primary`. А в тёмной
   у карточки свои значения (`#1e293b`, `#334155`, двойная тень) —
   заведены 16.08.2026 намеренно, чтобы карточка была светлее страницы.

   Из-за неверного токена общий `.card` этого подъёма не получал, и на
   экране выходило так (замер 17.08.2026, тёмная тема):

     «Сегодня»    #1e293b — свой класс `.today-card` берёт `--card-bg`
     «Приборы»    #151c25 — общий `.card`, на тон темнее
     «Документы»  #151c25 при 96% непрозрачности

   Один и тот же класс, три оттенка. Правильный не тот, что чаще
   встречается, а тот, для которого токен и заведён. 17.08.2026 */
.card {
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--radius-lg);
  box-shadow: var(--card-shadow);
}

.card-header {
  padding: var(--space-md) var(--card-padding-sm);
  border-bottom: 1px solid var(--border-color);
  background: var(--surface-secondary);
  color: var(--text-primary);
  font-weight: 600;
}

.card-body {
  padding: var(--card-padding-sm);
  color: var(--text-primary);
}

.card-body--md {
  padding: var(--card-padding-md);
}

.filter-control-compact {
  padding: 8px 12px;
  height: 36px;
}

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

.ds-toolbar-title {
  /* С 16.08.2026 это `h2`, а не `div` — гасим браузерные умолчания
     (1.5em и внешние отступы), иначе заголовок раздела становится
     крупнее заголовка страницы. */
  margin: 0;
  font-size: var(--font-size-base);
  line-height: var(--line-height-tight);
  font-weight: 600;
  color: var(--text-primary);
}

.ds-toolbar-actions {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}

.ds-empty {
  text-align: center;
  padding: 48px 16px;
  border: 1px dashed var(--border-color);
  border-radius: var(--radius-lg);
  background: var(--surface-secondary);
  /* 19.08.2026. Компонент не объявлял собственного начертания и
     наследовал его у страницы: в админке, где контейнер набран
     полужирным, пояснение под заголовком выходило ТЯЖЕЛЕЕ самого
     заголовка (600 против 500). Общий компонент обязан задавать свою
     типографику, иначе он выглядит по-разному на каждой странице. */
  font-weight: var(--font-weight-normal, 400);
}

.ds-empty > i {
  display: inline-flex;
  justify-content: center;
  width: 100%;
  color: var(--text-muted);
  /* Значок задуман бледным: в макросе стоял класс `text-gray-300`, но
     этой утилиты в собранном наборе нет (см. память про мёртвые
     Tailwind-классы), и значок 48 px рисовался цветом обычного текста —
     тёмным пятном над заголовком. Прозрачность работает в обеих темах и
     не зависит от того, собрана утилита или нет. 19.08.2026 */
  opacity: 0.35;
}

.ds-empty-description {
  margin: 0.75rem auto 0;
  max-width: 34rem;
  color: var(--text-muted);
  font-weight: var(--font-weight-normal, 400);
  line-height: var(--line-height-normal);
}

.ds-empty-actions {
  margin-top: 1rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  flex-wrap: wrap;
}

.ds-empty-help {
  margin-top: 0.75rem;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--primary-color);
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-decoration: none;
}

.ds-empty-help:hover,
.ds-empty-help:focus-visible {
  text-decoration: underline;
}

.ds-empty.hidden {
  display: none;
}

.ds-loading {
  display: flex;
  justify-content: center;
  padding: 48px 16px;
}

.ds-loading.hidden {
  display: none;
}

.ds-breadcrumbs {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin: 10px 0 18px;
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
}

.ds-breadcrumbs-link {
  color: var(--text-secondary);
  text-decoration: none;
  border-radius: 8px;
  padding: 4px 6px;
}

.ds-breadcrumbs-link:hover {
  background: var(--surface-hover);
  color: var(--text-primary);
}

.ds-breadcrumbs-sep {
  opacity: 0.6;
}

.ds-breadcrumbs-current {
  color: var(--text-primary);
  font-weight: 600;
}

@media (max-width: 768px) {
  body {
    overflow-x: clip;
  }

  .main-wrapper,
  .main-content,
  .page-container,
  .container-fluid,
  .container {
    min-width: 0;
    max-width: 100%;
  }

  .main-content {
    overflow-x: clip;
  }

  .app-menu-root.is-compact .app-quick-strip {
    display: none;
  }

  .header-minimal {
    width: calc(100vw - 1.5rem);
    top: calc(0.75rem + 3.25rem + 0.55rem);
    left: 0.75rem;
  }

  .app-header-bar {
    display: inline-flex;
    width: fit-content;
    max-width: calc(100vw - 1rem);
    margin: 0.5rem 0.5rem 0;
  }

  .app-menu-toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    width: auto;
    width: 3rem;
    min-width: 3rem;
    height: 3rem;
    padding: 0 var(--space-3);
  }

  .app-menu-backdrop.is-visible {
    background: rgba(15, 23, 42, 0.54);
  }

  .app-quick-strip {
    height: 3.25rem;
    gap: var(--space-1);
    padding: 0;
    border-radius: 0 8px 8px 0;
  }

  .quick-nav-item {
    height: 2.55rem;
    padding: 0 10px;
    gap: 6px;
  }

  .header-minimal-content {
    height: 100%;
    max-height: calc(100dvh - 1rem);
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: 1rem;
    gap: 14px;
  }

  .workspace-meta {
    padding-bottom: var(--space-1);
  }

  .workspace-section--nav {
    flex: 1 1 auto;
  }

  .workspace-section--nav .workspace-action-link {
    min-height: 3rem;
    padding: 6px 14px;
    border-color: color-mix(
      in srgb,
      var(--primary-500) 12%,
      var(--border-color)
    );
    background: color-mix(in srgb, var(--surface-secondary) 92%, transparent);
  }

  .workspace-section--nav .workspace-action-link.is-active {
    background: color-mix(
      in srgb,
      var(--primary-500) 16%,
      var(--surface-primary)
    );
    border-color: color-mix(
      in srgb,
      var(--primary-500) 30%,
      var(--border-color)
    );
  }

  .workspace-section--profile {
    margin-top: auto;
    padding-bottom: var(--space-1);
  }

  .workspace-switch-link {
    min-height: 2.85rem;
    padding: var(--space-2) 0;
  }

  .workspace-theme-btn {
    min-height: 2.85rem;
  }

  .quick-strip-profile-menu__dropdown {
    /* И на узком экране держимся правого края: кнопка профиля там же. */
    right: 0;
    left: auto;
    min-width: 200px;
  }

  .header-minimal-shell {
    height: 100%;
    max-height: 100%;
    border-radius: 10px;
    box-shadow: 0 28px 64px rgba(15, 23, 42, 0.34);
  }

  .header-minimal {
    top: 0.5rem;
    left: 0.5rem;
    width: min(21rem, calc(100vw - 1rem));
    max-width: calc(100vw - 1rem);
    height: calc(100dvh - 1rem);
    max-height: calc(100dvh - 1rem);
    transform: translate3d(-1rem, 0, 0) scale(0.985);
    transform-origin: left center;
  }
}

@media (max-width: 480px) {
  .header-minimal {
    width: calc(100vw - 1rem);
    left: 0.5rem;
    top: calc(0.5rem + 3rem + 0.5rem);
  }

  .app-menu-toggle {
    min-width: 3rem;
    padding: 0 var(--space-3);
  }

  .quick-strip-profile-menu__dropdown {
    min-width: min(18rem, calc(100vw - 1rem));
    max-width: calc(100vw - 1rem);
  }
}

@media (max-width: 320px) {
  .header-minimal {
    width: calc(100vw - 0.75rem);
    left: 0.375rem;
  }

  .app-menu-toggle {
    min-width: 2.75rem;
    padding: 0 10px;
  }

  .container,
  .container-fluid,
  .page-container {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
}

@media (max-width: 768px) {
  .main-wrapper > .main-content {
    padding-top: 14px;
  }
}

@media (max-width: 1280px) {
  .container {
    padding-left: 0.75rem;
    padding-right: 0.75rem;
  }

  .app-quick-strip {
    gap: 0.25rem;
  }

  .quick-nav-item {
    padding: 0 10px;
  }

  .quick-nav-text {
    display: none;
  }

  .quick-strip-tool-text {
    display: none;
  }

  .quick-strip-tools {
    padding-left: 6px;
    gap: 0.25rem;
  }

  .quick-strip-tool {
    padding: 0 var(--space-3);
  }

  .table-container,
  .table-wrapper {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
  }

  .table {
    min-width: 640px;
  }
}

/* Bootstrap-style badges (Bootstrap не подключён) */
.badge {
  display: inline-block;
  padding: 0.25em 10px;
  font-size: var(--font-size-xs);
  font-weight: 600;
  line-height: 1;
  text-align: center;
  white-space: nowrap;
  vertical-align: baseline;
  border-radius: 0.35rem;
}
/* Замер 13.08.2026: четыре плашки были покрашены палитрой Bootstrap
   (#dc3545, #17a2b8, #0d6efd, #6c757d) — ни один из этих цветов в системе
   не объявлен, бирюзовый «info» ни на что в продукте не похож. Переведены
   на токены. `success` и `warning` применяются в шаблонах шесть раз, но
   правил у них не было вовсе — плашка выходила бесцветной. */
.badge-danger {
  color: var(--text-inverse);
  background-color: var(--error-600);
}
.badge-info {
  color: var(--text-inverse);
  background-color: var(--gray-600);
}
.badge-primary {
  color: var(--text-inverse);
  background-color: var(--accent);
}
.badge-secondary {
  color: var(--text-inverse);
  background-color: var(--gray-700);
}
.badge-success {
  color: var(--text-inverse);
  background-color: var(--success-700);
}
.badge-warning {
  color: var(--text-inverse);
  background-color: var(--warning-700);
}

/* 15.09.2026. `badge-light` стоит семь раз на карточке контрагента (роли
   стороны), `badge-lg` — три раза в банковских счетах; правил не было ни у
   одного. Роль выходила бесцветной, «крупная» плашка — обычной. */
.badge-light {
  color: var(--text-secondary);
  background-color: var(--surface-secondary);
  border: 1px solid var(--border-color);
}

.badge-lg {
  padding: 0.35em 12px;
  font-size: var(--font-size-sm);
}

/* `badge-dark` — роль «администратор» на карточке контрагента.
   Первая попытка была `--text-inverse` на `--text-primary`: замер дал 1.05 в
   тёмной теме. Причина — `--text-inverse` равен #ffffff в ОБЕИХ темах, он не
   инвертируется (та же мина, что в [ui-page-header-white-on-white]). Поэтому
   как у всей семьи: белый литералом на тёмной ступени серой шкалы, которая
   темнеет вместе с темой. Замер: 14.63 в светлой, 17.15 в тёмной. */
.badge-dark {
  color: var(--text-inverse);
  background-color: var(--gray-800);
}

.ds-modal-footer-sticky {
  position: sticky;
  bottom: 0;
  z-index: 30;
  background: var(--glass-bg);
  border-top: 1px solid var(--border-color);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}

.ds-modal-footer-sticky .modal-esc-hint {
  color: var(--text-secondary);
  font-weight: 500;
}

.ds-modal-footer-layout {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  width: 100%;
}

@media (min-width: 640px) {
  .ds-modal-footer-layout {
    flex-direction: row;
    align-items: center;
  }
  .ds-modal-footer-danger {
    order: 1;
    margin-right: 1rem;
    padding-right: 1rem;
    border-right: 1px solid var(--border-color);
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }
  .ds-modal-footer-tools {
    order: 2;
  }
  .ds-modal-footer-primary {
    order: 3;
    margin-left: auto;
  }
  .ds-modal-footer-layout .modal-esc-hint {
    order: 4;
    margin-left: 0.75rem;
    flex: 0 0 auto;
    white-space: nowrap;
  }
}

.ds-sortable {
  cursor: pointer;
  user-select: none;
}

.ds-sortable::after {
  content: "↕";
  margin-left: 8px;
  opacity: 0;
  font-size: var(--font-size-sm);
  transition: opacity 0.2s ease;
}

.ds-sortable:hover::after {
  opacity: 0.35;
}

.ds-sortable.is-asc::after {
  content: "↑";
  opacity: 1;
  color: var(--primary-500);
}

.ds-sortable.is-desc::after {
  content: "↓";
  opacity: 1;
  color: var(--primary-500);
}

.ds-required {
  color: var(--status-error-text);
}

.ds-field-error {
  margin-top: 6px;
  font-size: var(--font-size-xs);
  color: var(--danger-600);
  min-height: 1em;
}

.ds-invalid {
  border-color: var(--danger-500);
  box-shadow: 0 0 0 2px rgba(239, 68, 68, 0.15);
}

.ds-form-section-title {
  font-size: var(--font-size-sm);
  font-weight: 600;
  color: var(--text-secondary);
  margin-top: 6px;
}

.skeleton {
  background: var(--surface-tertiary);
  border-radius: var(--radius-sm);
  position: relative;
  overflow: hidden;
}

.skeleton::after {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: var(--skeleton-shimmer);
  animation: skeleton-loading 1.5s infinite;
}

@keyframes skeleton-loading {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}

.skeleton-text {
  height: 1em;
  margin-bottom: 0.5em;
  width: 100%;
}

.skeleton-text:last-child {
  margin-bottom: 0;
}

.footer {
  border-top: 1px solid var(--border-color);
  background: var(--surface-primary);
  color: var(--text-secondary);
  padding: 1rem 0;
}

.footer .footer-content {
  gap: 0.5rem;
  font-size: var(--font-size-sm);
}

@media (max-width: 360px) {
  .footer .footer-content {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
  }

  .footer-separator {
    display: none;
  }
}

.footer-link {
  color: var(--footer-link-color);
  font-weight: 600;
  text-decoration: none;
  border-radius: 0.35rem;
  min-height: 2.75rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 6px 10px;
  transition:
    color 0.2s ease,
    background-color 0.2s ease,
    text-decoration-color 0.2s ease;
}

.footer-separator {
  color: var(--text-muted);
  opacity: 0.75;
}

.footer-version {
  /* 13.08.2026: единственный узел системы с кеглем 11.67 px — наследовал
     дробное значение от предка. Ставим нижнюю ступень шкалы. */
  font-size: var(--font-size-xs);
  letter-spacing: 0.01em;
}

.footer-link:visited {
  color: var(--primary-color);
}

.footer-link:hover,
.footer-link:focus-visible {
  color: var(--text-primary);
  background: var(--surface-hover);
  text-decoration: underline;
}

a.card-sub.card-trend-right {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.75rem;
  padding: 6px 10px;
  border-radius: 0.5rem;
}

.admin-container,
.monitoring-container {
  max-width: 1200px;
  margin: 0 auto;
  padding: 1.5rem;
}

.monitoring-header {
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  padding: 1.25rem 1.25rem;
  box-shadow: 0 10px 24px rgb(var(--shadow-color-rgb) / 0.08);
  margin-bottom: 1rem;
}

.settings-grid,
.monitoring-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 1rem;
  /* Карточки по высоте не равняются. По умолчанию строка сетки тянет все
     карточки до высоты самой длинной: «Проверки здоровья» из трёх строк и
     «Статистика базы данных» из двух растягивались до 464 px под соседнюю
     «Детали по памяти» со списком процессов — и рядом с тремя строками
     текста стояло по 350 px пустоты. 18.08.2026 */
  align-items: start;
}

@media (min-width: 900px) {
  .settings-content .settings-grid {
    display: block;
    column-count: 2;
    column-gap: 1rem;
  }

  .settings-content .settings-grid > .settings-card {
    display: inline-block;
    width: 100%;
    margin: 0 0 1rem;
    break-inside: avoid;
  }
}

/* ===== TOUCH TARGET FIXES (min 44×44) ===== */
/* Checkboxes inside table rows - увеличиваем зону клика */

/* Action buttons in tables */
td .btn-sm,
td .btn-xs,
td button.btn.btn-sm {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Nav arrows (‹ › ) */
.nav-btn {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Calendar close button */
.modal-close-beautiful,
.close-btn {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Filter clear / search clear buttons */
.filter-clear-btn,
.clear-search-btn {
  min-width: 44px;
  min-height: 44px;
}

/* Mobile hamburger toggle */
.mobile-nav-toggle,
.app-menu-toggle {
  min-width: 44px;
  min-height: 44px;
}

/* Scale/view toggle buttons in calendar/tables */
.scale-btn,
.view-btn {
  min-height: 44px;
  padding: 6px 0.75rem;
}

/* General small button in structured list contexts */
/* `:where()` вокруг атрибутных частей — сознательно. Селектор
   `button[aria-label]` имеет специфичность 0,1,1 и перебивал ЛЮБОЕ
   правило по классу, включая `display: none`. То есть кнопку с
   `aria-label` нельзя было ни скрыть, ни сделать меньше 44 px: 16.08.2026
   на этом попалась кнопка ящика в новой полосе — она обязана прятаться на
   широком экране и вылезала на всех страницах, где подключён этот файл.
   `:where()` обнуляет специфичность: те же значения остаются умолчанием,
   но компонент может их переопределить.
   Целевой размер 44 px там, где он действительно нужен, задан отдельно и
   правильнее — в блоке `@media (hover: none) and (pointer: coarse)`. */
.btn-icon-only,
:where(button[aria-label]),
:where(a[aria-label]) {
  min-width: 44px;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

/* Замер 13.08.2026 при окне 1490: три колонки давали карточку в 301 px.
   В ней «метка — значение» превращается в кашу: подпись просит 280,
   значению остаётся два десятка, и всё уезжает в перенос. Заголовок
   «Google Document AI (основной OCR)» вставал в две строки, абзац
   «Принцип» — в четыре. Оставляем две колонки: карточка ~460 px.
   Третью не возвращать без замера ширины карточки. */

.settings-card,
.monitoring-card,
.stats-card,
.status-card {
  background: var(--surface-primary);
  border: 1px solid var(--border-color);
  border-radius: var(--radius-lg);
  /* 13.08.2026: было 1.25rem (20) — единственные плитки с таким паддингом.
     Канон плитки показателя: паддинг 16, радиус 16, число 24/700. */
  padding: var(--card-padding-sm);
  box-shadow: 0 10px 24px rgb(var(--shadow-color-rgb) / 0.08);
}

.setting-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border-color);
}

/* Замер 12.08.2026 на /settings/: страница уходила в горизонтальную
   прокрутку (scrollWidth 1657 при окне 1639). Причина не в самой строке:
   `.settings-card .setting-item .input-group` требовал `min-width: 320px`
   внутри карточки шириной 252 — пол больше контейнера, в котором он
   стоит. К нему добавлялась подсказка `<small class="d-block">`, которую
   размечали отдельной строкой под полем, а flex-ряд без переноса ставил
   её третьим элементом в строку: 79 + 320 + 95 + два зазора = 526 px
   в 252.
   Переносим только те строки, где подсказка есть: сплошной `flex-wrap`
   на `.setting-item` разваливает обычную пару «подпись — значение»
   (замер: строка 42 px превращалась в 81, карточка вдвое выше). */
/* 25.08.2026: в список забыли `.setting-note` — а он и есть тот самый
   «связный текст на всю ширину», ради которого правило заведено. Ему
   ниже задан `flex: 1 0 100%`, но без переноса это означает «стой в той
   же строке и займи всю ширину контейнера СВЕРХ подписи»: на `/settings/`
   абзац про Document AI вылезал из карточки на 38 px и тянул за собой в
   горизонтальную прокрутку всю страницу (`page-container` 1226 в 1189). */
.setting-item:has(> small),
.setting-item:has(> .form-text),
.setting-item:has(> .setting-note) {
  flex-wrap: wrap;
}

.setting-item > small,
.setting-item > .form-text {
  flex: 1 0 100%;
  margin-top: 0.25rem;
}

.setting-item:last-child {
  border-bottom: none;
}

.setting-label,
.check-name,
.status-title {
  color: var(--text-secondary);
  font-size: var(--font-size-sm);
  font-weight: 600;
}

.setting-value,
.status-value {
  color: var(--text-primary);
  font-weight: 600;
}

/* Абзац — не значение. На /settings/ пояснение «Все распознавание по
   умолчанию идёт через Document AI…» было размечено как `.setting-value`:
   жирным, прижатым вправо, в колонке шириной с ноготь. Значение — это
   короткий факт справа от подписи; связный текст живёт отдельной строкой
   на всю ширину карточки. */
.setting-note {
  flex: 1 0 100%;
  margin: 0;
  color: var(--text-secondary);
  font-size: var(--font-size-sm);
  font-weight: 400;
  line-height: var(--line-height-normal);
}

/* Подпись у флажка — тоже текст, а не значение: не жирная и по левому краю. */
.setting-item .form-check-label {
  font-weight: 400;
  color: var(--text-primary);
  text-align: left;
}

.settings-card .setting-item .input-group {
  flex: 1 1 420px;
  min-width: 0;
}

.settings-card .setting-item .input-group .filter-control {
  min-width: 0;
}

.settings-card .setting-item .setting-label {
  flex: 0 1 280px;
}

/* 03.10.2026, замер на /settings/ и /admin/integrations/docai: карточки
   бывают по 190–250 px, и значение (адрес, идентификатор, переключатель)
   с `min-width: auto` не сжималось — вылезало за карточку до 150 px на всех
   ширинах до 1280, а на 1024 тянуло страницу вбок. Значение сжимается и
   переносится; кнопки с длинной надписью («Сохранить настройки Google
   Sheets») переносят текст, а не выпирают. */
.setting-item > .setting-value,
.setting-item > .setting-label {
  min-width: 0;
  overflow-wrap: anywhere;
}
.settings-card code,
.admin-card-body code {
  overflow-wrap: anywhere;
}
.settings-card .btn,
.admin-card-body .setting-item .btn {
  white-space: normal;
  max-width: 100%;
}
.settings-card .setting-item .input-group {
  flex-wrap: wrap;
}

/* Телефон (≤480): строка настройки с полем, списком и кнопкой не
   помещается в 250–300 px — переносится. На широком окне перенос не
   включаем: пара «подпись — значение» должна стоять в одну строку
   (см. выше, 12.08.2026). Замер 03.10.2026: «Распознавание счетов» —
   поле, список папок и кнопка вылезали на 30–117 px. */
@media (max-width: 480px) {
  .setting-item {
    flex-wrap: wrap;
  }
  .setting-item > * {
    min-width: 0;
    max-width: 100%;
  }
}

/* #3 Print styles — hide chrome, keep content */
@media print {
  /* ── печать: тема всегда светлая ──────────────────────────────────────
     Замер 18.08.2026: печатные правила задавали белый фон только `body`,
     а карточки и плитки сохраняли тёмную заливку и светлый текст. Браузер
     по умолчанию фон не печатает — на бумаге получался белый текст на
     белом листе, то есть пустая страница. Сбрасываем сами токены: всё,
     что построено на них (а после уборки этого месяца — почти всё),
     становится печатным без правил на каждый компонент. */
  :root,
  [data-theme="dark"],
  html[data-theme="dark"] {
    --surface-primary: var(--text-inverse);
    --surface-secondary: var(--text-inverse);
    --surface-tertiary: var(--text-inverse);
    --surface-hover: var(--text-inverse);
    --surface-muted: var(--text-inverse);
    --card-bg: var(--text-inverse);
    --bg-primary: var(--text-inverse);
    --bg-secondary: var(--text-inverse);
    --text-primary: var(--black);
    --text-secondary: var(--gray-legacy-222);
    --text-tertiary: var(--gray-legacy-444);
    --text-muted: var(--gray-legacy-444);
    --border-color: var(--gray-legacy-999);
    --border-color-strong: var(--gray-legacy-666);
    --card-border: var(--gray-legacy-999);
    --card-shadow: none;
    --shadow-sm: none;
    --shadow-md: none;
    --shadow-lg: none;
    --accent-text: var(--black);
    --link-color: var(--black);
    /* Статусные цвета как текст: на бумаге они остаются различимыми по
       оттенку, но читаются и в чёрно-белой печати. Светлые «тёмнотемные»
       значения (var(--success-800) и подобные) на белом листе исчезают. */
    --status-success-text: var(--success-100);
    --status-error-text: var(--danger-100);
    --status-warning-text: var(--warning-100);
    --status-info-text: var(--blue-900);
    /* Цвета категорий как текст: в тёмной теме это светлые оттенки
       (var(--blue-200) и подобные), на белом листе они пропадают. */
    --category-1-text: var(--blue-800);
    --category-2-text: var(--teal-800);
    --category-3-text: var(--violet-900);
  }

  /* ── плашки ───────────────────────────────────────────────────────────
     У плашек текст белый на цветной заливке, а браузер по умолчанию
     заливку не печатает — на бумаге оставался белый текст на белом.
     Флаг здесь по назначению (печать) и по необходимости: тематические
     правила вроде `html[data-theme="dark"] .app-shell .badge-grid >
     .status-badge.status-processing` имеют специфичность (0,5,0), и
     спорить с ними иначе нечем. 18.08.2026 */
  .badge,
  .status-badge,
  .chip,
  .rec-chip,
  .docs-filter-chip,
  [class*="badge-"] {
    background: transparent !important;
    background-image: none !important;
    color: var(--black) !important;
    border: 1px solid var(--gray-legacy-999) !important;
  }

  /* ── обвязка приложения не печатается ─────────────────────────────────
     Список селекторов был написан под старую разметку (`.sidebar`,
     `.top-bar`, `.subnav`) — таких классов в проекте нет, и боковая
     панель уезжала на бумагу целиком, занимая четверть ширины. */
  .app-sidebar,
  .app-topbar,
  .app-menu-root,
  .app-menu-backdrop,
  .app-menu-panel,
  .main-menu,
  .quick-strip,
  .page-actions,
  .filters,
  .filters-grid,
  .docs-filters-card,
  .rec-filters,
  .btn,
  button,
  .modal-overlay,
  .modal-container,
  .sidebar-backdrop,
  .toast-container,
  .skip-link,
  .floating-actions,
  #floating-actions-menu,
  #floating-actions-docs,
  footer,
  #app-menu-panel,
  #app-menu-backdrop,
  .header-minimal,
  nav {
    display: none !important;
  }

  .print-only {
    display: block !important;
  }

  /* ── раскладка ────────────────────────────────────────────────────── */
  body {
    font-size: 11pt;
    line-height: var(--line-height-normal);
    color: var(--black);
    background: var(--text-inverse);
  }

  /* Контекст `body` нужен, чтобы перебить `app-shell.css`: он грузится
     позже общего слоя и объявляет `.app-frame { display: grid;
     grid-template-columns: 240px 1fr }`. Со скрытой боковой панелью
     содержимое попадало в первую колонку и печаталось в 240 px — четверть
     листа с текстом, три четверти пустые. 18.08.2026 */
  body .app-frame,
  body .app-shell {
    display: block;
    grid-template-columns: none;
    height: auto;
    overflow: visible;
  }

  body .main-wrapper,
  body .main-content,
  body .container,
  body .page-container,
  body .page-wrapper,
  body .content-area,
  body .content-wrapper {
    margin: 0;
    padding: 0;
    width: 100%;
    max-width: 100%;
    height: auto;
    overflow: visible;
  }

  /* ── таблицы ──────────────────────────────────────────────────────── */
  .table-container,
  .table-wrapper,
  .table-wrap,
  table {
    overflow: visible !important;
    page-break-inside: auto;
  }
  tr {
    page-break-inside: avoid;
  }
  thead {
    display: table-header-group;
  }

  /* ── карточки и ссылки ────────────────────────────────────────────── */
  .card,
  .ds-card,
  .panel,
  .section,
  .rec-tile,
  .table-card {
    box-shadow: none;
    border: 1px solid var(--gray-legacy-999);
    break-inside: avoid;
  }

  a {
    color: var(--black);
    text-decoration: underline;
  }
}

.status-indicator {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  display: inline-block;
  margin-right: 0.5rem;
  vertical-align: middle;
}

.status-enabled,
.status-healthy {
  background: var(--success-500);
}

.status-disabled,
.status-warning {
  background: var(--warning-500);
}

.status-error {
  background: var(--danger-500);
}

.status-overview {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 1rem;
  margin-bottom: 1rem;
}

.health-check-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.5rem 0;
  border-bottom: 1px solid var(--border-color);
}

.health-check-item:last-child {
  border-bottom: none;
}

.check-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  color: var(--text-secondary);
  font-size: var(--font-size-sm);
}

.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 1rem;
  margin: 1rem 0;
}

.stats-number {
  font-size: var(--font-size-2xl);
  font-weight: 700;
  color: var(--text-primary);
  margin-top: 6px;
}

.stats-label {
  color: var(--text-secondary);
  font-size: var(--font-size-sm);
}

.admin-actions-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 1rem 0;
  flex-wrap: wrap;
}

.scrollbar-hide::-webkit-scrollbar {
  display: none;
}

.scrollbar-hide {
  -ms-overflow-style: none;
  scrollbar-width: none;
}

.dashboard-card {
  background: var(--card-bg);
  border: 1px solid var(--border-color);
  border-radius: 0.5rem;
  padding: 1.5rem;
  box-shadow:
    0 1px 3px 0 rgba(0, 0, 0, 0.1),
    0 1px 2px 0 rgba(0, 0, 0, 0.06);
}

.summary-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 1rem;
  width: 100%;
}

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 1rem;
  width: 100%;
}

.dashboard-grid.admin-tools {
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  justify-content: start;
}

.dashboard-grid.admin-tools > * {
  max-width: 420px;
}

.stats-icon {
  width: 42px;
  height: 42px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(59, 130, 246, 0.1);
  color: var(--primary-color);
}

/* `white-space: nowrap` — не украшение. Радиус 999px превращает бейдж с
   перенесённым текстом в овал: на 768 px колонке «Роль» достаётся 109 px,
   и «Системный администратор» становился эллипсом 85x86 с текстом в четыре
   строки и разрывом посреди слова, «Активен» — «Актив/ен» (замер
   22.09.2026, /admin/users). В одну строку бейдж снова пилюля 188x28, а
   таблица честно уезжает под прокрутку своей обёртки `.table-responsive`
   (overflow-x: auto; 746 против 688) — страница вбок не едет. */
.user-role,
.user-status {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: var(--space-1) 10px;
  border-radius: 999px;
  font-size: var(--font-size-xs);
  white-space: nowrap;
  border: 1px solid rgba(128, 128, 128, 0.25);
  background: rgba(148, 163, 184, 0.08);
  color: var(--text-secondary);
}

.user-role.role-admin {
  background: rgba(59, 130, 246, 0.12);
  color: var(--blue-700);
  border-color: rgba(59, 130, 246, 0.25);
}

.user-status.status-active {
  background: color-mix(
    in srgb,
    var(--success-500) 14%,
    var(--surface-primary)
  );
  color: var(--text-primary);
  border-color: color-mix(in srgb, var(--success-600) 24%, var(--border-color));
}

.user-status.status-inactive {
  background: rgba(239, 68, 68, 0.12);
  color: var(--error-700);
  border-color: rgba(239, 68, 68, 0.25);
}

.badge-glass {
  padding: 0.25rem 0.75rem;
  border-radius: 9999px;
  font-size: var(--font-size-xs);
  font-weight: 500;
  backdrop-filter: blur(4px);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.status-pending {
  background: rgba(251, 191, 36, 0.2);
  color: var(--status-warning-text);
  border: 1px solid rgba(251, 191, 36, 0.3);
}

.status-success,
.status-processed,
.status-ok,
.status-ocr_ready,
.status-ready,
.status-completed {
  background: color-mix(
    in srgb,
    var(--success-500) 14%,
    var(--surface-primary)
  );
  color: var(--text-primary);
  border: 1px solid
    color-mix(in srgb, var(--success-600) 24%, var(--border-color));
}

.status-error,
.status-rejected,
.status-fail {
  background: rgba(239, 68, 68, 0.2);
  color: var(--status-error-text);
  border: 1px solid rgba(239, 68, 68, 0.3);
}

.status-processing {
  background: rgba(59, 130, 246, 0.2);
  color: var(--status-info-text);
  border: 1px solid rgba(59, 130, 246, 0.3);
}

.status-queued,
/* `status-vacant` не был объявлен нигде: класс есть в разметке кабинета
 * собственника (плашка «Свободно» и имя арендатора с истёкшим договором),
 * а правил у него нет — плашка выглядела просто текстом, тогда как
 * соседняя `status-active` рисовалась зелёной. 18.08.2026 */
.status-vacant {
  background: rgba(107, 114, 128, 0.2);
  color: var(--status-neutral-text);
  border: 1px solid rgba(107, 114, 128, 0.3);
}

.status-needs_review,
/* `status-expiring` — та же история, что у `status-vacant`: класс в
 * разметке есть, правил нет. Плашка «Истекает через 43 дн.» выводилась
 * обычным текстом рядом с зелёной плашкой арендатора. 18.08.2026 */
.status-expiring {
  background: rgba(251, 191, 36, 0.2);
  color: var(--status-warning-text);
  border: 1px solid rgba(251, 191, 36, 0.3);
}

.status-progress-fill {
  height: 100%;
  background-color: var(--primary-color);
  border-radius: 9999px;
  transition: width 0.3s ease;
  width: 0%;
}

/* Тосты не должны падать на шапку приложения.
 *
 * `top: 20px` при полосе `.app-topbar` высотой 56 px клал тост поверх
 * строки «Обновлено …» и кнопок «Печать» / «Обновить» в кабинете
 * собственника. Отступаем на высоту полосы. 18.08.2026 */
#toast-container,
.toast-container {
  position: fixed;
  top: 72px;
  right: 20px;
  z-index: 9999;
}

.toast {
  min-width: 250px;
  margin-bottom: 10px;
  padding: 15px;
  border-radius: 4px;
  color: var(--text-inverse);
  opacity: 0.9;
  transition: opacity 0.3s ease-in-out;
  box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
}

.toast.success,
.toast.toast-success {
  background-color: var(--success-700);
  color: var(--button-primary-text);
}

.toast.error,
.toast.toast-error {
  background-color: var(--error-700);
  color: var(--button-primary-text);
}

.toast.info,
.toast.toast-info {
  background-color: var(--info-700);
  color: var(--button-primary-text);
}

.toast.warning,
.toast.toast-warning {
  background-color: var(--warning-700);
  color: var(--button-primary-text);
}

.bg-primary-600 {
  background-color: var(--primary-600);
}

.bg-success-600 {
  background-color: var(--success-600);
}

.bg-info-600 {
  background-color: var(--info-600);
}

.bg-warning-600 {
  background-color: var(--warning-600);
}

.mt-3 {
  margin-top: 0.75rem;
}

.modal-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.5);
  display: none;
  justify-content: center;
  align-items: center;
  z-index: 1000;
}

.modal-overlay.show {
  display: flex;
}

.modal-container {
  background: var(--bg-primary);
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
  width: 90%;
  max-width: 500px;
  display: flex;
  flex-direction: column;
  max-height: 90vh;
}

.modal-lg {
  max-width: 800px;
}

.modal-header {
  padding: 1rem;
  border-bottom: 1px solid var(--border-color);
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.modal-body {
  padding: 1rem;
  overflow-y: auto;
}

.btn-close {
  background: transparent;
  border: none;
  font-size: 1.5rem;
  cursor: pointer;
  color: var(--text-secondary);
}

.db-stats-container {
  margin-top: 1rem;
}

.db-stats-summary {
  display: flex;
  gap: 2rem;
  margin-bottom: 1.5rem;
  padding: 1rem;
  background-color: var(--card-bg);
  border-radius: 0.5rem;
  border: 1px solid var(--border-color);
}

.db-stat-item {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.db-stat-label {
  font-size: var(--font-size-sm);
  color: var(--text-secondary);
  margin-bottom: 0.25rem;
}

.db-stat-value {
  font-size: var(--font-size-2xl);
  font-weight: 600;
  color: var(--primary-color);
}

@media (max-width: 1024px) {
  .dashboard-grid {
    grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  }
}

@media (max-width: 640px) {
  .dashboard-grid {
    grid-template-columns: 1fr;
  }
}

/* Sidebar nav AA dark pair (universal: base.html + portal_base.html pages).
   Scope: only admin nav wrapper with bg-white/dark:bg-gray-800 Tailwind classes,
   not breadcrumb nav or top bar nav.
   — Tailwind v3 dark rule is `.dark\:bg-gray-800:is(.dark *)` which depends on `.dark` class.
     We also guard by `[data-theme="dark"]` attribute (always present before CSS applies per
     inline init script in base.html / portal_base.html <head>). That lets us win on equal
     specificity by cascade order (unified-bundle loads BEFORE tailwind.css — NO, earlier loses).
   — We therefore use EXTRA specificity (html[data-theme="dark"] + body + nested class path)
     AND to guarantee override regardless of cascade order.
*/
html[data-theme="dark"] body nav.lg\:w-64.flex-shrink-0 > div.bg-white,
html[data-theme="dark"]
  body
  nav.lg\:w-64.flex-shrink-0
  > div.bg-white.dark\:bg-gray-800,
html[data-theme="dark"] body nav.flex-shrink-0 > div.bg-white,
html[data-theme="dark"] body aside.sidebar,
html[data-theme="dark"] body div.bg-white.dark\:bg-gray-800.admin-nav,
html[data-theme="dark"] body nav > div.bg-white.dark\:bg-gray-800,
html[data-theme="dark"] .dark\:bg-gray-800.admin-nav {
  background-color: var(--sidebar-surface-bg);
  border-color: var(--sidebar-surface-border);
}
html[data-theme="dark"] body nav.lg\:w-64.flex-shrink-0 > div.bg-white a,
html[data-theme="dark"]
  body
  nav.lg\:w-64.flex-shrink-0
  > div.bg-white.dark\:bg-gray-800
  a,
html[data-theme="dark"]
  body
  nav.lg\:w-64.flex-shrink-0
  > div.bg-white
  a.flex.items-center,
html[data-theme="dark"] body nav.flex-shrink-0 > div.bg-white a,
html[data-theme="dark"] body aside.sidebar a,
html[data-theme="dark"] body nav > div.bg-white.dark\:bg-gray-800 a,
html[data-theme="dark"] nav div a.flex.items-center {
  background-color: var(--sidebar-nav-bg);
  color: var(--sidebar-nav-text);
}
html[data-theme="dark"] body nav.lg\:w-64.flex-shrink-0 a.active,
html[data-theme="dark"] body nav.flex-shrink-0 > div a.active,
html[data-theme="dark"] body aside.sidebar a.active,
html[data-theme="dark"] body nav > div a.active {
  background-color: var(--sidebar-nav-active-bg);
  color: var(--sidebar-nav-active-text);
  border-color: var(--sidebar-nav-active-border);
}
html[data-theme="dark"] body nav.lg\:w-64.flex-shrink-0 span.inline-flex,
html[data-theme="dark"] body nav.flex-shrink-0 div span.inline-flex,
html[data-theme="dark"] nav span.inline-flex.rounded-md {
  background-color: var(--sidebar-nav-active-bg);
  color: var(--sidebar-nav-active-text);
  border: 1px solid var(--sidebar-nav-active-border);
}

/* FontAwesome 6.4.0 subset */
@font-face {
  font-family: "Font Awesome 6 Free";
  font-style: normal;
  font-weight: 900;
  font-display: block;
  src: url("../fonts/fa-solid-900.woff2") format("woff2");
}
@font-face {
  font-family: "Font Awesome 6 Free";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/fa-regular-400.woff2") format("woff2");
}
@font-face {
  font-family: "Font Awesome 6 Brands";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/fa-brands-400.woff2") format("woff2");
}
.fa,
.fas,
.far,
.fab {
  -moz-osx-font-smoothing: grayscale;
  -webkit-font-smoothing: antialiased;
  display: inline-block;
  font-style: normal;
  font-variant: normal;
  text-rendering: auto;
  line-height: 1;
}
.fa,
.fas {
  font-family: "Font Awesome 6 Free";
  font-weight: 900;
}
.far {
  font-family: "Font Awesome 6 Free";
  font-weight: 400;
}
.fab {
  font-family: "Font Awesome 6 Brands";
  font-weight: 400;
}
.fa-lg {
  font-size: var(--font-size-xl);
  vertical-align: -0.075em;
}
.fa-2x {
  font-size: 2em;
}
.fa-spin {
  animation: fa-spin 2s linear infinite;
}
@keyframes fa-spin {
  0% {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(1turn);
  }
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.fa-align-left:before {
  content: "\f036";
}
.fa-arrow-down:before {
  content: "\f063";
}
.fa-arrow-left:before {
  content: "\f060";
}
.fa-arrow-right:before {
  content: "\f061";
}
.fa-arrow-up:before {
  content: "\f062";
}
.fa-at:before {
  content: "\40";
}
.fa-bell:before {
  content: "\f0f3";
}
.fa-archive:before {
  content: "\f187";
}
.fa-box-archive:before {
  content: "\f187";
}
.fa-broom:before {
  content: "\f51a";
}
.fa-bug:before {
  content: "\f188";
}
.fa-building:before {
  content: "\f1ad";
}
.fa-calculator:before {
  content: "\f1ec";
}
.fa-calendar:before {
  content: "\f133";
}
.fa-calendar-day:before {
  content: "\f783";
}
.fa-calendar-days:before {
  content: "\f073";
}
.fa-calendar-plus:before {
  content: "\f271";
}
.fa-chart-bar:before {
  content: "\f080";
}
.fa-check:before {
  content: "\f00c";
}
.fa-chevron-down:before {
  content: "\f078";
}
.fa-chevron-left:before {
  content: "\f053";
}
.fa-chevron-right:before {
  content: "\f054";
}
.fa-circle-check:before {
  content: "\f058";
}
.fa-circle-notch:before {
  content: "\f1ce";
}
.fa-clock:before {
  content: "\f017";
}
.fa-clone:before {
  content: "\f24d";
}
.fa-code:before {
  content: "\f121";
}
.fa-coins:before {
  content: "\f51e";
}
.fa-comments:before {
  content: "\f086";
}
.fa-compass:before {
  content: "\f14e";
}
.fa-copy:before {
  content: "\f0c5";
}
.fa-credit-card:before {
  content: "\f09d";
}
.fa-cube:before {
  content: "\f1b2";
}
.fa-door-open:before {
  content: "\f52b";
}
.fa-download:before {
  content: "\f019";
}
.fa-edit:before {
  content: "\f044";
}
.fa-envelope:before {
  content: "\f0e0";
}
.fa-envelope-open-text:before {
  content: "\f658";
}
.fa-exclamation-circle:before {
  content: "\f06a";
}
.fa-eye:before {
  content: "\f06e";
}
.fa-eye-slash:before {
  content: "\f070";
}
.fa-pen-to-square:before {
  content: "\f044";
}
.fa-file:before {
  content: "\f15b";
}
.fa-file-circle-xmark:before {
  content: "\e5a1";
}
.fa-file-code:before {
  content: "\f1c9";
}
.fa-file-contract:before {
  content: "\f56c";
}
.fa-file-csv:before {
  content: "\f6dd";
}
.fa-file-excel:before {
  content: "\f1c3";
}
.fa-file-image:before {
  content: "\f1c5";
}
.fa-file-invoice:before {
  content: "\f570";
}
.fa-file-invoice-dollar:before {
  content: "\f571";
}
.fa-file-pdf:before {
  content: "\f1c1";
}
.fa-file-signature:before {
  content: "\f573";
}
.fa-file-word:before {
  content: "\f1c2";
}
.fa-filter:before {
  content: "\f0b0";
}
.fa-fire:before {
  content: "\f06d";
}
.fa-flag:before {
  content: "\f024";
}
.fa-folder:before {
  content: "\f07b";
}
.fa-folder-open:before {
  content: "\f07c";
}
.fa-folder-plus:before {
  content: "\f65e";
}
.fa-globe:before {
  content: "\f0ac";
}
.fa-google:before {
  content: "\f1a0";
}
.fa-google-drive:before {
  content: "\f3aa";
}
.fa-handshake:before {
  content: "\f2b5";
}
.fa-heart-crack:before {
  content: "\f7a9";
}
.fa-heartbeat:before {
  content: "\f21e";
}
.fa-heart-pulse:before {
  content: "\f21e";
}
.fa-history:before {
  content: "\f1da";
}
.fa-hourglass-half:before {
  content: "\f252";
}
.fa-house:before {
  content: "\f015";
}
.fa-id-card:before {
  content: "\f2c2";
}
.fa-inbox:before {
  content: "\f01c";
}
.fa-industry:before {
  content: "\f275";
}
.fa-info:before {
  content: "\f129";
}
.fa-info-circle:before {
  content: "\f05a";
}
.fa-key:before {
  content: "\f084";
}
.fa-layer-group:before {
  content: "\f5fd";
}
.fa-lightbulb:before {
  content: "\f0eb";
}
.fa-link:before {
  content: "\f0c1";
}
.fa-list:before {
  content: "\f03a";
}
.fa-lock:before {
  content: "\f023";
}
.fa-map:before {
  content: "\f279";
}
.fa-map-marked-alt:before {
  content: "\f5a0";
}
.fa-map-marker-alt:before {
  content: "\f3c5";
}
.fa-minus-circle:before {
  content: "\f056";
}
.fa-money-bill-wave:before {
  content: "\f53a";
}
.fa-moon:before {
  content: "\f186";
}
.fa-paintbrush:before {
  content: "\f1fc";
}
.fa-paper-plane:before {
  content: "\f1d8";
}
.fa-pause:before {
  content: "\f04c";
}
.fa-pause-circle:before {
  content: "\f28b";
}
.fa-phone:before {
  content: "\f095";
}
.fa-play:before {
  content: "\f04b";
}
.fa-plug:before {
  content: "\f1e6";
}
.fa-plus:before {
  content: "\2b";
}
.fa-plus-circle:before {
  content: "\f055";
}
.fa-question-circle:before {
  content: "\f059";
}
.fa-receipt:before {
  content: "\f543";
}
.fa-redo:before {
  content: "\f01e";
}
.fa-robot:before {
  content: "\f544";
}
.fa-ruler-combined:before {
  content: "\f546";
}
.fa-save:before {
  content: "\f0c7";
}
.fa-search:before {
  content: "\f002";
}
.fa-server:before {
  content: "\f233";
}
.fa-cog:before {
  content: "\f013";
}
.fa-cogs:before {
  content: "\f085";
}
.fa-gear:before {
  content: "\f013";
}
.fa-shield-halved:before {
  content: "\f3ed";
}
.fa-shopping-cart:before {
  content: "\f07a";
}
.fa-sign-out-alt:before {
  content: "\f2f5";
}
.fa-right-from-bracket:before {
  content: "\f2f5";
}
.fa-skull:before {
  content: "\f54c";
}
.fa-sort-amount-down:before {
  content: "\f160";
}
.fa-sort-down:before {
  content: "\f0dd";
}
.fa-sort-up:before {
  content: "\f0de";
}
.fa-spinner:before {
  content: "\f110";
}
.fa-star:before {
  content: "\f005";
}
.fa-stethoscope:before {
  content: "\f0f1";
}
.fa-sticky-note:before {
  content: "\f249";
}
.fa-store:before {
  content: "\f54e";
}
.fa-sun:before {
  content: "\f185";
}
.fa-sync:before {
  content: "\f021";
}
.fa-sync-alt:before {
  content: "\f2f1";
}
.fa-table:before {
  content: "\f0ce";
}
.fa-tachometer-alt:before {
  content: "\f625";
}
.fa-tags:before {
  content: "\f02c";
}
.fa-tasks:before {
  content: "\f0ae";
}
.fa-telegram:before {
  content: "\f2c6";
}
.fa-th-large:before {
  content: "\f009";
}
.fa-tint:before {
  content: "\f043";
}
.fa-tools:before {
  content: "\f7d9";
}
.fa-trash:before {
  content: "\f1f8";
}
.fa-undo:before {
  content: "\f0e2";
}
.fa-university:before {
  content: "\f19c";
}
.fa-unlink:before {
  content: "\f127";
}
.fa-upload:before {
  content: "\f093";
}
.fa-user:before {
  content: "\f007";
}
.fa-user-check:before {
  content: "\f4fc";
}
.fa-user-circle:before {
  content: "\f2bd";
}
.fa-user-lock:before {
  content: "\f502";
}
.fa-user-plus:before {
  content: "\f234";
}
.fa-user-shield:before {
  content: "\f505";
}
.fa-user-tag:before {
  content: "\f507";
}
.fa-user-tie:before {
  content: "\f508";
}
.fa-users:before {
  content: "\f0c0";
}
.fa-wallet:before {
  content: "\f555";
}
.fa-wand-magic:before {
  content: "\f0d0";
}
.fa-warehouse:before {
  content: "\f494";
}
.fa-weight-hanging:before {
  content: "\f5cd";
}
.fa-whatsapp:before {
  content: "\f232";
}
.fa-wifi:before {
  content: "\f1eb";
}

[aria-current="page"] {
  color: var(--text-primary);
  font-weight: 500;
}
.fa-xmark:before {
  content: "\f00d";
}

.ds-status-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: var(--space-2);
  flex: none;
}
.ds-status-dot--ok {
  background: var(--success-500);
}
.ds-status-dot--warn {
  background: var(--warning-500);
}
.ds-status-dot--muted {
  background: var(--border-color);
}

/* Canonical Entity Modal Component (R1 reference = /properties modal) */
.ds-entity-modal-wrapper.visible {
  display: flex;
  pointer-events: auto;
}
.ds-entity-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 6, 23, 0.82);
  backdrop-filter: blur(3px);
  -webkit-backdrop-filter: blur(3px);
}
.ds-entity-modal {
  position: relative;
  z-index: 2;
  width: min(1120px, calc(100vw - 32px));
  max-height: calc(100dvh - 32px);
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border-color-strong);
  background: var(--surface-primary);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.04),
    0 4px 24px rgba(2, 6, 23, 0.18),
    0 22px 70px rgba(2, 6, 23, 0.45);
  overflow-x: hidden;
  overflow-y: auto;
  pointer-events: auto;
}
/* 23.08.2026. Панель в разметке несла ещё и утилиту `overflow-hidden`: та же
   специфичность (0,1,0), но объявлена позже — и побеждала. Модалка переставала
   прокручиваться, карточка объекта резалась на 1043 px, карточка контрагента на
   1286 px. Пользователь видел это как «пропали характеристики и интеграция с
   DaData»: кадастровый номер, площадь, этаж, стоимость, кнопка «Заполнить из
   КАДАСТР», реквизиты банка, ОГРН, ОКПО, ОКВЭД, основание и подписант были за
   нижним краем и недосягаемы. Утилиту из разметки убрали; класс здесь
   продублирован, чтобы правило пережило её возможный возврат. */
.ds-entity-modal.ds-entity-modal {
  overflow-y: auto;
}
.ds-entity-modal-content {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: var(--space-4) var(--space-4) 0.25rem;
  text-align: left;
}
#modal-title,
.ds-entity-modal-content > header h2,
.ds-entity-modal-content h2 {
  font-size: var(--font-size-base);
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: 0.25rem;
}
.ds-entity-form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-bottom: 5.25rem;
}
.ds-entity-form > * {
  margin-top: 0;
}
.ds-entity-section,
.ds-entity-section-primary,
.ds-entity-section-soft {
  padding: 1rem var(--space-4);
  border-radius: var(--radius-md);
  border: 1px solid var(--entity-section-border);
  background: var(--entity-section-bg);
  box-shadow:
    0 1px 0 rgba(0, 0, 0, 0.04),
    0 16px 30px rgba(0, 0, 0, 0.06);
}
.ds-entity-section > .mb-1.border-b,
.ds-entity-section > .mb-2.border-b,
.ds-entity-form > .mb-1.border-b {
  margin-bottom: var(--space-2);
  padding-bottom: 6px;
  border-color: var(--border-color);
  opacity: 0.75;
}
/* Прописные у подписей разделов формы сняты 17.08.2026: для кириллицы
   они читаются хуже строчных, и это правило по продукту приняли ещё
   13.08 — до модальных окон оно тогда не дошло. «ОСНОВНАЯ ИНФОРМАЦИЯ»
   и «ТЕХНИЧЕСКИЕ ДАННЫЕ» в окне «Добавить объект» оставались капсом. */
.ds-form-section-title {
  margin-top: 0;
  margin-bottom: var(--space-2);
  font-size: var(--font-size-xs);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-transform: none;
  color: var(--entity-section-title-color);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}
.ds-form-section-title::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--color-primary);
  box-shadow: 0 0 0 3px rgba(var(--focus-ring-color-rgb), 0.16);
  flex: 0 0 auto;
}
.ds-entity-form label {
  display: block;
  margin-bottom: var(--space-1);
  color: var(--entity-label-color);
  font-size: var(--font-size-sm);
  font-weight: 600;
  text-align: left;
}
.ds-entity-form .theme-input,
.ds-entity-form select,
.ds-entity-form textarea {
  min-height: 38px;
  border-radius: var(--radius-md);
  border: 1px solid var(--entity-field-border);
  /* 17.08.2026: было `background: …`. Сокращение сбрасывает
     background-image, и общая стрелка селекта из ds-components.css
     исчезала — в модалке «Добавить объект» «Тип объекта» и «Статус»
     выглядели как поля ввода с пустым отступом 32 px справа.
     Ровно та же ошибка описана в ds-components.css от 12.08.2026;
     заливка задаётся только background-color. */
  background-color: var(--entity-field-bg);
  color: var(--entity-field-text);
  font-family: inherit;
  font-size: var(--font-size-sm);
  line-height: var(--line-height-snug);
  transition:
    border-color 0.15s ease,
    box-shadow 0.15s ease;
}
.ds-entity-form .theme-input::placeholder,
.ds-entity-form textarea::placeholder {
  color: var(--entity-field-placeholder);
  opacity: 1;
}
/* 27.08.2026. Было 64 px — ровно две строки. Поля «Адрес», «Кем выдан»,
   «Основание» размечены как однострочные (`rows="1"`) и растут сами по мере
   набора (`auto-expand`), но открывались всегда двухстрочными, с пустой
   второй строкой под текстом. Нижняя граница теперь как у обычного поля
   ввода; заданное разметкой число строк (`rows="3"` у заметок) это правило
   не трогает — оно только пол, а не потолок. Замечание Tim. */
.ds-entity-form textarea.theme-input {
  min-height: 38px;
}
.ds-entity-form .theme-input:focus,
.ds-entity-form select:focus,
.ds-entity-form textarea:focus {
  border-color: var(--entity-field-focus-border);
  outline: 2px solid var(--focus-ring-color);
  outline-offset: 0;
  background-color: var(--entity-field-bg);
  transform: none;
}
.ds-entity-inline-action {
  min-height: 40px;
  border-radius: 4px;
  font-weight: 600;
  white-space: nowrap;
}
.ds-modal-close-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 4px;
  border: 1px solid var(--border-color-strong);
  background: var(--surface-primary);
  color: var(--text-secondary);
  transition: var(--transition-fast);
}
.ds-modal-close-btn:hover {
  background: var(--surface-hover);
  border-color: var(--border-color-strong);
  color: var(--text-primary);
}
.ds-modal-close-btn:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(var(--focus-ring-color-rgb), 0.22);
}
.ds-entity-modal .modal-esc-hint {
  display: none;
}
.ds-entity-modal .ds-modal-footer-sticky {
  padding: 10px 1rem;
  background: var(--entity-modal-footer-bg);
  border-top: 1px solid var(--entity-modal-footer-border);
  backdrop-filter: blur(8px);
  gap: 0.5rem;
}
.ds-entity-modal .ds-modal-footer-layout,
.ds-entity-modal .ds-modal-footer-tools,
.ds-entity-modal .ds-modal-footer-danger,
.ds-entity-modal .ds-modal-footer-primary {
  gap: 0.5rem;
}
.ds-entity-modal .ds-modal-footer-danger {
  margin-top: 0;
  padding-left: 0;
  border-left: 0;
}
.ds-entity-modal .ds-modal-footer-sticky .btn {
  min-height: 32px;
  padding-top: 6px;
  padding-bottom: 6px;
}
.ds-entity-modal .ds-modal-footer-sticky .btn-sm {
  font-size: var(--font-size-xs);
}
.ds-entity-modal
  .ds-modal-footer-sticky[data-footer-mode="create"]
  .ds-modal-footer-tools,
.ds-entity-modal
  .ds-modal-footer-sticky[data-footer-mode="create"]
  .ds-modal-footer-danger {
  display: none;
}
.ds-entity-modal
  .ds-modal-footer-sticky[data-footer-mode="create"]
  .ds-modal-footer-layout {
  flex-direction: row;
  justify-content: flex-end;
  align-items: center;
}
.ds-entity-modal
  .ds-modal-footer-sticky[data-footer-mode="create"]
  .ds-modal-footer-primary {
  margin-left: auto;
  width: auto;
  justify-content: flex-end;
}
.ds-entity-modal
  .ds-modal-footer-sticky[data-footer-mode="create"]
  .btn#btn-save {
  min-width: 7.5rem;
}
.ds-entity-modal
  .ds-modal-footer-sticky[data-footer-mode="create"]
  .btn#btn-cancel {
  min-width: 6.5rem;
}

/* ── Переключатель режима списка («Архив») ────────────────────────────────
   Кнопка, у которой есть состояние «включено», обязана его показывать. До
   15.08.2026 «Архив» выглядел обычной кнопкой: нажал — список сменился, а по
   виду не отличить, смотришь ты рабочие записи или архивные. */
.btn-toggle {
  position: relative;
  gap: 8px;
}
.btn-toggle::before {
  content: "";
  width: 26px;
  height: 15px;
  flex: 0 0 auto;
  border-radius: 999px;
  background: var(--button-secondary-border);
  transition: background 0.15s ease;
}
.btn-toggle::after {
  content: "";
  position: absolute;
  left: 13px;
  width: 11px;
  height: 11px;
  border-radius: 50%;
  background: var(--text-inverse);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
  transition: transform 0.15s ease;
}
.btn.btn-toggle[aria-pressed="true"],
.btn.btn-toggle.active,
.btn.btn-toggle[aria-pressed="true"]:hover,
.btn.btn-toggle.active:hover {
  background: var(--brand-600);
  border-color: var(--brand-600);
  color: var(--text-inverse);
}
.btn-toggle[aria-pressed="true"]::before,
.btn-toggle.active::before {
  background: rgba(255, 255, 255, 0.55);
}
.btn-toggle[aria-pressed="true"]::after,
.btn-toggle.active::after {
  transform: translateX(11px);
}
.btn-toggle .fa-archive {
  display: none;
}

/* Пояснение под заголовком: это не подсказка мелким шрифтом, а объяснение
   того, почему список выглядит иначе. Оно должно читаться. */
.list-mode-note {
  margin: 10px 0 14px;
  padding: 10px 14px;
  border-radius: 6px;
  border-left: 3px solid var(--brand-600);
  background: var(--surface-muted, rgba(109, 40, 217, 0.06));
  color: var(--text-primary);
  font-size: 14px;
  line-height: 1.45;
}

/* Показания приборов при приёмке документа: строка на прибор — что за прибор,
   что было в прошлый раз, поле для цифры с акта и посчитанный расход. */
.documents-review-meters-row {
  display: grid;
  /* Первая графа с 27.08.2026 несёт не подпись, а поля: ресурс списком и
     заводской номер. Приборы, заведённые по акту, приезжают с ошибками
     разбора, и править их надо здесь же. */
  grid-template-columns:
    minmax(320px, 1.6fr) minmax(120px, 0.8fr) minmax(180px, 0.9fr)
    minmax(110px, 0.7fr);
  gap: 12px;
  align-items: center;
  padding: 8px 0;
  border-bottom: 1px solid var(--border-color);
}
.documents-review-meters-resource-select {
  max-width: 190px;
}
.documents-review-meters-no-input {
  max-width: 160px;
}
.documents-review-meters-value {
  display: flex;
  gap: 6px;
  align-items: flex-end;
}
.documents-review-meters-value .documents-review-meters-field {
  flex: 1 1 auto;
  min-width: 0;
}
.documents-review-meters-value .documents-review-meters-input {
  width: 100%;
  min-width: 0;
}
/* Подпись над полем: в узкой правой колонке поля стоят столбиком, и без
   подписи заполненные «№ счётчика» и «Показание» неотличимы — обе просто
   цифры. Подпись видна всегда, а не только пока placeholder. Tim 30.08.2026. */
.documents-review-meters-field {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.documents-review-meters-field-label {
  color: var(--text-secondary);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.documents-review-meters-link {
  font-size: 12px;
  white-space: nowrap;
}
.documents-review-meters-hint {
  margin: 0 0 10px;
  padding: 8px 10px;
  border-radius: 6px;
  background: var(--surface-muted, rgba(109, 40, 217, 0.06));
  color: var(--text-secondary);
  font-size: 13px;
  line-height: 1.45;
}
.documents-review-meters-row:last-child {
  border-bottom: none;
}
.documents-review-meters-name {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: baseline;
}
.documents-review-meters-resource {
  font-weight: 600;
}
.documents-review-meters-no {
  font-variant-numeric: tabular-nums;
}
.documents-review-meters-muted {
  color: var(--text-secondary);
  font-size: 13px;
}
.documents-review-meters-prev {
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.documents-review-meters-input {
  font-variant-numeric: tabular-nums;
}
.documents-review-meters-consumption {
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.documents-review-meters-consumption--bad {
  color: var(--error-600);
  font-weight: 600;
}
/* Показание, подставленное из документа, помечено: человек должен видеть,
   что цифра не введена им и её стоит сверить с бумагой. 27.08.2026 */
.documents-review-meters-input--from-doc {
  border-color: var(--brand-600);
}
.documents-review-meters-from-doc {
  padding: 1px 6px;
  border-radius: 999px;
  background: var(--surface-muted, rgba(109, 40, 217, 0.08));
  color: var(--text-secondary);
  font-size: 12px;
}
/* Приборы, которых в системе нет. Документ их назвал, но в акте показания
   рукописные и распознавание их путает — поэтому строки правятся здесь же:
   ресурс, номер, показание. Замечание Tim 27.08.2026. */
.documents-review-meters-new {
  margin-top: 12px;
}
.documents-review-meters-new-title {
  margin-bottom: 6px;
  color: var(--text-secondary);
  font-size: 13px;
}
.documents-review-meters-newrow {
  display: grid;
  grid-template-columns: minmax(160px, 1.2fr) minmax(140px, 1fr) 140px 84px;
  gap: 8px;
  align-items: end;
  padding: 4px 0;
}
.documents-review-meters-newrow-actions {
  display: flex;
  gap: 4px;
}
.documents-review-meters-new-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  align-items: center;
  margin-top: 10px;
}
@media (max-width: 900px) {
  .documents-review-meters-newrow {
    grid-template-columns: 1fr 1fr;
  }
}
.documents-review-meters-head {
  display: flex;
  align-items: end;
  gap: 12px;
  margin: 10px 0 12px;
}
.documents-review-meters-date {
  display: flex;
  flex-direction: column;
  gap: 6px;
  max-width: 200px;
}
.documents-review-status-error {
  color: var(--error-600);
}
@media (max-width: 900px) {
  .documents-review-meters-row {
    grid-template-columns: 1fr 1fr;
  }
}

/* Двухколонный вид карточки: правая колонка бывает уже 500 px, а строка
   прибора в ней просила 730. Поля и кнопки выпадали за край, снизу вылезала
   горизонтальная полоса (замечание Tim 27.08.2026). Ширину меряем У САМОГО
   БЛОКА, а не у окна: в двухколонном виде окно широкое, а места нет.
   Медиазапрос по окну выше остаётся запасным для браузеров без @container. */
.documents-review-meters {
  container-type: inline-size;
  container-name: meters;
}

@container meters (max-width: 760px) {
  .documents-review-meters-row {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  .documents-review-meters-name {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
  }
  .documents-review-meters-resource-select,
  .documents-review-meters-no-input {
    max-width: none;
  }
  .documents-review-meters-newrow {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  .documents-review-meters-head {
    flex-wrap: wrap;
    align-items: center;
  }
}

@container meters (max-width: 460px) {
  .documents-review-meters-row,
  .documents-review-meters-newrow {
    grid-template-columns: minmax(0, 1fr);
  }
  .documents-review-meters-prev {
    order: 3;
  }
}

/* Кнопка в узкой колонке строки настройки (col-md-2 при окне 1024–1180). */
.setting-item .btn {
  white-space: normal;
  max-width: 100%;
}

/* «Пригласить пользователя»: колонки 6/4/2 — доли узкой карточки; при
   окне 1024–1180 кнопке в col-md-2 доставалось ~80 px, «Пригласить» не
   помещалось (замер 03.10.2026). Колонки — по содержимому с переносом. */
.settings-invite-row > [class*="col-"] {
  flex: 1 1 200px;
  max-width: none;
  min-width: 0;
}
.settings-invite-row > .col-md-2 {
  flex: 0 1 auto;
}
