/* ============================================================================
   Eska Design System
   Источник стиля: https://1eska.ru (Aspro Allcorp2, кастом)
   Прототип и обоснование решений: research/design-system/README.md
   ============================================================================ */

/* Порядок каскадных слоёв. Задаётся ЗДЕСЬ, потому что ds.css подключается первым
   (base.html, login.html) — кто первым объявил, тот и определяет порядок.

   Зачем вообще: Tailwind v4 держит все утилиты в `@layer utilities`, а неслоёвый
   (unlayered) CSS по спецификации каскада сильнее ЛЮБОГО слоя — независимо от
   порядка <link> и специфичности. Пока этот файл был unlayered, каждое его
   правило перебивало утилиты: `class="alert ... hidden"` показывался всегда
   (пустая красная плашка на /services/forum-search), `class="btn ... w-full"`
   молча игнорировал ширину. Регрессия появилась с переходом на локальную
   сборку Tailwind v4 (issue 014); см. docs/_Общее/issue/019_css_cascade_layers/.

   Три вещи, которые здесь легко сломать:
   1. `properties` обязан стоять первым. Иначе слой впервые встретится уже в
      tailwind.css и допишется ПОСЛЕ utilities — тогда `*{--tw-*:initial}`
      перебьёт значения от утилит, и разом умрут все transform/shadow/gradient.
   2. Имя слоя для этого файла — именно `components`: Tailwind сам объявляет его
      между `base` и `utilities`. Со своим именем (например `ds`) слой при потере
      этой строки уехал бы в конец и вернул исходный баг.
   3. `components` не должен оказаться раньше `base`: preflight задаёт
      `h1..h6{font-size:inherit}`, `a{color:inherit}`, `*{margin:0}` теми же
      селекторами, что секция «База» ниже, а между слоями специфичность не
      считается — вся типографика и цвет ссылок умрут. */
@layer properties, theme, base, components, utilities;

