/* ==========================================================================
   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-container: var(--radius-lg);
  --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; }
/* Активный отчёт «Готового отчёта» (/app/analitika): заливка бренда, форма и
   граница те же, что у .btn-secondary — раскладка не сдвигается. */
.btn-secondary.is-active { background: var(--color-primary-700); color: var(--color-neutral-0); border-color: var(--color-primary-700); }
.btn-secondary.is-active:hover { background: var(--color-primary-800); border-color: var(--color-primary-800); }

/* -- Статус-бейджи --------------------------------------------------------- */
.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); }
/* Тап-зона кликабельных бейджей (сам <a> — цель клика, контейнер не нужен):
   .badge остаётся некликабельным дефолтом (карточка тендера, лента) — этот
   класс добавляется РЯДОМ, только на <a class="badge …">. Реальный рост
   бокса (не псевдоэлемент), чтобы в ряду .fd-card__ai (gap .35rem) зоны
   соседних бейджей не перекрывались — flex-gap считается от новых, больших
   границ бокса. */
.badge-tap { min-height: 2rem; min-width: 2rem; justify-content: center; }

/* Компактная вторичная кнопка-действие воронки (_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-container);
  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-600);
}
.field-control {
  width: 100%;
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-md);
  padding: .5rem .75rem;
  /* 16px на всех вьюпортах: iOS Safari зумит страницу при фокусе поля с кеглем <16px
     и обратно не возвращает (#987, M-8 аудита). */
  font-size: var(--text-base);
  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; }

/* Режим «Все тендеры» (0043) — тот же чекбокс, но выделенный: он отвечает на
   вопрос секции раньше ключевых слов и меняет смысл всей формы (тема больше не
   нужна, AI выключается принудительно). Роль цвета — «времени ещё есть»/
   нейтральное информирование primary, а НЕ urgent: срочность в продукте значит
   только близкий дедлайн. Растягиваем на всю ширину секции: строка-подсказка
   переносится, а inline-flex родителя ужал бы её до содержимого. */
.match-all {
  display: flex;
  align-items: flex-start;
  width: 100%;
  padding: var(--space-3);
  border: 1px solid var(--color-primary-200);
  border-radius: var(--radius-md);
  background: var(--color-primary-50);
}
.match-all input { margin-top: .2rem; }

/* Плашка «профиль ничего не найдёт» (0043). Роль цвета — предупреждение о
   настройке, а не срочность времени: оранжевый `--status-urgent` в продукте
   занят только близким дедлайном, поэтому берём янтарь действия — клиенту
   нужно ДЕЙСТВИЕ, и рядом стоит ссылка на правку профиля. */
.profile-silent {
  margin-top: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--color-accent-500);
  border-radius: var(--radius-md);
  background: var(--color-accent-50);
  font-size: var(--text-xs);
  color: var(--color-neutral-700);
}
.profile-silent a {
  display: inline-block;
  margin-top: var(--space-1);
  font-weight: 600;
  color: var(--color-accent-600);
  text-decoration: underline;
}

/* Гейт-подсказка: недоступное на тарифе поле + 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; }
/* «Подробнее» на /izvori: <summary> — первый потомок <details>, тап-зона по обеим осям ≥2rem. */
/* Паспорт площадки (/izvori, карточка тендера): строка на виду + «Подробнее». */
.source-passport { overflow-wrap: anywhere; }
.source-details { overflow-wrap: anywhere; }
.source-details__summary { display: flex; align-items: center; min-height: 2rem; min-width: 2rem; }
/* Образец — .tpl-more (маркер ▸/▾ и :focus-visible), см. ниже. */
.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);
  /* #592: на низком окне (десктоп/планшет боком, <~340px) меню в ~336px
     обрезалось нижним краем, нижние пункты недостижимы — меню absolute внутри
     липкой шапки, страница его не прокручивает. Режем по высоте вьюпорта и даём
     собственную прокрутку (100vh — фолбэк без dvh); телефон переопределяет то же
     самое в @media (max-width: 639px). */
  max-height: calc(100vh - var(--header-h) - var(--space-2));
  max-height: calc(100dvh - var(--header-h) - var(--space-2));
  overflow-y: auto;
  overscroll-behavior: contain;
}
/* Пункты внутри — во всю ширину меню (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; }

/* ИА кабинета (D1 10.10.2026): метка тарифа у инструмента в «Alati ▾», заголовки
   групп мобильного меню (бейдж статуса — в строке логина, см. .whoami-badge). Мобильное
   меню «Meni» (.nav-mobile) на десктопе скрыто — ряд ссылок там обычный. */
.nav-mobile { display: none; }
.nav-tool-badge { margin-left: .5rem; }
.nav-group-title {
  margin: .375rem 0 0;
  padding: .25rem .5rem 0;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-neutral-500);
}
.nav-group-title:first-child { margin-top: 0; }
.nav-menu-lang { margin-left: 0; padding: .25rem .25rem 0; }

/* Самостоятельная строка-ссылка «Тендеры из источников: N →» (кокпит и /tenderi):
   стоит отдельной строкой, а не внутри предложения, поэтому тап-зона >=2rem.
   Шрифт не растёт — только высота цели. */
.src-link { display: inline-flex; align-items: center; min-height: 2rem; }
/* Топ заказчиков в светофоре аналитики (_market_summary.html, [data-market-lights]):
   строка-ссылка в списке, не внутри предложения → тап-зона ≥2rem по обеим осям
   (замер shot.sh 390px: высота 17px у 4 из 4 ссылок, #1056 п.1). */
.mkt-light-link { display: inline-flex; align-items: center; min-height: 2rem; min-width: 2rem; }

/* -- Переключатель языка ЛК (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);
}
/* Список пользователей: страница скроллится сама (внутренний вертикальный скролл
   прятал горизонтальный бегунок под 20 строк — жалоба D1 01.11). */
.admin-table__wrap--flow { max-height: none; }
.admin-table__wrap--flow .admin-table thead th,
.admin-table__wrap--flow .admin-table tbody td { padding-inline: var(--space-2); }
.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;
}
/* Числовые колонки: заголовок и цифра по центру (перебивает text-align:left у thead th). */
.admin-table .num { text-align: center; font-variant-numeric: tabular-nums; }
.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); }

/* -- Админка: широкий контейнер и таблица пользователей (D1 02.11) ----------
   .max-w-admin — ~1280px, ТОЛЬКО для админских страниц (блок main_width в base.html);
   клиентские страницы остаются на max-w-5xl. Email переносится где угодно: длинный
   адрес не растягивает таблицу. На узком экране горизонтальный скролл остаётся, у
   краёв — тень (background-attachment: local, без JS); зебра/hover там прозрачны,
   иначе строки закрывали бы тень. */
.max-w-admin { max-width: 80rem; }
.admin-table__email { overflow-wrap: anywhere; min-width: 12rem; }
.admin-table__ai { white-space: nowrap; font-size: var(--text-xs); line-height: 1.3; }
.admin-table__wrap--flow {
  background:
    linear-gradient(to right, var(--color-neutral-0), rgba(255, 255, 255, 0)) left center / 1.5rem 100% no-repeat local,
    linear-gradient(to left, var(--color-neutral-0), rgba(255, 255, 255, 0)) right center / 1.5rem 100% no-repeat local,
    linear-gradient(to right, rgba(15, 23, 42, .22), rgba(15, 23, 42, 0)) left center / .5rem 100% no-repeat scroll,
    linear-gradient(to left, rgba(15, 23, 42, .22), rgba(15, 23, 42, 0)) right center / .5rem 100% no-repeat scroll,
    var(--color-neutral-0);
}
@media (max-width: 639.98px) {
  .admin-table__wrap--flow .admin-table tbody tr:nth-child(even),
  .admin-table__wrap--flow .admin-table tbody tr:hover { background: transparent; }
  .admin-table__wrap--flow .admin-table thead th { background: transparent; }
}

/* -- Массовые действия: подписи НАД полями, подсказка видимой строкой ------- */
.bulk-form { display: flex; flex-wrap: wrap; align-items: flex-start; gap: var(--space-3); }
.bulk-form__field { display: flex; flex-direction: column; gap: var(--space-1); min-width: 0; }
.bulk-form__field .field-control { width: auto; max-width: 100%; }
/* Числовое поле «Файлов в разборе»: 6rem на широком экране; на телефоне — полная ширина
   поля (правило ниже в media, одинаковая специфичность, стоит позже). Раньше ширина
   стояла инлайном style="width:6rem" и перебивала 100% < 640px. */
