/* ==========================================================================
   TenderSRB — дизайн-система (VG-28.1)
   Токены + базовые компоненты. Смена hex-значений токенов ниже перекрашивает
   весь UI из одного места. Палитра — ПРЕДЛОЖЕНИЕ на утверждение D1 (см. REPORT).
   Ниже, после этого блока, — неизменный собранный Tailwind CSS.
   ========================================================================== */
:root {
  /* Бренд — глубокий сине-индиго (доверие B2B/госзакупки), НЕ голый slate */
  --color-primary-50: #eef2f9;
  --color-primary-100: #d7e1f0;
  --color-primary-200: #adc0dd;
  --color-primary-300: #7f9bc6;
  --color-primary-400: #5779ac;
  --color-primary-500: #3a5d8f;
  --color-primary-600: #2a4874;
  --color-primary-700: #1f3760; /* основной бренд-цвет */
  --color-primary-800: #172a49;
  --color-primary-900: #101e34;

  /* Акцент — тёплый янтарь для CTA/выделений, не пересекается со статусами */
  --color-accent-500: #c07f1a;
  --color-accent-600: #9c6714;
  /* Светлая заливка янтарного бейджа. Подобрана по КОНТРАСТУ, а не на глаз:
     accent-600 на ней даёт 4.66 (норма мелкого текста 4.5), тогда как на
     более насыщенном #fdf6e8 было бы 4.47 — ниже порога. */
  --color-accent-50: #fffbf3;

  /* Нейтральная шкала (совместима с существующей slate-палитрой Tailwind) */
  --color-neutral-0: #ffffff;
  --color-neutral-50: #f8fafc;
  --color-neutral-100: #f1f5f9;
  --color-neutral-200: #e2e8f0;
  --color-neutral-300: #cbd5e1;
  --color-neutral-400: #94a3b8;
  --color-neutral-500: #64748b;
  --color-neutral-600: #475569;
  --color-neutral-700: #334155;
  --color-neutral-800: #1e293b;
  --color-neutral-900: #0f172a;

  /* Семантика статусов тендера: новый / горящий дедлайн / истёк / успех / ошибка */
  --status-new: #2563eb;
  --status-new-bg: #eff6ff;
  --status-new-border: #bfdbfe;
  --status-urgent: #c2410c;
  --status-urgent-bg: #fff7ed;
  --status-urgent-border: #fed7aa;
  --status-expired: #475569; /* neutral-600, а не -500: на #f1f5f9 контраст 6.92 (было 4.34 — «истёк» не дотягивал до 4.5 при 12px/700) */
  --status-expired-bg: #f1f5f9;
  --status-expired-border: #e2e8f0;
  --status-success: #15803d;
  --status-success-bg: #f0fdf4;
  --status-success-border: #bbf7d0;
  --status-error: #b91c1c;
  --status-error-bg: #fef2f2;
  --status-error-border: #fecaca;

  /* Типографическая шкала */
  --text-xs: .75rem;
  --text-sm: .875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.25rem;
  --text-2xl: 1.5rem;
  --text-3xl: 1.875rem;

  /* Spacing-сетка (кратно 4px) */
  --space-1: .25rem;
  --space-2: .5rem;
  --space-3: .75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;

  /* Радиусы */
  --radius-sm: .25rem;
  --radius-md: .5rem;
  --radius-lg: .75rem;
  --radius-full: 9999px;

  /* Тени */
  --shadow-sm: 0 1px 2px 0 rgb(15 23 42 / .06);
  --shadow-md: 0 4px 6px -1px rgb(15 23 42 / .08), 0 2px 4px -2px rgb(15 23 42 / .06);
  --shadow-lg: 0 10px 15px -3px rgb(15 23 42 / .10), 0 4px 6px -4px rgb(15 23 42 / .05);

  /* Высота липкой шапки (Этап 9) — ЕДИНЫЙ источник для scroll-margin якорей.
     Меняешь вертикальный ритм .site-header — правь здесь, иначе якоря
     (#telegram-card, #analysis, клики календаря) уедут под шапку. */
  --header-h: 3.5rem;
}

/* -- Глобальная типографика (web-ux-polish): иерархия заголовков и базовая
   читаемость. Reset Tailwind сбрасывает h1–h6 в inherit (размер body, без
   иерархии) — задаём ритм из шкалы --text-*/весов. Правила на ЭЛЕМЕНТЫ:
   утилитарные классы (.text-xl и т.п.) специфичнее и продолжают точечно
   переопределять; margin-bottom (0-0-1) уступает .mb-* (0-1-0) — заголовки
   с утилитой отступа не сдвигаются, «голые» получают разумный ритм.
   Палитра и токены-цвета НЕ меняются. */
body { line-height: 1.6; }
h1, h2, h3, h4, h5, h6 {
  color: var(--color-neutral-900);
  line-height: 1.25;
  text-wrap: balance;
}
h1 { font-size: var(--text-3xl); font-weight: 700; letter-spacing: -.01em; margin-bottom: var(--space-4); }
h2 { font-size: var(--text-2xl); font-weight: 700; margin-bottom: var(--space-3); }
h3 { font-size: var(--text-xl); font-weight: 600; margin-bottom: var(--space-2); }
h4 { font-size: var(--text-lg); font-weight: 600; margin-bottom: var(--space-1); }
/* Мера строки для длинного текстового контента (читаемость ≈70 симв.). */
.prose-measure { max-width: 68ch; }

/* -- Кнопки: иерархия primary/secondary/ghost/danger --------------------- */
.btn-primary, .btn-secondary, .btn-ghost, .btn-danger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  border-radius: var(--radius-md);
  padding: .5rem 1rem;
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.25rem;
  border: 1px solid transparent;
  cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease;
  text-decoration: none;
}
.btn-primary { background: var(--color-primary-700); color: var(--color-neutral-0); }
.btn-primary:hover { background: var(--color-primary-800); }
.btn-secondary { background: var(--color-neutral-0); color: var(--color-primary-700); border-color: var(--color-primary-200); }
.btn-secondary:hover { background: var(--color-primary-50); }
.btn-ghost { background: transparent; color: var(--color-neutral-600); }
.btn-ghost:hover { background: var(--color-neutral-100); color: var(--color-neutral-900); }
.btn-danger { background: var(--status-error); color: var(--color-neutral-0); }
.btn-danger:hover { background: #7f1d1d; }

/* -- Статус-бейджи --------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .125rem .625rem;
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: 600;
  border: 1px solid transparent;
  white-space: nowrap;
  /* Дефолт голого .badge (без модификатора): без него цвет=inherit, фон=нет,
     рамка transparent → бейдж-обёртка невидим. Модификаторы ниже перекрывают. */
  color: var(--color-neutral-600);
  background: var(--color-neutral-100);
  border-color: var(--color-neutral-200);
}
.badge-new { color: var(--status-new); background: var(--status-new-bg); border-color: var(--status-new-border); }
.badge-urgent { color: var(--status-urgent); background: var(--status-urgent-bg); border-color: var(--status-urgent-border); }
.badge-expired { color: var(--status-expired); background: var(--status-expired-bg); border-color: var(--status-expired-border); }
.badge-success { color: var(--status-success); background: var(--status-success-bg); border-color: var(--status-success-border); }
.badge-error { color: var(--status-error); background: var(--status-error-bg); border-color: var(--status-error-border); }
/* Нейтральный бейдж для МЕТАДАННЫХ (перевод, ярлык тарифа, «консорциум»,
   стадия, спокойный дедлайн «до ДД.ММ»): серый ≠ «истёк». Оранжевый бейдж
   остаётся ТОЛЬКО за срочностью, красноватый — за истёкшим. */
.badge-muted { color: var(--color-neutral-600); background: var(--color-neutral-100); border-color: var(--color-neutral-200); }
/* Янтарный бейдж — роль «действие и апсейл» (канон ролей цвета). Введён для
   ярлыка «AI» на лендинге: метка требовала акцента, но синий занят временем
   и оценкой соответствия. Контраст: текст 4.66, граница 3.23 на своей заливке
   и 3.34 на белой странице — оба порога (4.5 / 3.0) пройдены. */
.badge-accent { color: var(--color-accent-600); background: var(--color-accent-50); border-color: var(--color-accent-500); }

/* Компактная вторичная кнопка-действие воронки (_tender_actions): «Следить»,
   «в папку», «+ заметка». Раньше были .badge-new (синий) — но синий в карточке
   закреплён за срочностью и match-score, «действие» им красить нельзя. Нейтраль
   с primary-текстом = «доступное действие»; активное состояние остаётся зелёным
   (.badge-success). Тап-зона min-height 2rem. Работает и на <button>, и на
   <summary> (сброс маркера — как у .nav-more/.faq). */
.act-btn {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  min-height: 2rem;
  padding: .25rem .6rem;
  border-radius: var(--radius-md);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-primary-800);
  background: var(--color-neutral-0);
  border: 1px solid var(--color-neutral-300);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  list-style: none;
  transition: background-color .15s ease, border-color .15s ease;
}
.act-btn::-webkit-details-marker { display: none; }
.act-btn:hover { background: var(--color-primary-50); border-color: var(--color-primary-200); }
.act-btn:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }

/* Пункты внутри выпадашек «Стадия»/«В папку» (_tender_actions.html): голые
   утилиты (px-2 py-1 text-sm) давали ~24px — ниже тап-нормы 2rem. Класс
   добавляется РЯДОМ с существующими утилитами, не заменяет их. */
.act-menu-item { display: flex; align-items: center; min-height: 2rem; }

/* -- Карточка --------------------------------------------------------------- */
.card {
  background: var(--color-neutral-0);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-4);
}

/* -- Empty-state (единый компонент, см. _empty_state.html) ----------------- */
.empty-state {
  background: var(--color-neutral-0);
  border: 1px dashed var(--color-neutral-300);
  border-radius: var(--radius-lg);
  padding: var(--space-8) var(--space-6);
  text-align: center;
}
.empty-state__title { font-size: var(--text-base); color: var(--color-neutral-700); }
.empty-state__hint { margin-top: var(--space-1); font-size: var(--text-sm); color: var(--color-neutral-500); }
.empty-state__actions {
  margin-top: var(--space-4);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}

/* -- Формы кабинета: секции, поля, гейт-подсказки, онбординг (web-ux-2) ----- */
.form-section {
  background: var(--color-neutral-0);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-4);
}
.form-section + .form-section { margin-top: var(--space-4); }
.form-section__title {
  font-size: var(--text-sm);
  font-weight: 700;
  color: var(--color-primary-800);
  text-transform: uppercase;
  letter-spacing: .03em;
}
.form-section__desc {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-neutral-500);
}
.form-section__body {
  margin-top: var(--space-3);
  display: grid;
  gap: var(--space-4);
}

.field__label {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-neutral-700);
  margin-bottom: var(--space-1);
}
.field__req { color: var(--status-error); margin-left: .125rem; }
.field__hint {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-neutral-500);
}
.field-control {
  width: 100%;
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-md);
  padding: .5rem .75rem;
  font-size: var(--text-sm);
  color: var(--color-neutral-900);
  background: var(--color-neutral-0);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.field-control:focus {
  /* Кольцо primary-100 давало контраст 1.26 к белому — фокус практически не
     виден. Явный outline primary-500 + более плотное кольцо primary-200. */
  outline: 2px solid var(--color-primary-500);
  outline-offset: 1px;
  border-color: var(--color-primary-500);
  box-shadow: 0 0 0 3px var(--color-primary-200);
}
.field-check {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-neutral-700);
}
.field-check input { flex: none; }