/* ---------- 1. Шрифты (self-host, только latin+cyrillic — см. README) ---- */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/inter-400-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('/static/fonts/inter-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/inter-500-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('/static/fonts/inter-500-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/inter-600-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/inter-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/montserrat-600-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/static/fonts/montserrat-600-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/static/fonts/montserrat-700-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Montserrat';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('/static/fonts/montserrat-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Unbounded (вариативный, отдаём одним файлом на вес 700-900) — заголовочный
   шрифт для инстансов с собственным брендом (напр. dodo-goretskih.css,
   issue 015). Не подключается по умолчанию — используется, только если
   тема инстанса переопределит --font-display на 'Unbounded'. */
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 700 900;
  font-display: swap;
  src: url('/static/fonts/unbounded-800-cyrillic.woff2') format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: 'Unbounded';
  font-style: normal;
  font-weight: 700 900;
  font-display: swap;
  src: url('/static/fonts/unbounded-800-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---------- 2. Токены ---------------------------------------------------- */
:root {
  /* --- Бренд (взято с 1eska.ru) --- */
  --brand-50:  #e6fbf4;
  --brand-100: #c2f5e4;
  --brand-200: #8aebcd;
  --brand-300: #4bddb2;
  --brand-400: #17d29b;
  --brand-500: #00ca89;   /* основной акцент 1eska */
  --brand-600: #26a47b;   /* hover / нажатие */
  --brand-700: #1c7f60;
  --brand-900: #0a2a2a;   /* глубокий тёмно-зелёный, фон сайдбара/hero */

  /* --- Нейтральные (шкала Tailwind gray — её же использует 1eska.ru) --- */
  --gray-50:  #f9fafb;
  --gray-100: #f3f4f6;
  --gray-200: #e5e7eb;
  --gray-300: #d1d5db;
  --gray-400: #9ca3af;
  --gray-500: #6b7280;
  --gray-600: #4b5563;
  --gray-700: #374151;
  --gray-800: #1f2937;
  --gray-900: #111827;

  /* --- Статусные --- */
  --ok:    #16a34a;  --ok-bg:    #ddf8e5;  --ok-fg:   #15803d;
  --warn:  #f6a142;  --warn-bg:  #fff4e3;  --warn-fg: #b45309;
  --err:   #dc2626;  --err-bg:   #fee2e2;  --err-fg:  #dc2626;
  --info:  #2563eb;  --info-bg:  #e3f4ff;  --info-fg: #2563eb;
  --muted-accent: #7c3aed; --muted-accent-bg: #f9e8ff; --muted-accent-fg: #7c3aed;

  /* --- Семантика: светлая тема --- */
  --bg:            var(--gray-50);
  --bg-elevated:   #ffffff;
  --bg-sunken:     var(--gray-100);
  --bg-hover:      var(--gray-50);
  --surface-line:  var(--gray-200);
  --line-strong:   var(--gray-300);

  --fg:            var(--gray-900);
  --fg-secondary:  var(--gray-600);
  --fg-muted:      var(--gray-500);
  --fg-faint:      var(--gray-400);
  --fg-on-accent:  #ffffff;

  --accent:        var(--brand-500);
  --accent-hover:  var(--brand-600);
  --accent-soft:   var(--brand-50);
  --accent-fg:     var(--brand-700);

  --sidebar-bg:    var(--brand-900);
  --sidebar-fg:    #cfe6df;
  --sidebar-fg-active: #ffffff;
  /* По умолчанию сайдбар сплошной (все три точки градиента равны
     --sidebar-bg) — вертикальный градиент включается per-instance темой
     (issue 015), переопределив --sidebar-grad-mid/--sidebar-grad-end/
     --sidebar-glow, а не правкой .sidebar здесь. См. themes/dodo.css. */
  --sidebar-grad-mid: var(--sidebar-bg);
  --sidebar-grad-end: var(--sidebar-bg);
  --sidebar-glow: transparent;
  /* Подсветка активного пункта сайдбара и «чернила» на акцентной плашке.
     Были зашиты 1eska-зелёным прямо в правилах — из-за этого тема заказчика
     проступала зелёным (issue 015, брендирование инстансов). */
  --nav-active-bg: rgba(0, 202, 137, .16);
  --on-accent-ink: #06231c;
  /* Промежуточные остановки градиента hero/акцентной статистики. */
  --grad-mid:  #10403a;
  --grad-late: #14524a;
  /* Световое пятно в углу hero — тоже брендовое. */
  --hero-glow: rgba(0, 202, 137, .35);

  /* --- Палитра графиков ---
     Проверено scripts/validate_palette.js (dataviz) против поверхности #ffffff:
     lightness band, chroma floor, CVD-разделение, normal-vision floor, контраст — ALL CHECKS PASS.
     Порядок фиксированный: серия N всегда берёт --c-N, цвет привязан к сущности,
     а не к позиции в отфильтрованном списке. 7-я серия → «Прочее» или small multiples. */
  --c-1: #0f9b74;  /* мятный — бренд, всегда «основная» серия */
  --c-2: #2563eb;
  --c-3: #c2740e;
  --c-4: #9333ea;
  --c-5: #be185d;
  --c-6: #0891b2;
  /* Последовательная шкала (одна тональность, светлая→тёмная) — тепловые карты, интенсивность */
  --seq-1: #3fcba3; --seq-2: #12b489; --seq-3: #0d9068; --seq-4: #0a6b4e; --seq-5: #064c37;
  /* Расходящаяся: два полюса + нейтральная середина (план/факт, отклонение) */
  --div-neg: #be185d; --div-mid: var(--gray-300); --div-pos: #0f9b74;
  /* Сетка и оси — рецессивные */
  --chart-grid: var(--surface-line);
  --chart-axis: var(--fg-faint);

  /* --- Типографика --- */
  --font-display: 'Montserrat', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-ui:      'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace;

  --fs-xs:  11px;  --fs-sm: 13px;  --fs-md: 14px;
  --fs-lg:  16px;  --fs-xl: 20px;  --fs-2xl: 26px;  --fs-3xl: 34px;

  /* --- Скругления (1eska: 8/12/14/16, pill) --- */
  --r-sm: 8px;  --r-md: 12px;  --r-lg: 16px;  --r-xl: 22px;  --r-pill: 999px;

  /* --- Тени (мягкие, как на 1eska.ru) --- */
  --sh-sm: 0 1px 2px rgba(10, 42, 42, .05);
  --sh-md: 0 4px 14px rgba(10, 42, 42, .06);
  --sh-lg: 0 12px 32px -8px rgba(10, 42, 42, .16);
  --sh-accent: 0 6px 16px rgba(0, 202, 137, .28);

  /* --- Отступы (шаг 4px) --- */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px;
  --s-5: 20px; --s-6: 24px; --s-8: 32px; --s-10: 40px; --s-12: 48px;

  --shell-sidebar: 244px;
  --shell-sidebar-collapsed: 72px;
  --shell-topbar: 60px;
  --transition: 140ms cubic-bezier(.4, 0, .2, 1);
}

/* ---------- 3. База ------------------------------------------------------ */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font-ui);
  font-size: var(--fs-md);
  line-height: 1.5;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, .display { font-family: var(--font-display); font-weight: 700; margin: 0; letter-spacing: -.01em; }
h1 { font-size: var(--fs-3xl); }
h2 { font-size: var(--fs-2xl); }
h3 { font-size: var(--fs-xl); }
h4 { font-size: var(--fs-lg); }
p  { margin: 0 0 var(--s-3); }
a  { color: var(--accent-fg); text-decoration: none; }
a:hover { text-decoration: underline; }

/* Имена совпадают с утилитами Tailwind — и это осознанно: правила нужны здесь,
   потому что утилита из `@layer utilities` слабее неслоёвого селектора `h3`
   выше, и без них `<h3 class="text-sm">` вырос бы с 13px до 20px. Те же
   значения продублированы токенами --text-sm/--text-xs в tailwind-src.css,
   чтобы утилита давала тот же размер на обычных элементах (issue 019). */
.text-sm    { font-size: var(--fs-sm); }
.text-xs    { font-size: var(--fs-xs); }
.muted      { color: var(--fg-muted); }
.secondary  { color: var(--fg-secondary); }
.num        { font-variant-numeric: tabular-nums; }
.mono       { font-family: var(--font-mono); font-size: var(--fs-sm); }

/* ---------- 4. Оболочка (shell) ------------------------------------------ */
.shell { grid-template-columns: var(--shell-sidebar) 1fr; min-height: 100vh;
  transition: grid-template-columns var(--transition);
  /* колонка сайдбара остаётся тёмной на всю высоту документа, а не только первого экрана */
  background: linear-gradient(to right, var(--sidebar-bg) 0 var(--shell-sidebar), var(--bg) var(--shell-sidebar));
}
body.sidebar-collapsed .shell {
  grid-template-columns: var(--shell-sidebar-collapsed) 1fr;
  background: linear-gradient(to right, var(--sidebar-bg) 0 var(--shell-sidebar-collapsed), var(--bg) var(--shell-sidebar-collapsed));
}

.sidebar {
  background: linear-gradient(180deg, var(--sidebar-bg) 0%, var(--sidebar-grad-mid) 55%, var(--sidebar-grad-end) 100%);
  color: var(--sidebar-fg); flex-direction: column;
  position: sticky; top: 0; height: 100vh; overflow-x: hidden; overflow-y: auto;
  z-index: 50;
}
/* Свечение снизу — тот же приём, что у .hero, но в нижнем углу.
   z-index:-1 топит его под обычными (не спозиционированными) детьми
   сайдбара внутри его же стекового контекста (сайдбар — sticky + z-index).
   --sidebar-glow: transparent по умолчанию — см. --sidebar-grad-mid выше. */
.sidebar::after {
  content: ''; position: absolute; left: -60px; bottom: -60px; width: 220px; height: 220px;
  border-radius: 50%; background: radial-gradient(circle, var(--sidebar-glow), transparent 70%);
  pointer-events: none; z-index: -1;
}
.sidebar__brand-row { align-items: center; justify-content: space-between; gap: var(--s-2);
  padding: var(--s-5) var(--s-3) var(--s-4) var(--s-5);
}
.sidebar__brand { align-items: center; gap: var(--s-3); min-width: 0;
  font-family: var(--font-display); font-weight: 700; font-size: var(--fs-lg);
  color: #fff;
}
.sidebar__brand:hover { text-decoration: none; }
.sidebar__logo {
  width: 30px; height: 30px; border-radius: var(--r-sm);
  background: var(--brand-500); color: var(--brand-900); place-items: center; font-size: var(--fs-sm); font-weight: 700;
  flex-shrink: 0;
}
/* Логотип инстанса как картинка (issue 015) — свой фон уже в самой картинке,
   тут только размер/форма, без цветовой заливки текстовой марки. */
.sidebar__logo--img {
  background: none; object-fit: cover;
}
.sidebar__group { padding: var(--s-3) var(--s-3) 0; }
.sidebar__label {
  font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .08em;
  color: rgba(255,255,255,.34); padding: var(--s-2) var(--s-3); font-weight: 600;
}
.nav-item { align-items: center; gap: var(--s-3);
  padding: 9px var(--s-3); border-radius: var(--r-sm);
  color: var(--sidebar-fg); font-size: var(--fs-sm); font-weight: 500;
  transition: background var(--transition), color var(--transition);
}
.nav-item:hover { background: rgba(255,255,255,.07); color: #fff; text-decoration: none; }
.nav-item--active { background: var(--nav-active-bg); color: #fff; box-shadow: inset 2px 0 0 var(--brand-500); }
.nav-item svg { width: 17px; height: 17px; flex-shrink: 0; opacity: .85; }
/* Счётчик непрочитанного в пункте меню. Без объявления display намеренно: правило
   неслоёвое, и `display` здесь перебил бы утилиту `hidden`, которой скрипт прячет
   пустой бейдж (issue 019, тот же капкан). Элемент и так блокифицируется как
   flex-элемент .nav-item, поэтому padding и min-width работают. */
.nav-item__badge {
  margin-left: auto; background: var(--brand-500); color: var(--on-accent-ink);
  font-size: 11px; font-weight: 700; line-height: 1; padding: 3px 7px;
  border-radius: var(--r-pill); min-width: 20px; text-align: center;
}
.sidebar__footer { margin-top: auto; padding: var(--s-4); border-top: 1px solid rgba(255,255,255,.08); }

.sidebar__collapse-btn { color: rgba(255,255,255,.6); flex-shrink: 0; }
.sidebar__collapse-btn:hover { color: #fff; background: rgba(255,255,255,.07); }
.sidebar__collapse-btn svg { transition: transform var(--transition); }
body.sidebar-collapsed .sidebar__collapse-btn svg { transform: rotate(180deg); }

/* Свёрнутый сайдбар (десктоп) — только иконки, ширина см. --shell-sidebar-collapsed */
body.sidebar-collapsed .sidebar__brand span,
body.sidebar-collapsed .sidebar__label,
body.sidebar-collapsed .nav-item span,
body.sidebar-collapsed .sidebar__user-info {
  display: none;
}
body.sidebar-collapsed .sidebar__brand-row {
  flex-direction: column; align-items: center; gap: var(--s-2);
  padding: var(--s-4) var(--s-2);
}
body.sidebar-collapsed .nav-item { justify-content: center; padding-inline: 0; }
body.sidebar-collapsed .sidebar__footer .row { flex-direction: column; gap: var(--s-2); }

.main { flex-direction: column; min-width: 0; }

.topbar {
  height: var(--shell-topbar); align-items: center; gap: var(--s-4);
  padding: 0 var(--s-6);
  background: var(--bg-elevated);
  border-bottom: 1px solid var(--surface-line);
  position: sticky; top: 0; z-index: 20;
}
.topbar__title { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-lg); }
.topbar__spacer { flex: 1; }

/* Общий колокольчик уведомлений (issue 041) — виден на любой странице любого
   сервиса, не только там, где topbar_actions что-то определил. */
.notif-bell { position: relative; }
.notif-bell__badge {
  position: absolute; top: 2px; right: 2px;
  min-width: 16px; height: 16px; padding: 0 4px;
  border-radius: 999px; background: var(--err-fg); color: #fff;
  font-size: 10px; line-height: 16px; text-align: center;
  font-variant-numeric: tabular-nums;
}
.notif-bell__panel {
  position: absolute; top: calc(100% + 8px); right: 0;
  width: 360px; max-height: 420px; overflow-y: auto;
  z-index: 30; padding: var(--s-3);
}
.notif-bell__header {
  align-items: center; justify-content: space-between;
  margin-bottom: var(--s-2); padding-bottom: var(--s-2);
  border-bottom: 1px solid var(--surface-line);
}
.notif-bell__header button { color: var(--accent-fg); }
.notif-bell__item {
  width: 100%; text-align: left; padding: var(--s-2);
  border-radius: var(--r-sm); cursor: pointer; background: none; border: 0;
}
.notif-bell__item:hover { background: var(--bg-hover); }
.notif-bell__item--unread { background: var(--accent-soft); }
.notif-bell__item-title { font-size: 13px; color: var(--fg); }
.notif-bell__item-meta { font-size: 11px; color: var(--fg-secondary); margin-top: 2px; }
.notif-bell__empty { padding: var(--s-4); text-align: center; }

/* Верхнеуровневые вкладки страницы в топбаре (issue 028) — усиление
   переполнения через app/static/js/topbar-tabs.js. min-width:0, чтобы
   flex-контейнер топбара мог сжимать эту группу (иначе overflow не
   наступит, потому что flex-item не сжимается ниже intrinsic-ширины). */
.topbar > .tabs {
  border-bottom: 0; margin: 0; min-width: 0; flex-shrink: 1;
  overflow: hidden; flex-wrap: nowrap;
}
.topbar > .tabs .tab { padding: 8px var(--s-3); font-size: var(--fs-sm); }
.topbar__pagetabs-overflow { position: relative; flex-shrink: 0; }
.topbar__pagetabs-more { flex-shrink: 0; }
.topbar__pagetabs-panel {
  top: calc(100% + 4px); right: 0; left: auto; min-width: 200px;
  flex-direction: column; padding: 6px; gap: 2px;
}
.topbar__pagetabs-panel .tab {
  text-align: left; border-bottom: 0; border-radius: var(--r-sm);
  padding: 8px 10px; margin: 0;
}
.topbar__pagetabs-panel .tab:hover { background: var(--bg-sunken); }
.topbar__pagetabs-panel .tab[aria-selected="true"] { background: var(--accent-soft); color: var(--accent-fg); }

.content { padding: var(--s-6); max-width: 1560px; width: 100%; }
.page-head { margin-bottom: var(--s-6); }
.page-head p { color: var(--fg-secondary); margin: var(--s-2) 0 0; }
.sidebar-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,.35); z-index: 45;
  opacity: 0; pointer-events: none; transition: opacity var(--transition);
}
.sidebar-backdrop.is-open { opacity: 1; pointer-events: auto; }

/* ---------- 5. Карточки -------------------------------------------------- */
.card {
  background: var(--bg-elevated);
  border-style: solid;
  border-radius: var(--r-lg);
  box-shadow: var(--sh-sm);
}
/* Толщина и цвет рамки — в слое: разметка навешивает на карточки акцентные
   `border-l-4 border-l-red-500` (issue 019, шаг 2) и они должны перебивать
   дефолт. Остальные свойства карточки остаются unlayered, иначе неслоёвая
   базовая типографика начинает перебивать `.card__head h3`, и заголовки
   внутри карточек вырастают с 14px до 20px (проверено пробой). */
@layer components {
  .card { border-width: 1px; border-color: var(--surface-line); }
}
.card--pad   { padding: var(--s-5); }
.card--hover { transition: box-shadow var(--transition), transform var(--transition), border-color var(--transition); }
.card--hover:hover { box-shadow: var(--sh-md); transform: translateY(-2px); border-color: var(--brand-200); }
.card__head { align-items: center; gap: var(--s-3);
  padding: var(--s-4) var(--s-5); border-bottom: 1px solid var(--surface-line);
}
.card__title { font-family: var(--font-display); font-weight: 600; font-size: var(--fs-md); }
.card__body { padding: var(--s-5); }

/* ---------- 6. Кнопки ---------------------------------------------------- */
.btn { align-items: center; justify-content: center; gap: var(--s-2);
  font-family: var(--font-ui); font-weight: 600; font-size: var(--fs-sm);
  padding: 9px 16px; border-radius: var(--r-sm);
  border: 1px solid transparent; cursor: pointer; white-space: nowrap;
  transition: background var(--transition), color var(--transition), box-shadow var(--transition), border-color var(--transition);
}
.btn svg { width: 16px; height: 16px; }
.btn:hover { text-decoration: none; }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:disabled, .btn[disabled] { opacity: .5; cursor: not-allowed; box-shadow: none; }

.btn--primary { background: var(--accent); color: #fff; box-shadow: var(--sh-accent); }
.btn--primary:hover:not(:disabled) { background: var(--accent-hover); color: #fff; }

.btn--secondary { background: var(--bg-elevated); color: var(--fg); border-color: var(--line-strong); }
.btn--secondary:hover:not(:disabled) { background: var(--bg-hover); border-color: var(--fg-faint); }

.btn--ghost { background: transparent; color: var(--fg-secondary); }
.btn--ghost:hover:not(:disabled) { background: var(--bg-sunken); color: var(--fg); }

.btn--danger { background: var(--err); color: #fff; }
.btn--danger:hover:not(:disabled) { filter: brightness(.92); }

.btn--sm { padding: 5px 11px; font-size: var(--fs-xs); border-radius: 7px; }
.btn--lg { padding: 12px 24px; font-size: var(--fs-md); border-radius: var(--r-md); }
.btn--icon { padding: 8px; width: 34px; height: 34px; }

/* ---------- 7. Бейджи / чипы --------------------------------------------- */
.badge { align-items: center; gap: 5px;
  padding: 3px 9px; border-radius: var(--r-pill);
  font-size: var(--fs-xs); font-weight: 600; line-height: 1.5;
  background: var(--bg-sunken); color: var(--fg-secondary);
}
.badge--ok    { background: var(--ok-bg);    color: var(--ok-fg); }
.badge--warn  { background: var(--warn-bg);  color: var(--warn-fg); }
.badge--err   { background: var(--err-bg);   color: var(--err-fg); }
.badge--info  { background: var(--info-bg);  color: var(--info-fg); }
.badge--accent{ background: var(--accent-soft); color: var(--accent-fg); }
.badge--ai    { background: var(--muted-accent-bg); color: var(--muted-accent-fg); }
.badge__dot   { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* ---------- 8. Формы ----------------------------------------------------- */
.field { flex-direction: column; gap: 6px; }
.label { font-size: var(--fs-xs); font-weight: 600; color: var(--fg-secondary); text-transform: uppercase; letter-spacing: .04em; }
.input, .select, .textarea {
  font-family: var(--font-ui); font-size: var(--fs-sm); color: var(--fg);
  background: var(--bg-elevated);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  padding: 8px 11px;
  transition: border-color var(--transition), box-shadow var(--transition);
}
/* width:100% только внутри .field — сознательного layout-контейнера.
   Без .field элемент сохраняет свой обычный intrinsic/explicit размер,
   поэтому класс можно безопасно навешивать на старую разметку рядом с
   любым существующим w-32/min-w-[...] без изменения раскладки. */
.field .input, .field .select, .field .textarea { width: 100%; }
.input::placeholder, .textarea::placeholder { color: var(--fg-faint); }
.input:focus, .select:focus, .textarea:focus {
  outline: none; border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-soft);
}
.select {
  appearance: none; padding-right: 30px; cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%236b7280'%3E%3Cpath d='M5.5 7.5 10 12l4.5-4.5z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 16px;
}
.textarea { resize: vertical; min-height: 84px; line-height: 1.55; }
.input-group { position: relative; }
.input-group .input { padding-left: 34px; }
.input-group svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); width: 16px; height: 16px; color: var(--fg-faint); }

.filters { flex-wrap: wrap; align-items: flex-end; gap: var(--s-3); }
.filters .field { min-width: 150px; }

/* Список с поиском вместо браузерного <select> (issue 027) — усиление
   через app/static/js/searchable-select.js, только pointer:fine. Исходный
   <select> остаётся в DOM (для форм/существующего JS), визуально скрыт. */
.searchable-select { position: relative; }
/* !important — `.field .select { width: 100% }` (специфичность 0-2-0) иначе
   перебивает скрытие 0-1-0 у нативного select внутри .field: он остаётся
   растянутым на всю ширину обёртки, absolute-позиционирование выносит эту
   ширину в scrollable overflow страницы — невидимый select ломает горизонтальный
   скролл всей страницы (issue 027, найдено на «Отчётах» кассы). */
.searchable-select__native {
  position: absolute; opacity: 0; pointer-events: none;
  width: 1px !important; height: 1px !important; overflow: hidden;
}
/* Тот же шеврон, что у нативного .select — иначе поле не читается как
   "выбор из списка" и выглядит обычным текстовым вводом (issue 027). */
.searchable-select__input {
  width: 100%; appearance: none; cursor: pointer; padding-right: 30px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20' fill='%236b7280'%3E%3Cpath d='M5.5 7.5 10 12l4.5-4.5z'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 8px center; background-size: 16px;
}
.searchable-select__panel {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 50;
  width: 100%; min-width: 180px; max-height: 260px; overflow-y: auto;
  padding: 4px;
}
.searchable-select__option {
  padding: 7px 10px; border-radius: var(--r-sm); cursor: pointer;
  font-size: var(--fs-sm); color: var(--fg);
}
.searchable-select__option:hover, .searchable-select__option.is-active {
  background: var(--accent-soft); color: var(--accent-fg);
}
.searchable-select__empty {
  padding: 7px 10px; font-size: var(--fs-sm); color: var(--fg-faint);
}

/* Сегментированный переключатель — вместо голых радио/табов */
.segmented { background: var(--bg-sunken); border-radius: var(--r-sm); padding: 3px; gap: 2px; }
.segmented button {
  border: 0; background: transparent; cursor: pointer;
  font-family: var(--font-ui); font-size: var(--fs-sm); font-weight: 500; color: var(--fg-secondary);
  padding: 6px 13px; border-radius: 6px; transition: all var(--transition);
}
.segmented button[aria-selected="true"] { background: var(--bg-elevated); color: var(--fg); box-shadow: var(--sh-sm); font-weight: 600; }

/* Выпадающая панель (например, настройки сервиса из шестерёнки в топбаре) */
.dropdown { position: relative; }
.dropdown__panel {
  position: absolute; right: 0; top: calc(100% + 8px); z-index: 50;
  width: 320px;
}

/* Пикер периода (кнопка + панель с тремя годами месяцев, drag-выделение — паттерн 1С) */
.period-picker { position: relative; }
.period-picker__btn { align-items: center; gap: var(--s-2);
  min-width: 220px; padding: 9px var(--s-4);
  border: 1px solid var(--line-strong); border-radius: var(--r-sm);
  background: var(--bg-elevated); color: var(--fg);
  font-family: var(--font-ui); font-size: var(--fs-sm); font-weight: 500;
  cursor: pointer; transition: border-color var(--transition), background var(--transition);
}
.period-picker__btn:hover { background: var(--bg-sunken); }
.period-picker__btn svg { width: 16px; height: 16px; flex-shrink: 0; color: var(--fg-muted); }
.period-picker__btn .period-picker__chevron { margin-left: auto; }

.period-panel {
  position: absolute; top: calc(100% + 6px); left: 0; z-index: 50;
  width: auto; min-width: 620px; padding: var(--s-4);
  user-select: none;
}
/* Кнопка у правого края контейнера (см. period_picker(align='right')) —
   панель открывается влево от кнопки, а не вправо за пределы экрана. */
.period-panel--right { left: auto; right: 0; }

.period-panel__nav { align-items: center; justify-content: space-between;
  gap: var(--s-3); margin-bottom: var(--s-3);
}
.period-panel__nav-btn { place-items: center; width: 30px; height: 30px;
  border-radius: var(--r-pill); border: none; background: transparent;
  color: var(--fg-muted); font-size: 16px; cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.period-panel__nav-btn:hover { background: var(--bg-sunken); color: var(--fg); }

.period-years { gap: var(--s-5); flex: 1; justify-content: center; }
.period-year-col { flex-direction: column; align-items: center; gap: var(--s-2); }
.period-year-label { font-family: var(--font-display); font-weight: 700; font-size: var(--fs-sm); color: var(--fg); }
.period-year-grid { grid-template-columns: repeat(3, 1fr); gap: 4px; }

.period-month-btn {
  min-width: 52px; padding: 7px 10px; border-radius: var(--r-sm);
  border: 1px solid transparent; background: transparent;
  font-family: var(--font-ui); font-size: var(--fs-sm); color: var(--fg-secondary);
  cursor: pointer; transition: background var(--transition), color var(--transition), border-color var(--transition);
}
.period-month-btn:hover { background: var(--bg-sunken); color: var(--fg); }
.period-month-btn.is-current { color: var(--accent-fg); font-weight: 600; border-color: var(--accent-soft); }
.period-month-btn.is-in-range { background: var(--accent-soft); color: var(--accent-fg); font-weight: 600; }
.period-month-btn.is-dragging { background: var(--accent); color: var(--on-accent-ink); font-weight: 600; }

.period-panel__presets { grid-template-columns: repeat(4, 1fr); gap: var(--s-2);
  padding: var(--s-3) 0; border-top: 1px solid var(--surface-line);
}
.period-panel__preset-btn {
  padding: 7px 0; border-radius: var(--r-sm); border: 1px solid var(--surface-line);
  background: var(--bg-elevated); color: var(--fg-secondary);
  font-family: var(--font-ui); font-size: var(--fs-xs); cursor: pointer;
  transition: background var(--transition), color var(--transition);
}
.period-panel__preset-btn:hover { background: var(--bg-sunken); color: var(--fg); }

.period-panel__custom { align-items: center; gap: var(--s-2);
  padding-top: var(--s-3); border-top: 1px solid var(--surface-line);
}
.period-panel__custom .input { flex: 1; }

/* ---------- 9. Метрики (KPI) --------------------------------------------- */
.stat-grid { gap: var(--s-4); grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }
.stat {
  background: var(--bg-elevated); border: 1px solid var(--surface-line);
  border-radius: var(--r-lg); padding: var(--s-4) var(--s-5); flex-direction: column; gap: 6px;
}
.stat__label { font-size: var(--fs-xs); font-weight: 600; color: var(--fg-muted); text-transform: uppercase; letter-spacing: .05em; }
.stat__value { font-family: var(--font-display); font-size: var(--fs-2xl); font-weight: 700; line-height: 1.1; font-variant-numeric: tabular-nums; }
.stat__foot  { font-size: var(--fs-xs); color: var(--fg-muted); align-items: center; gap: 5px; }
.delta       { font-weight: 600; font-variant-numeric: tabular-nums; }
.delta--up   { color: var(--ok); }
.delta--down { color: var(--err); }
.stat--accent { background: linear-gradient(135deg, var(--brand-900), var(--grad-mid)); border-color: transparent; color: #fff; }
.stat--accent .stat__label, .stat--accent .stat__foot { color: rgba(255,255,255,.6); }
.stat--accent .stat__value { color: var(--brand-400); }

/* ---------- 10. Таблицы -------------------------------------------------- */
/* :where() обнуляет вклад ".table"/"tbody" в специфичность — правила ниже
   действуют как ДЕФОЛТ и всегда проигрывают любому Tailwind-утилити-классу
   на том же элементе (text-right/text-center/py-2 и т.п., которых в старой
   разметке много). Без :where() ".table th{text-align:left}" (0,1,1) перебивал
   бы одиночный класс ".text-right" (0,1,0) и молча разворачивал бы выравнивание
   у числовых колонок в уже существующих таблицах. */
.table-wrap { overflow-x: auto; border-radius: var(--r-lg); }
/* В слое `components`, потому что эти правила — намеренно слабый ДЕФОЛТ (см.
   комментарий выше и :where(), обнуляющий специфичность): разметка таблиц
   рассчитывает, что `text-right` на числовой колонке, `py-2` на th и т.п.
   перебивают дизайн-систему. Одного :where() для этого больше не хватает —
   неслоёвый CSS сильнее любого слоя, включая utilities (issue 019, шаг 2). */
@layer components {
  :where(.table) { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--fs-sm); }
  :where(.table) th {
    text-align: left; font-size: var(--fs-xs); font-weight: 600;
    text-transform: uppercase; letter-spacing: .05em; color: var(--fg-muted);
    background: var(--bg-sunken); padding: 10px var(--s-4);
    border-bottom: 1px solid var(--surface-line); white-space: nowrap;
    position: sticky; top: 0; z-index: 1;
  }
  :where(.table) td { padding: 11px var(--s-4); border-bottom: 1px solid var(--surface-line); vertical-align: middle; }
  :where(.table) tbody tr { transition: background var(--transition); }
  :where(.table) tbody tr:hover { background: var(--bg-hover); }
  :where(.table) tbody tr:last-child td { border-bottom: 0; }
}
.table .num, .table .t-right { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.table .t-name { white-space: nowrap; font-weight: 600; }
.table--compact td { padding: 7px var(--s-4); }

/* ---------- 10b. Графики ------------------------------------------------- */
.chart { position: relative; }
.chart svg { display: block; width: 100%; overflow: visible; }
.chart .grid line { stroke: var(--chart-grid); stroke-width: 1; }
.chart .axis text { fill: var(--fg-muted); font-size: 11px; font-family: var(--font-ui); }
.chart .axis line, .chart .axis path { stroke: var(--chart-axis); }
/* Текст носит текстовые токены, а не цвет серии */
.chart .value-label { fill: var(--fg-secondary); font-size: 11px; font-variant-numeric: tabular-nums; }
.chart .series-line { fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
/* 2px «шов» цветом поверхности между соседними заливками */
.chart .bar { stroke: var(--bg-elevated); stroke-width: 2; }
.chart .dot { stroke: var(--bg-elevated); stroke-width: 2; }

.hbar { grid-template-columns: 170px 1fr 64px; align-items: center; gap: var(--s-3); padding: 5px 0; }
.hbar__label { font-size: var(--fs-sm); color: var(--fg-secondary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hbar__track { height: 9px; background: var(--bg-sunken); border-radius: var(--r-pill); overflow: hidden; }
.hbar__fill  { height: 100%; border-radius: var(--r-pill); transition: width 400ms cubic-bezier(.4,0,.2,1); }
.hbar__value { font-size: var(--fs-sm); color: var(--fg); text-align: right; font-weight: 600; }
.hbar:hover .hbar__label { color: var(--fg); }

.legend { flex-wrap: wrap; gap: var(--s-4); font-size: var(--fs-xs); color: var(--fg-secondary); }
.legend__item { align-items: center; gap: 6px; }
.legend__swatch { width: 10px; height: 10px; border-radius: 3px; flex-shrink: 0; }

.chart-tip {
  position: absolute; pointer-events: none; opacity: 0; transform: translate(-50%, -120%);
  background: var(--bg-elevated); border: 1px solid var(--surface-line);
  border-radius: var(--r-sm); box-shadow: var(--sh-lg);
  padding: 8px 10px; font-size: var(--fs-xs); white-space: nowrap; z-index: 30;
  transition: opacity var(--transition);
}
.chart-tip[data-open="true"] { opacity: 1; }
.chart-tip b { font-family: var(--font-display); font-size: var(--fs-sm); display: block; margin-bottom: 4px; }
.chart-tip .row { gap: 6px; justify-content: space-between; }
.chart-tip .num { font-weight: 600; font-variant-numeric: tabular-nums; }

/* ---------- 11. Пустое состояние / загрузка ------------------------------ */
.empty { text-align: center; padding: var(--s-12) var(--s-6); color: var(--fg-muted); }
.empty svg { width: 42px; height: 42px; color: var(--fg-faint); margin-bottom: var(--s-3); }
.empty h4 { color: var(--fg); margin-bottom: var(--s-2); }

.skeleton { background: linear-gradient(90deg, var(--bg-sunken) 25%, var(--surface-line) 50%, var(--bg-sunken) 75%);
  background-size: 200% 100%; animation: sk 1.4s infinite; border-radius: 6px; }

.spinner { width: 18px; height: 18px; border: 2px solid var(--surface-line); border-top-color: var(--accent);
  border-radius: 50%; animation: spin .7s linear infinite; }

/* "Устаревший отчёт" (window.createReportRunner.markStale, base.html) —
   фильтры поменялись, а на экране всё ещё старые результаты. Тяжёлые отчёты
   (1С/OData) сознательно не обновляются автоматически при смене фильтра,
   поэтому вместо тихого расхождения — затемнение + плавающая плашка. */
.report-zone { position: relative; }
.report-body { transition: filter 200ms ease, opacity 200ms ease; }
.report-stale .report-body {
  filter: blur(3px) saturate(.7);
  opacity: .55;
  pointer-events: none;
  user-select: none;
}
.stale-pill {
  position: absolute;
  top: 8px; left: 50%;
  transform: translate(-50%, -12px) scale(.96);
  z-index: 5;
  display: flex; align-items: center; gap: 12px;
  padding: 10px 10px 10px 16px;
  border-radius: var(--r-pill);
  background: color-mix(in srgb, var(--bg-elevated) 78%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  border: 1px solid color-mix(in srgb, var(--warn) 35%, var(--surface-line));
  box-shadow: 0 8px 24px -6px rgba(180,83,9,.16), 0 2px 8px rgba(0,0,0,.06);
  font-size: var(--fs-sm); font-weight: 600; color: var(--fg);
  white-space: nowrap;
  opacity: 0; visibility: hidden;
  transition: opacity 220ms ease, transform 220ms cubic-bezier(.2,.8,.2,1), visibility 220ms;
}
.report-stale .stale-pill {
  opacity: 1; visibility: visible;
  transform: translate(-50%, 0) scale(1);
}
.stale-pill__icon {
  display: grid; place-items: center;
  width: 22px; height: 22px; border-radius: 50%;
  background: var(--warn); color: #fff; flex-shrink: 0;
}
.stale-pill__icon svg { width: 13px; height: 13px; }
.stale-pill .btn { border-radius: var(--r-pill); }

/* ---------- 12. Прочее --------------------------------------------------- */
.alert { gap: var(--s-3); padding: var(--s-4); border-radius: var(--r-md); font-size: var(--fs-sm); border: 1px solid transparent; }
.alert svg { width: 18px; height: 18px; flex-shrink: 0; margin-top: 1px; }
.alert--info { background: var(--info-bg); color: var(--info-fg); border-color: rgba(37,99,235,.2); }
.alert--ok   { background: var(--ok-bg);   color: var(--ok-fg); }
.alert--warn { background: var(--warn-bg); color: var(--warn-fg); }
.alert--err  { background: var(--err-bg);  color: var(--err-fg); }

/* overflow-x:auto — страницы с 6+ вкладками (напр. update_analysis.html)
   иначе переносили текст внутри вкладки на 2 строки вместо горизонтального
   скролла (flex-shrink сжимал кнопку раньше, чем текст мог себе позволить
   не завернуться). flex-shrink:0 на .tab держит вкладки в один ряд. */
.tabs { gap: var(--s-1); border-bottom: 1px solid var(--surface-line); overflow-x: auto; }
.tab {
  padding: 10px var(--s-4); font-size: var(--fs-sm); font-weight: 600; color: var(--fg-muted);
  cursor: pointer; background: none; white-space: nowrap; flex-shrink: 0;
  border: 0; border-bottom: 2px solid transparent; margin-bottom: -1px;
  font-family: var(--font-ui); transition: all var(--transition);
}
.tab:hover { color: var(--fg); }
.tab[aria-selected="true"] { color: var(--accent-fg); border-bottom-color: var(--accent); }

.avatar { width: 30px; height: 30px; border-radius: 50%; background: var(--accent-soft); color: var(--accent-fg); place-items: center; font-size: var(--fs-xs); font-weight: 700; flex-shrink: 0; overflow: hidden; }
.avatar img { width: 100%; height: 100%; object-fit: cover; }

.progress { height: 6px; background: var(--bg-sunken); border-radius: var(--r-pill); overflow: hidden; }
.progress__bar { height: 100%; background: var(--accent); border-radius: var(--r-pill); }

.divider { height: 1px; background: var(--surface-line); border: 0; margin: var(--s-5) 0; }

/* утилиты компоновки */
.row { align-items: center; gap: var(--s-3); }
.row--between { justify-content: space-between; }
.col { flex-direction: column; gap: var(--s-3); }
.stack-4 > * + * { margin-top: var(--s-4); }
.stack-6 > * + * { margin-top: var(--s-6); }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); gap: var(--s-4); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); gap: var(--s-4); }

/* ---------- 12b. Документы (план/факт/расхождение) ----------------------- */
/* Паттерн для денежных документов со строками план/факт/расхождение +
   опциональный комментарий (issue 018, «Смена» dodo — первый потребитель,
   design review 2026-08-23, research/design-system/README.md §3.1). Второй
   потребитель — «Приказы» (issue 018, фаза 3), поэтому вынесено сюда, а не
   оставлено инлайн-стилями внутри шаблона одного сервиса.

   Карточка-обёртка — обычный `.card`, статус — обычный `.badge`, компоновка
   заголовка документа — `.row`/`.row--between`: новых классов под то, что
   уже есть в дизайн-системе, не заводим. */
.doc-section { margin-bottom: var(--s-6); }
.doc-section__label {
  font-family: var(--font-display); font-size: var(--fs-xs); font-weight: 700;
  text-transform: uppercase; letter-spacing: .07em; color: var(--fg-faint);
  padding: 0 2px var(--s-3);
}
.card--muted { background: var(--bg-sunken); }

/* Заголовок колонок — один раз на карточку, а не на каждой строке (план/
   факт по 4 раза подряд читается как повторяющийся шум, не как таблица).
   Та же сетка колонок у .doc-cols и .doc-row__top — иначе числа "плывут"
   относительно заголовка и друг друга, как только состав ячеек в очередной
   строке меняется (пусто/инпут/бейдж). */
.doc-cols {
  grid-template-columns: 1fr 84px 116px 72px; align-items: center; gap: var(--s-4);
  padding: var(--s-3) var(--s-5); background: var(--bg-sunken); border-bottom: 1px solid var(--surface-line);
}
.doc-cols span { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .06em; color: var(--fg-faint); font-weight: 700; text-align: right; }
.doc-cols span:first-child { text-align: left; }
.card--muted .doc-cols { background: var(--bg-hover); }

.doc-row { padding: var(--s-3) var(--s-5); border-bottom: 1px solid var(--surface-line); }
.doc-row:last-child { border-bottom: 0; }
.doc-row__top { grid-template-columns: 1fr 84px 116px 72px; align-items: center; gap: var(--s-4); }
.doc-row__label { min-width: 0; font-weight: 600; font-size: var(--fs-sm); }
.doc-row__label small { display: block; font-weight: 400; color: var(--fg-muted); font-size: var(--fs-xs); margin-top: 2px; }
/* Комментарий — справа от названия статьи, в той же первой колонке (там,
   где план/факт/расхождение всё равно пустые для этой строки), а не
   отдельной строкой ниже — так карточка не растёт по высоте без нужды. */
.doc-row__label--with-comment { align-items: center; gap: var(--s-4); }
.doc-row__label-text { flex-shrink: 0; font-weight: 600; }

.doc-val { text-align: right; }
.doc-val__num { font-weight: 600; font-size: var(--fs-sm); font-variant-numeric: tabular-nums; }
.doc-val--muted .doc-val__num { color: var(--fg-faint); font-weight: 400; }
.doc-val--empty .doc-val__num { color: var(--fg-faint); }

/* "Тихая" ячейка-инпут — рамка появляется только на hover/focus, а не
   всегда: иначе на строке из 4 колонок инпут в рамке рядом с обычным
   текстом и цветным бейджем расхождения читается как три конкурирующих
   друг с другом элемента вместо одной строки таблицы. */
.doc-fact-input, .doc-comment {
  border: 1px solid transparent; border-radius: var(--r-sm); background: var(--bg-sunken);
  font-family: var(--font-ui); color: var(--fg); padding: 6px 9px;
}
.doc-fact-input { width: 100%; text-align: right; font-size: var(--fs-sm); font-weight: 600; }
.doc-comment { flex: 1; min-width: 0; font-size: var(--fs-xs); color: var(--fg-secondary); }
.doc-fact-input::placeholder, .doc-comment::placeholder { color: var(--fg-faint); font-weight: 400; }
.doc-fact-input:hover, .doc-comment:hover { border-color: var(--line-strong); }
.doc-fact-input:focus, .doc-comment:focus {
  outline: none; background: var(--bg-elevated); border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft);
}

.doc-diff { text-align: right; font-weight: 700; font-size: var(--fs-sm); justify-self: end; font-variant-numeric: tabular-nums; }
.doc-diff--neg { color: var(--err-fg); }
.doc-diff--pos { color: var(--ok-fg); }
.doc-diff--na { color: var(--fg-faint); font-weight: 400; }

.doc-future-note { align-items: center; gap: var(--s-2); font-size: var(--fs-xs); color: var(--fg-faint); padding: var(--s-3) var(--s-5) var(--s-4); }

/* Итоговое поле, блокирующее закрытие документа без заполнения (ТЗ dodo,
   «сумма доступная для инкассации») — акцентная рамка, а не просто ещё
   один .card, чтобы взгляд сразу находил обязательное поле в самом низу
   длинного документа. */
.doc-required { border: 1px solid var(--accent); border-radius: var(--r-md); background: var(--accent-soft); padding: var(--s-4) var(--s-5); }
.doc-required__label { font-size: var(--fs-xs); text-transform: uppercase; letter-spacing: .05em; color: var(--accent-fg); font-weight: 700; margin-bottom: var(--s-2); }
.doc-required input {
  width: 100%; padding: 9px 12px; border: 1.5px solid var(--accent); border-radius: var(--r-sm);
  font-size: var(--fs-md); font-weight: 700; text-align: right; background: var(--bg-elevated); font-family: var(--font-ui);
}

/* ---------- 13. Главная — hero и карточки сервисов ----------------------- */
.hero {
  background: linear-gradient(135deg, var(--brand-900) 0%, var(--grad-mid) 60%, var(--grad-late) 100%);
  border-radius: var(--r-xl); padding: 34px 38px; color: #fff;
  position: relative; overflow: hidden; margin-bottom: var(--s-6);
}
.hero::after {
  content: ''; position: absolute; right: -70px; top: -70px; width: 300px; height: 300px;
  border-radius: 50%; background: radial-gradient(circle, var(--hero-glow), transparent 68%);
}
.hero h1 { font-size: 32px; margin-bottom: 10px; position: relative; }
.hero p  { color: rgba(255,255,255,.72); max-width: 620px; position: relative; margin: 0; }
.hero__stats { gap: 34px; margin-top: 26px; position: relative; flex-wrap: wrap; }
.hero__stat b { display: block; font-family: var(--font-display); font-size: 26px; color: var(--brand-400); }
.hero__stat span { font-size: 12px; color: rgba(255,255,255,.55); }

.svc { flex-direction: column; padding: 20px; height: 100%; }
.svc__icon {
  width: 42px; height: 42px; border-radius: var(--r-md);
  background: var(--accent-soft); color: var(--accent-fg); place-items: center; margin-bottom: 14px;
}
.svc__icon svg { width: 21px; height: 21px; }
.svc__name { font-family: var(--font-display); font-weight: 600; font-size: 15px; margin-bottom: 6px; }
.svc__desc { font-size: 13px; color: var(--fg-secondary); line-height: 1.5; flex: 1; margin-bottom: 14px; }
.svc__foot { align-items: center; justify-content: space-between; gap: 8px; }
.svc--off { opacity: .55; }
.svc-link { color: inherit; }
.svc-link:hover { text-decoration: none; }
.group-title { font-family: var(--font-display); font-size: 13px; font-weight: 700;
               text-transform: uppercase; letter-spacing: .07em; color: var(--fg-muted); margin: var(--s-8) 0 var(--s-4); }
.group-title:first-child { margin-top: 0; }

@media (max-width: 900px) {
  .shell, body.sidebar-collapsed .shell { grid-template-columns: 1fr; background: var(--bg); }
  .sidebar {
    position: fixed; inset: 0 auto 0 0; width: var(--shell-sidebar);
    transform: translateX(-100%); transition: transform var(--transition);
  }
  .sidebar.is-open { transform: translateX(0); box-shadow: var(--sh-lg); }
  .content { padding: var(--s-4); }
}


/* Анимации — снаружи слоя: имена глобальны, в каскаде свойств не участвуют. */
@keyframes sk { from { background-position: 200% 0; } to { background-position: -200% 0; } }
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- 14. display-объявления компонентов — в слое `components` ----- */
/* Здесь и только здесь дизайн-система задаёт `display`. Причина: Tailwind v4
   держит `.hidden` (и `flex`, `lg:block`, `sm:table-cell`) в `@layer utilities`,
   а неслоёвый CSS сильнее любого слоя — из-за этого `class="alert ... hidden"`
   показывался всегда (issue 019). Перенос ТОЛЬКО display оставляет остальным
   правилам файла прежнюю силу, поэтому вёрстка выглядит как до миграции, а
   утилиты display наконец работают.
   Добавляете новый компонент с display — объявляйте его здесь, иначе
   `hidden` на нём снова перестанет действовать (сторож: tests/test_css_layers_guard.py). */
@layer components {
  .shell { display: grid; }
  .sidebar { display: flex; }
  .sidebar__brand-row { display: flex; }
  .sidebar__brand { display: flex; }
  .sidebar__logo { display: grid; }
  .nav-item { display: flex; }
  .main { display: flex; }
  .topbar { display: flex; }
  .nav-toggle { display: none; }
  .card__head { display: flex; }
  .btn { display: inline-flex; }
  .badge { display: inline-flex; }
  .field { display: flex; }
  .filters { display: flex; }
  .segmented { display: inline-flex; }
  .dropdown { display: inline-flex; }
  .period-picker { display: inline-flex; }
  .period-picker__btn { display: flex; }
  .period-panel__nav { display: flex; }
  .period-panel__nav-btn { display: grid; }
  .period-years { display: flex; }
  .period-year-col { display: flex; }
  .period-year-grid { display: grid; }
  .period-panel__presets { display: grid; }
  .period-panel__custom { display: flex; }
  .stat-grid { display: grid; }
  .stat { display: flex; }
  .stat__foot { display: flex; }
  .hbar { display: grid; }
  .legend { display: flex; }
  .legend__item { display: inline-flex; }
  .alert { display: flex; }
  .tabs { display: flex; }
  .topbar__pagetabs-panel { display: flex; }
  .avatar { display: grid; }
  .row { display: flex; }
  .col { display: flex; }
  .grid-2 { display: grid; }
  .grid-3 { display: grid; }
  .hero__stats { display: flex; }
  .svc { display: flex; }
  .svc__icon { display: grid; }
  .svc__foot { display: flex; }
  .doc-cols { display: grid; }
  .doc-row__top { display: grid; }
  .doc-row__label--with-comment { display: flex; }
  .notif-bell__header { display: flex; }
  .notif-bell__item { display: block; }
  @media (max-width: 900px) {
    .nav-toggle { display: inline-flex; }
    .sidebar__collapse-btn { display: none; }
  }
}