.bulk-form__field .bulk-form__files { width: 6rem; }
.bulk-form__hint { font-size: var(--text-xs); color: var(--color-neutral-500); max-width: 22rem; }
.bulk-form__submit { align-self: flex-start; margin-top: 1.4rem; min-height: 2rem; }
@media (max-width: 639.98px) {
  .bulk-form__field { flex: 1 1 100%; }
  .bulk-form__field .field-control { width: 100%; }
  .bulk-form__field .bulk-form__files { width: 100%; }
  .bulk-form__submit { flex: 1 1 100%; margin-top: 0; }
}
.ai-legend { font-size: var(--text-xs); color: var(--color-neutral-600); display: grid; grid-template-columns: max-content 1fr; gap: var(--space-1) var(--space-3); }
.ai-legend dt { font-weight: 600; color: var(--color-neutral-900); }
.ai-legend dd { margin: 0; }
@media (max-width: 639.98px) { .ai-legend { grid-template-columns: 1fr; } .ai-legend dd { margin-bottom: var(--space-1); } }
/* Поле «Файлов в разборе» на карточке пользователя: то же правило, что .bulk-form__files
   (6rem; на телефоне — полная ширина). Инлайн style перебивал медиа-правило. */
.ai-files-input { width: 6rem; }
@media (max-width: 639.98px) { .ai-files-input { width: 100%; } }

/* -- Панель фильтров списка (поиск + селект) — 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); }
/* Идентификация сессии в шапке ЛК (whoami, D1 20.09.2026) — тонкая строка НАД
   основным рядом бренда/навигации, а не внутри него: .site-header__bar уже
   рвался на телефоне от лишней ширины (см. --header-h ниже), добавлять туда
   ещё один flex-элемент рискованно. Длинный email не имеет права распирать
   шапку — truncate вместо переноса, `title` несёт полный текст. */
.site-header__identity {
  padding-top: .375rem;
  /* D1 11.10.2026: справа в этой же строке — переключатель языка (десктоп).
     whoami сжимается (min-width:0 + ellipsis), язык — нет.
     Строка на всю ширину окна: язык прижат к правому краю окна (1rem), а whoami
     держит левый край контейнера max-w-5xl, как логотип ниже (D1 11.10.2026).
     overflow не задаём: он срезал фокус-обводку .lang-pill; обрезку длинного
     email делает сам .whoami (overflow:hidden + ellipsis). */
  padding-left: max(1rem, calc((100% - 64rem) / 2 + 1rem));
  padding-right: 1rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
}
/* Левая часть строки логина (D1 11.10.2026): ссылка «Moj kabinet:» + бейдж статуса.
   Сжимается первой — ellipsis у .whoami__who, язык и «Выход» справа не сжимаются. */
.site-header__who { flex: 0 1 auto; min-width: 0; display: flex; align-items: center; gap: .5rem; }
.site-header__who .whoami { min-width: 0; }
.site-header__identity .lang-switch { flex-shrink: 0; margin-left: auto; }
.whoami {
  display: flex;
  align-items: center;
  /* Разделитель «·» и тенант — отдельные flex-элементы: без gap пробел у «·»
     съедался (ДОО Пример· client). Gap даёт ровный зазор с обеих сторон. */
  gap: .25rem;
  min-height: 2rem;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-size: var(--text-xs);
  color: var(--color-neutral-500);
  text-decoration: none;
}
/* Вход в ЛК — кнопка во второй строке шапки (D1 27.10.2026): видна всегда у
   залогиненного, в т.ч. без email. Вторичная кнопка (.btn-secondary), высота
   подогнана под тап-зону 2rem по обеим осям (padding .25rem + line 1.25rem + рамка
   = 30px, min-height доводит до 32px); flex:none — не сжимается при длинном email. */
.whoami-entry { flex: none; min-height: 2rem; min-width: 2rem; padding: .25rem .75rem; font-size: var(--text-xs); }
.whoami__who { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.whoami__tenant { color: var(--color-neutral-700); }
/* Бейдж статуса в строке логина — ссылка на /cabinet/account#status. Тап-зона
   2rem по ОБЕИМ осям (бейдж сам был 26px по высоте); подчёркивание при наведении,
   обводка при фокусе — как у whoami. */
.whoami-badge {
  display: inline-flex;
  align-items: center;
  flex: none;
  min-height: 2rem;
  min-width: 2rem;
  text-decoration: none;
  border-radius: var(--radius-md);
}
.whoami-badge:hover { text-decoration: underline; }
.whoami-badge:focus-visible { outline: 2px solid var(--color-accent-500); outline-offset: 2px; }
/* «Выход» в строке идентификации (справа от языков, 1024px+ с пунктом Admin).
   Тап-зона 2rem по обеим осям; текст — как whoami, без рамки. */
.whoami-logout-form { display: flex; flex-shrink: 0; margin: 0 0 0 .25rem; }
.whoami-logout {
  min-height: 2rem;
  min-width: 2rem;
  padding: 0 .5rem;
  background: none;
  border: 0;
  font: inherit;
  font-size: var(--text-xs);
  color: var(--color-neutral-500);
  cursor: pointer;
}
.whoami-logout:hover { color: var(--color-neutral-900); text-decoration: underline; }
.whoami-logout:focus-visible { outline: 2px solid var(--color-accent-500); outline-offset: 2px; }
/* -- Публичная шапка (public_base.html): бренд + языки + навигация ------------
   Языки и навигация прижаты вправо (margin-left:auto у языков поглощает
   свободное место, бренд остаётся слева) — десктопный вид как был. На телефоне
   строка переносится (см. @media max-width:639px): бренд+языки в первой строке,
   навигация во второй, ничего не уходит за вьюпорт. */
.site-header--public .lang-switch { margin-left: auto; }
/* ≥640px: ru-подписи + языки не помещались в одну строку (замер 11.10:
   scrollWidth 812 > 640/768 на витрине). Бренд и языки не сжимаются, ряд ссылок
   переносится под ними, а не вылезает за вьюпорт. */
@media (min-width: 640px) {
  .site-header--public .site-header__bar { flex-wrap: wrap; row-gap: 0; }
  .site-header--public .brand { flex-shrink: 0; white-space: nowrap; }
  .site-header--public .site-header__actions { flex-wrap: wrap; justify-content: flex-end; min-width: 0; gap: .25rem 1rem; }
}
/* Шапка ЛК ≥640px: бренд не сжимается и не наезжает на меню; пункты занимают
   остаток ряда, прижаты вправо, а при нехватке места переносятся (не
   перекрывают логотип). Язык — в строке whoami выше, не в этом ряду. */
@media (min-width: 640px) {
  .site-header--cabinet .brand { flex-shrink: 0; white-space: nowrap; }
  .site-header--cabinet .site-header__actions { flex: 1 1 0; min-width: 0; justify-content: flex-end; }
}

/* -- Значок Telegram-канала в шапке (витрина и ЛК, D1 04.11.2026) ---------- */
/* Обёртка бренда и значка: один flex-элемент в .site-header__bar, поэтому
   порядок/перенос шапки (order, display:contents выше) по-прежнему относятся к
   целому блоку. Значок — вторичная ссылка: цвет нейтральный, не акцент. */
.site-header__brandrow { display: flex; align-items: center; gap: .5rem; min-width: 0; }
.tg-header-link { display: inline-flex; align-items: center; gap: .375rem; min-width: 2rem; min-height: 2rem; padding: .375rem; color: var(--color-neutral-500); text-decoration: none; border-radius: var(--radius-sm); font-size: var(--text-sm); white-space: nowrap; }
.tg-header-link:hover { color: var(--color-neutral-900); background: var(--color-neutral-100); }
.tg-header-link:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.tg-header-link__icon { width: 20px; height: 20px; flex-shrink: 0; }
/* ≥640px подпись рядом со значком; на телефоне — только значок, тап-зона 2.75rem
   по обеим осям (как у пунктов меню). */
@media (max-width: 639.98px) {
  .tg-header-link { min-width: 2.75rem; min-height: 2.75rem; justify-content: center; }
  .tg-header-link__label { display: none; }
}

/* -- Акцентный текст на бренд-токене (лендинг, заголовки) ------------------ */
.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 колонка на телефоне, ряд — только с 768px. Свой класс
   вместо sm:grid-cols-3: на 640–760px три колонки давали ~190px под цену, подпись
   и 8 фич — тесно. Сборки Tailwind нет, поэтому breakpoint здесь, а не в утилите. */
.plan-grid { grid-template-columns: 1fr; }
@media (min-width: 768px) {
  /* Колонок столько, сколько карточек (Pro + Business — 2; Free с витрины убран). */
  .plan-grid { grid-auto-flow: column; grid-auto-columns: 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); }
/* Лимиты тарифа (limits-view): янтарь = приближение (действие/апсейл), красный = исчерпано. */
.bar-fill--near { background: var(--color-accent-500); }
.bar-fill--out { background: var(--status-error); }
.sr-only { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

/* -- 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-600);
}
.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);
}

/* Одна витрина по отраслям (library_showcase, 01.10.2026). */
/* Пакет «вся отрасль» — первая карточка отрасли; метка над заголовком. */
.tpl-card--pkg { border-color: var(--color-primary-200); }
.tpl-card__badge {
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--color-primary-700);
}
.tpl-card__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-top: auto;
}
.tpl-card__actions .tpl-card__cta { margin-top: 0; }
.tpl-card__more { min-height: 2rem; min-width: 2rem; }
/* Чипы отраслей — якоря на секции; тап-зона 2rem по обеим осям. */
.tpl-sector-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
}
.tpl-sector-nav__chip {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  min-width: 2rem;
  padding: .25rem .75rem;
  font-size: var(--text-sm);
  font-weight: 500;
  border-radius: var(--radius-full);
  border: 1px solid var(--color-neutral-200);
  background: var(--color-neutral-0);
  color: var(--color-neutral-700);
  text-decoration: none;
}
.tpl-sector-nav__chip:hover { border-color: var(--color-primary-200); color: var(--color-primary-700); }
.tpl-sector-nav__chip:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.tpl-group { scroll-margin-top: calc(var(--header-h, 3.5rem) + var(--space-2)); }
.tpl-search {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
}
.tpl-search .field-control { flex: 1 1 14rem; width: auto; }
/* /cpv-kodovi: строка результата поиска и сводка раздела (cpv_directory.js, cpv_directory.html). */
.cd-head, .cd-meta { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0.25rem 0.5rem; }
.cd-meta { align-items: center; gap: 0 0.75rem; margin-top: 0.25rem; font-size: 0.875rem; }
.cd-link { display: inline-flex; align-items: center; min-height: 2rem; text-decoration: underline; }
.cd-sum { padding-block: 0.5rem; }
/* «Как работают шаблоны» и «узкие шаблоны отрасли» — <details> без JS. */
.tpl-howto, .tpl-more {
  margin-bottom: var(--space-6);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  background: var(--color-neutral-0);
}
.tpl-more { margin-top: var(--space-3); margin-bottom: 0; }
.tpl-howto > summary, .tpl-more > summary {
  display: flex;
  align-items: center;
  min-height: 2.5rem;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-neutral-700);
  cursor: pointer;
}
/* Маркер раскрытия: display:flex у summary снимает штатный треугольник. */
.tpl-howto > summary::before, .tpl-more > summary::before, .source-details__summary::before {
  content: "▸";
  margin-right: var(--space-2);
  color: var(--color-neutral-500);
}
.tpl-howto[open] > summary::before, .tpl-more[open] > summary::before, .source-details[open] > .source-details__summary::before { content: "▾"; }
.tpl-howto > summary:focus-visible, .tpl-more > summary:focus-visible, .source-details__summary:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.tpl-more[open] > summary { border-bottom: 1px solid var(--color-neutral-200); }
.tpl-more > .tpl-grid { padding: var(--space-3); }
.tpl-howto__list {
  list-style: decimal;
  padding: 0 var(--space-4) var(--space-4) calc(var(--space-4) + 1.25rem);
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-neutral-700);
}
.tpl-howto__list li + li { margin-top: var(--space-1); }
/* Страница состава шаблона. */
.tpl-detail {
  display: grid;
  gap: var(--space-4);
  margin-bottom: var(--space-6);
  padding: var(--space-4);
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-lg);
  background: var(--color-neutral-0);
}
.tpl-detail__row { display: grid; gap: var(--space-1); }
.tpl-detail__key { font-size: var(--text-xs); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; color: var(--color-neutral-500); }
.tpl-detail__val { font-size: var(--text-sm); color: var(--color-neutral-800); min-width: 0; overflow-wrap: anywhere; }
.tpl-detail__hint { font-size: var(--text-xs); color: var(--color-neutral-500); margin-bottom: var(--space-2); }
.tpl-detail__cpv { display: grid; gap: var(--space-2); }
.tpl-tag--stop { color: var(--color-neutral-600); background: var(--color-neutral-100); text-decoration: line-through; }
.tpl-detail__actions { display: grid; gap: var(--space-3); margin-bottom: var(--space-8); }
.tpl-detail__buttons { display: flex; flex-wrap: wrap; gap: var(--space-2); }
@media (min-width: 640px) {
  .tpl-detail__row { grid-template-columns: 11rem minmax(0, 1fr); gap: var(--space-4); }
}