/* Гейт-подсказка: недоступное на тарифе поле + CTA на /plans. Апсейл, а НЕ
   тревога → акцент-токены + primary-50, не urgent. Оранжевый (urgent) в
   продукте значит ТОЛЬКО срочность времени, поэтому апсейл его не занимает. */
.gate-note {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  flex-wrap: wrap;
  margin-top: var(--space-2);
  padding: .375rem .625rem;
  font-size: var(--text-xs);
  color: var(--color-accent-600);
  background: var(--color-primary-50);
  border: 1px solid var(--color-accent-500);
  border-radius: var(--radius-md);
}
.gate-note a { color: var(--color-accent-600); font-weight: 700; text-decoration: underline; }
.gate-note a:hover { color: var(--color-primary-800); }

/* Микро-онбординг: зачем нужен профиль (первый заход, 0 профилей) */
.onboard-tip {
  background: var(--color-primary-50);
  border: 1px solid var(--color-primary-100);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin-bottom: var(--space-4);
}
.onboard-tip__title { font-weight: 600; color: var(--color-primary-800); }
.onboard-tip__text {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--color-neutral-600);
}

/* «Собрано из шаблона …»: что именно подставлено в форму. Заметнее микро-
   онбординга (это ответ на вопрос «почему тут эти слова»), но не тревожно —
   янтарь занят действием, поэтому левая линия бренд-цветом. */
.prefill-note {
  background: var(--color-neutral-50);
  border: 1px solid var(--color-neutral-200);
  border-left: 3px solid var(--color-primary-500);
  border-radius: var(--radius-lg);
  padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4);
}
.prefill-note__title { font-weight: 600; color: var(--color-neutral-800); }
.prefill-note__text {
  margin-top: var(--space-1);
  font-size: var(--text-sm);
  color: var(--color-neutral-600);
}

/* Панель действий формы */
.form-actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  margin-top: var(--space-4);
}

/* -- Tooltip/hint ------------------------------------------------------------ */
.hint {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  font-size: var(--text-xs);
  color: var(--color-neutral-500);
  border-bottom: 1px dotted var(--color-neutral-400);
  cursor: help;
}

/* -- Контекстная «?»-подсказка (VG-30): единый компонент _hint_tip.html ------
   Иконка-триггер + всплывающая пузырь-подсказка. Показ по наведению И по
   фокусу (клавиатура/скринридер): триггер — настоящая <button>. Только токены,
   палитра неизменна. */
.tip { position: relative; display: inline-flex; vertical-align: middle; }
.tip__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  min-height: 2rem;
  padding: 0;
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-full);
  background: var(--color-neutral-100);
  color: var(--color-neutral-600);
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  cursor: help;
  transition: color .15s ease, background-color .15s ease, border-color .15s ease;
}
.tip__icon:hover,
.tip__icon:focus-visible {
  color: var(--color-primary-700);
  background: var(--color-primary-50);
  border-color: var(--color-primary-700);
  outline: none;
}
.tip__bubble {
  position: absolute;
  bottom: calc(100% + .5rem);
  left: 50%;
  transform: translateX(-50%);
  z-index: 30;
  width: max-content;
  /* Никогда шире вьюпорта минус поля: на телефоне пузырь у края формы/шапки
     раньше вываливался за край и добавлял горизонтальную прокрутку. */
  max-width: min(16rem, calc(100vw - 2rem));
  padding: var(--space-2) var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-neutral-800);
  color: var(--color-neutral-0);
  font-size: var(--text-xs);
  font-weight: 400;
  line-height: 1.4;
  text-align: left;
  white-space: normal;
  box-shadow: var(--shadow-md);
  opacity: 0;
  visibility: hidden;
  transition: opacity .15s ease, visibility .15s ease;
  pointer-events: none;
}
.tip__bubble::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: var(--color-neutral-800);
}
.tip:hover .tip__bubble,
.tip:focus-within .tip__bubble { opacity: 1; visibility: visible; }

/* -- Навигация с активным состоянием ----------------------------------------- */
.nav-link {
  color: var(--color-neutral-600);
  font-size: var(--text-sm);
  padding: .375rem .625rem;
  border-radius: var(--radius-md);
  text-decoration: none;
  transition: color .15s ease, background-color .15s ease;
}
.nav-link:hover { color: var(--color-neutral-900); background: var(--color-neutral-100); }
.nav-link.is-active { color: var(--color-primary-700); background: var(--color-primary-50); font-weight: 600; }

/* -- Навигация кабинета: вторичные пункты в компактную «Ещё»-выпадашку -------
   (web-ux-polish). Чистый <details>, без JS. Первичные пункты и «Тарифы»
   остаются inline; выпадашка снимает перегрузку строки (~12 ссылок). Только
   токены. */
.nav-more { position: relative; }
.nav-more > summary { list-style: none; cursor: pointer; -webkit-user-select: none; user-select: none; }
.nav-more > summary::-webkit-details-marker { display: none; }
.nav-more[open] > summary { color: var(--color-primary-700); background: var(--color-primary-50); }
.nav-more__menu {
  position: absolute;
  right: 0;
  top: calc(100% + .25rem);
  z-index: 40;
  min-width: 12.5rem;
  display: flex;
  flex-direction: column;
  gap: .125rem;
  padding: var(--space-2);
  background: var(--color-neutral-0);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
}
/* Пункты внутри — во всю ширину меню (nav-link по умолчанию inline). */
.nav-more__menu .nav-link { display: block; }
/* Копии «Тарифы»/«Выход» внутри меню нужны ТОЛЬКО на телефоне (там inline-версии
   скрыты) — на десктопе прячем, чтобы пункт не задваивался. Раскрывает их
   @media (max-width: 639px) выше по source-order. */
.nav-more__menu .nav-show-mobile { display: none; }

/* -- Переключатель языка ЛК (i18n Фаза 1.1) --------------------------------
   Три пилюли SR/RU/EN в шапке. В ЛК — POST-форма (пишет users.locale +
   cookie), пилюли на <button> с полным сбросом кнопочной хромы, активный
   язык — <span>.is-active (не кликается). На публичной шапке (public_base.html)
   тот же класс на <a href="?lang=">, т.к. переключение там идёт query-параметром,
   без формы — компонент один, разметка-носитель разная. Только токены палитры.
   Тап-зона: было ~20px (голый текст без паддинга/высоты) — min-height 2rem.
   ‼️ Высоты мало: замер 02.08 (shots) показал 27×32 на всех шести публичных
   экранах — по ширине пилюля не добирала до минимума, а палец мажет по обеим
   осям. min-width замыкает вторую ось; ширину шапки это двигает на ~15px и
   потому проверяется scrollWidth (инварианты размера и ширины конфликтуют). */
.lang-switch { display: inline-flex; align-items: center; gap: .125rem; margin-left: .25rem; }
.lang-pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2rem;
  min-width: 2rem;
  appearance: none;
  border: 0;
  background: transparent;
  cursor: pointer;
  font: inherit;
  font-size: var(--text-xs);
  line-height: 1;
  color: var(--color-neutral-500);
  padding: .25rem .375rem;
  border-radius: var(--radius-md);
  text-decoration: none;
  transition: color .15s ease, background-color .15s ease;
}
.lang-pill:hover { color: var(--color-neutral-900); background: var(--color-neutral-100); }
.lang-pill:focus-visible { outline: 2px solid var(--color-accent-500); outline-offset: 2px; }
.lang-pill.is-active { color: var(--color-primary-700); font-weight: 600; cursor: default; }

/* -- Строка согласия на регистрации (аудит 02.08, пакет 3) ------------------
   ‼️ Чинится РАЗМЕР ЦЕЛИ, а не зона клика: чекбокс лежит ВНУТРИ <label>, и
   клик по тексту согласия галочку уже ставит (проверено кликом в 12px от края
   строки — checked стал true). Дефект в другом: сам квадратик отдавался
   браузерным дефолтом 13×13 — вдвое меньше минимума 2rem, мелкая цель для
   пальца и плохо различимое состояние на мобильном. Строка при этом была
   высотой 20px. Ссылки внутри текста согласия намеренно НЕ растягиваем —
   инлайновой ссылке насильная высота рвёт ритм строки (CLAUDE.md). */
.consent-row { min-height: 2rem; }
.consent-row input[type="checkbox"] {
  width: 1.125rem;
  height: 1.125rem;
  flex: none;
}

/* -- Таблица админки: липкая шапка, зебра, ровный вертикальный ритм ---------
   (web-ux-polish). Скролл-обёртка (max-height) держит шапку над строками при
   прокрутке длинного списка. Только токены. */
.admin-table__wrap {
  max-height: 70vh;
  overflow: auto;
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  background: var(--color-neutral-0);
}
.admin-table { width: 100%; font-size: var(--text-sm); border-collapse: collapse; }
.admin-table thead th {
  position: sticky;
  top: 0;
  z-index: 10;
  background: var(--color-neutral-50);
  border-bottom: 1px solid var(--color-neutral-200);
  padding: var(--space-3) var(--space-4);
  text-align: left;
  font-weight: 600;
  color: var(--color-neutral-600);
  white-space: nowrap;
}
.admin-table tbody td {
  padding: var(--space-3) var(--space-4);
  border-bottom: 1px solid var(--color-neutral-200);
  vertical-align: middle;
}
.admin-table tbody tr:last-child td { border-bottom: 0; }
.admin-table tbody tr:nth-child(even) { background: var(--color-neutral-50); }
.admin-table tbody tr:hover { background: var(--color-primary-50); }

/* -- Панель фильтров списка (поиск + селект) — web-ux-polish ---------------- */
.filter-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.filter-bar__field { display: flex; flex-direction: column; gap: var(--space-1); }
.filter-bar__label { font-size: var(--text-xs); font-weight: 600; color: var(--color-neutral-500); }

/* -- Skeleton-плейсхолдер ----------------------------------------------------- */
.skeleton {
  position: relative;
  overflow: hidden;
  background: var(--color-neutral-200);
  border-radius: var(--radius-md);
}
.skeleton::after {
  content: "";
  position: absolute;
  inset: 0;
  transform: translateX(-100%);
  background: linear-gradient(90deg, transparent, rgb(255 255 255 / .55), transparent);
  animation: skeleton-shimmer 1.4s infinite;
}
@keyframes skeleton-shimmer { 100% { transform: translateX(100%); } }

/* -- Каркас: шапка/бренд ------------------------------------------------------ */
.site-header { background: var(--color-neutral-0); border-bottom: 1px solid var(--color-neutral-200); }
.brand { display: inline-flex; align-items: center; gap: .5rem; font-weight: 700; font-size: var(--text-lg); color: var(--color-primary-800); text-decoration: none; min-height: 2rem; }
.brand img { width: 28px; height: 28px; border-radius: var(--radius-sm); }
/* -- Публичная шапка (public_base.html): бренд + языки + навигация ------------
   Языки и навигация прижаты вправо (margin-left:auto у языков поглощает
   свободное место, бренд остаётся слева) — десктопный вид как был. На телефоне
   строка переносится (см. @media max-width:639px): бренд+языки в первой строке,
   навигация во второй, ничего не уходит за вьюпорт. */
.site-header--public .lang-switch { margin-left: auto; }

/* -- Акцентный текст на бренд-токене (лендинг, заголовки) ------------------ */
.text-brand { color: var(--color-primary-700); }

/* -- Числовой маркер шага («как это работает» на лендинге) ---------------- */
.step-num { background: var(--color-primary-700); color: var(--color-neutral-0); }
.step-num.is-done { background: var(--status-success); }
.step-num.is-pending { background: var(--color-neutral-300); color: var(--color-neutral-600); }

/* -- Онбординг-степпер (VG-30b, «Начало работы» на дашборде) ---------------- */
.onboarding-step.is-done { opacity: .6; }
.onboarding-step__title.is-done { text-decoration: line-through; color: var(--color-neutral-500); }

/* -- Витрина тарифов: популярный план + матрица ценности (VG-12 ф.2) -------- */
/* Сетка карточек тарифов: 1 колонка на телефоне, 3 — только с 768px. Свой класс
   вместо sm:grid-cols-3: на 640–760px три колонки давали ~190px под цену, подпись
   и 8 фич — тесно. Сборки Tailwind нет, поэтому breakpoint здесь, а не в утилите. */
.plan-grid { grid-template-columns: 1fr; }
@media (min-width: 768px) {
  .plan-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}
/* Выделение популярного плана (Pro) бренд-рамкой и тенью — из токенов. */
.plan-featured { border-color: var(--color-primary-700); box-shadow: var(--shadow-md); }
/* Ленточка «Популярный» — акцентный янтарь, отдельно от «Ваш план» (slate). */
.plan-badge {
  background: var(--color-accent-500);
  /* Тёмный текст на янтаре: белый на #c07f1a = 3.34 (мало при 12px/600),
     neutral-900 = 5.12. Янтарь фона сохраняем. */
  color: var(--color-neutral-900);
  border-radius: var(--radius-full);
  font-size: var(--text-xs);
  font-weight: 600;
  padding: .125rem .75rem;
  white-space: nowrap;
}
/* Строка матрицы: галочка/прочерк + подпись + лимит справа. */
.feature-row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-neutral-600);
}
.feature-row.feature-off { color: var(--color-neutral-500); }
.feature-row__mark { flex: none; margin-top: .125rem; }
.feature-yes { color: var(--status-success); }
/* neutral-500, а не -300: прочерк «нет функции» — носитель смысла, обязан читаться. */
.feature-no { color: var(--color-neutral-500); }
.feat-limit {
  margin-left: auto;
  padding-left: var(--space-2);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-primary-700);
  white-space: nowrap;
}

/* -- AI-артефакты тендера: вердикт, score-шкала, чек-лист, черновик, метрики
   (web-ux-3). Только presentation — рендерят уже сохранённый output-JSON.
   Цвета — из статус-токенов, палитра не расширяется. --------------------- */

/* Крупная вердикт-плашка «стоит ли участвовать» (go/caution/no_go). */
.verdict {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  border: 1px solid transparent;
}
.verdict--go { background: var(--status-success-bg); border-color: var(--status-success-border); }
.verdict--caution { background: var(--status-urgent-bg); border-color: var(--status-urgent-border); }
.verdict--no_go { background: var(--status-error-bg); border-color: var(--status-error-border); }
.verdict--none { background: var(--color-neutral-50); border-color: var(--color-neutral-200); }
.verdict__icon { font-size: 1.75rem; line-height: 1; flex: none; }
.verdict__label { font-size: var(--text-lg); font-weight: 700; line-height: 1.2; }
.verdict--go .verdict__label { color: var(--status-success); }
.verdict--caution .verdict__label { color: var(--status-urgent); }
.verdict--no_go .verdict__label { color: var(--status-error); }
.verdict--none .verdict__label { color: var(--color-neutral-600); }
.verdict__score { margin-left: auto; text-align: right; flex: none; }
.verdict__score-num { font-size: var(--text-2xl); font-weight: 700; line-height: 1; color: var(--color-neutral-900); }
.verdict__score-max { font-size: var(--text-sm); color: var(--color-neutral-500); }

/* Горизонтальная score-шкала 0..100; цвет заливки — по порогу вердикта. */
.score-meter { margin-top: var(--space-3); }
.score-meter__track {
  height: .5rem;
  border-radius: var(--radius-full);
  background: var(--color-neutral-200);
  overflow: hidden;
}
.score-meter__fill { height: 100%; border-radius: var(--radius-full); background: var(--color-neutral-400); }
.score-meter__fill--go { background: var(--status-success); }
.score-meter__fill--caution { background: var(--status-urgent); }
.score-meter__fill--no_go { background: var(--status-error); }
.score-meter__scale {
  display: flex;
  justify-content: space-between;
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-neutral-500);
}

/* Панель причин с цветной полосой слева (за / против / риски). */
.reason-panel {
  border-left: 3px solid var(--color-neutral-300);
  padding-left: var(--space-3);
}
.reason-panel--pro { border-left-color: var(--status-success); }
.reason-panel--con { border-left-color: var(--status-urgent); }
.reason-panel--risk { border-left-color: var(--status-error); }
.reason-panel__title { display: flex; align-items: center; gap: .375rem; font-weight: 600; font-size: var(--text-sm); margin-bottom: var(--space-2); }
.reason-panel--pro .reason-panel__title { color: var(--status-success); }
.reason-panel--con .reason-panel__title { color: var(--status-urgent); }
.reason-panel--risk .reason-panel__title { color: var(--status-error); }
.reason-panel ul { list-style: none; display: flex; flex-direction: column; gap: var(--space-1); font-size: var(--text-sm); color: var(--color-neutral-700); }
.reason-panel li { display: flex; gap: .5rem; align-items: baseline; }
.reason-panel li::before { content: "•"; color: var(--color-neutral-400); flex: none; }

/* Чек-лист документов: строки-чекбоксы + категория-чип. */
.chk-list { display: flex; flex-direction: column; gap: var(--space-2); }
.chk-item { display: flex; align-items: flex-start; gap: var(--space-2); font-size: var(--text-sm); }
.chk-item__box { flex: none; font-size: var(--text-base); line-height: 1.4; }
.chk-item__note { display: block; margin-top: .125rem; font-size: var(--text-xs); color: var(--color-neutral-500); }
.chip {
  display: inline-block;
  padding: 0 .4rem;
  font-size: var(--text-xs);
  font-weight: 600;
  border-radius: var(--radius-sm);
  background: var(--color-neutral-100);
  color: var(--color-neutral-600);
  vertical-align: middle;
}

/* Черновик: тулбар (копировать/скачать) + читаемый блок тела. */
.artifact-toolbar { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-3); }
.artifact-body {
  background: var(--color-neutral-50);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-md);
  padding: var(--space-4);
  font-size: var(--text-sm);
  line-height: 1.6;
  color: var(--color-neutral-800);
}
.artifact-body__heading { font-weight: 700; color: var(--color-primary-800); margin-top: var(--space-4); }
.artifact-body__heading:first-child { margin-top: 0; }
.artifact-body__text { white-space: pre-wrap; overflow-wrap: anywhere; margin-top: var(--space-1); }

/* Метрика-плитка аналитики (наручилац/конкурент). */
.metric {
  border: 1px solid var(--color-neutral-200);
  background: var(--color-neutral-50);
  border-radius: var(--radius-md);
  padding: var(--space-3);
}
.metric__value { font-size: var(--text-xl); font-weight: 700; color: var(--color-neutral-900); line-height: 1.2; }
.metric__value small { font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-500); }
.metric__label { margin-top: .125rem; font-size: var(--text-xs); color: var(--color-neutral-500); }

/* Полоса концентрации (доля топ-1 наручиоца) — наглядно вместо голого %. */
.bar-track { height: .375rem; border-radius: var(--radius-full); background: var(--color-neutral-200); overflow: hidden; }
.bar-fill { height: 100%; border-radius: var(--radius-full); background: var(--color-primary-500); }
.bar-fill--hot { background: var(--status-urgent); }

/* -- Help-центр (web-ux-4): якорь-навигация, шаги, карточки AI-функций,
   команды бота, FAQ-аккордеон. Только presentation, из существующих
   токенов; палитра не расширяется. ---------------------------------------- */

/* Якорь-навигация: пилюли-ссылки на разделы */
.help-nav { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.help-chip {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .375rem .75rem;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-primary-700);
  background: var(--color-primary-50);
  border: 1px solid var(--color-primary-100);
  border-radius: var(--radius-full);
  text-decoration: none;
  transition: background-color .15s ease, color .15s ease;
}
.help-chip:hover { background: var(--color-primary-100); color: var(--color-primary-800); }

/* Заголовок раздела с иконкой-акцентом */
.help-section__head { display: flex; align-items: center; gap: var(--space-3); }
.help-section__icon {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  font-size: 1.25rem;
  border-radius: var(--radius-lg);
  background: var(--color-primary-50);
  border: 1px solid var(--color-primary-100);
}
.help-section__title { font-size: var(--text-xl); font-weight: 700; color: var(--color-primary-800); }

/* Быстрый старт: пронумерованные шаги-карточки */
.help-steps { display: grid; gap: var(--space-4); }
.help-step { display: flex; gap: var(--space-3); align-items: flex-start; }
.help-step__num {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-full);
  font-size: var(--text-sm);
  font-weight: 700;
  background: var(--color-primary-700);
  color: var(--color-neutral-0);
}
.help-step__title { font-weight: 600; color: var(--color-neutral-900); }
.help-step__text { margin-top: .125rem; font-size: var(--text-sm); color: var(--color-neutral-600); }

/* AI-функции: сетка карточек (имя + бейдж тарифа / что делает / как вызвать) */
.help-feature-grid { display: grid; gap: var(--space-4); }
.help-feature { display: flex; flex-direction: column; height: 100%; }
.help-feature__head { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); }
.help-feature__name { font-weight: 600; color: var(--color-neutral-900); }
.help-feature__what { margin-top: var(--space-2); font-size: var(--text-sm); color: var(--color-neutral-600); }
.help-feature__how {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--color-primary-700);
  display: flex;
  align-items: baseline;
  gap: .375rem;
}
.help-feature__how::before { content: "→"; flex: none; }

/* Команды бота: моно-код + описание */
.help-cmd { display: flex; gap: var(--space-2); align-items: baseline; font-size: var(--text-sm); }
.help-cmd code {
  flex: none;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  background: var(--color-neutral-100);
  color: var(--color-primary-800);
  border-radius: var(--radius-sm);
  padding: .0625rem .375rem;
  font-size: var(--text-xs);
  font-weight: 600;
}

/* FAQ-аккордеон */
.faq-item {
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-md);
  background: var(--color-neutral-0);
}
.faq-item + .faq-item { margin-top: var(--space-2); }
.faq-item__q {
  list-style: none;
  cursor: pointer;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-neutral-800);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
.faq-item__q::-webkit-details-marker { display: none; }
.faq-item__q::after { content: "+"; flex: none; color: var(--color-primary-500); font-weight: 700; }
.faq-item[open] .faq-item__q::after { content: "–"; }
.faq-item__a { padding: 0 var(--space-4) var(--space-4); font-size: var(--text-sm); color: var(--color-neutral-600); }

/* ≥640px: AI-функции в 2 колонки. Шаги (3 шт.) — только с 768px: на 640–760px
   три колонки давали ~190px на шаг и текст жался. */