/* ≥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;
  /* Тап-зона ≥2rem по обеим осям (#989): ширина — текст, высота — min-height. */
  min-height: 2rem;
}
.tp-back:hover { color: var(--color-primary-700); }
/* Ссылки-действия карточки («jnportal» в фактах, «Kako radi →» в доверии) — той же
   тап-зоны. Заголовки и ссылки внутри предложения сюда НЕ входят (exemptTargets). */
.tp-fact__value > a,
.tp-trust__more > a {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
}

/* Верхняя карточка тендера */
.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-changes { font-size: var(--text-sm); line-height: 1.5; color: var(--color-neutral-700); overflow-wrap: anywhere; }
.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); }
/* Свёрнутый блок «Iz dokumentacije» — описание из одних выдержек файлов. */
.tp-docs > summary { cursor: pointer; font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-700); min-height: 2rem; padding: var(--space-1) 0; }
/* Чекбокс-хак вместо <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-container);
  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: repeat(3, minmax(0, 1fr));
  gap: var(--space-2);
}

/* Плитка показателя. Цифры — табличные: при анимации счётчика ширина не пляшет. */
.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__hint a { color: inherit; text-decoration: underline; }
/* Нулевая плитка с пояснением: на всю ширину ряда и последней — длинный текст не втискивается в треть. */
.ck-hero__grid .ck-tile--explain { grid-column: 1 / -1; order: 4; }
.ck-tile__hint a:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
/* Срочность подписки — только семантические статус-токены. */
.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); }
/* v2: .cal — только сетка месяца в правой колонке (агенда — в ROKOVI). */
.cal__head {
  display: flex;
  align-items: center;
  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; }
/* Стрелки месяца: тап-зона 2rem по обеим осям (frontend.md), фокус — :focus-visible. */
.cal__nav {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2rem; min-height: 2rem; padding: 0;
  border: 0; border-radius: var(--radius-md); background: transparent;
  color: var(--color-neutral-600); font: inherit; font-size: var(--text-base); line-height: 1;
  text-decoration: none; cursor: pointer;
}
.cal__nav:hover { background: var(--color-neutral-100); color: var(--color-neutral-900); }
.cal__nav:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.cal__nav:disabled { opacity: .35; cursor: default; background: transparent; }
.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-peek { box-shadow: inset 0 0 0 2px var(--color-accent-500); }

/* Нерабочие дни: выходной — приглушённый фон; праздник — тот же фон, но число
   жирное с тонким кольцом, а точка — ПОЛАЯ (контур): срок и действие — залитые
   точки, их с праздником не спутать. Рамка и точки «есть события» остаются поверх:
   фон у выходного с событиями — тот же, иначе busy-выходные теряли бы пометку. */
.cal__day.is-weekend,
.cal__day.is-holiday { background: var(--color-neutral-100); color: var(--color-neutral-600); }
.cal__day.is-holiday .cal__num { font-weight: 700; box-shadow: inset 0 0 0 1px var(--color-primary-700); }
/* ‼️ Выбранный день — ПОСЛЕ выходных/праздников: у `.is-weekend` и `.is-selected` одна
 * специфичность (0,2,0), и раньше поздний `.is-weekend` перекрывал фон выбранного
 * выходного. Порядок тут — часть инварианта, менять его нельзя. */
.cal__day.is-selected {
  border-color: var(--color-primary-700);
  background: var(--color-primary-50);
  color: var(--color-primary-800);
}
.cal__dot--holiday { background: transparent; box-shadow: inset 0 0 0 1px var(--color-primary-700); }
.cal__swatch { width: .7rem; height: .7rem; border-radius: var(--radius-sm); display: inline-block; }
.cal__swatch--weekend { background: var(--color-neutral-100); box-shadow: inset 0 0 0 1px var(--color-neutral-300); }

/* Ячейка становится кнопкой только под 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__err { margin: var(--space-2) 0 0; font-size: var(--text-xs); color: var(--color-neutral-500); }
/* Тап-зона кнопки повтора — не меньше 2rem по обеим осям (высота И ширина). */
.cal__retry { min-width: 2rem; min-height: 2rem; padding: 0 var(--space-2); text-decoration: underline; color: inherit; background: none; border: 0; cursor: pointer; }
.cal__retry:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
/* Шапка выбранного дня: без display у блока — `hidden` работает. Чип праздника —
   та же роль цвета, что кольцо праздника в сетке (primary-700). */
.cal__head-date { margin: 0; font-weight: 600; color: var(--color-neutral-600); }
.cal__head-count { margin: 0; }
.cal__chip { display: inline-flex; align-items: center; margin: .2rem .3rem .2rem 0; padding: .1rem .5rem; border-radius: 999px; border: 1px solid var(--color-neutral-300); background: var(--color-neutral-0); color: var(--color-neutral-600); }
.cal__chip--holiday { border-color: var(--color-primary-700); color: var(--color-primary-700); }
.cal__holidays { margin: var(--space-2) 0 0; font-size: var(--text-xs); color: var(--color-neutral-500); }
.cal__holidays-title { font-weight: 600; }
.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; }
/* ‼️ Мобильный: строка агенды — ДВА ряда, а не три колонки.
   Замер на живом проде 10.08.2026 (тенант с реальным потоком, вьюпорт 390):
   дата 58px + бейдж 105px — фиксированные колонки, телу оставалось 109px из
   324 (34%), заголовок-ссылка получала 84px и рассыпалась на ПЯТЬ строк по
   одному-два слова. Медианная высота строки 279px против 123px на 1280 —
   то есть дашборд раздували не данные, а раскладка: суммарно 28 296px на 101
   строку вместо 13 005px.
   Чиним РАСКЛАДКОЙ (инвариант: переполнение и длину чинит раскладка, а не
   уменьшение целей): дата и бейдж делят первый ряд, тело занимает второй
   целиком. Тап-зоны не трогаем — .agenda__title-link намеренно вне
   правила ≥2rem (насильная высота рвёт ритм списка). */