@media (min-width: 640px) {
  .help-feature-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 768px) {
  .help-steps { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* -- Библиотека шаблонов (web-ux-5): интро, группы-категории, карточки ------
   Только presentation: рендерит публичные шаблоны template_library. -------- */
.tpl-intro { margin-bottom: var(--space-6); }
.tpl-meta {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-neutral-500);
}
.tpl-group { margin-bottom: var(--space-8); }
.tpl-group__head {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-neutral-200);
}
.tpl-group__title {
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--color-neutral-800);
}
.tpl-count {
  flex: none;
  min-width: 1.25rem;
  padding: 0 .45rem;
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.25rem;
  text-align: center;
  border-radius: var(--radius-full);
  color: var(--color-primary-700);
  background: var(--color-primary-50);
}
.tpl-grid {
  display: grid;
  gap: var(--space-3);
  grid-template-columns: 1fr;
}
.tpl-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  background: var(--color-neutral-0);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-4);
  transition: box-shadow .15s ease, border-color .15s ease;
}
.tpl-card:hover {
  box-shadow: var(--shadow-md);
  border-color: var(--color-primary-200);
}
.tpl-card__body { display: flex; flex-direction: column; gap: var(--space-2); }
.tpl-card__title {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-neutral-900);
}
.tpl-card__desc {
  font-size: var(--text-xs);
  line-height: 1.4;
  color: var(--color-neutral-500);
}
.tpl-tags { display: flex; flex-wrap: wrap; gap: .375rem; }
.tpl-tag {
  padding: .125rem .5rem;
  font-size: var(--text-xs);
  border-radius: var(--radius-sm);
  color: var(--color-neutral-600);
  background: var(--color-neutral-100);
}
.tpl-tag--cpv {
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  color: var(--color-primary-700);
  background: var(--color-primary-50);
}
.tpl-tag--more { color: var(--color-neutral-500); background: transparent; }
.tpl-card__cta { margin-top: auto; }
/* Живая цифра «≈ N тендеров за 30 дней» — главный сигнал карточки: шаблон
   живой ещё ДО нажатия. Цвет — синий --status-new («оценка соответствия», та же
   роль, что у совпадения профиля), а не янтарь: янтарь занят действием. */
.tpl-card__count {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--status-new);
}
/* Ноль — не «срочно» и не «действие», а выключенное состояние: серый. */
.tpl-card__count--zero {
  font-weight: 400;
  color: var(--color-neutral-500);
}
/* Карточка «показывать все» стоит одна над сеткой — тянуть её на всю ширину
   незачем, но и теряться она не должна: подсвечиваем рамкой бренда. */
.tpl-card--all {
  margin-bottom: var(--space-6);
  border-color: var(--color-primary-200);
  background: var(--color-primary-50);
}

/* ≥640px: карточки шаблонов в две колонки */
@media (min-width: 640px) {
  .tpl-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* -- Публичная карточка тендера (web-ux-6): точка входа/рост. Наглядная
   карточка (заголовок/наручилац/факты/CPV/описание) + конверсионный CTA.
   Только presentation, из существующих токенов; палитра не расширяется. --- */
.tp-back {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: var(--text-sm);
  color: var(--color-neutral-500);
  text-decoration: none;
}
.tp-back:hover { color: var(--color-primary-700); }

/* Верхняя карточка тендера */
.tp-card {
  background: var(--color-neutral-0);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--space-6);
}
.tp-card__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.tp-title { font-size: var(--text-2xl); font-weight: 700; line-height: 1.25; color: var(--color-neutral-900); }
.tp-customer {
  display: inline-flex;
  align-items: baseline;
  gap: .4rem;
  margin-top: var(--space-2);
  font-size: var(--text-base);
  color: var(--color-neutral-600);
}
.tp-alts {
  margin-top: var(--space-3);
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  padding: .125rem .625rem;
  font-size: var(--text-xs);
  color: var(--color-neutral-500);
  background: var(--color-neutral-100);
  border-radius: var(--radius-full);
}

/* Сетка фактов: дедлайн / сумма / статус / регион / процедура */
.tp-facts {
  margin-top: var(--space-5);
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}
.tp-fact {
  border: 1px solid var(--color-neutral-200);
  background: var(--color-neutral-50);
  border-radius: var(--radius-md);
  padding: var(--space-3);
}
.tp-fact--accent { border-color: var(--status-urgent-border); background: var(--status-urgent-bg); }
.tp-fact__label { font-size: var(--text-xs); text-transform: uppercase; letter-spacing: .03em; color: var(--color-neutral-500); }
.tp-fact__value { margin-top: .2rem; font-size: var(--text-base); font-weight: 600; color: var(--color-neutral-900); }
.tp-fact__value small { font-size: var(--text-xs); font-weight: 500; color: var(--color-neutral-500); margin-left: .3rem; }
.tp-fact--accent .tp-fact__value { color: var(--status-urgent); }
/* Внутри акцентной (срочной) карточки мелкий текст тоже в urgent-тоне —
   иначе серый на #fff7ed фоне теряет и контраст, и семантику. */
.tp-fact--accent .tp-fact__value small { color: var(--status-urgent); }

/* CPV-чипы */
.tp-tags { margin-top: var(--space-5); display: flex; flex-wrap: wrap; gap: .375rem; }
.tp-cpv {
  display: inline-flex;
  align-items: baseline;
  gap: .375rem;
  padding: .2rem .6rem;
  font-size: var(--text-xs);
  border-radius: var(--radius-full);
  color: var(--color-primary-700);
  background: var(--color-primary-50);
  border: 1px solid var(--color-primary-100);
}
.tp-cpv__code { font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace; font-weight: 700; }

/* Описание/ТЗ с раскрытием, если длинно */
.tp-section { margin-top: var(--space-6); }
.tp-section__title { font-size: var(--text-sm); font-weight: 700; text-transform: uppercase; letter-spacing: .03em; color: var(--color-primary-800); margin-bottom: var(--space-2); }
.tp-desc { font-size: var(--text-sm); line-height: 1.65; color: var(--color-neutral-700); white-space: pre-wrap; overflow-wrap: anywhere; }
/* Заголовок вложенного документа внутри описания — маркер парсера
   `### имя файла` (documents_fetch.py) рендерится подписью, не текстом.
   Инлайновый (не <p>): .tp-desc__full сворачивается -webkit-line-clamp'ом,
   который считает строки инлайнового потока и ломается на блочных детях. */
.tp-desc__doc-title { color: var(--color-neutral-600); }
/* Чекбокс-хак вместо <details>: сам текст ТЗ — обычный <div.tp-desc__full>
   (выделяется мышью, объявляется скринридером как текст, а не «кнопка»).
   Скрытый чекбокс держит состояние; кламп/раскрытие и подписи переключаются
   каскадом `~` от его :checked. Чекбокс НЕ display:none (иначе выпадет из
   таб-порядка) — уводим за экран через opacity/position, фокус сохраняется. */
/* Контейнер раскрытия: позиционирующий контекст для скрытого чекбокса. */
.tp-desc--clamp { position: relative; }
.tp-desc__cb {
  position: absolute;
  width: 1px; height: 1px;
  opacity: 0;
  pointer-events: none;
}
.tp-desc__full { display: block; }
.tp-desc__cb:not(:checked) ~ .tp-desc__full {
  display: -webkit-box; -webkit-line-clamp: 6; -webkit-box-orient: vertical; overflow: hidden;
}
.tp-desc__toggle { display: block; cursor: pointer; }
/* Подпись-переключатель под превью; клик по label тоглит чекбокс. */
.tp-desc__hint {
  margin-top: var(--space-2);
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-primary-700);
}
.tp-desc__hint::after { content: "▾"; }
.tp-desc__cb:checked ~ .tp-desc__toggle .tp-desc__hint::after { content: "▴"; }
.tp-desc__cb:checked ~ .tp-desc__toggle .tp-desc__more { display: none; }
.tp-desc__cb:not(:checked) ~ .tp-desc__toggle .tp-desc__less { display: none; }
.tp-desc-none { font-size: var(--text-sm); color: var(--color-neutral-500); }
.tp-source { margin-top: var(--space-5); }

/* Trust: прозрачность источника (eNabavke) + как считаем срочность */
.tp-trust {
  margin-top: var(--space-6);
  border: 1px solid var(--color-neutral-200);
  background: var(--color-neutral-50);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}
.tp-trust__title {
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .03em;
  color: var(--color-neutral-500);
  margin-bottom: var(--space-2);
}
.tp-trust__list { display: grid; grid-template-columns: 1fr; gap: var(--space-2); }
.tp-trust__item {
  display: flex;
  align-items: baseline;
  gap: .5rem;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--color-neutral-600);
}
.tp-trust__ico { flex: none; }
.tp-trust__more { margin-top: var(--space-3); font-size: var(--text-xs); }
.tp-trust__more a { color: var(--color-primary-700); text-decoration: none; }
.tp-trust__more a:hover { text-decoration: underline; }

/* Конверсионный CTA — главный для роста (аноним и залогиненный) */
.tp-cta {
  margin-top: var(--space-8);
  border: 1px solid var(--color-primary-100);
  background: var(--color-primary-50);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}
.tp-cta__title { font-size: var(--text-xl); font-weight: 700; color: var(--color-primary-800); }
.tp-cta__subtitle { margin-top: var(--space-2); font-size: var(--text-sm); line-height: 1.6; color: var(--color-neutral-600); }
.tp-cta__grid { margin-top: var(--space-5); display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
.tp-cta__item { background: var(--color-neutral-0); border: 1px solid var(--color-primary-100); border-radius: var(--radius-md); padding: var(--space-3); }
.tp-cta__item-title { display: flex; align-items: center; gap: .4rem; font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-900); }
.tp-cta__item-desc { margin-top: .2rem; font-size: var(--text-xs); line-height: 1.4; color: var(--color-neutral-500); }
.tp-cta__actions { margin-top: var(--space-5); display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.tp-cta__trust { margin-top: var(--space-3); font-size: var(--text-xs); color: var(--color-neutral-500); }

/* AI-разбор (залогиненный, свой tenant) — обёртка над готовым output-JSON */
.tp-ai { margin-top: var(--space-6); }
.tp-ai__title { display: flex; align-items: center; gap: .4rem; font-size: var(--text-lg); font-weight: 700; color: var(--color-neutral-900); margin-bottom: var(--space-3); }

/* ≥640px: факты в 2 колонки, преимущества CTA в 3 */
@media (min-width: 640px) {
  .tp-facts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .tp-cta__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* Скролл-в-боксе для длинных списков (напр. «Мои тендеры»): список не растит
   страницу бесконечно, шапка/фильтры остаются видны над контейнером. */
.scroll-box {
  max-height: 70vh;
  overflow-y: auto;
}

/* ==========================================================================
   Кокпит дашборда (портал, Этап 1): «моя неделя», календарь, требует действия.
   Только зафиксированная палитра (--color-primary-* / --color-accent-* /
   нейтрали / --status-*): второго акцента и картиночных фонов здесь нет.
   Все состояния — на transform/opacity/цвете фона, чтобы анимация кокпита
   (GSAP, cockpit.js) не дралась с раскладкой.
   ========================================================================== */

/* -- Hero-полоса «Моя неделя» ----------------------------------------------- */
.ck-hero {
  background: var(--color-primary-700);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
  color: var(--color-neutral-0);
  box-shadow: var(--shadow-md);
}
.ck-hero__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}
.ck-hero__title {
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--color-neutral-0);
  margin: 0;
}
.ck-hero__sub { font-size: var(--text-sm); color: var(--color-primary-200); }
.ck-hero__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
}