@media (max-width: 639px) {
  .agenda__item {
    display: grid;
    grid-template-columns: auto 1fr;
    column-gap: var(--space-3);
    row-gap: var(--space-1);
    align-items: start;
  }
  .agenda__date {
    grid-column: 1;
    grid-row: 1;
    width: auto;
    text-align: left;
  }
  .agenda__day { display: inline; font-size: var(--text-sm); }
  .agenda__left { grid-column: 2; grid-row: 1; justify-self: end; }
  .agenda__body { grid-column: 1 / -1; grid-row: 2; }
}

/* Хвост агенды: «Показать ещё 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); }
/* Список дня в календаре — не хвост ROKOVI: отступ сверху лишний (фрагмент `/app/kalendar/den`). */
[data-cal-items] > .agenda-more__list { margin-top: 0; }

/* -- Второстепенные блоки дашборда: свёрнуто, но доступно -------------------- */
.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: плитки чуть просторнее (три в ряд — на всех ширинах: v2 держит hero
   в один ряд, на 390px это ~110px на плитку, подпись переносится). */
@media (min-width: 640px) {
  .ck-hero__grid { gap: var(--space-3); }
  /* число и подпись — в строку: плитка ~48px вместо ~85px (замер длины экрана). */
  .ck-hero { padding: var(--space-4) var(--space-5); }
  .ck-hero__head { margin-bottom: var(--space-3); }
  .ck-hero__grid .ck-tile { display: flex; align-items: center; gap: var(--space-3); padding: var(--space-2) var(--space-4); }
  .ck-hero__grid .ck-tile__label { margin-top: 0; font-size: var(--text-sm); }
  .ck-hero__grid .ck-tile__value { font-size: var(--text-2xl); }
}

/* ==========================================================================
   Дашборд v2 (D1 13.10): каркас, единая плашка-тревога, шаблоны в строку.
   Три типа контейнеров: .card / .alert / .ck-hero; одно скругление
   (--radius-container); один отступ между секциями (gap у .dash).
   ========================================================================== */
.dash { display: flex; flex-direction: column; gap: var(--space-6); }
.dash__body { display: flex; flex-direction: column; gap: var(--space-6); }
/* Ниже 1024px колонки-обёртки «растворены»: их дети — прямые участники flex
   `.dash__body`, и порядок на мобильном задаётся `order`:
   ROKOVI → NOVO → МОЙ ПОТОК → VESTI → ШАБЛОНЫ (календарь — вкладка «Месяц» в ROKOVI). */
.dash-main, .dash-side { display: contents; }
.dash-rokovi { order: 1; }
.dash-novo { order: 2; display: flex; flex-direction: column; gap: var(--space-6); }
/* «Мой поток» без своего order вставал ПЕРВЫМ, выше ROKOVI (замер 04.11: top 408 против 1607 на 390px). */
#dash-flow { order: 3; }
/* «Похожие на ваши» — приглушённый блок: пунктирная рамка, нейтральный заголовок (не главный путь). */
.dash-similar { border-style: dashed; background: var(--color-neutral-50); }
.dash-similar__title { font-size: var(--text-base); font-weight: 600; color: var(--color-neutral-600); margin-bottom: var(--space-1); }
.dash-vesti { order: 4; }
.dash-tpl { order: 5; }
.dash-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); }
.dash-head .ck-section__title { margin-bottom: var(--space-2); }
/* ≥1024px: основная колонка 2/3 + правая 1/3, правая липнет под шапкой. */
@media (min-width: 1024px) {
  .dash__body { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); align-items: start; }
  .dash-main, .dash-side { display: flex; flex-direction: column; gap: var(--space-6); min-width: 0; }
  .dash-side { position: sticky; top: calc(var(--header-h) + var(--space-4)); }
  /* Правая колонка — Vesti первой (календарь ушёл во вкладку ROKOVI). */
  .dash-vesti { order: 1; }
}
/* Вкладка «Месяц» ROKOVI: корень сетки (цель htmx-листания, #rokovi-month). */
.rokovi-month { margin-top: var(--space-3); }

/* Плашка-тревога — единый контейнер с тонами. Заливка и рамка — статус-токены;
   текст — нейтрали (контраст считается от них, не от тона). */
.alert {
  border: 1px solid var(--color-neutral-200);
  border-radius: var(--radius-container);
  padding: var(--space-3) var(--space-4);
  color: var(--color-neutral-800);
  margin-bottom: var(--space-6);
}
.dash .alert { margin-bottom: 0; }
.alert--error { background: var(--status-error-bg); border-color: var(--status-error-border); }
.alert--warn { background: var(--status-urgent-bg); border-color: var(--status-urgent-border); }
.alert--info { background: var(--status-new-bg); border-color: var(--status-new-border); }
.alert__title { font-weight: 600; color: var(--color-neutral-900); }
.alert__body { margin-top: var(--space-1); font-size: var(--text-sm); color: var(--color-neutral-700); }
.alert__extra { padding-top: var(--space-2); border-top: 1px solid var(--color-neutral-200); }
.alert__cta { display: inline-block; margin-top: var(--space-3); }
.alert__list { margin-top: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); }
.alert__list li { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); font-size: var(--text-sm); }

/* ROKOVI компактно: заказчик — в той же строке, что заголовок (замер: строка
   агенды 2–3 ряда → 1–2, экран-обзор короче). Только внутри блока ROKOVI. */
.dash-rokovi .agenda { gap: var(--space-1); }
.dash-rokovi .agenda__item { padding: var(--space-1) var(--space-3); align-items: center; }
.dash-rokovi .agenda__body { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--space-2); }
.dash-rokovi .agenda__meta { margin-top: 0; }
/* Статус/заказчик — всегда ВТОРОЙ строкой под названием. body — flex-wrap, и у строк
   «действие» с коротким названием статус «✅ Učestvujem» вставал в ту же строку, тогда как
   у дедлайнов (длинное название) заказчик падал вниз: выравнивание зависело от длины. */
.dash-rokovi .agenda__meta { flex: 1 1 100%; }
/* Иконка события и заголовок (блок из _card_title.html) — в одной строке. */
.dash-rokovi .agenda__title [data-card-title] { display: inline; }

/* Тизер доставок: заказчик/шаблон — в одной строке с заголовком (≥640px). */
@media (min-width: 640px) {
  .dash-feed__main { display: flex; flex-wrap: wrap; align-items: baseline; column-gap: var(--space-3); }
}

/* Шаблоны: ОДНА строка на шаблон (имя · доставлено N · статус · тумблер). */
.dash-tpl__limit { font-size: var(--text-xs); color: var(--color-neutral-500); margin-bottom: var(--space-1); }
.dash-tpl__list { margin: 0; padding: 0; list-style: none; }
.dash-tpl__row { padding: var(--space-1) 0; border-top: 1px solid var(--color-neutral-200); }
.dash-tpl__row:first-child { border-top: 0; padding-top: 0; }
.dash-tpl__line { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }
.dash-tpl__name { flex: 1 1 8rem; min-width: 0; display: inline-flex; align-items: center; min-height: 2rem; font-weight: 500; overflow-wrap: anywhere; }
.dash-tpl__name:hover { text-decoration: underline; }
.dash-tpl__count { font-size: var(--text-xs); color: var(--color-neutral-500); white-space: nowrap; }

/* Vesti: дата + заголовок-ссылка. */
.vesti__list { display: flex; flex-direction: column; gap: var(--space-2); }
.vesti__date { display: block; font-size: var(--text-xs); color: var(--color-neutral-500); font-variant-numeric: tabular-nums; }
.vesti__link { display: inline-flex; align-items: center; min-height: 2rem; font-size: var(--text-sm); font-weight: 500; overflow-wrap: anywhere; }
.vesti__link:hover { text-decoration: underline; }
.vesti__meta { font-size: var(--text-xs); color: var(--color-neutral-500); overflow-wrap: anywhere; }
.vesti__top { margin: var(--space-1) 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--space-1); }

/* ‼️ Уважение к 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; }
/* Истёкший срок / закрытый тендер (роль «истекло» = серый, .claude/rules/frontend.md):
   фон neutral-50, заголовок neutral-600 (контраст ≥4.5 на neutral-50). Бейдж срока остаётся. */