/* Плитка показателя. Цифры — табличные: при анимации счётчика ширина не пляшет. */
.ck-tile {
  background: rgb(255 255 255 / .08);
  /* .22, а не .14: на тёмном hero-фоне граница /.14 давала контраст 1.52 —
     плитки сливались в одно полотно. */
  border: 1px solid rgb(255 255 255 / .22);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  display: block;
  text-decoration: none;
  color: inherit;
  transition: background-color .2s ease, transform .2s ease;
}
a.ck-tile:hover { background: rgb(255 255 255 / .16); }
a.ck-tile:active { transform: scale(.98); }
a.ck-tile:focus-visible,
.ck-chip:focus-visible {
  outline: 2px solid var(--color-accent-500);
  outline-offset: 2px;
}
.ck-tile__value {
  font-size: var(--text-3xl);
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
}
.ck-tile__value--sm { font-size: var(--text-2xl); }
.ck-tile__label {
  margin-top: var(--space-1);
  font-size: var(--text-xs);
  color: var(--color-primary-100);
}
.ck-tile__hint { margin-top: var(--space-2); font-size: var(--text-xs); color: var(--color-primary-200); }
/* Срочность подписки — только семантические статус-токены. */
.ck-tile.is-urgent { background: var(--status-urgent-bg); border-color: var(--status-urgent-border); }
.ck-tile.is-urgent .ck-tile__value { color: var(--status-urgent); }
.ck-tile.is-urgent .ck-tile__label,
.ck-tile.is-urgent .ck-tile__hint { color: var(--color-neutral-600); }
.ck-tile.is-error { background: var(--status-error-bg); border-color: var(--status-error-border); }
.ck-tile.is-error .ck-tile__value { color: var(--status-error); }
.ck-tile.is-error .ck-tile__label,
.ck-tile.is-error .ck-tile__hint { color: var(--color-neutral-600); }

/* Чипы разбивки воронки и бейджи статуса внутри hero. */
.ck-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.ck-chip {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .15rem .5rem;
  border-radius: var(--radius-full);
  background: rgb(255 255 255 / .12);
  border: 1px solid rgb(255 255 255 / .18);
  font-size: var(--text-xs);
  color: var(--color-neutral-0);
  text-decoration: none;
}
.ck-chip:hover { background: rgb(255 255 255 / .22); }
.ck-chip__num { font-weight: 700; font-variant-numeric: tabular-nums; }

/* Секции кокпита: заголовок в sentence case, вес 600, плотнее обычного h2. */
.ck-section__title {
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -.01em;
  margin-bottom: var(--space-3);
}

/* -- Календарь дедлайнов и событий ------------------------------------------ */
/* minmax(0, 1fr), НЕ голый 1fr: голый = minmax(auto,1fr), и одна широкая строка
   агенды (длинный токен в названии тендера/наручиоца) раздувала колонку по
   min-content — календарь (cal__head/cal__grid делят ту же колонку) уезжал за
   вьюпорт (кокпит: 442 > 390). minmax(0,…) даёт колонке ужиматься, контент
   переносится (overflow-wrap у agenda__title/…meta). */
.cal { display: grid; grid-template-columns: minmax(0, 1fr); gap: var(--space-5); }
.cal__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
  margin-bottom: var(--space-2);
}
.cal__month { font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-700); text-transform: capitalize; }
.cal__legend { display: flex; flex-wrap: wrap; gap: var(--space-3); font-size: var(--text-xs); color: var(--color-neutral-500); }
.cal__legend span { display: inline-flex; align-items: center; gap: .3rem; }
.cal__grid { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: 2px; }
.cal__wd {
  text-align: center;
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-neutral-500);
  padding-bottom: var(--space-1);
}
.cal__day {
  min-height: 2.5rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  padding: .2rem;
  text-align: center;
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--color-neutral-700);
  background: var(--color-neutral-50);
}
.cal__day.is-out { color: var(--color-neutral-400); background: transparent; }
.cal__day.has-events { background: var(--color-neutral-0); border-color: var(--color-neutral-200); }

/* Четыре состояния ячейки, намеренно разного РОДА — чтобы не путались, когда
   совпадают на одной дате (сегодня + есть события + выбрана + peek):
     сегодня  — число в залитом диске (постоянный маркер «где я»);
     события  — фон/рамка ячейки + точки снизу;
     выбрана  — рамка и фон бренд-тона (кликнута, состояние стойкое);
     peek     — тонкое янтарное кольцо (наведение на пункт агенды, транзиентно).
   ‼️ Раньше «сегодня» задавалось фоном ячейки и молча проигрывало правилу
   .has-events ниже по файлу — то есть пропадало ровно в те дни, когда календарь
   и нужен. Диск на .cal__num от фона ячейки не зависит вовсе. */
.cal__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 1.375rem;
  height: 1.375rem;
  border-radius: var(--radius-full);
  line-height: 1;
}
.cal__day.is-today .cal__num {
  background: var(--color-primary-700);
  color: var(--color-neutral-0);
  font-weight: 700;
}
.cal__day.is-selected {
  border-color: var(--color-primary-700);
  background: var(--color-primary-50);
  color: var(--color-primary-800);
}
.cal__day.is-peek { box-shadow: inset 0 0 0 2px var(--color-accent-500); }

/* Ячейка становится кнопкой только под JS (role проставляет cockpit_calendar.js) —
   курсор и hover вешаем на ту же роль, чтобы без JS не обещать клик. */
.cal__day[role="button"] { cursor: pointer; transition: background-color .2s ease, box-shadow .2s ease; }
.cal__day[role="button"]:hover { background: var(--color-primary-50); }
.cal__day[role="button"]:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.cal__note { margin-top: var(--space-2); font-size: var(--text-xs); color: var(--color-neutral-500); }
.cal__dots { display: flex; justify-content: center; gap: 2px; margin-top: .15rem; min-height: .4rem; }
.cal__dot { width: .35rem; height: .35rem; border-radius: var(--radius-full); display: inline-block; }
.cal__dot--deadline { background: var(--status-urgent); }
.cal__dot--action { background: var(--color-primary-700); }
/* primary-400, а не accent: янтарь резервируем за действием/апсейлом, не за
   событием подписки (иначе оранжевый теряет единый смысл «срочность/CTA»). */
.cal__dot--subscription { background: var(--color-primary-400); }

/* Агенда: ближайшие события списком (доступна и без сетки, и без JS). */
.agenda { display: flex; flex-direction: column; gap: var(--space-2); }
.agenda__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-neutral-200);
  border-left-width: 3px;
  border-radius: var(--radius-md);
  background: var(--color-neutral-0);
  text-decoration: none;
  color: inherit;
  transition: background-color .2s ease, transform .2s ease;
}
.agenda__item:hover { background: var(--color-primary-50); }
.agenda__item:active { transform: scale(.99); }
.agenda__item:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
/* Пункты выбранной в календаре даты: лёгкая заливка бренд-тона + кольцо, чтобы
   выделение читалось и поверх обычного :hover соседей. Тон низкой насыщенности —
   подсветка, а не тревога. */
.agenda__item.is-highlighted {
  background: var(--color-primary-50);
  border-color: var(--color-primary-200);
  box-shadow: 0 0 0 1px var(--color-primary-200);
}
.agenda__item--deadline { border-left-color: var(--status-urgent); }
.agenda__item--action { border-left-color: var(--color-primary-700); }
.agenda__item--subscription { border-left-color: var(--color-accent-500); }
.agenda__date {
  flex: none;
  width: 3.6rem;
  text-align: center;
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  color: var(--color-neutral-500);
}
.agenda__day { display: block; font-size: var(--text-base); font-weight: 700; line-height: 1.2; color: var(--color-neutral-900); }
.agenda__body { min-width: 0; flex: 1 1 auto; }
/* Заголовок-ссылка внутри строки агенды. Строка перестала быть <a> (внутри
   живёт кнопка перевода), поэтому подчёркивание и фокус — на самой ссылке. */
.agenda__title-link { color: inherit; text-decoration: none; }
.agenda__title-link:hover { text-decoration: underline; }
.agenda__title-link:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; border-radius: var(--radius-sm); }
/* overflow-wrap: длинный неразрывный токен в названии тендера/наручиоца иначе
   раздувает min-content колонки .cal и уводит календарь за вьюпорт (см. .cal). */
.agenda__title { font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-900); overflow-wrap: anywhere; }
.agenda__meta { margin-top: .1rem; font-size: var(--text-xs); color: var(--color-neutral-500); overflow-wrap: anywhere; }
.agenda__left { flex: none; align-self: center; }

/* Хвост агенды: «Показать ещё N» / «Свернуть» (_agenda_list.html).
   Подпись переключается СОСТОЯНИЕМ [open], а не скриптом: при CSP
   `script-src 'self'` инлайновых обработчиков нет, а блок обязан работать и
   без JS. Маркер-треугольник снимаем (list-style + ::-webkit-details-marker),
   вместо него — своя стрелка в ::before, поворачивающаяся при раскрытии.
   ‼️ Тап-зона ≥2rem по ОБЕИМ осям: min-height даёт высоту, display:flex —
   ширину колонки (inline-flex сжал бы строку до подписи). */
.agenda-more { margin-top: var(--space-2); }
.agenda-more__toggle {
  display: flex;
  align-items: center;
  gap: .4rem;
  min-height: 2rem;
  padding: var(--space-1) 0;
  cursor: pointer;
  list-style: none;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-primary-700);
  -webkit-user-select: none;
  user-select: none;
}
.agenda-more__toggle::-webkit-details-marker { display: none; }
.agenda-more__toggle::before {
  content: "▾";
  font-size: var(--text-xs);
  line-height: 1;
  transition: transform .2s ease;
}
.agenda-more[open] > .agenda-more__toggle::before { transform: rotate(180deg); }
.agenda-more__toggle:hover { color: var(--color-primary-800); text-decoration: underline; }
.agenda-more__toggle:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; border-radius: var(--radius-sm); }
.agenda-more__label { display: inline; }
.agenda-more__label--open { display: none; }
.agenda-more[open] .agenda-more__label--closed { display: none; }
.agenda-more[open] .agenda-more__label--open { display: inline; }
.agenda-more__list { margin-top: var(--space-2); }

/* -- Второстепенные блоки дашборда: свёрнуто, но доступно -------------------- */
.ck-more { border-top: 1px solid var(--color-neutral-200); margin-top: var(--space-8); padding-top: var(--space-4); }
.ck-more > summary {
  cursor: pointer;
  list-style: none;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-neutral-600);
  padding: var(--space-2) 0;
  -webkit-user-select: none;
  user-select: none;
}
.ck-more > summary::-webkit-details-marker { display: none; }
.ck-more > summary:hover { color: var(--color-neutral-900); }
.ck-more > summary:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }

/* ≥640px: плитки кокпита 2×2 (по ~150px на плитку с числом 30px было тесно),
   календарь — сетка слева, агенда справа. Все 4 плитки в ряд — только с 1024px. */
@media (min-width: 640px) {
  .ck-hero__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .cal { grid-template-columns: minmax(0, 17rem) minmax(0, 1fr); }
}
@media (min-width: 1024px) {
  .ck-hero__grid { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}

/* ‼️ Уважение к prefers-reduced-motion: переходы и появления выключены, всё
   сразу в финальном состоянии. cockpit.js при этом флаге вообще не анимирует —
   правило ниже страхует CSS-переходы. */
@media (prefers-reduced-motion: reduce) {
  .ck-tile, .agenda__item, .cal__day[role="button"] { transition: none; }
  .agenda-more__toggle::before { transition: none; }
  a.ck-tile:active, .agenda__item:active { transform: none; }
}

/* ==========================================================================
   «Мои тендеры» — доска-воронка (портал, Этап 2). Язык кокпита: заголовки в
   sentence case весом 600, elevation только ради иерархии, состояния — на
   transform/цвете фона. Палитра — только существующие токены (--color-primary-*
   / --color-accent-* / нейтрали / --status-*), второго акцента здесь нет.
   ========================================================================== */

/* -- Сегмент-контрол фильтра стадий ----------------------------------------- */
.seg {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  padding: 3px;
  border-radius: var(--radius-md);
  background: var(--color-neutral-100);
  border: 1px solid var(--color-neutral-200);
}
.seg__item {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  gap: .35rem;
  padding: .3rem .7rem;
  border-radius: var(--radius-sm);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-neutral-600);
  text-decoration: none;
  transition: background-color .2s ease, color .2s ease;
}
.seg__item:hover { background: var(--color-neutral-0); color: var(--color-neutral-900); }
.seg__item:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.seg__item.is-active {
  background: var(--color-primary-700);
  color: var(--color-neutral-0);
  box-shadow: var(--shadow-sm);
}
.seg__num { font-variant-numeric: tabular-nums; opacity: .75; }
/* <640px .seg → горизонтальный скролл-таб: правило вынесено в общий мобильный
   блок @media (max-width: 639px) у липкой шапки (там же --header-h), чтобы не
   плодить второй max-width-блок. */