.fn-row--expired { background: var(--color-neutral-50); border-color: var(--color-neutral-200); }
.fn-row--expired:hover { background: var(--color-neutral-50); border-color: var(--color-neutral-200); }
.fn-row--expired .fn-row__title { color: var(--color-neutral-600); }
/* Кнопки стадии под строкой (с доски): перенос по ширине, без растяжки. */
.fn-row__actions { margin-top: var(--space-2); display: flex; flex-wrap: wrap; gap: .35rem; }
.fn-row__actions .act-btn.htmx-request { opacity: .6; }
/* «В архив» у истёкшей строки — заметнее остальных действий (порядок + рамка). */
.fn-row--expired .act-btn--archive { border-color: var(--color-primary-700); }
/* Свёрнутый блок «Срок истёк (N)» внутри колонки — отступ от живых строк. */
.fn-expired { margin-top: var(--space-3); border-top: 0; padding-top: 0; }

/* -- Папки: вторичный организатор под доской -------------------------------- */
.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 a.text-amber-800.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); }
/* Правый блок строки — СТОЛБИК на всех ширинах: сверху срок (бейдж), под ним значение
   (доставлено / найдено / сумма / лимит) мелким серым. Оба выровнены ВПРАВО, поэтому
   наложения быть не может: колонка стоит одна, и значение не ставится рядом с бейджем.
   Раньше было две фиксированные колонки (9.5rem | 7.5rem) — бейдж с датой (≈205 px)
   в 152 px наезжал на значение (fd_overlap_probe.js: до 18.7 px, 1280 и 640).
   Ширина — по содержимому; на ≥640px колонка не уже самого длинного бейджа (см. медиа
   ниже), чтобы бейджи соседних строк стояли в линию. Пустое значение — просто нет
   строки (нет дыры: в сетке нет пустой ячейки). */
.fd-card__side--cols {
  display: grid;
  grid-template-columns: minmax(0, max-content);
  justify-items: end;
  align-items: end;
  align-self: flex-end; /* в телефонной колонке (.fd-card__head) — прижат вправо, край не гуляет */
  gap: .2rem;
}
/* Значение переносится, если не влезает в ширину блока (на 320px «delivered 14.10» длиннее
   бейджа в узком столбце — перенос безопаснее обрезки). */