/* -- Доска ------------------------------------------------------------------ */
.fn { display: block; margin-bottom: var(--space-6); }
.fn__head { margin-bottom: var(--space-3); }
.fn__sub { font-size: var(--text-sm); color: var(--color-neutral-500); margin-top: calc(-1 * var(--space-2)); }
.fn__note { margin-top: var(--space-4); font-size: var(--text-sm); color: var(--color-neutral-500); }
/* minmax(0, 1fr) — колонки не распирают сетку длинными словами, поэтому у body
   горизонтального скролла не возникает; overflow-x на самой доске — страховка
   для узких вьюпортов, скроллит контейнер, а не страница. */
.fn__board {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-3);
  overflow-x: auto;
}
.fn-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding: var(--space-3);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  background: var(--color-neutral-0);
  box-shadow: var(--shadow-sm);
}
.fn__board--archive { margin-top: var(--space-3); }
/* Исходы (won/lost/skipped) — архив: без elevation, приглушённый фон. */
.fn-col--archive { background: var(--color-neutral-50); box-shadow: none; }
.fn-col__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-2);
}
.fn-col__title { font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-800); margin: 0; }
.fn-col__count {
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -.02em;
  color: var(--color-primary-700);
}
.fn-col.is-empty .fn-col__count { color: var(--color-neutral-500); }
.fn-col__note { margin-top: var(--space-1); font-size: var(--text-xs); color: var(--color-neutral-500); }
/* Длинная колонка скроллит СЕБЯ — соседние стадии остаются на виду. */
.fn-col__list {
  margin-top: var(--space-3);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  max-height: 26rem;
  overflow-y: auto;
}
.fn-col__empty { margin-top: var(--space-3); font-size: var(--text-xs); color: var(--color-neutral-500); }

/* -- Строка тендера на доске ------------------------------------------------ */
.fn-row {
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-md);
  background: var(--color-neutral-0);
  transition: background-color .2s ease, border-color .2s ease;
}
.fn-row:hover { background: var(--color-primary-50); border-color: var(--color-primary-200); }
.fn-row__title { font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-900); text-decoration: none; }
a.fn-row__title:hover { text-decoration: underline; }
a.fn-row__title:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.fn-row__meta { margin-top: .15rem; font-size: var(--text-xs); color: var(--color-neutral-500); overflow-wrap: anywhere; }
.fn-row__note { margin-top: .25rem; font-size: var(--text-xs); color: var(--color-neutral-600); }
.fn-row__badges { margin-top: var(--space-2); display: flex; flex-wrap: wrap; gap: .35rem; }

/* -- Папки: вторичный организатор под доской -------------------------------- */
.fn-archive, .fn-folders { margin-top: var(--space-6); }
.fn-folder {
  padding: var(--space-3);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-md);
  background: var(--color-neutral-0);
}

/* ≥768px: доска в три колонки по ходу воронки. */
@media (min-width: 768px) {
  .fn__board { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ‼️ prefers-reduced-motion: переходы выключены; my_tenders.js при этом флаге
   не анимирует вовсе — правило ниже страхует CSS-переходы. */
@media (prefers-reduced-motion: reduce) {
  .seg__item, .fn-row { transition: none; }
}

/* ==========================================================================
   «Все совпадения» — архив ленты (портал, Этап 3). Тот же язык, что у кокпита
   и доски-воронки: заголовки sentence case весом 600, tabular-nums на числах,
   elevation только ради иерархии, палитра — существующие токены.
   ========================================================================== */

/* -- Секции срочности ------------------------------------------------------- */
.fd-group { margin-bottom: var(--space-6); }
.fd-group__title {
  display: flex;
  align-items: baseline;
  gap: var(--space-2);
  font-size: var(--text-lg);
  font-weight: 600;
  letter-spacing: -.01em;
  color: var(--color-neutral-900);
  margin-bottom: var(--space-1);
}
/* Вторая секция — тише первой: «Скоро дедлайн» обязан выигрывать по весу. */
.fd-group__title--quiet { font-size: var(--text-sm); color: var(--color-neutral-500); }
.fd-group__num {
  font-size: var(--text-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--color-primary-700);
}
.fd-group__title--quiet .fd-group__num { color: var(--color-neutral-500); }
.fd-group__sub { font-size: var(--text-xs); color: var(--color-neutral-500); margin-bottom: var(--space-3); }
.fd-list { display: flex; flex-direction: column; gap: var(--space-2); }

/* -- Карточка совпадения ---------------------------------------------------- */
.fd-card {
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-neutral-200);
  border-left: 3px solid var(--color-neutral-200);
  border-radius: var(--radius-md);
  background: var(--color-neutral-0);
  transition: background-color .2s ease, border-color .2s ease, box-shadow .2s ease;
}
.fd-card:hover { background: var(--color-primary-50); border-color: var(--color-primary-200); box-shadow: var(--shadow-sm); }
/* Горит по-настоящему (≤2 дн.) — цветной корешок слева: срочность видно при
   беглом просмотре, до чтения бейджа. Только статус-токены, второго акцента нет. */
.fd-card.is-urgent { border-left-color: var(--status-urgent); }
.fd-card.is-urgent:hover { border-color: var(--status-urgent-border); border-left-color: var(--status-urgent); }
.fd-card__head { display: flex; flex-direction: column; gap: var(--space-2); }
.fd-card__main { min-width: 0; }
.fd-card__title {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-neutral-900);
  text-decoration: none;
  overflow-wrap: anywhere;
}
a.fd-card__title:hover { text-decoration: underline; }
a.fd-card__title:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.fd-card__customer { margin-top: .15rem; font-size: var(--text-xs); color: var(--color-neutral-500); overflow-wrap: anywhere; }
/* Профиль — ЗАМЕТНЫЙ тег в бренд-тоне (Этап 4): «с чем совпадение» — вопрос,
   ради которого лента и открывается, а нейтрально-серый тег отвечал на него
   шёпотом. Тон — существующие primary-токены (второго акцента не заводим:
   янтарь остаётся за CTA), вес 600 и явная граница отделяют тег от строки
   заказчика над ним. Тег кликабелен → ведёт себя как элемент управления:
   hover/focus-visible обязательны. */
/* Мелкие интерактивные элементы ЛК, у которых нет своего компонента: ссылки
   «← На панель» / «Мои тендеры →» / «Нужна помощь?», кнопка «Все разделы» в
   CPV-виджете и <summary> статистики. Все они были 16–20px — ниже инварианта
   тап-зон (2rem). Селекторы по КОНТЕКСТУ, а не по утилитарным классам Tailwind:
   класс `text-sm text-brand` держит цвет и кегль, к нему нельзя привязывать
   поведение. Якорь — `#main` (обёртка страницы в base.html и public_base.html),
   чтобы правило не задевало шапку и подвал, у которых свои размеры. */
#main a.text-brand,
#main a.text-slate-500.underline,
#main summary.text-xs,
#main button.text-slate-600 {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
}

.fd-card__profile {
  /* Тап-зона от 2rem: это ссылка-фильтр («показать ленту этого профиля»), а не
     подпись — по инварианту тап-зон бейдж обязан быть от 32px (было 25px). */
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  margin-top: var(--space-2);
  padding: .15rem .5rem;
  border-radius: var(--radius-sm);
  /* Заливка primary-100, а НЕ primary-50: у карточки на :hover фон как раз
     primary-50 — тег с такой же заливкой на наведении растворился бы. */
  background: var(--color-primary-100);
  border: 1px solid var(--color-primary-200);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-primary-800);
  text-decoration: none;
  transition: background-color .2s ease, border-color .2s ease;
}
a.fd-card__profile:hover { background: var(--color-primary-200); border-color: var(--color-primary-300); }
a.fd-card__profile:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
/* Подводка страницы: одна строка, зачем эта лента — под h1, до фильтров. */
.fd-lede {
  max-width: 62ch;
  margin-bottom: var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-neutral-500);
  text-wrap: pretty;
}
.fd-card__side { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; flex: none; }
.fd-card__sent { font-size: var(--text-xs); font-variant-numeric: tabular-nums; color: var(--color-neutral-500); }
/* -- AI-кластер: что готово + вход в разбор --------------------------------- */
.fd-card__ai {
  margin-top: var(--space-3);
  padding-top: var(--space-2);
  border-top: 1px solid var(--color-neutral-100);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .35rem;
}
.fd-card__ready { font-size: var(--text-xs); color: var(--color-neutral-500); margin-right: .15rem; }
.fd-card__more { font-size: var(--text-xs); font-weight: 600; color: var(--color-primary-700); text-decoration: none; margin-left: auto; }
.fd-card__more:hover { text-decoration: underline; }
.fd-card__more:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
/* Ничего не готово — один заметный CTA вместо россыпи бейджей. */
.fd-card__cta {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  gap: .35rem;
  padding: .3rem .7rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--color-primary-200);
  background: var(--color-primary-50);
  font-size: var(--text-xs);
  font-weight: 600;
  color: var(--color-primary-700);
  text-decoration: none;
  transition: background-color .2s ease, color .2s ease;
}
.fd-card__cta:hover { background: var(--color-primary-700); color: var(--color-neutral-0); border-color: var(--color-primary-700); }
.fd-card__cta:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }

/* -- Пагинация -------------------------------------------------------------- */
.fd-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-neutral-200);
}
.fd-pager__total { font-size: var(--text-xs); color: var(--color-neutral-500); }
.fd-pager__controls { display: flex; align-items: center; gap: var(--space-3); }
.fd-pager__pos { font-size: var(--text-sm); color: var(--color-neutral-500); font-variant-numeric: tabular-nums; }
.fd-pager__num { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--color-neutral-700); }

/* ≥640px: шапка карточки в строку — бейдж срочности уходит вправо. */
@media (min-width: 640px) {
  .fd-card__head { flex-direction: row; justify-content: space-between; }
  .fd-card__side { justify-content: flex-end; }
}

/* ‼️ prefers-reduced-motion: переходы выключены; feed.js при этом флаге не
   анимирует вовсе — правило ниже страхует CSS-переходы. */
@media (prefers-reduced-motion: reduce) {
  .fd-card, .fd-card__cta { transition: none; }
}

/* ==========================================================================
   Навигация длинных страниц (портал, Этап 9)
   Дашборд и лента длинные: от последних тендеров до навигации была «долгая
   прокрутка колесом». Три средства — липкая шапка (навигация всегда под
   рукой), кнопка «наверх» и плавный скролл якорей. Только существующие
   токены, ни одной новой зависимости.
   ========================================================================== */

/* Плавный скролл якорей: календарь → тендер, «Подключить Telegram ↓»,
   разделы AI-разбора. Кнопка «наверх» свой behavior задаёт сама. */
html { scroll-behavior: smooth; }

/* ‼️ Якорь не должен уезжать ПОД липкую шапку. Правило на [id], а не на
   перечень секций: новый якорь получает отступ автоматически, забыть его
   нельзя. scroll-margin влияет ТОЛЬКО на скролл-к-элементу, не на раскладку. */
[id] { scroll-margin-top: calc(var(--header-h) + var(--space-4)); }

/* -- Skip-link (a11y) -------------------------------------------------------- */
/* Первый фокусируемый элемент <body>: клавиатура/скринридер прыгает сразу к
   #main, минуя шапку и навигацию. По умолчанию уведён за верхний край экрана
   (не занимает место, не виден мышью), при :focus въезжает. z-index 60 — выше
   липкой шапки (50), иначе фокус-баннер прятался бы под ней. */
.skip-link {
  position: fixed;
  top: 0;
  left: var(--space-4);
  z-index: 60;
  transform: translateY(-120%);
  padding: .5rem 1rem;
  background: var(--color-primary-700);
  color: var(--color-neutral-0);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
  box-shadow: var(--shadow-md);
  transition: transform .15s ease;
}
.skip-link:focus { transform: translateY(0); outline: 2px solid var(--color-accent-500); outline-offset: 2px; }

/* -- Липкая шапка ----------------------------------------------------------- */
/* z-index 50 — выше контента, карточек и баннеров. Выпадашка «Ещё» (z-index
   40) лежит ВНУТРИ шапки: шапка создаёт стековый контекст, поэтому меню
   всплывает вместе с ней и перекрывает контент, оставаясь под ней самой.
   Фон полупрозрачный с blur — под шапкой видно, что контент продолжается,
   но текст не просвечивает. */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgb(255 255 255 / .82);
  -webkit-backdrop-filter: blur(12px) saturate(180%);
  backdrop-filter: blur(12px) saturate(180%);
  box-shadow: var(--shadow-sm);
}
/* Нет backdrop-filter — полупрозрачный фон дал бы просвечивающий текст:
   отдаём непрозрачный, шапка остаётся читаемой. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header { background: var(--color-neutral-0); }
}

/* <640px: на телефоне inline только 3 первичных пункта, «Тарифы» и «Выход»
   уезжают в выпадашку «Ещё» (nav-hide-mobile прячет их, nav-show-mobile
   раскрывает копии внутри меню). Тап-зона nav-link — полноценные 2.75rem (было
   ~26px, ниже нормы 44px). Пунктов меньше → строк меньше, но каждая выше:
   --header-h держит ~2 строки, а scroll-margin добавляет к нему буфер space-4,
   чтобы якоря (#telegram-card, #analysis, дни календаря) не уходили под шапку. */
@media (max-width: 639px) {
  /* Бренд теперь занимает первый ряд целиком (без переноса), навигация — 2
     собственных ряда под ним (3 первичных пункта + «Ещё ▾»/языки) — итого 3
     ряда шапки. Замерено локально (playwright, 390×844) после правки: 149px
     фактической высоты .site-header на /app, /app/feed, /app/my, /library,
     /cabinet/telegram → округлено вверх до 9.5rem (152px). */
  :root { --header-h: 9.5rem; }
  .site-header .nav-link {
    min-height: 2.75rem;
    padding: .375rem .5rem;
    font-size: var(--text-xs);
    display: inline-flex;
    align-items: center;
  }
  .site-header .brand { font-size: var(--text-base); flex-shrink: 0; white-space: nowrap; }
  .site-header .brand img { width: 22px; height: 22px; }
  .site-header .nav-hide-mobile { display: none; }
  .site-header .nav-show-mobile { display: block; }
  /* Публичная шапка одной строкой (бренд+языки+навигация) не влезала на телефон
     (scrollWidth 510 > 390 после тап-зон #446). Переносим: бренд и языки в
     первой строке, навигация — во второй во всю ширину. Тап-зоны не трогаем. */
  .site-header--public .site-header__bar { flex-wrap: wrap; }
  .site-header--public .site-header__actions { flex-basis: 100%; justify-content: flex-start; }
  /* Шапка ЛК (base.html): без flex-wrap строка не переносилась, а сжимала
     .brand ниже его max-content ширины — без nowrap (выше) текст рвался на
     три строки («Tender / Bot / Serbia»), навигация обтекала справа (аудит
     boss'а 03.08). Тот же паттерн переноса, что у публичной шапки: бренд
     занимает первый ряд целиком, навигация — второй во всю ширину. */
  .site-header--cabinet .site-header__bar { flex-wrap: wrap; }
  .site-header--cabinet .site-header__actions { flex-basis: 100%; }
  /* Контекстные «?»-подсказки: на узком экране пузырь, отцентрованный по иконке
     у края формы/шапки, вываливался за левый (/profiles/new: left −33) или
     правый (кокпит) край и добавлял горизонтальную прокрутку. Удержать
     центрирование в границах вьюпорта без JS нельзя, поэтому на телефоне пузырь —
     нижняя плашка во всю ширину минус поля: всегда целиком на экране, прокрутки
     не создаёт. Стрелка без якоря к иконке убирается. */
  .tip__bubble {
    position: fixed;
    left: 1rem;
    right: 1rem;
    top: auto;
    bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
    transform: none;
    width: auto;
    max-width: none;
  }
  .tip__bubble::after { display: none; }
  /* Сегмент-контрол фильтра стадий (my_tenders): при 5+ профилях перенос занимал
     треть первого экрана — на телефоне горизонтальный скролл-таб (nowrap +
     overflow-x), пилюли не сжимаются (flex:none). На десктопе перенос как был. */
  .seg { flex-wrap: nowrap; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .seg__item { flex: none; }
  /* M-8 аудита: 14px в .field-control ниже порога 16px, за которым iOS Safari
     зумит страницу при фокусе поля. Только размер шрифта — ширину контейнера
     формы (max-w-md) не трогаем. */
  .field-control { font-size: 1rem; }
}

/* -- Плавающая кнопка «Наверх» ---------------------------------------------- */
/* Прогрессивное улучшение: в разметке кнопка есть всегда, но класс is-visible
   ставит только scroll_nav.js. Пока его нет (CSP срезал, сеть, старый
   браузер), visibility:hidden держит кнопку и вне экрана, и вне таб-порядка —
   без JS её попросту нет, а вёрстка цела.
   z-index 45 — над контентом и подсказками (30), но ПОД шапкой (50): уезжая,
   кнопка уходит под шапку, а не поверх навигации.
   safe-area-inset — чтобы не попасть под системную панель iOS. */
.to-top {
  position: fixed;
  right: var(--space-4);
  bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px));
  z-index: 45;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 1px solid var(--color-primary-800);
  border-radius: var(--radius-lg);
  background: var(--color-primary-700);
  color: var(--color-neutral-0);
  font-size: var(--text-lg);
  line-height: 1;
  box-shadow: var(--shadow-md);
  cursor: pointer;
  opacity: 0;
  visibility: hidden;
  transform: translateY(.5rem);
  transition: opacity .2s ease, transform .2s ease, visibility .2s ease, background-color .15s ease;
}
.to-top.is-visible { opacity: 1; visibility: visible; transform: none; }
.to-top:hover { background: var(--color-primary-800); }
.to-top:focus-visible { outline: 2px solid var(--color-accent-500); outline-offset: 2px; }
/* После .is-visible — иначе transform:none перебил бы нажатие. */
.to-top:active { transform: scale(.96); }

/* ‼️ prefers-reduced-motion: reduce — ни плавного скролла, ни анимации
   появления. scroll_nav.js при этом флаге скроллит behavior:'auto'; правило
   ниже снимает CSS-часть (иначе якоря продолжали бы «ехать»). */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .to-top { transition: none; }
  .to-top:active { transform: none; }
  .skip-link { transition: none; }
}

/* -- Доп. Tailwind-утилиты вне замороженного сабсета (FIX-PLANS-CSS) --------
   Классы, которые шаблоны используют, но которых не было в purge-сабсете
   на момент VG-28.1 (сборка ниже). Семантика 1:1 с Tailwind v3.4, значения
   не менять без сверки с https://tailwindcss.com/docs. -------------------- */
.list-decimal{list-style-type:decimal}
.relative{position:relative}
.absolute{position:absolute}
.cursor-default{cursor:default}
.left-1\/2{left:50%}
.-top-3{top:-.75rem}
.-translate-x-1\/2{--tw-translate-x:-50%;transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}
.h-3{height:.75rem}
.h-4{height:1rem}
.w-3{width:.75rem}
.w-4{width:1rem}
.rounded-2xl{border-radius:1rem}
.gap-1\.5{gap:.375rem}
.gap-6{gap:1.5rem}
.gap-y-1{row-gap:.25rem}
.mb-5{margin-bottom:1.25rem}
.ml-1{margin-left:.25rem}
.pb-2{padding-bottom:.5rem}
.pb-6{padding-bottom:1.5rem}
.pb-14{padding-bottom:3.5rem}
.pt-14{padding-top:3.5rem}
.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}
.last\:pb-0:last-child{padding-bottom:0}
.border-blue-200{--tw-border-opacity:1;border-color:rgb(191 219 254/var(--tw-border-opacity,1))}
.border-emerald-200{--tw-border-opacity:1;border-color:rgb(167 243 208/var(--tw-border-opacity,1))}
.border-slate-200{--tw-border-opacity:1;border-color:rgb(226 232 240/var(--tw-border-opacity,1))}
.border-slate-900{--tw-border-opacity:1;border-color:rgb(15 23 42/var(--tw-border-opacity,1))}
.text-amber-800{--tw-text-opacity:1;color:rgb(146 64 14/var(--tw-text-opacity,1))}
.text-blue-800{--tw-text-opacity:1;color:rgb(30 64 175/var(--tw-text-opacity,1))}
.text-emerald-500{--tw-text-opacity:1;color:rgb(16 185 129/var(--tw-text-opacity,1))}
.text-emerald-800{--tw-text-opacity:1;color:rgb(6 95 70/var(--tw-text-opacity,1))}
.ring-2{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}
.ring-slate-900{--tw-ring-opacity:1;--tw-ring-color:rgb(15 23 42/var(--tw-ring-opacity,1))}
@media (min-width:640px){
  .sm\:flex-row{flex-direction:row}
  .sm\:items-center{align-items:center}
  .sm\:justify-between{justify-content:space-between}
  .sm\:grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}
}

/* ==========================================================================
   Читаемость и состояния (contrast-pass): индикатор htmx, единый фокус ДС,
   тап-зоны, плейсхолдеры. Только токены/существующие классы; палитра неизменна.
   ========================================================================== */

/* -- Индикатор ожидания htmx ------------------------------------------------
   В шаблонах не было ни одного hx-indicator, при этом AI-генерация, тумблер
   перевода и действия воронки — htmx-POST: без обратной связи юзер жмёт
   повторно. htmx вешает .htmx-request на элемент запроса на время полёта. */
.htmx-request { opacity: .6; pointer-events: none; }
button.htmx-request { position: relative; }
button.htmx-request::after {
  content: "";
  display: inline-block;
  width: .85em;
  height: .85em;
  margin-left: .4rem;
  vertical-align: -.1em;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: var(--radius-full);
  animation: htmx-spin .6s linear infinite;
}
@keyframes htmx-spin { to { transform: rotate(360deg); } }
/* prefers-reduced-motion: спиннер не крутим — статичное многоточие-ожидание. */
@media (prefers-reduced-motion: reduce) {
  button.htmx-request::after {
    content: "…";
    width: auto;
    height: auto;
    margin-left: .3rem;
    border: 0;
    animation: none;
  }
}