.fd-card__side--cols .fd-card__value { white-space: normal; }
.fd-card__deadline { display: flex; min-width: 0; justify-self: end; }
.fd-card__value {
  justify-self: end;
  margin: 0;
  font-variant-numeric: tabular-nums;
  color: var(--color-neutral-500);
  white-space: nowrap;
  text-align: right;
}
/* -- «Za pregled» (дашборд-входящие) и приглушённая карточка «Не интересно» ----- */
#inbox-count[hidden] { display: none; }
.dash-inbox__actions { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: var(--space-2); }
.act-btn--quiet { font-weight: 500; color: var(--color-neutral-600); }
/* -- «Не присылать такое»: меню у пропуска + список исключений профиля ------ */
.skip-ex { display: inline-block; }
.skip-ex > summary { list-style: none; cursor: pointer; }
.skip-ex > summary::-webkit-details-marker { display: none; }
.skip-ex__panel { display: flex; flex-direction: column; align-items: stretch; gap: .35rem; margin-top: .35rem; padding: .5rem; max-width: 100%; border: 1px solid var(--color-neutral-200); border-radius: .5rem; background: #fff; }
.skip-ex__hint { margin: 0; font-size: .8125rem; color: var(--color-neutral-600); }
.skip-ex__opt { text-align: left; white-space: normal; overflow-wrap: anywhere; }
.skip-ex__kw { display: flex; flex-wrap: wrap; gap: .35rem; align-items: center; }
.skip-ex__kw .field-control { flex: 1 1 10rem; min-width: 0; }
.skip-ex-refused { margin-top: .35rem; max-width: 100%; }
.nf-list { list-style: none; margin: .5rem 0 0; padding: 0; }
.nf-list__row { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; padding: .35rem 0; border-top: 1px solid var(--color-neutral-200); }
.nf-list__kind { color: var(--color-neutral-600); min-width: 6rem; }
.nf-list__value { flex: 1 1 8rem; min-width: 0; overflow-wrap: anywhere; font-weight: 500; }
.fd-card--skipped { background: var(--color-neutral-50); border-left-color: var(--color-neutral-300); }
.fd-card--skipped .fd-card__title,
.fd-card--skipped .fd-card__customer { 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);
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 2.25rem; min-height: 2.25rem; border: 1px solid transparent;
}
/* Текущая страница — заливка брендом, а не «ещё одна ссылка»: белый на #1f3760 (AA). */
.fd-pager__num[aria-current="page"] { background: var(--color-primary-700); border-color: var(--color-primary-700); color: var(--color-neutral-0); }
/* Пейджер на 390px: номера переносятся строкой, а не выталкивают страницу вбок. */
.fd-pager__controls { flex-wrap: wrap; }
.fd-pager__arrow, .fd-pager__m-only { display: none; }
.fd-pager__jump { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.fd-pager__jump .field-control { width: 6rem; }
.fd-pager__gap { color: var(--color-neutral-500); padding: 0 .25rem; }
/* <640px: ОДНА строка номеров — окно ±1, ««» и «»» уходят (есть форма «Перейти»),
   стрелки — знаками ‹ ›, без слов. */
@media (max-width: 639px) {
  .fd-pager__controls { flex-wrap: nowrap; gap: var(--space-1); }
  .fd-pager__wide, .fd-pager__edge, .fd-pager__word { display: none; }
  .fd-pager__arrow, .fd-pager__m-only { display: inline; }
  .fd-pager__step { min-width: 2.25rem; padding-left: .5rem; padding-right: .5rem; }
  .fd-pager__num { padding-left: .25rem; padding-right: .25rem; }
}

/* ≥640px: шапка карточки в строку — бейдж срочности уходит вправо. */
@media (min-width: 640px) {
  .fd-card__head { flex-direction: row; justify-content: space-between; }
  .fd-card__side { justify-content: flex-end; }
  /* Столбик не уже самого длинного бейджа с датой («02.11.2026 · preostalo 2 dana»,
     замер 205 px = 12.8rem): бейджи соседних строк выровнены по правому краю и не
     прыгают в ширине. Меряется fd_overlap_probe.js; число — подбирать замером. */
  .fd-card__side--cols { min-width: 13rem; align-self: center; }
}

/* ‼️ 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) {
  /* Бренд+языки — первый ряд, пункты меню под ним (#581): 2 ряда (≈101px), если
     пункты влезают в один (sr/en 390px, en 360px), иначе пункты переносятся и
     получается 3 ряда (≈145px: ru 390, sr/ru 360, 320). Замер 03.10.2026
     (scripts/shots, стенд stand_nav, /help): 101 / 145 px. --header-h = худший
     случай 145px → 9.1rem (146px): scroll-margin якорей и max-height меню
     «Ещё» считаются от него, меньший случай даёт лишь запас. */
  :root { --header-h: 9.1rem; }
  .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; }
  /* Копии внутри меню «Ещё» — та же геометрия, что у остальных пунктов
     (inline-flex + центровка по высоте 2.75rem): с display:block текст липнет
     к верху строки и зазоры Cenovnik↔Izvori / Odjava↔Pomoć выглядят неровно. */
  .site-header .nav-show-mobile { display: inline-flex; }
  /* Публичная шапка одной строкой (бренд+языки+навигация) не влезала на телефон
     (scrollWidth 510 > 390 после тап-зон #446). Переносим: бренд и языки в
     первой строке, навигация — во второй во всю ширину. Тап-зоны не трогаем. */
  .site-header--public .site-header__bar { flex-wrap: wrap; }
  /* Второй ряд (Tenderi/Cenovnik/Pomoć/Prijava + «Registracija») при gap-4 давал
     scrollWidth 405 > 390 — главная кнопка обрезалась справа (замер 30.09.2026).
     Зазор сужаем до 0.25rem (у nav-link свой padding — тап-зоны 2.75rem не
     меняются), а перенос страхует длинные подписи ru/en: лишнее уходит в новый
     ряд, а не за вьюпорт. */
  .site-header--public .site-header__actions { flex-basis: 100%; justify-content: flex-start; flex-wrap: wrap; gap: .25rem; }
  /* ru-подписи (Тендеры/Тарифы/Помощь/Вход) длиннее sr/en: при паддинге .5rem
     «Регистрация» уходила в третий ряд. Высота 2.75rem не меняется, ширина
     самой короткой цели («Вход») остаётся >2rem. */
  .site-header--public .nav-link { padding-left: .375rem; padding-right: .375rem; }
  /* Шапка ЛК (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%; }
  /* #581: языки переезжают в строку бренда (справа), пункты меню остаются
     ОДНИМ рядом под ней — вместо трёх рядов (бренд / 3 пункта / 2 пункта+языки)
     получаются два, если пункты влезают (sr 390px). <nav> раскрывается в
     display:contents: его дети становятся flex-элементами .site-header__bar,
     а порядок задаёт order — бренд(0), языки(1), разрыв строки ::after(2),
     пункты(3). Пункты и их порядок в DOM не меняются. */
  .site-header--cabinet .site-header__actions { display: contents; }
  .site-header--cabinet .site-header__bar::after { content: ""; order: 2; flex-basis: 100%; height: 0; }
  .site-header--cabinet .brand { order: 0; }
  .site-header--cabinet .lang-switch { order: 1; margin-left: auto; }
  .site-header--cabinet .site-header__actions > :not(.lang-switch) { order: 3; }
  /* Ряд пунктов узкий: горизонтальный паддинг .25rem вместо .5rem. Высота
     2.75rem и min-width 2rem (обе оси тап-зоны) не меняются. */
  .site-header--cabinet .site-header__actions > .nav-link,
  .site-header--cabinet .nav-more > summary { padding-left: .25rem; padding-right: .25rem; min-width: 2rem; justify-content: center; }
  /* Меню «Ещё» на телефоне: якорь right:0 у <details> стоит посреди ряда, и
     минимальные 12.5rem уезжали за левый край (замер 390px: ru −36, sr −57,
     en −130). Снимаем позиционирование с <details>, меню позиционируется от
     липкой шапки и растягивается по её ширине с полями — ни вправо, ни влево
     за вьюпорт выйти не может, на любом языке. */
  .site-header--cabinet .nav-more { position: static; }
  /* Ряд один: бренд · «Meni ▾». Вход в кабинет и бейдж — в строке логина выше. Остальное (пункты, язык, выход)
     — внутри .nav-mobile; в шапке на телефоне их нет (nav-hide-mobile). */
  .site-header--cabinet .nav-mobile { display: block; }
  /* «Odjava» — <button> с inline `font:inherit`: без !important шрифт крупнее соседних ссылок. */
  .site-header .nav-mobile button.nav-link { font-size: var(--text-xs) !important; }
  .site-header--cabinet .site-header__actions > .nav-mobile { order: 1; margin-left: auto; }
  .site-header--cabinet .nav-more__menu {
    left: var(--space-2);
    right: var(--space-2);
    top: 100%;
    min-width: 0;
    /* Низкий экран (320×568, телефон боком): меню ≈475px + шапка ≈149px не
       влезает, а меню — absolute внутри липкой шапки, страница его не
       прокручивает → нижние пункты недостижимы. Режем по высоте вьюпорта и
       даём меню собственную прокрутку (100vh — фолбэк без dvh). */
    max-height: calc(100vh - var(--header-h) - var(--space-2));
    max-height: calc(100dvh - var(--header-h) - var(--space-2));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /* Контекстные «?»-подсказки: на узком экране пузырь, отцентрованный по иконке
     у края формы/шапки, вываливался за левый (/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; }
}

/* -- Плавающая кнопка «Наверх» ---------------------------------------------- */
/* Прогрессивное улучшение: в разметке кнопка есть всегда, но класс 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))}

/* ==========================================================================
   Читаемость и состояния (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); }

/* -- Вспышка «лимит исчерпан» ----------------------------------------------
   Требование D1 от 15.08.2026: отказ по лимиту обязан ВСПЫХИВАТЬ крупно и ярко
   при попытке задействовать AI, предлагать тариф побольше и уходить сам через
   несколько секунд, чтобы не раздражать.

   ‼️ Только CSS: при CSP `script-src 'self'` инлайн-обработчики молча не
   выполняются, а таймер на JS потребовал бы вендорный файл с SRI. Появление и
   автоскрытие делает одна пара keyframes.
   ‼️ Вспышка — ПРИВЛЕЧЕНИЕ ВНИМАНИЯ, а не состояние: она исчезает, а причина
   отказа остаётся постоянной строкой в самом слоте (_ai_slot.html). Иначе через
   6 секунд клиент видел бы просто неработающую кнопку — тот же «молча».
   Роль цвета — янтарь (действие/апсейл); оранжевый (срочность) и красный
   (ошибка) не занимаем: у них в системе другой смысл.
   z-index 55 — выше липкой шапки (50), ниже skip-link (60). */
.limit-flash {
  position: fixed;
  left: 50%;
  top: calc(var(--header-h) + .5rem);
  z-index: 55;
  width: min(30rem, calc(100vw - 1.5rem));
  background: var(--color-accent-50);
  border: 2px solid var(--color-accent-500);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  padding: .875rem 1rem;
  animation:
    limit-flash-in .18s ease-out both,
    limit-flash-out .45s ease-in 5.6s forwards;
}
.limit-flash__title {
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1.25;
  color: var(--color-accent-600);
}
.limit-flash__body {
  margin-top: .25rem;
  font-size: var(--text-sm);
  color: var(--color-neutral-700);
}
.limit-flash__actions {
  margin-top: .625rem;
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  align-items: center;
}
@keyframes limit-flash-in {
  from { opacity: 0; transform: translate(-50%, -.75rem) scale(.96); }
  to   { opacity: 1; transform: translate(-50%, 0) scale(1); }
}
@keyframes limit-flash-out {
  from { opacity: 1; transform: translate(-50%, 0); visibility: visible; }
  to   { opacity: 0; transform: translate(-50%, -.5rem); visibility: hidden; }
}
/* Уважаем системную настройку: без движения — только выдержка и мягкий уход.
   Полностью отключать исчезновение нельзя (иначе плашка висит поверх экрана),
   поэтому остаётся тот же тайминг, но без сдвига и масштабирования. */
@media (prefers-reduced-motion: reduce) {
  .limit-flash {
    transform: translateX(-50%);
    animation: limit-flash-out-static .3s linear 5.7s forwards;
  }
  @keyframes limit-flash-out-static {
    from { opacity: 1; visibility: visible; }
    to   { opacity: 0; visibility: hidden; }
  }
}


/* ==========================================================================
   Мастер создания шаблона (D1 22.09.2026): три шага одной формы + живой счётчик
   ========================================================================== */

/* Полоска шагов — СТАТУС, а не навигация: кликать нечего, поэтому <ol> с
   подписями, а не кнопки (требование тап-зоны ≥2rem — к интерактиву, а не к
   подписи). Без JS скрыта классом .hidden: листать нечего, все шаги развёрнуты. */
.wizard-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-neutral-500);
}
.wizard-nav__item { display: inline-flex; align-items: center; gap: .375rem; }
.wizard-nav__item + .wizard-nav__item::before {
  content: "→";
  margin-right: .375rem;
  color: var(--color-neutral-300);
}
.wizard-nav__num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: var(--radius-full);
  background: var(--color-neutral-100);
  color: var(--color-neutral-600);
  font-size: var(--text-xs);
  font-weight: 700;
}
.wizard-nav__item--active { color: var(--color-primary-800); font-weight: 600; }
.wizard-nav__item--active .wizard-nav__num {
  background: var(--color-primary-700);
  color: var(--color-neutral-0);
}
.wizard-nav__item--done .wizard-nav__num {
  background: var(--color-primary-100);
  color: var(--color-primary-800);
}

/* Свёрнутое «Дополнительно». ‼️ <summary> обязан быть ПЕРВЫМ потомком <details>;
   заголовок h3 живёт ВНУТРИ summary — иначе UA прячет содержимое целиком. */
.form-section__summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 2rem;
  cursor: pointer;
  list-style: none;
}
.form-section__summary::-webkit-details-marker { display: none; }
.form-section__summary::after { content: "▾"; color: var(--color-neutral-500); }
details[open] > .form-section__summary::after { content: "▴"; }

/* Живой счётчик шага («≈ N тендеров за 30 дней»). Цифру считает тот же
   preview_service.preview_count, что рисует карточки витрины. */
.preview-live {
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-primary-200);
  border-radius: var(--radius-md);
  background: var(--color-primary-50);
  transition: opacity .15s ease;
}
.preview-live__count {
  font-size: var(--text-lg);
  font-weight: 700;
  color: var(--color-primary-800);
}
.preview-live__count--zero {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-neutral-700);
}
.preview-live__hint { font-size: var(--text-xs); color: var(--color-neutral-600); }
.preview-live__warn {
  margin-top: var(--space-2);
  font-size: var(--text-xs);
  color: var(--status-urgent);
}
.preview-live__forms { margin-top: var(--space-2); font-size: var(--text-xs); }
/* Индикатор полёта запроса: общий .htmx-request гасит плашку, спиннер в углу
   показывает, что цифра пересчитывается, а не «просто побледнела». */
.preview-live.htmx-request { position: relative; }
.preview-live.htmx-request::after {
  content: "";
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: .85rem;
  height: .85rem;
  border: 2px solid var(--color-primary-200);
  border-right-color: transparent;
  border-radius: var(--radius-full);
  animation: htmx-spin .6s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .preview-live.htmx-request::after {
    content: "…";
    width: auto;
    height: auto;
    border: 0;
    animation: none;
  }
}