/* -- Единый видимый фокус базовых компонентов ДС ----------------------------
   Частные компоненты (ck-tile, seg, cal, fd-*, to-top, agenda) уже имеют
   focus-visible; базовые кнопки/ссылки/раскрывашки — нет. */
.btn-primary:focus-visible,
.btn-secondary:focus-visible,
.btn-ghost:focus-visible,
.btn-danger:focus-visible,
.nav-link:focus-visible,
.help-chip:focus-visible,
.faq-item__q:focus-visible,
.nav-more > summary:focus-visible {
  outline: 2px solid var(--color-primary-700);
  outline-offset: 2px;
}
/* Фокус на скрытом чекбоксе → видимое кольцо на его label (иначе клавиатура
   «слепнет»: чекбокс за экраном, а фокус реально на нём). */
.tp-desc__cb:focus-visible ~ .tp-desc__toggle {
  outline: 2px solid var(--color-primary-700);
  outline-offset: 2px;
}

/* -- Тап-зоны ---------------------------------------------------------------
   Кнопки-бейджи воронки — основной рабочий инструмент, сейчас ~20px высотой;
   поднимаем до 32px и даём видимый фокус. */
button.badge,
summary.badge {
  min-height: 2rem;
  padding: .35rem .75rem;
}
button.badge:focus-visible,
summary.badge:focus-visible {
  outline: 2px solid var(--color-primary-700);
  outline-offset: 2px;
}
/* Иконка «?»-подсказки крупнее (1rem→1.25rem) + невидимая тап-зона вокруг —
   позиционируем ::before от самой иконки (relative), а не от .tip. */
/* Тап-зона ≥2rem по ОБЕИМ осям (замер 03.08: 20×32 — высоту уже держит
   min-height, ширину нет; тот же класс дефекта, что .lang-pill в #480).
   min-width замыкает вторую ось; justify-content центрует иконку внутри
   расширенного бокса, как у .lang-pill/footer a. */
.tip__icon { width: 1.25rem; height: 1.25rem; min-width: 2rem; position: relative; }
.tip__icon::before { content: ""; position: absolute; inset: -.6rem; }
/* Ссылки подвала (Politika privatnosti / Uslovi korišćenja / Impresum и
   соседние) были ~20px — голый текст в строке без своей тап-зоны. Селектор
   по <footer>, а не по классу: подвал в base.html и public_base.html держит
   разную разметку (div/nav), но обе — внутри <footer>.
   ‼️ min-height одной оси мало (тот же класс дефекта, что .lang-pill в #480):
   замер 03.08 (`shot.sh`, 390×844, `?lang=en`) на /plans, /signup, /login,
   /help дал ровно одну мелкую цель на экран — короткая подпись "Help"
   (28×32): высоту уже держит min-height, ширину — нет. min-width замыкает
   вторую ось; justify-content центрует текст, если бокс шире содержимого
   (короткие подписи EN), как у .lang-pill. */
footer a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2rem;
  min-width: 2rem;
}

/* -- Плейсхолдеры -----------------------------------------------------------
   reset Tailwind ставит #9ca3af (2.54 к белому). Префикс body поднимает
   специфичность выше reset-правила, которое ниже в исходнике файла. */
body input::placeholder,
body textarea::placeholder { color: var(--color-neutral-500); }

/* -- Утилиты, которых нет в сабсете, но ставит JS-виджет (не шаблон) --------
   Сборки Tailwind нет: сторож test_css_template_coverage.py сканировал
   только *.html и не видел className/classList в JS — cpv_widget.js ставил
   пять классов, которых в собранном CSS не было (ml-2/pr-1/truncate/
   max-w-full молча не применялись; перевод CPV слипался с названием без
   пробела). Значения — как у соседних Tailwind-утилит того же шага. */
.ml-2 { margin-left: .5rem; }
.pr-1 { padding-right: .25rem; }
.truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.max-w-full { max-width: 100%; }

/* -- Консоль оператора (админ-навигация) ------------------------------------
   Ряд навигации админки шёл вторым рядом под белой шапкой ЛК (.site-header),
   тем же border-b — визуально сливался с ней (D1 04.08 не смог найти
   /admin/users). Тёмный бренд-контейнер делает контур оператора отличимым с
   первого взгляда; роли статусных цветов не занимаем (оранжевый/красный —
   только срочность/ошибка). */
.admin-console {
  background: var(--color-primary-800);
  border: 1px solid var(--color-primary-900);
  border-radius: var(--radius-md);
  padding: .5rem .625rem;
}
.admin-console__label {
  display: inline-flex;
  align-items: center;
  color: var(--color-neutral-0);
  background: var(--color-primary-600);
  border-radius: var(--radius-sm);
  padding: .25rem .5rem;
  margin-right: .25rem;
  font-size: var(--text-xs);
  font-weight: 700;
  letter-spacing: .04em;
}
.admin-console .nav-link { color: var(--color-primary-100); }
.admin-console .nav-link:hover { color: var(--color-neutral-0); background: var(--color-primary-700); }
.admin-console .nav-link.is-active { color: var(--color-neutral-0); background: var(--color-primary-600); font-weight: 600; }
/* Фокус-кольцо базового .nav-link (--color-primary-700) тонет на тёмном фоне
   консоли — здесь нужен светлый контур. */
.admin-console .nav-link:focus-visible { outline-color: var(--color-neutral-0); }

*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.19 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.mx-auto{margin-left:auto;margin-right:auto}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-16{margin-top:4rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-5{margin-top:1.25rem}.mt-6{margin-top:1.5rem}.mt-8{margin-top:2rem}.mt-auto{margin-top:auto}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-7{height:1.75rem}.max-h-40{max-height:10rem}.max-h-48{max-height:12rem}.w-7{width:1.75rem}.w-full{width:100%}.min-w-0{min-width:0}.max-w-2xl{max-width:42rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.flex-none{flex:none}.flex-shrink-0,.shrink-0{flex-shrink:0}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.list-inside{list-style-position:inside}.list-disc{list-style-type:disc}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-center{align-items:center}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-x-4{-moz-column-gap:1rem;column-gap:1rem}.space-x-4>:not([hidden])~:not([hidden]){--tw-space-x-reverse:0;margin-right:calc(1rem*var(--tw-space-x-reverse));margin-left:calc(1rem*(1 - var(--tw-space-x-reverse)))}.space-y-1>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.25rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.25rem*var(--tw-space-y-reverse))}.space-y-2>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.5rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.5rem*var(--tw-space-y-reverse))}.space-y-3>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(.75rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(.75rem*var(--tw-space-y-reverse))}.space-y-4>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-top:calc(1rem*(1 - var(--tw-space-y-reverse)));margin-bottom:calc(1rem*var(--tw-space-y-reverse))}.divide-y>:not([hidden])~:not([hidden]){--tw-divide-y-reverse:0;border-top-width:calc(1px*(1 - var(--tw-divide-y-reverse)));border-bottom-width:calc(1px*var(--tw-divide-y-reverse))}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.border{border-width:1px}.border-y{border-top-width:1px}.border-b,.border-y{border-bottom-width:1px}.border-t{border-top-width:1px}.border-amber-200{--tw-border-opacity:1;border-color:rgb(253 230 138/var(--tw-border-opacity,1))}.border-green-200{--tw-border-opacity:1;border-color:rgb(187 247 208/var(--tw-border-opacity,1))}.border-red-200{--tw-border-opacity:1;border-color:rgb(254 202 202/var(--tw-border-opacity,1))}.border-red-300{--tw-border-opacity:1;border-color:rgb(252 165 165/var(--tw-border-opacity,1))}.border-slate-300{--tw-border-opacity:1;border-color:rgb(203 213 225/var(--tw-border-opacity,1))}.bg-amber-50{--tw-bg-opacity:1;background-color:rgb(255 251 235/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(239 246 255/var(--tw-bg-opacity,1))}.bg-emerald-50{--tw-bg-opacity:1;background-color:rgb(236 253 245/var(--tw-bg-opacity,1))}.bg-green-50{--tw-bg-opacity:1;background-color:rgb(240 253 244/var(--tw-bg-opacity,1))}.bg-green-700{--tw-bg-opacity:1;background-color:rgb(21 128 61/var(--tw-bg-opacity,1))}.bg-red-50{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.bg-red-600{--tw-bg-opacity:1;background-color:rgb(220 38 38/var(--tw-bg-opacity,1))}.bg-slate-100{--tw-bg-opacity:1;background-color:rgb(241 245 249/var(--tw-bg-opacity,1))}.bg-slate-50{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.bg-slate-700{--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity,1))}.bg-slate-900{--tw-bg-opacity:1;background-color:rgb(15 23 42/var(--tw-bg-opacity,1))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.pb-1{padding-bottom:.25rem}.pb-12{padding-bottom:3rem}.pt-16{padding-top:4rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.italic{font-style:italic}.leading-none{line-height:1}.tracking-tight{letter-spacing:-.025em}.text-amber-600{--tw-text-opacity:1;color:rgb(217 119 6/var(--tw-text-opacity,1))}.text-amber-700{--tw-text-opacity:1;color:rgb(180 83 9/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(37 99 235/var(--tw-text-opacity,1))}.text-blue-700{--tw-text-opacity:1;color:rgb(29 78 216/var(--tw-text-opacity,1))}.text-emerald-700{--tw-text-opacity:1;color:rgb(4 120 87/var(--tw-text-opacity,1))}.text-green-600{--tw-text-opacity:1;color:rgb(22 163 74/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-red-600{--tw-text-opacity:1;color:rgb(220 38 38/var(--tw-text-opacity,1))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity,1))}.text-slate-300{--tw-text-opacity:1;color:rgb(203 213 225/var(--tw-text-opacity,1))}.text-slate-400{--tw-text-opacity:1;color:rgb(148 163 184/var(--tw-text-opacity,1))}.text-slate-500{--tw-text-opacity:1;color:rgb(100 116 139/var(--tw-text-opacity,1))}.text-slate-600{--tw-text-opacity:1;color:rgb(71 85 105/var(--tw-text-opacity,1))}.text-slate-700{--tw-text-opacity:1;color:rgb(51 65 85/var(--tw-text-opacity,1))}.text-slate-800{--tw-text-opacity:1;color:rgb(30 41 59/var(--tw-text-opacity,1))}.text-slate-900{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.last\:border-b-0:last-child{border-bottom-width:0}.hover\:bg-green-800:hover{--tw-bg-opacity:1;background-color:rgb(22 101 52/var(--tw-bg-opacity,1))}.hover\:bg-red-50:hover{--tw-bg-opacity:1;background-color:rgb(254 242 242/var(--tw-bg-opacity,1))}.hover\:bg-slate-50:hover{--tw-bg-opacity:1;background-color:rgb(248 250 252/var(--tw-bg-opacity,1))}.hover\:bg-slate-700:hover{--tw-bg-opacity:1;background-color:rgb(51 65 85/var(--tw-bg-opacity,1))}.hover\:bg-slate-800:hover{--tw-bg-opacity:1;background-color:rgb(30 41 59/var(--tw-bg-opacity,1))}.hover\:bg-white:hover{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.hover\:text-red-500:hover{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.hover\:text-slate-900:hover{--tw-text-opacity:1;color:rgb(15 23 42/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:text-4xl{font-size:2.25rem;line-height:2.5rem}}@media (min-width:768px){.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}