/* Экран подтверждения «что получится» и экран результата. */
.recap { display: grid; gap: var(--space-2); margin-top: var(--space-3); }
.recap__row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  padding-bottom: var(--space-2);
  border-bottom: 1px solid var(--color-neutral-200);
  font-size: var(--text-sm);
}
.recap__row:last-child { border-bottom: 0; padding-bottom: 0; }
.recap__key { color: var(--color-neutral-500); min-width: 9rem; }
.recap__val { color: var(--color-neutral-800); font-weight: 500; }
/* Примеры под счётчиком (_preview_examples.html): совпавшее слово — <mark> на
   фоне плашки счётчика (primary-50) — подложка на ступень темнее, текст свой.
   Длинные сербские составные слова («gradjevinsko-zanatskih») на 390px
   переносятся внутри ссылки, а не распирают строку. */
.preview-live__examples-title {
  margin-top: var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-neutral-700);
}
.preview-examples__link { overflow-wrap: anywhere; }
/* Ключевые слова чипами (keyword_chips.js). Поле выглядит как .field-control,
   чипы переносятся строками; × — тап-зона 2rem по ОБЕИМ осям. */
.kw-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-md);
  background: var(--color-neutral-0);
}
/* Поле ввода внутри без своей рамки — фокус показывает контейнер, как у .field-control. */
.kw-chips:focus-within {
  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);
}
.kw-chips__list { display: contents; }
.kw-chip {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  padding-left: var(--space-2);
  border-radius: var(--radius-full);
  background: var(--color-primary-50);
  border: 1px solid var(--color-primary-200);
  color: var(--color-primary-800);
  font-size: var(--text-sm);
  overflow-wrap: anywhere;
}
.kw-chip__remove {
  min-width: 2rem;
  min-height: 2rem;
  border-radius: var(--radius-full);
  color: var(--color-neutral-600);
  font-size: var(--text-base);
  line-height: 1;
}
.kw-chip__remove:hover { color: var(--color-neutral-800); }
.kw-chip__remove:focus-visible { outline: 2px solid var(--color-primary-500); outline-offset: -2px; }
/* Шаг 3 мастера: канал не подключён — подключение прямо на шаге. Янтарь не
   берём (это не апсейл): нейтральная плашка с рамкой. */
.channel-connect {
  display: grid;
  gap: var(--space-2);
  justify-items: start;
  margin-top: var(--space-3);
  padding: var(--space-3);
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-md);
  background: var(--color-neutral-50);
}
.channel-connect__title { font-weight: 600; font-size: var(--text-sm); color: var(--color-neutral-800); }
.channel-connect__email { width: 100%; }
.kw-chips__input {
  flex: 1 1 10rem;
  min-width: 0;
  min-height: 2rem;
  border: 0;
  outline: 0;
  background: transparent;
  font-size: 1rem;
}
/* Без мастера (правка шаблона) шаги 1 и 2 видны разом — примеры показываем
   один раз, под первым счётчиком; в мастере виден один шаг, и примеры есть у обоих. */
#profileForm:not([data-wizard]) #previewStep2 .preview-live__examples { display: none; }
.preview-examples__link mark {
  background: var(--color-primary-200);
  color: inherit;
  border-radius: var(--radius-sm);
}

/* -- Портал /tenderi: поиск, фильтры, сортировка, чипы (portal_filters). Форма
   GET без JS. Мобильно (≤640px) — одна колонка, тап-зоны ≥2rem по обеим осям. -- */
.pf { margin-top: var(--space-6); }
.pf__sr {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.pf__main { display: grid; gap: var(--space-2); grid-template-columns: 1fr; }
.ck-teaser__search { display: flex; gap: var(--space-2); margin-top: var(--space-3); }
.ck-teaser__search .field-control { flex: 1; min-width: 0; }
/* Мобильный: поле поиска — на всю ширину, кнопки ниже (в одной строке поле сжималось до «Naslo»).
   ‼️ Правило ОБЯЗАНО стоять ПОСЛЕ базового `.field-control { flex: 1 }` выше: раньше жило в
   блоке дашборда (~1873), базовое по порядку перебивало его при равной специфичности. */
@media (max-width: 639px) {
  .ck-teaser__search { flex-wrap: wrap; }
  .ck-teaser__search .field-control { flex: 1 1 100%; }
}
.ck-teaser__tabs { display: flex; gap: var(--space-2); margin: var(--space-3) 0; }
.ck-teaser__tab {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 2rem; min-width: 2rem; padding: 0 var(--space-3);
  border-radius: var(--radius-sm); font-size: var(--text-sm);
  color: var(--color-neutral-500); text-decoration: none;
}
.ck-teaser__tab:hover { text-decoration: underline; }
.ck-teaser__tab[aria-current] { background: var(--color-primary-200); color: inherit; font-weight: 600; }
.ck-teaser__tab:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.pf__search { position: relative; }
.pf__search .field-control { padding-right: 2.25rem; }
.pf__clear {
  position: absolute; top: 0; right: 0; display: flex; align-items: center;
  justify-content: center; min-width: 2rem; min-height: 2.5rem; height: 100%;
  color: var(--color-neutral-500); text-decoration: none; font-size: 1.25rem;
}
.pf__clear:hover { color: inherit; }
.pf__clear:focus-visible { outline: 2px solid currentColor; outline-offset: -2px; }
.pf__search, .pf__sort { min-width: 0; }
.pf__submit { min-height: 2.5rem; }
.pf__more { margin-top: var(--space-3); }
.pf__grid { display: grid; gap: var(--space-3); grid-template-columns: 1fr; margin-top: var(--space-2); }
.pf__grid > div { min-width: 0; }
.pf__check { align-self: end; }
.pf__actions { margin-top: var(--space-3); }
.pf__status { margin-top: var(--space-4); }
.pf__found { font-size: var(--text-sm); font-weight: 600; color: var(--color-neutral-700); }
.pf__chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-2); list-style: none; }
.pf__chip, .pf__reset {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2rem;
  min-width: 2rem;
  padding: 0 .75rem;
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  text-decoration: none;
  overflow-wrap: anywhere;
}
.pf__chip { background: var(--color-neutral-100); color: var(--color-neutral-700); border: 1px solid var(--color-neutral-200); }
.pf__chip:hover { background: var(--color-neutral-200); }
.pf__reset { color: var(--color-primary-700); font-weight: 600; }
.pf__reset:hover { text-decoration: underline; }
.pf__chip:focus-visible, .pf__reset:focus-visible {
  outline: 2px solid var(--color-primary-500);
  outline-offset: 2px;
}
@media (min-width: 640px) {
  .pf__main { grid-template-columns: 1fr 15rem auto; }
  .pf__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

*,: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: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))}
}
@media (min-width:768px){.md\:grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}}
/* Заказчики «следить / исключить» (customer_picker.js, 0046). Чип — отмеченный
   чекбокс с именем (без JS снять галку = убрать); × и строки подсказки —
   тап-зона 2rem по ОБЕИМ осям. Длинные имена переносятся, а не режутся. */
.cust-picker { min-width: 0; }
.cust-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-1); }
.cust-chips:empty { display: none; }
.cust-chip {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  padding-left: var(--space-2);
  border-radius: var(--radius-lg);
  background: var(--color-primary-50);
  border: 1px solid var(--color-primary-200);
  color: var(--color-primary-800);
  font-size: var(--text-sm);
}
.cust-chip__label {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 2rem;
  min-width: 0;
  overflow-wrap: anywhere;
  cursor: pointer;
}
.cust-chip__label input { flex: none; }
.cust-chip__remove {
  flex: none;
  min-width: 2rem;
  min-height: 2rem;
  border-radius: var(--radius-full);
  color: var(--color-neutral-500);
  font-size: var(--text-base);
  line-height: 1;
}
.cust-chip__remove:hover { color: var(--color-neutral-800); }
.cust-chip__remove:focus-visible { outline: 2px solid var(--color-primary-500); outline-offset: -2px; }
.cust-search { margin-top: var(--space-2); }
.cust-results {
  margin-top: var(--space-1);
  max-height: 16rem;
  overflow-y: auto;
  border: 1px solid var(--color-neutral-300);
  border-radius: var(--radius-md);
  background: var(--color-neutral-0);
  font-size: var(--text-sm);
}
.cust-results__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  min-height: 2rem;
  padding: var(--space-1) var(--space-2);
  overflow-wrap: anywhere;
  cursor: pointer;
}
.cust-results__item:hover,
.cust-results__item[aria-selected="true"] { background: var(--color-primary-50); }
.cust-results__count { flex: none; color: var(--color-neutral-500); font-variant-numeric: tabular-nums; }
.cust-results__empty { padding: var(--space-2); color: var(--color-neutral-500); }

/* Подряды (M8, podugovor.html): сумма не переносится («500 000 / 000 RSD»).
   На <640px строка таблицы — карточка (шапка скрыта, ячейки блоками): 7 колонок в 390px
   не помещаются даже без второстепенных, поэтому без горизонтального скролла. */
.sp-amount { white-space: nowrap; }
/* Шанс субподряда (★) и история лида: скринридер видит «N из 3», зрение — звёзды. */
.sp-stars { letter-spacing: 0.05em; }
.sp-hist > summary { min-height: 2rem; display: inline-flex; align-items: center; }
@media (max-width: 639px) {
  .sp-table thead { display: none; }
  .sp-table,
  .sp-table tbody,
  .sp-table tr,
  .sp-table td { display: block; width: 100%; }
  .sp-table tr { padding: var(--space-2) 0; }
  .sp-table td { padding: var(--space-1) 0; text-align: left; overflow-wrap: anywhere; }
  .sp-table td.sp-amount { font-weight: 600; }
  /* Подпись ячейки-карточки (data-label = заголовок колонки); цвет — нейтральный, как у подписей в ЛК. */
  .sp-table td[data-label]::before { content: attr(data-label) ": "; color: var(--color-neutral-500); font-weight: 400; }
}

/* M2: раскрытие «работает в N группах CPV» — <details>, без JS (CSP). Тап-зона ≥2rem по обеим осям. */
.uni-badge { position: relative; display: inline-block; vertical-align: top; max-width: 100%; }
.uni-badge-sum { display: inline-flex; align-items: center; min-width: 2rem; min-height: 2rem; cursor: pointer; list-style: none; }
.uni-badge-sum::-webkit-details-marker { display: none; }
.uni-badge-sum:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
/* В потоке, не абсолютно: обёртка таблицы (.overflow-x-auto) режет по вертикали и обрезала раскрытие. */
.uni-badge-body { position: static; width: min(22rem, 100%); margin-top: var(--space-1); padding: var(--space-2) var(--space-3); border: 1px solid var(--color-neutral-300); border-radius: 0.375rem; background: #fff; color: var(--color-neutral-700); font-size: 0.8125rem; font-weight: 400; line-height: 1.4; text-align: left; overflow-wrap: anywhere; box-shadow: 0 4px 12px rgb(15 23 42 / 0.12); }
.uni-badge-hint { margin: 0 0 var(--space-2); }
.uni-group + .uni-group { margin-top: var(--space-2); }
.uni-group-head { font-weight: 600; color: var(--color-primary-700); }
.uni-group-list { margin: var(--space-1) 0 0; padding-left: 1rem; list-style: disc; }
.uni-code { font-weight: 600; font-variant-numeric: tabular-nums; }
/* «Мой поток» / графики: своя подсказка (chart_tip.js) и зона нажатия столбца (charts_svg.HIT_MIN_W). */
.chart-tip { position: fixed; z-index: 60; max-width: 18rem; padding: var(--space-1) var(--space-2); border-radius: 0.375rem; background: var(--color-primary-700); color: var(--color-neutral-0); font-size: 0.8125rem; line-height: 1.35; pointer-events: none; }
.chart-tip[hidden] { display: none; }
svg a.chart-hit { cursor: pointer; }
svg a.chart-hit:focus { outline: none; }
svg a.chart-hit:focus-visible > rect.chart-hit-zone { stroke: var(--color-accent-500); stroke-width: 2; }

/* «Мой поток» (_flow.html): воронка из трёх цифр, плашки проблем, список площадок.
   Токены палитры; тап-зона <summary> — высота ≥2rem, ширина — вся строка. */
.flow-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; }
.flow-funnel { list-style: none; margin: var(--space-3) 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-4); }
.flow-funnel--two { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.flow-funnel__step { position: relative; display: flex; flex-direction: column; min-width: 0; }
.flow-funnel__num { order: 0; font-size: var(--text-2xl); font-weight: 700; line-height: 1.1; color: var(--color-primary-700); white-space: nowrap; font-variant-numeric: tabular-nums; }
.flow-funnel__label { order: 1; font-size: var(--text-xs); color: var(--color-neutral-600); overflow-wrap: anywhere; }
.flow-funnel__sub { order: 2; font-size: var(--text-xs); color: var(--color-neutral-600); font-variant-numeric: tabular-nums; }
.flow-funnel__arrow { position: absolute; top: .35rem; right: calc(var(--space-4) * -1); width: var(--space-4); text-align: center; color: var(--color-neutral-500); }
.flow-alerts { margin-top: var(--space-2); display: grid; gap: var(--space-2); }
.flow-alert { display: flex; gap: var(--space-2); align-items: flex-start; margin: 0; padding: var(--space-2) var(--space-3); border: 1px solid; border-radius: .5rem; font-size: var(--text-sm); font-weight: 500; }
.flow-alert--delay { background: var(--color-accent-50); border-color: var(--color-accent-600); color: var(--color-accent-600); }
.flow-alert--down { background: var(--status-error-bg); border-color: var(--status-error-border); color: var(--status-error); }
.flow-alert__icon { flex-shrink: 0; }
.flow-sources { margin-top: var(--space-3); font-size: var(--text-sm); }
.flow-sources > summary { display: flex; align-items: center; min-height: 2rem; cursor: pointer; color: var(--color-neutral-700); font-weight: 500; list-style: none; }
.flow-sources > summary::-webkit-details-marker { display: none; }
.flow-sources > summary::before { content: "▸"; margin-right: var(--space-2); color: var(--color-neutral-500); }
.flow-sources[open] > summary::before { content: "▾"; }
.flow-sources > summary:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.flow-sources__icon { margin-right: var(--space-1); }
.flow-sources__table { width: 100%; margin-top: var(--space-2); border-collapse: collapse; }
.flow-sources__table th, .flow-sources__table td { padding: var(--space-1) var(--space-2); text-align: left; vertical-align: top; border-bottom: 1px solid var(--color-neutral-200); }
.flow-sources__name { font-weight: 500; color: var(--color-neutral-800); overflow-wrap: anywhere; min-width: 0; }
.flow-sources__when { color: var(--color-neutral-600); }
.flow-sources__st { white-space: nowrap; color: var(--color-neutral-700); }
.flow-sources__st--delay { color: var(--color-accent-600); }
.flow-sources__st--down { color: var(--status-error); }
.flow-sources__st--ok { color: var(--color-neutral-700); }
/* Легенда — одна на оба вида (SVG и список); заливки — те же токены, что у SVG (FLOW_FILLS). */
.flow-legend { display: flex; flex-wrap: wrap; gap: var(--space-1) var(--space-4); margin: var(--space-2) 0; font-size: var(--text-xs); color: var(--color-neutral-600); }
.flow-legend__item { display: inline-flex; align-items: center; gap: var(--space-1); }
.flow-legend__sw { display: inline-block; width: .625rem; height: .625rem; border-radius: 2px; }
.flow-legend__note { flex-basis: 100%; }
.flow-legend__sw--delivered, .flow-row__seg--delivered { background: var(--color-primary-700); }
.flow-legend__sw--web, .flow-row__seg--web { background: var(--color-primary-200); }
/* «Мой поток» на телефоне (<640px): столбики → список строк; выше 640px — наоборот. */
@media (max-width: 639.98px) { .flow-svg { display: none; } }
.flow-rows { display: block; }
@media (min-width: 640px) { .flow-rows { display: none; } }
.flow-rows__list { list-style: none; margin: 0; padding: 0; }
.flow-rows__item { border-bottom: 1px solid var(--color-neutral-200); }
.flow-row { display: flex; align-items: center; gap: var(--space-2); min-height: 2rem; padding: var(--space-1) 0; color: var(--color-neutral-800); text-decoration: none; }
.flow-row:hover .flow-row__label { text-decoration: underline; }
.flow-row:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
.flow-row__label { flex: 0 0 5rem; font-size: var(--text-sm); font-variant-numeric: tabular-nums; }
.flow-row__bar { flex: 1 1 auto; min-width: 0; display: flex; height: .5rem; background: var(--color-neutral-100); border-radius: 2px; overflow: hidden; }
.flow-row__seg { display: block; height: 100%; }
.flow-row__num { flex: 0 0 auto; min-width: 4.5rem; text-align: right; font-size: var(--text-sm); font-weight: 600; color: var(--color-primary-700); font-variant-numeric: tabular-nums; }
.flow-row__sub { font-weight: 400; color: var(--color-neutral-600); }
.flow-row--zero .flow-row__label, .flow-row--zero .flow-row__num { color: var(--color-neutral-500); font-weight: 400; }
.flow-rows__more > summary { display: flex; align-items: center; min-height: 2rem; cursor: pointer; font-size: var(--text-sm); color: var(--color-neutral-700); font-weight: 500; list-style: none; }
.flow-rows__more > summary::-webkit-details-marker { display: none; }
.flow-rows__more > summary::before { content: "▸"; margin-right: var(--space-2); color: var(--color-neutral-500); }
.flow-rows__more[open] > summary::before { content: "▾"; }
.flow-rows__more > summary:focus-visible { outline: 2px solid var(--color-primary-700); outline-offset: 2px; }
/* Тап-зона «Показать таблицей» (summary таблицы-дубля «Мой поток»): высота ≥2rem. */
[data-chart-table] > summary { display: flex; align-items: center; min-height: 2rem; }
@media (min-width: 640px) {
  .flow-funnel__num { font-size: var(--text-3xl); }
  .flow-funnel__label, .flow-funnel__sub { font-size: var(--text-sm); }
}
